2017-11-18 02:14:09 +08:00
|
|
|
//===- WriterUtils.cpp ----------------------------------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2017-11-18 02:14:09 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#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;
|
|
|
|
|
|
|
|
namespace lld {
|
2019-10-10 13:25:39 +08:00
|
|
|
std::string 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";
|
|
|
|
case ValType::V128:
|
|
|
|
return "v128";
|
|
|
|
case ValType::EXNREF:
|
|
|
|
return "exnref";
|
2020-06-17 06:41:20 +08:00
|
|
|
case ValType::EXTERNREF:
|
|
|
|
return "externref";
|
2019-10-10 13:25:39 +08:00
|
|
|
}
|
|
|
|
llvm_unreachable("Invalid wasm::ValType");
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string toString(const WasmSignature &sig) {
|
|
|
|
SmallString<128> s("(");
|
|
|
|
for (ValType type : sig.Params) {
|
|
|
|
if (s.size() != 1)
|
|
|
|
s += ", ";
|
|
|
|
s += toString(type);
|
|
|
|
}
|
|
|
|
s += ") -> ";
|
|
|
|
if (sig.Returns.empty())
|
|
|
|
s += "void";
|
|
|
|
else
|
|
|
|
s += toString(sig.Returns[0]);
|
2020-01-29 03:23:46 +08:00
|
|
|
return std::string(s.str());
|
2019-10-10 13:25:39 +08:00
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
std::string toString(const WasmGlobalType &type) {
|
|
|
|
return (type.Mutable ? "var " : "const ") +
|
|
|
|
toString(static_cast<ValType>(type.Type));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string toString(const WasmEventType &type) {
|
|
|
|
if (type.Attribute == WASM_EVENT_ATTRIBUTE_EXCEPTION)
|
|
|
|
return "exception";
|
|
|
|
return "unknown";
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace wasm {
|
|
|
|
void 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
|
|
|
}
|
|
|
|
|
2020-06-06 00:03:12 +08:00
|
|
|
void writeUleb128(raw_ostream &os, uint64_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);
|
|
|
|
}
|
|
|
|
|
2020-06-06 00:03:12 +08:00
|
|
|
void writeSleb128(raw_ostream &os, int64_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);
|
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void 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
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void 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
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void writeU8(raw_ostream &os, uint8_t byte, const Twine &msg) {
|
2018-03-01 08:42:57 +08:00
|
|
|
debugWrite(os.tell(), msg + " [0x" + utohexstr(byte) + "]");
|
|
|
|
os << byte;
|
|
|
|
}
|
2017-11-18 02:14:09 +08:00
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void writeU32(raw_ostream &os, uint32_t number, const Twine &msg) {
|
2018-03-01 08:42:57 +08:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-04-30 04:26:27 +08:00
|
|
|
void writeU64(raw_ostream &os, uint64_t number, const Twine &msg) {
|
|
|
|
debugWrite(os.tell(), msg + "[0x" + utohexstr(number) + "]");
|
|
|
|
support::endian::write(os, number, support::little);
|
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void writeValueType(raw_ostream &os, ValType type, const Twine &msg) {
|
2018-10-04 06:25:32 +08:00
|
|
|
writeU8(os, static_cast<uint8_t>(type),
|
2018-11-01 09:08:37 +08:00
|
|
|
msg + "[type: " + toString(type) + "]");
|
2017-11-18 02:14:09 +08:00
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void 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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void writeI32Const(raw_ostream &os, int32_t number, const Twine &msg) {
|
2019-09-05 03:50:39 +08:00
|
|
|
writeU8(os, WASM_OPCODE_I32_CONST, "i32.const");
|
|
|
|
writeSleb128(os, number, msg);
|
|
|
|
}
|
|
|
|
|
2020-06-06 00:03:12 +08:00
|
|
|
void writeI64Const(raw_ostream &os, int64_t number, const Twine &msg) {
|
2019-09-05 03:50:39 +08:00
|
|
|
writeU8(os, WASM_OPCODE_I64_CONST, "i64.const");
|
|
|
|
writeSleb128(os, number, msg);
|
|
|
|
}
|
|
|
|
|
2020-06-06 00:03:12 +08:00
|
|
|
void writeMemArg(raw_ostream &os, uint32_t alignment, uint64_t offset) {
|
2019-09-05 03:50:39 +08:00
|
|
|
writeUleb128(os, alignment, "alignment");
|
|
|
|
writeUleb128(os, offset, "offset");
|
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void writeInitExpr(raw_ostream &os, const WasmInitExpr &initExpr) {
|
2017-11-18 02:14:09 +08:00
|
|
|
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;
|
2020-04-30 04:26:27 +08:00
|
|
|
case WASM_OPCODE_F32_CONST:
|
|
|
|
writeU32(os, initExpr.Value.Float32, "literal (f32)");
|
|
|
|
break;
|
|
|
|
case WASM_OPCODE_F64_CONST:
|
|
|
|
writeU64(os, initExpr.Value.Float64, "literal (f64)");
|
|
|
|
break;
|
2019-01-08 14:25:55 +08:00
|
|
|
case WASM_OPCODE_GLOBAL_GET:
|
2017-11-18 02:14:09 +08:00
|
|
|
writeUleb128(os, initExpr.Value.Global, "literal (global index)");
|
|
|
|
break;
|
2020-06-17 06:41:20 +08:00
|
|
|
case WASM_OPCODE_REF_NULL:
|
|
|
|
writeValueType(os, ValType::EXTERNREF, "literal (externref type)");
|
|
|
|
break;
|
2017-11-18 02:14:09 +08:00
|
|
|
default:
|
|
|
|
fatal("unknown opcode in init expr: " + Twine(initExpr.Opcode));
|
|
|
|
}
|
|
|
|
writeU8(os, WASM_OPCODE_END, "opcode:end");
|
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void 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");
|
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void 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
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void 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);
|
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void writeEventType(raw_ostream &os, const WasmEventType &type) {
|
2018-12-08 14:17:43 +08:00
|
|
|
writeUleb128(os, type.Attribute, "event attribute");
|
|
|
|
writeUleb128(os, type.SigIndex, "sig index");
|
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void writeEvent(raw_ostream &os, const WasmEvent &event) {
|
2018-12-08 14:17:43 +08:00
|
|
|
writeEventType(os, event.Type);
|
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void writeTableType(raw_ostream &os, const llvm::wasm::WasmTable &type) {
|
2019-01-08 14:25:55 +08:00
|
|
|
writeU8(os, WASM_TYPE_FUNCREF, "table type");
|
2018-03-28 01:38:51 +08:00
|
|
|
writeLimits(os, type.Limits);
|
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void writeImport(raw_ostream &os, const WasmImport &import) {
|
2017-11-18 02:14:09 +08:00
|
|
|
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;
|
2018-12-08 14:17:43 +08:00
|
|
|
case WASM_EXTERNAL_EVENT:
|
|
|
|
writeEventType(os, import.Event);
|
|
|
|
break;
|
2017-11-18 02:14:09 +08:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
void writeExport(raw_ostream &os, const WasmExport &export_) {
|
2017-11-18 02:14:09 +08:00
|
|
|
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;
|
2020-04-04 21:56:35 +08:00
|
|
|
case WASM_EXTERNAL_EVENT:
|
|
|
|
writeUleb128(os, export_.Index, "event index");
|
|
|
|
break;
|
2017-11-18 02:14:09 +08:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
2018-12-08 14:17:43 +08:00
|
|
|
|
2019-10-10 13:25:39 +08:00
|
|
|
} // namespace wasm
|
|
|
|
} // namespace lld
|