2017-11-18 02:14:09 +08:00
|
|
|
//===- WriterUtils.cpp ----------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Linker
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "WriterUtils.h"
|
|
|
|
#include "lld/Common/ErrorHandler.h"
|
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Support/EndianStream.h"
|
|
|
|
#include "llvm/Support/LEB128.h"
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "lld"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::wasm;
|
|
|
|
using namespace lld::wasm;
|
|
|
|
|
2018-10-04 06:25:32 +08:00
|
|
|
static const char *valueTypeToString(ValType Type) {
|
2017-11-18 02:14:09 +08:00
|
|
|
switch (Type) {
|
2018-10-04 06:25:32 +08:00
|
|
|
case wasm::ValType::I32:
|
2017-11-18 02:14:09 +08:00
|
|
|
return "i32";
|
2018-10-04 06:25:32 +08:00
|
|
|
case wasm::ValType::I64:
|
2017-11-18 02:14:09 +08:00
|
|
|
return "i64";
|
2018-10-04 06:25:32 +08:00
|
|
|
case wasm::ValType::F32:
|
2017-11-18 02:14:09 +08:00
|
|
|
return "f32";
|
2018-10-04 06:25:32 +08:00
|
|
|
case wasm::ValType::F64:
|
2017-11-18 02:14:09 +08:00
|
|
|
return "f64";
|
|
|
|
default:
|
|
|
|
llvm_unreachable("invalid value type");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace lld {
|
|
|
|
|
2018-02-17 04:38:00 +08:00
|
|
|
void wasm::debugWrite(uint64_t Offset, const Twine &Msg) {
|
2018-05-15 21:36:20 +08:00
|
|
|
LLVM_DEBUG(dbgs() << format(" | %08lld: ", Offset) << Msg << "\n");
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
2018-03-01 08:42:57 +08:00
|
|
|
void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
|
2018-02-17 04:38:00 +08:00
|
|
|
debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]");
|
2017-11-18 02:14:09 +08:00
|
|
|
encodeULEB128(Number, OS);
|
|
|
|
}
|
|
|
|
|
2018-03-01 08:42:57 +08:00
|
|
|
void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg) {
|
2018-02-17 04:38:00 +08:00
|
|
|
debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]");
|
2017-11-18 02:14:09 +08:00
|
|
|
encodeSLEB128(Number, OS);
|
|
|
|
}
|
|
|
|
|
2018-02-17 03:53:29 +08:00
|
|
|
void wasm::writeBytes(raw_ostream &OS, const char *Bytes, size_t Count,
|
2018-03-01 08:42:57 +08:00
|
|
|
const Twine &Msg) {
|
2018-02-17 04:38:00 +08:00
|
|
|
debugWrite(OS.tell(), Msg + " [data[" + Twine(Count) + "]]");
|
2018-02-17 03:53:29 +08:00
|
|
|
OS.write(Bytes, Count);
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
2018-03-01 08:42:57 +08:00
|
|
|
void wasm::writeStr(raw_ostream &OS, StringRef String, const Twine &Msg) {
|
2018-02-17 04:38:00 +08:00
|
|
|
debugWrite(OS.tell(),
|
|
|
|
Msg + " [str[" + Twine(String.size()) + "]: " + String + "]");
|
|
|
|
encodeULEB128(String.size(), OS);
|
|
|
|
OS.write(String.data(), String.size());
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
2018-03-01 08:42:57 +08:00
|
|
|
void wasm::writeU8(raw_ostream &OS, uint8_t Byte, const Twine &Msg) {
|
|
|
|
debugWrite(OS.tell(), Msg + " [0x" + utohexstr(Byte) + "]");
|
|
|
|
OS << Byte;
|
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
|
2018-03-01 08:42:57 +08:00
|
|
|
void wasm::writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg) {
|
|
|
|
debugWrite(OS.tell(), Msg + "[0x" + utohexstr(Number) + "]");
|
2018-05-19 03:46:24 +08:00
|
|
|
support::endian::write(OS, Number, support::little);
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
2018-10-04 06:25:32 +08:00
|
|
|
void wasm::writeValueType(raw_ostream &OS, ValType Type, const Twine &Msg) {
|
|
|
|
writeU8(OS, static_cast<uint8_t>(Type),
|
|
|
|
Msg + "[type: " + valueTypeToString(Type) + "]");
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) {
|
2018-03-02 02:06:39 +08:00
|
|
|
writeU8(OS, WASM_TYPE_FUNC, "signature type");
|
2018-10-04 06:25:32 +08:00
|
|
|
writeUleb128(OS, Sig.Params.size(), "param Count");
|
|
|
|
for (ValType ParamType : Sig.Params) {
|
2017-11-18 02:14:09 +08:00
|
|
|
writeValueType(OS, ParamType, "param type");
|
|
|
|
}
|
2018-10-04 06:25:32 +08:00
|
|
|
writeUleb128(OS, Sig.Returns.size(), "result Count");
|
|
|
|
if (Sig.Returns.size()) {
|
|
|
|
writeValueType(OS, Sig.Returns[0], "result type");
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) {
|
|
|
|
writeU8(OS, InitExpr.Opcode, "opcode");
|
|
|
|
switch (InitExpr.Opcode) {
|
|
|
|
case WASM_OPCODE_I32_CONST:
|
|
|
|
writeSleb128(OS, InitExpr.Value.Int32, "literal (i32)");
|
|
|
|
break;
|
|
|
|
case WASM_OPCODE_I64_CONST:
|
|
|
|
writeSleb128(OS, InitExpr.Value.Int64, "literal (i64)");
|
|
|
|
break;
|
|
|
|
case WASM_OPCODE_GET_GLOBAL:
|
|
|
|
writeUleb128(OS, InitExpr.Value.Global, "literal (global index)");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fatal("unknown opcode in init expr: " + Twine(InitExpr.Opcode));
|
|
|
|
}
|
|
|
|
writeU8(OS, WASM_OPCODE_END, "opcode:end");
|
|
|
|
}
|
|
|
|
|
|
|
|
void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) {
|
2018-03-02 02:06:39 +08:00
|
|
|
writeU8(OS, Limits.Flags, "limits flags");
|
2017-11-18 02:14:09 +08:00
|
|
|
writeUleb128(OS, Limits.Initial, "limits initial");
|
|
|
|
if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
|
|
|
|
writeUleb128(OS, Limits.Maximum, "limits max");
|
|
|
|
}
|
|
|
|
|
2018-02-01 03:54:34 +08:00
|
|
|
void wasm::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) {
|
2018-10-04 06:25:32 +08:00
|
|
|
// TODO: Update WasmGlobalType to use ValType and remove this cast.
|
|
|
|
writeValueType(OS, ValType(Type.Type), "global type");
|
2018-03-02 02:06:39 +08:00
|
|
|
writeU8(OS, Type.Mutable, "global mutable");
|
2018-02-01 03:54:34 +08:00
|
|
|
}
|
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) {
|
2018-02-01 03:54:34 +08:00
|
|
|
writeGlobalType(OS, Global.Type);
|
2017-11-18 02:14:09 +08:00
|
|
|
writeInitExpr(OS, Global.InitExpr);
|
|
|
|
}
|
|
|
|
|
2018-03-28 01:38:51 +08:00
|
|
|
void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) {
|
|
|
|
writeU8(OS, WASM_TYPE_ANYFUNC, "table type");
|
|
|
|
writeLimits(OS, Type.Limits);
|
|
|
|
}
|
|
|
|
|
2017-11-18 02:14:09 +08:00
|
|
|
void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) {
|
|
|
|
writeStr(OS, Import.Module, "import module name");
|
|
|
|
writeStr(OS, Import.Field, "import field name");
|
|
|
|
writeU8(OS, Import.Kind, "import kind");
|
|
|
|
switch (Import.Kind) {
|
|
|
|
case WASM_EXTERNAL_FUNCTION:
|
|
|
|
writeUleb128(OS, Import.SigIndex, "import sig index");
|
|
|
|
break;
|
|
|
|
case WASM_EXTERNAL_GLOBAL:
|
2018-02-01 03:54:34 +08:00
|
|
|
writeGlobalType(OS, Import.Global);
|
2017-11-18 02:14:09 +08:00
|
|
|
break;
|
|
|
|
case WASM_EXTERNAL_MEMORY:
|
|
|
|
writeLimits(OS, Import.Memory);
|
|
|
|
break;
|
2018-03-28 01:38:51 +08:00
|
|
|
case WASM_EXTERNAL_TABLE:
|
|
|
|
writeTableType(OS, Import.Table);
|
|
|
|
break;
|
2017-11-18 02:14:09 +08:00
|
|
|
default:
|
|
|
|
fatal("unsupported import type: " + Twine(Import.Kind));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) {
|
|
|
|
writeStr(OS, Export.Name, "export name");
|
|
|
|
writeU8(OS, Export.Kind, "export kind");
|
|
|
|
switch (Export.Kind) {
|
|
|
|
case WASM_EXTERNAL_FUNCTION:
|
|
|
|
writeUleb128(OS, Export.Index, "function index");
|
|
|
|
break;
|
|
|
|
case WASM_EXTERNAL_GLOBAL:
|
|
|
|
writeUleb128(OS, Export.Index, "global index");
|
|
|
|
break;
|
|
|
|
case WASM_EXTERNAL_MEMORY:
|
|
|
|
writeUleb128(OS, Export.Index, "memory index");
|
|
|
|
break;
|
2018-03-28 01:38:51 +08:00
|
|
|
case WASM_EXTERNAL_TABLE:
|
|
|
|
writeUleb128(OS, Export.Index, "table index");
|
|
|
|
break;
|
2017-11-18 02:14:09 +08:00
|
|
|
default:
|
|
|
|
fatal("unsupported export type: " + Twine(Export.Kind));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace lld
|
2017-11-30 09:40:08 +08:00
|
|
|
|
|
|
|
std::string lld::toString(ValType Type) {
|
|
|
|
switch (Type) {
|
|
|
|
case ValType::I32:
|
|
|
|
return "I32";
|
|
|
|
case ValType::I64:
|
|
|
|
return "I64";
|
|
|
|
case ValType::F32:
|
|
|
|
return "F32";
|
|
|
|
case ValType::F64:
|
|
|
|
return "F64";
|
2018-09-21 06:07:18 +08:00
|
|
|
case ValType::V128:
|
|
|
|
return "V128";
|
2018-03-08 12:06:57 +08:00
|
|
|
case ValType::EXCEPT_REF:
|
|
|
|
return "except_ref";
|
2017-11-30 09:40:08 +08:00
|
|
|
}
|
|
|
|
llvm_unreachable("Invalid wasm::ValType");
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string lld::toString(const WasmSignature &Sig) {
|
|
|
|
SmallString<128> S("(");
|
2018-10-04 06:25:32 +08:00
|
|
|
for (ValType Type : Sig.Params) {
|
2017-11-30 09:40:08 +08:00
|
|
|
if (S.size() != 1)
|
|
|
|
S += ", ";
|
2018-10-04 06:25:32 +08:00
|
|
|
S += toString(Type);
|
2017-11-30 09:40:08 +08:00
|
|
|
}
|
|
|
|
S += ") -> ";
|
2018-10-04 06:25:32 +08:00
|
|
|
if (Sig.Returns.size() == 0)
|
2017-11-30 09:40:08 +08:00
|
|
|
S += "void";
|
|
|
|
else
|
2018-10-04 06:25:32 +08:00
|
|
|
S += toString(Sig.Returns[0]);
|
2017-11-30 09:40:08 +08:00
|
|
|
return S.str();
|
|
|
|
}
|
2018-02-23 13:08:53 +08:00
|
|
|
|
|
|
|
std::string lld::toString(const WasmGlobalType &Sig) {
|
2018-03-02 22:54:34 +08:00
|
|
|
return (Sig.Mutable ? "var " : "const ") +
|
2018-03-07 21:28:16 +08:00
|
|
|
toString(static_cast<ValType>(Sig.Type));
|
2018-02-23 13:08:53 +08:00
|
|
|
}
|