Commit 78f6f838 authored by binji's avatar binji Committed by Commit bot

[Wasm] Convert many of the fixed-size values to LEB128.

This CL modifies the following to be LEB128:
* Function table indices
* Import table signature indices
* Export table function indices
* Function signature param count
* br/br_if break depth
* br_table target count
* block/loop expression count

Still to do:
* Import/export names (LEB128 count + inline data)
* Data segments (LEB128 offset + size + inline data)
* Function header stuff (should seperate into function sig and body sections)
* Memory access alignment + offset (still discussing)

BUG=
R=titzer@chromium.org

Review URL: https://codereview.chromium.org/1775873002

Cr-Commit-Position: refs/heads/master@{#34603}
parent fd405704
......@@ -138,13 +138,14 @@ class AsmWasmBuilderImpl : public AstVisitor {
: builder_(builder) {
builder_->breakable_blocks_.push_back(std::make_pair(stmt, is_loop));
builder_->current_function_builder_->Emit(opcode);
index_ = builder_->current_function_builder_->EmitEditableImmediate(0);
index_ =
builder_->current_function_builder_->EmitEditableVarIntImmediate();
prev_block_size_ = builder_->block_size_;
builder_->block_size_ = initial_block_size;
}
~BlockVisitor() {
builder_->current_function_builder_->EditImmediate(index_,
builder_->block_size_);
builder_->current_function_builder_->EditVarIntImmediate(
index_, builder_->block_size_);
builder_->block_size_ = prev_block_size_;
builder_->breakable_blocks_.pop_back();
}
......@@ -193,7 +194,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
}
}
DCHECK(i >= 0);
current_function_builder_->EmitWithU8(kExprBr, block_distance);
current_function_builder_->EmitWithVarInt(kExprBr, block_distance);
current_function_builder_->Emit(kExprNop);
}
......@@ -216,7 +217,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
}
}
DCHECK(i >= 0);
current_function_builder_->EmitWithU8(kExprBr, block_distance);
current_function_builder_->EmitWithVarInt(kExprBr, block_distance);
current_function_builder_->Emit(kExprNop);
}
......@@ -292,7 +293,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
RECURSE(Visit(stmt->body()));
current_function_builder_->Emit(kExprIf);
RECURSE(Visit(stmt->cond()));
current_function_builder_->EmitWithU8(kExprBr, 0);
current_function_builder_->EmitWithVarInt(kExprBr, 0);
current_function_builder_->Emit(kExprNop);
}
......@@ -302,7 +303,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
1);
current_function_builder_->Emit(kExprIf);
RECURSE(Visit(stmt->cond()));
current_function_builder_->EmitWithU8(kExprBr, 0);
current_function_builder_->EmitWithVarInt(kExprBr, 0);
RECURSE(Visit(stmt->body()));
}
......@@ -319,7 +320,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
current_function_builder_->Emit(kExprIf);
current_function_builder_->Emit(kExprI32Eqz);
RECURSE(Visit(stmt->cond()));
current_function_builder_->EmitWithU8(kExprBr, 1);
current_function_builder_->EmitWithVarInt(kExprBr, 1);
current_function_builder_->Emit(kExprNop);
}
if (stmt->body() != nullptr) {
......@@ -331,7 +332,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
RECURSE(Visit(stmt->next()));
}
block_size_++;
current_function_builder_->EmitWithU8(kExprBr, 0);
current_function_builder_->EmitWithVarInt(kExprBr, 0);
current_function_builder_->Emit(kExprNop);
}
......@@ -1058,7 +1059,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
VariableProxy* var = p->obj()->AsVariableProxy();
DCHECK_NOT_NULL(var);
FunctionTableIndices* indices = LookupFunctionTable(var->var());
current_function_builder_->EmitWithU8(kExprCallIndirect,
current_function_builder_->EmitWithVarInt(kExprCallIndirect,
indices->signature_index);
current_function_builder_->Emit(kExprI32Add);
// TODO(bradnelson): variable size
......@@ -1283,7 +1284,7 @@ class AsmWasmBuilderImpl : public AstVisitor {
break;
}
case Token::COMMA: {
current_function_builder_->EmitWithU8(kExprBlock, 2);
current_function_builder_->EmitWithVarInt(kExprBlock, 2);
break;
}
default:
......
......@@ -200,7 +200,7 @@ class WasmDecoder : public Decoder {
size_t block_depth) {
// Verify table.
for (uint32_t i = 0; i < operand.table_count + 1; i++) {
uint16_t target = operand.read_entry(this, i);
uint32_t target = operand.read_entry(this, i);
if (target >= block_depth) {
error(operand.table + i * 2, "improper branch in br_table");
return false;
......@@ -1107,7 +1107,7 @@ class SR_WasmDecoder : public WasmDecoder {
SsaEnv* prev = ssa_env_;
SsaEnv* copy = Steal(prev);
for (uint32_t i = 0; i < operand.table_count + 1; i++) {
uint16_t target = operand.read_entry(this, i);
uint32_t target = operand.read_entry(this, i);
SsaEnv* env = copy;
if (build_switch) {
ssa_env_ = env = Split(env);
......
......@@ -97,8 +97,7 @@ struct BreakDepthOperand {
Block* target;
int length;
inline BreakDepthOperand(Decoder* decoder, const byte* pc) {
depth = decoder->checked_read_u8(pc, 1, "break depth");
length = 1;
depth = decoder->checked_read_u32v(pc, 1, &length, "break depth");
target = nullptr;
}
};
......@@ -107,8 +106,7 @@ struct BlockCountOperand {
uint32_t count;
int length;
inline BlockCountOperand(Decoder* decoder, const byte* pc) {
count = decoder->checked_read_u8(pc, 1, "block count");
length = 1;
count = decoder->checked_read_u32v(pc, 1, &length, "block count");
}
};
......@@ -147,19 +145,22 @@ struct BranchTableOperand {
const byte* table;
int length;
inline BranchTableOperand(Decoder* decoder, const byte* pc) {
table_count = decoder->checked_read_u16(pc, 1, "expected #entries");
length = 2 + table_count * 2 + 2;
int varint_length;
table_count =
decoder->checked_read_u32v(pc, 1, &varint_length, "expected #entries");
length = varint_length + (table_count + 1) * sizeof(uint32_t);
if (decoder->check(pc, 3, table_count * 2 + 2,
uint32_t table_start = 1 + varint_length;
if (decoder->check(pc, table_start, (table_count + 1) * sizeof(uint32_t),
"expected <table entries>")) {
table = pc + 3;
table = pc + table_start;
} else {
table = nullptr;
}
}
inline uint16_t read_entry(Decoder* decoder, int i) {
inline uint32_t read_entry(Decoder* decoder, int i) {
DCHECK(i >= 0 && static_cast<uint32_t>(i) <= table_count);
return table ? decoder->read_u16(table + i * sizeof(uint16_t)) : 0;
return table ? decoder->read_u32(table + i * sizeof(uint32_t)) : 0;
}
};
......
......@@ -55,6 +55,16 @@ void EmitVarInt(byte** b, size_t val) {
}
}
}
size_t SizeOfVarInt(size_t value) {
size_t size = 0;
do {
size++;
value = value >> 7;
} while (value > 0);
return size;
}
} // namespace
......@@ -121,16 +131,41 @@ void WasmFunctionBuilder::EmitWithU8(WasmOpcode opcode, const byte immediate) {
body_.push_back(immediate);
}
void WasmFunctionBuilder::EmitWithVarInt(WasmOpcode opcode,
uint32_t immediate) {
body_.push_back(static_cast<byte>(opcode));
size_t immediate_size = SizeOfVarInt(immediate);
body_.insert(body_.end(), immediate_size, 0);
byte* p = &body_[body_.size() - immediate_size];
EmitVarInt(&p, immediate);
}
uint32_t WasmFunctionBuilder::EmitEditableImmediate(const byte immediate) {
body_.push_back(immediate);
uint32_t WasmFunctionBuilder::EmitEditableVarIntImmediate() {
// Guess that the immediate will be 1 byte. If it is more, we'll have to
// shift everything down.
body_.push_back(0);
return static_cast<uint32_t>(body_.size()) - 1;
}
void WasmFunctionBuilder::EditVarIntImmediate(uint32_t offset,
const uint32_t immediate) {
uint32_t immediate_size = static_cast<uint32_t>(SizeOfVarInt(immediate));
// In EmitEditableVarIntImmediate, we guessed that we'd only need one byte.
// If we need more, shift everything down to make room for the larger
// immediate.
if (immediate_size > 1) {
uint32_t diff = immediate_size - 1;
body_.insert(body_.begin() + offset, diff, 0);
void WasmFunctionBuilder::EditImmediate(uint32_t offset, const byte immediate) {
DCHECK(offset < body_.size());
body_[offset] = immediate;
for (size_t i = 0; i < local_indices_.size(); ++i) {
if (local_indices_[i] >= offset) {
local_indices_[i] += diff;
}
}
}
DCHECK(offset + immediate_size <= body_.size());
byte* p = &body_[offset];
EmitVarInt(&p, immediate);
}
......@@ -446,15 +481,6 @@ WasmModuleWriter::WasmModuleWriter(Zone* zone)
indirect_functions_(zone),
globals_(zone) {}
size_t SizeOfVarInt(size_t value) {
size_t size = 0;
do {
size++;
value = value >> 7;
} while (value > 0);
return size;
}
struct Sizes {
size_t header_size;
size_t body_size;
......@@ -485,7 +511,8 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
sizes.AddSection(signatures_.size());
for (auto sig : signatures_) {
sizes.Add(2 + sig->parameter_count(), 0);
sizes.Add(1 + SizeOfVarInt(sig->parameter_count()) + sig->parameter_count(),
0);
}
sizes.AddSection(globals_.size());
......@@ -510,7 +537,9 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
}
sizes.AddSection(indirect_functions_.size());
sizes.Add(2 * static_cast<uint32_t>(indirect_functions_.size()), 0);
for (auto function_index : indirect_functions_) {
sizes.Add(SizeOfVarInt(function_index), 0);
}
if (sizes.body_size > 0) sizes.Add(1, 0);
......@@ -525,8 +554,8 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
// -- emit memory declaration ------------------------------------------------
EmitUint8(&header, kDeclMemory);
EmitUint8(&header, 16); // min memory size
EmitUint8(&header, 16); // max memory size
EmitVarInt(&header, 16); // min memory size
EmitVarInt(&header, 16); // max memory size
EmitUint8(&header, 0); // memory export
// -- emit globals -----------------------------------------------------------
......@@ -547,7 +576,7 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
EmitVarInt(&header, signatures_.size());
for (FunctionSig* sig : signatures_) {
EmitUint8(&header, static_cast<byte>(sig->parameter_count()));
EmitVarInt(&header, sig->parameter_count());
if (sig->return_count() > 0) {
EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetReturn()));
} else {
......@@ -591,7 +620,7 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
EmitVarInt(&header, indirect_functions_.size());
for (auto index : indirect_functions_) {
EmitUint16(&header, index);
EmitVarInt(&header, index);
}
}
......
......@@ -55,8 +55,9 @@ class WasmFunctionBuilder : public ZoneObject {
const uint32_t* local_indices, uint32_t indices_size);
void Emit(WasmOpcode opcode);
void EmitWithU8(WasmOpcode opcode, const byte immediate);
uint32_t EmitEditableImmediate(const byte immediate);
void EditImmediate(uint32_t offset, const byte immediate);
void EmitWithVarInt(WasmOpcode opcode, uint32_t immediate);
uint32_t EmitEditableVarIntImmediate();
void EditVarIntImmediate(uint32_t offset, const uint32_t immediate);
void Exported(uint8_t flag);
void External(uint8_t flag);
void SetName(const unsigned char* name, int name_length);
......
......@@ -195,7 +195,7 @@ class ModuleDecoder : public Decoder {
if (failed()) break;
TRACE("DecodeFunctionTable[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
uint16_t index = consume_u16();
uint16_t index = consume_u32v(&length);
if (index >= module->functions.size()) {
error(pc_ - 2, "invalid function index");
break;
......@@ -244,7 +244,7 @@ class ModuleDecoder : public Decoder {
WasmImport* import = &module->import_table.back();
const byte* sigpos = pc_;
import->sig_index = consume_u16("signature index");
import->sig_index = consume_u32v(&length, "signature index");
if (import->sig_index >= module->signatures.size()) {
error(sigpos, "invalid signature index");
......@@ -278,7 +278,7 @@ class ModuleDecoder : public Decoder {
WasmExport* exp = &module->export_table.back();
const byte* sigpos = pc_;
exp->func_index = consume_u16("function index");
exp->func_index = consume_u32v(&length, "function index");
if (exp->func_index >= module->functions.size()) {
error(sigpos, sigpos,
"function index %u out of bounds (%d functions)",
......@@ -566,7 +566,8 @@ class ModuleDecoder : public Decoder {
// Parses an inline function signature.
FunctionSig* consume_sig() {
byte count = consume_u8("param count");
int length;
byte count = consume_u32v(&length, "param count");
LocalType ret = consume_local_type();
FunctionSig::Builder builder(module_zone, ret == kAstStmt ? 0 : 1, count);
if (ret != kAstStmt) builder.AddReturn(ret);
......
......@@ -16,9 +16,10 @@
#define WASM_MODULE_HEADER U32_LE(kWasmMagic), U32_LE(kWasmVersion)
#define SIG_INDEX(v) U16_LE(v)
#define FUNC_INDEX(v) U16_LE(v)
#define FUNC_INDEX(v) U32V_1(v)
#define NAME_OFFSET(v) U32_LE(v)
#define BR_TARGET(v) U16_LE(v)
#define BR_TARGET(v) U32_LE(v)
#define MASK_7 ((1 << 7) - 1)
#define MASK_14 ((1 << 14) - 1)
......@@ -71,7 +72,7 @@
#define WASM_UNREACHABLE kExprUnreachable
#define WASM_BR_TABLE(key, count, ...) \
kExprBrTable, U16_LE(count), __VA_ARGS__, key
kExprBrTable, U32V_1(count), __VA_ARGS__, key
#define WASM_CASE(x) static_cast<byte>(x), static_cast<byte>(x >> 8)
#define WASM_CASE_BR(x) static_cast<byte>(x), static_cast<byte>(0x80 | (x) >> 8)
......
......@@ -64,7 +64,7 @@ static const size_t kDeclDataSegmentSize = 13;
struct WasmFunction {
FunctionSig* sig; // signature of the function.
uint32_t func_index; // index into the function table.
uint16_t sig_index; // index into the signature table.
uint32_t sig_index; // index into the signature table.
uint32_t name_offset; // offset in the module bytes of the name, if any.
uint32_t code_start_offset; // offset in the module bytes of code start.
uint32_t code_end_offset; // offset in the module bytes of code end.
......@@ -79,14 +79,14 @@ struct WasmFunction {
// Static representation of an imported WASM function.
struct WasmImport {
FunctionSig* sig; // signature of the function.
uint16_t sig_index; // index into the signature table.
uint32_t sig_index; // index into the signature table.
uint32_t module_name_offset; // offset in module bytes of the module name.
uint32_t function_name_offset; // offset in module bytes of the import name.
};
// Static representation of an exported WASM function.
struct WasmExport {
uint16_t func_index; // index into the function table.
uint32_t func_index; // index into the function table.
uint32_t name_offset; // offset in module bytes of the name to export.
};
......
......@@ -1089,7 +1089,7 @@ TEST(Run_Wasm_BrTable_br2) {
TEST(Run_Wasm_BrTable4) {
for (int i = 0; i < 4; i++) {
for (int t = 0; t < 4; t++) {
uint16_t cases[] = {0, 1, 2, 3};
uint32_t cases[] = {0, 1, 2, 3};
cases[i] = t;
byte code[] = {B2(B2(B2(B2(B1(WASM_BR_TABLE(
WASM_GET_LOCAL(0), 3, BR_TARGET(cases[0]),
......@@ -1119,7 +1119,7 @@ TEST(Run_Wasm_BrTable4x4) {
for (byte c = 0; c < 4; c++) {
for (byte d = 0; d < 4; d++) {
for (int i = 0; i < 4; i++) {
uint16_t cases[] = {a, b, c, d};
uint32_t cases[] = {a, b, c, d};
byte code[] = {
B2(B2(B2(B2(B1(WASM_BR_TABLE(
WASM_GET_LOCAL(0), 3, BR_TARGET(cases[0]),
......
......@@ -164,7 +164,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
emit_varint(bytes, this.signatures.length);
for (sig of this.signatures) {
var params = sig.length - 1;
emit_u8(bytes, params);
emit_varint(bytes, params);
for (var j = 0; j < sig.length; j++) {
emit_u8(bytes, sig[j]);
}
......@@ -177,7 +177,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
emit_u8(bytes, kDeclImportTable);
emit_varint(bytes, this.imports.length);
for (imp of this.imports) {
emit_u16(bytes, imp.sig_index);
emit_varint(bytes, imp.sig_index);
emit_string(bytes, imp.module);
if (imp.name == undefined) {
emit_u32(bytes, 0);
......@@ -228,7 +228,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
local_decls.push({count: l.f64_count, type: kAstF64});
}
}
emit_u8(bytes, local_decls.length);
emit_varint(bytes, local_decls.length);
for (decl of local_decls) {
emit_varint(bytes, decl.count);
emit_u8(bytes, decl.type);
......@@ -257,7 +257,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
emit_u8(bytes, kDeclFunctionTable);
emit_varint(bytes, this.function_table.length);
for (index of this.function_table) {
emit_u16(bytes, index);
emit_varint(bytes, index);
}
}
......@@ -267,7 +267,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
emit_varint(bytes, exports);
for (func of this.functions) {
for (exp of func.exports) {
emit_u16(bytes, func.index);
emit_varint(bytes, func.index);
emit_string(bytes, exp);
}
}
......
......@@ -108,6 +108,80 @@ TEST_F(EncoderTest, Function_Builder_Indexing_Variable_Width) {
body = buffer + f->HeaderSize();
}
TEST_F(EncoderTest, Function_Builder_Block_Variable_Width) {
Zone zone;
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
uint16_t f_index = builder->AddFunction();
WasmFunctionBuilder* function = builder->FunctionAt(f_index);
function->EmitWithVarInt(kExprBlock, 200);
for (int i = 0; i < 200; ++i) {
function->Emit(kExprNop);
}
WasmFunctionEncoder* f = function->Build(&zone, builder);
CHECK_EQ(f->BodySize(), 204);
}
TEST_F(EncoderTest, Function_Builder_EmitEditableVarIntImmediate) {
Zone zone;
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
uint16_t f_index = builder->AddFunction();
WasmFunctionBuilder* function = builder->FunctionAt(f_index);
function->Emit(kExprLoop);
uint32_t offset = function->EmitEditableVarIntImmediate();
for (int i = 0; i < 200; ++i) {
function->Emit(kExprNop);
}
function->EditVarIntImmediate(offset, 200);
WasmFunctionEncoder* f = function->Build(&zone, builder);
CHECK_EQ(f->BodySize(), 204);
}
TEST_F(EncoderTest, Function_Builder_EmitEditableVarIntImmediate_Locals) {
Zone zone;
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
uint16_t f_index = builder->AddFunction();
WasmFunctionBuilder* function = builder->FunctionAt(f_index);
function->Emit(kExprBlock);
uint32_t offset = function->EmitEditableVarIntImmediate();
for (int i = 0; i < 200; ++i) {
AddLocal(function, kAstI32);
}
function->EditVarIntImmediate(offset, 200);
WasmFunctionEncoder* f = function->Build(&zone, builder);
ZoneVector<uint8_t> buffer_vector(f->HeaderSize() + f->BodySize(), &zone);
byte* buffer = &buffer_vector[0];
byte* header = buffer;
byte* body = buffer + f->HeaderSize();
f->Serialize(buffer, &header, &body);
body = buffer + f->HeaderSize();
CHECK_EQ(f->BodySize(), 479);
const uint8_t varint200_low = (200 & 0x7f) | 0x80;
const uint8_t varint200_high = (200 >> 7) & 0x7f;
offset = 0;
CHECK_EQ(body[offset++], 1); // Local decl count.
CHECK_EQ(body[offset++], varint200_low);
CHECK_EQ(body[offset++], varint200_high);
CHECK_EQ(body[offset++], kLocalI32);
CHECK_EQ(body[offset++], kExprBlock);
CHECK_EQ(body[offset++], varint200_low);
CHECK_EQ(body[offset++], varint200_high);
// GetLocal with one-byte indices.
for (int i = 0; i <= 127; ++i) {
CHECK_EQ(body[offset++], kExprGetLocal);
CHECK_EQ(body[offset++], i);
}
// GetLocal with two-byte indices.
for (int i = 128; i < 200; ++i) {
CHECK_EQ(body[offset++], kExprGetLocal);
CHECK_EQ(body[offset++], (i & 0x7f) | 0x80);
CHECK_EQ(body[offset++], (i >> 7) & 0x7f);
}
CHECK_EQ(offset, 479);
}
TEST_F(EncoderTest, LEB_Functions) {
byte leb_value[5] = {0, 0, 0, 0, 0};
......
......@@ -681,10 +681,7 @@ TEST_F(WasmModuleVerifyTest, DataSegmentWithInvalidDest) {
// To make below tests for indirect calls much shorter.
#define FUNCTION(sig_index, external) \
kDeclFunctionImport, static_cast<byte>(sig_index), \
static_cast<byte>(sig_index >> 8)
#define FUNCTION(sig_index, external) kDeclFunctionImport, SIG_INDEX(sig_index)
TEST_F(WasmModuleVerifyTest, OneIndirectFunction) {
static const byte data[] = {
......@@ -693,7 +690,7 @@ TEST_F(WasmModuleVerifyTest, OneIndirectFunction) {
// func#0 ------------------------------------------------------
kDeclFunctions, 1, FUNCTION(0, 0),
// indirect table ----------------------------------------------
kDeclFunctionTable, 1, 0, 0};
kDeclFunctionTable, 1, U32V_1(0)};
ModuleResult result = DecodeModule(data, data + arraysize(data));
EXPECT_TRUE(result.ok());
......@@ -719,14 +716,14 @@ TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) {
FUNCTION(1, 1), // --
// indirect table ----------------------------------------------
kDeclFunctionTable, 8,
U16_LE(0), // --
U16_LE(1), // --
U16_LE(2), // --
U16_LE(3), // --
U16_LE(0), // --
U16_LE(1), // --
U16_LE(2), // --
U16_LE(3), // --
U32V_1(0), // --
U32V_1(1), // --
U32V_1(2), // --
U32V_1(3), // --
U32V_1(0), // --
U32V_1(1), // --
U32V_1(2), // --
U32V_1(3), // --
};
ModuleResult result = DecodeModule(data, data + arraysize(data));
......@@ -1087,7 +1084,7 @@ TEST_F(WasmModuleVerifyTest, ImportTable_one_sig) {
VOID_VOID_SIG,
kDeclImportTable,
1, // --
SIG_INDEX(0), // sig index
U32V_1(0), // sig index
NAME_OFFSET(1), // module name
NAME_OFFSET(1) // function name
};
......
......@@ -93,7 +93,7 @@ TEST_F(WasmMacroGenTest, MacroStatements) {
}
TEST_F(WasmMacroGenTest, BrTable) {
EXPECT_SIZE(7, WASM_BR_TABLE(WASM_ZERO, 1, BR_TARGET(1)));
EXPECT_SIZE(8, WASM_BR_TABLE(WASM_ZERO, 1, BR_TARGET(1)));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment