[wasm] Refactor import handling for 0xC.

Imports and exports in 0xC can be much more than functions, including
tables, memories, and globals. This CL refactors the underlying
organization of imports and exports to support these new import types.

BUG=

Review-Url: https://codereview.chromium.org/2390113003
Cr-Commit-Position: refs/heads/master@{#40033}
This commit is contained in:
titzer 2016-10-06 05:30:38 -07:00 committed by Commit bot
parent 94c8170a88
commit 599f8a8342
23 changed files with 1290 additions and 727 deletions

View File

@ -3151,8 +3151,8 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module,
Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target, Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
wasm::FunctionSig* sig, uint32_t index, wasm::FunctionSig* sig, uint32_t index,
Handle<String> import_module, Handle<String> module_name,
MaybeHandle<String> import_function) { MaybeHandle<String> import_name) {
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Create the Graph // Create the Graph
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -3215,14 +3215,14 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) { if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
const char* function_name = nullptr; const char* function_name = nullptr;
int function_name_size = 0; int function_name_size = 0;
if (!import_function.is_null()) { if (!import_name.is_null()) {
Handle<String> handle = import_function.ToHandleChecked(); Handle<String> handle = import_name.ToHandleChecked();
function_name = handle->ToCString().get(); function_name = handle->ToCString().get();
function_name_size = handle->length(); function_name_size = handle->length();
} }
RecordFunctionCompilation( RecordFunctionCompilation(
CodeEventListener::FUNCTION_TAG, isolate, code, "wasm-to-js", index, CodeEventListener::FUNCTION_TAG, isolate, code, "wasm-to-js", index,
{import_module->ToCString().get(), import_module->length()}, {module_name->ToCString().get(), module_name->length()},
{function_name, function_name_size}); {function_name, function_name_size});
} }

View File

@ -84,8 +84,8 @@ class WasmCompilationUnit final {
// Wraps a JS function, producing a code object that can be called from WASM. // Wraps a JS function, producing a code object that can be called from WASM.
Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target, Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
wasm::FunctionSig* sig, uint32_t index, wasm::FunctionSig* sig, uint32_t index,
Handle<String> import_module, Handle<String> module_name,
MaybeHandle<String> import_function); MaybeHandle<String> import_name);
// Wraps a given wasm code object, producing a code object. // Wraps a given wasm code object, producing a code object.
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module, Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module,

View File

@ -318,7 +318,7 @@ class ModuleDecoder : public Decoder {
// ===== Imported global ========================================= // ===== Imported global =========================================
import->index = static_cast<uint32_t>(module->globals.size()); import->index = static_cast<uint32_t>(module->globals.size());
module->globals.push_back( module->globals.push_back(
{kAstStmt, false, NO_INIT, 0, true, false}); {kAstStmt, false, WasmInitExpr(), 0, true, false});
WasmGlobal* global = &module->globals.back(); WasmGlobal* global = &module->globals.back();
global->type = consume_value_type(); global->type = consume_value_type();
global->mutability = consume_u8("mutability") != 0; global->mutability = consume_u8("mutability") != 0;
@ -399,7 +399,8 @@ class ModuleDecoder : public Decoder {
TRACE("DecodeGlobal[%d] module+%d\n", i, TRACE("DecodeGlobal[%d] module+%d\n", i,
static_cast<int>(pc_ - start_)); static_cast<int>(pc_ - start_));
// Add an uninitialized global and pass a pointer to it. // Add an uninitialized global and pass a pointer to it.
module->globals.push_back({kAstStmt, false, NO_INIT, 0, false, false}); module->globals.push_back(
{kAstStmt, false, WasmInitExpr(), 0, false, false});
WasmGlobal* global = &module->globals.back(); WasmGlobal* global = &module->globals.back();
DecodeGlobalInModule(module, i, global); DecodeGlobalInModule(module, i, global);
} }
@ -545,9 +546,9 @@ class ModuleDecoder : public Decoder {
TRACE("DecodeDataSegment[%d] module+%d\n", i, TRACE("DecodeDataSegment[%d] module+%d\n", i,
static_cast<int>(pc_ - start_)); static_cast<int>(pc_ - start_));
module->data_segments.push_back({ module->data_segments.push_back({
NO_INIT, // dest_addr WasmInitExpr(), // dest_addr
0, // source_offset 0, // source_offset
0 // source_size 0 // source_size
}); });
WasmDataSegment* segment = &module->data_segments.back(); WasmDataSegment* segment = &module->data_segments.back();
DecodeDataSegmentInModule(module, segment); DecodeDataSegmentInModule(module, segment);
@ -647,13 +648,19 @@ class ModuleDecoder : public Decoder {
const byte* pos = pc(); const byte* pos = pc();
global->init = consume_init_expr(module, kAstStmt); global->init = consume_init_expr(module, kAstStmt);
switch (global->init.kind) { switch (global->init.kind) {
case WasmInitExpr::kGlobalIndex: case WasmInitExpr::kGlobalIndex: {
if (global->init.val.global_index >= index) { uint32_t other_index = global->init.val.global_index;
if (other_index >= index) {
error("invalid global index in init expression"); error("invalid global index in init expression");
} else if (module->globals[index].type != global->type) { } else if (module->globals[other_index].type != global->type) {
error("type mismatch in global initialization"); error(pos, pos,
"type mismatch in global initialization "
"(from global #%u), expected %s, got %s",
other_index, WasmOpcodes::TypeName(global->type),
WasmOpcodes::TypeName(module->globals[other_index].type));
} }
break; break;
}
default: default:
if (global->type != TypeOf(module, global->init)) { if (global->type != TypeOf(module, global->init)) {
error(pos, pos, error(pos, pos,

View File

@ -255,8 +255,9 @@ void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder* function) {
} }
uint32_t WasmModuleBuilder::AddGlobal(LocalType type, bool exported, uint32_t WasmModuleBuilder::AddGlobal(LocalType type, bool exported,
bool mutability) { bool mutability,
globals_.push_back({type, exported, mutability}); const WasmInitExpr& init) {
globals_.push_back({type, exported, mutability, init});
return static_cast<uint32_t>(globals_.size() - 1); return static_cast<uint32_t>(globals_.size() - 1);
} }
@ -344,29 +345,64 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
for (auto global : globals_) { for (auto global : globals_) {
buffer.write_u8(WasmOpcodes::LocalTypeCodeFor(global.type)); buffer.write_u8(WasmOpcodes::LocalTypeCodeFor(global.type));
buffer.write_u8(global.mutability ? 1 : 0); buffer.write_u8(global.mutability ? 1 : 0);
switch (global.type) { switch (global.init.kind) {
case kAstI32: { case WasmInitExpr::kI32Const: {
static const byte code[] = {WASM_I32V_1(0)}; DCHECK_EQ(kAstI32, global.type);
const byte code[] = {WASM_I32V_5(global.init.val.i32_const)};
buffer.write(code, sizeof(code)); buffer.write(code, sizeof(code));
break; break;
} }
case kAstF32: { case WasmInitExpr::kI64Const: {
static const byte code[] = {WASM_F32(0)}; DCHECK_EQ(kAstI64, global.type);
const byte code[] = {WASM_I64V_10(global.init.val.i64_const)};
buffer.write(code, sizeof(code)); buffer.write(code, sizeof(code));
break; break;
} }
case kAstI64: { case WasmInitExpr::kF32Const: {
static const byte code[] = {WASM_I64V_1(0)}; DCHECK_EQ(kAstF32, global.type);
const byte code[] = {WASM_F32(global.init.val.f32_const)};
buffer.write(code, sizeof(code)); buffer.write(code, sizeof(code));
break; break;
} }
case kAstF64: { case WasmInitExpr::kF64Const: {
static const byte code[] = {WASM_F64(0.0)}; DCHECK_EQ(kAstF64, global.type);
const byte code[] = {WASM_F64(global.init.val.f64_const)};
buffer.write(code, sizeof(code)); buffer.write(code, sizeof(code));
break; break;
} }
default: case WasmInitExpr::kGlobalIndex: {
UNREACHABLE(); const byte code[] = {kExprGetGlobal,
U32V_5(global.init.val.global_index)};
buffer.write(code, sizeof(code));
break;
}
default: {
// No initializer, emit a default value.
switch (global.type) {
case kAstI32: {
const byte code[] = {WASM_I32V_1(0)};
buffer.write(code, sizeof(code));
break;
}
case kAstI64: {
const byte code[] = {WASM_I64V_1(0)};
buffer.write(code, sizeof(code));
break;
}
case kAstF32: {
const byte code[] = {WASM_F32(0.0)};
buffer.write(code, sizeof(code));
break;
}
case kAstF64: {
const byte code[] = {WASM_F64(0.0)};
buffer.write(code, sizeof(code));
break;
}
default:
UNREACHABLE();
}
}
} }
buffer.write_u8(kExprEnd); buffer.write_u8(kExprEnd);
} }

View File

@ -212,7 +212,8 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
imports_[index].name_length = name_length; imports_[index].name_length = name_length;
} }
WasmFunctionBuilder* AddFunction(FunctionSig* sig = nullptr); WasmFunctionBuilder* AddFunction(FunctionSig* sig = nullptr);
uint32_t AddGlobal(LocalType type, bool exported, bool mutability = true); uint32_t AddGlobal(LocalType type, bool exported, bool mutability = true,
const WasmInitExpr& init = WasmInitExpr());
void AddDataSegment(const byte* data, uint32_t size, uint32_t dest); void AddDataSegment(const byte* data, uint32_t size, uint32_t dest);
uint32_t AddSignature(FunctionSig* sig); uint32_t AddSignature(FunctionSig* sig);
void AddIndirectFunction(uint32_t index); void AddIndirectFunction(uint32_t index);
@ -241,6 +242,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
LocalType type; LocalType type;
bool exported; bool exported;
bool mutability; bool mutability;
WasmInitExpr init;
}; };
struct WasmDataSegment { struct WasmDataSegment {

File diff suppressed because it is too large Load Diff

View File

@ -86,12 +86,16 @@ struct WasmInitExpr {
double f64_const; double f64_const;
uint32_t global_index; uint32_t global_index;
} val; } val;
};
#define NO_INIT \ WasmInitExpr() : kind(kNone) {}
{ \ explicit WasmInitExpr(int32_t v) : kind(kI32Const) { val.i32_const = v; }
WasmInitExpr::kNone, { 0u } \ explicit WasmInitExpr(int64_t v) : kind(kI64Const) { val.i64_const = v; }
explicit WasmInitExpr(float v) : kind(kF32Const) { val.f32_const = v; }
explicit WasmInitExpr(double v) : kind(kF64Const) { val.f64_const = v; }
WasmInitExpr(WasmInitKind kind, uint32_t global_index) : kind(kGlobalIndex) {
val.global_index = global_index;
} }
};
// Static representation of a WASM function. // Static representation of a WASM function.
struct WasmFunction { struct WasmFunction {
@ -384,8 +388,9 @@ class WasmCompiledModule : public FixedArray {
#define CORE_WCM_PROPERTY_TABLE(MACRO) \ #define CORE_WCM_PROPERTY_TABLE(MACRO) \
MACRO(OBJECT, FixedArray, code_table) \ MACRO(OBJECT, FixedArray, code_table) \
MACRO(OBJECT, FixedArray, import_data) \ MACRO(OBJECT, FixedArray, imports) \
MACRO(OBJECT, FixedArray, exports) \ MACRO(OBJECT, FixedArray, exports) \
MACRO(OBJECT, FixedArray, inits) \
MACRO(OBJECT, FixedArray, startup_function) \ MACRO(OBJECT, FixedArray, startup_function) \
MACRO(OBJECT, FixedArray, indirect_function_tables) \ MACRO(OBJECT, FixedArray, indirect_function_tables) \
MACRO(OBJECT, String, module_bytes) \ MACRO(OBJECT, String, module_bytes) \
@ -395,7 +400,6 @@ class WasmCompiledModule : public FixedArray {
MACRO(OBJECT, ByteArray, data_segments) \ MACRO(OBJECT, ByteArray, data_segments) \
MACRO(SMALL_NUMBER, uint32_t, globals_size) \ MACRO(SMALL_NUMBER, uint32_t, globals_size) \
MACRO(OBJECT, JSArrayBuffer, heap) \ MACRO(OBJECT, JSArrayBuffer, heap) \
MACRO(SMALL_NUMBER, bool, export_memory) \
MACRO(SMALL_NUMBER, ModuleOrigin, origin) \ MACRO(SMALL_NUMBER, ModuleOrigin, origin) \
MACRO(WEAK_LINK, WasmCompiledModule, next_instance) \ MACRO(WEAK_LINK, WasmCompiledModule, next_instance) \
MACRO(WEAK_LINK, WasmCompiledModule, prev_instance) \ MACRO(WEAK_LINK, WasmCompiledModule, prev_instance) \
@ -424,7 +428,6 @@ class WasmCompiledModule : public FixedArray {
static Handle<WasmCompiledModule> New(Isolate* isolate, static Handle<WasmCompiledModule> New(Isolate* isolate,
uint32_t min_memory_pages, uint32_t min_memory_pages,
uint32_t globals_size, uint32_t globals_size,
bool export_memory,
ModuleOrigin origin); ModuleOrigin origin);
static Handle<WasmCompiledModule> Clone(Isolate* isolate, static Handle<WasmCompiledModule> Clone(Isolate* isolate,
@ -454,9 +457,6 @@ class WasmCompiledModule : public FixedArray {
void PrintInstancesChain(); void PrintInstancesChain();
private: private:
#if DEBUG
static uint32_t instance_id_counter_;
#endif
void Init(); void Init();
DISALLOW_IMPLICIT_CONSTRUCTORS(WasmCompiledModule); DISALLOW_IMPLICIT_CONSTRUCTORS(WasmCompiledModule);

View File

@ -429,3 +429,94 @@ TEST(Run_WasmModule_GrowMemOobVariableIndex) {
CHECK(try_catch.HasCaught()); CHECK(try_catch.HasCaught());
isolate->clear_pending_exception(); isolate->clear_pending_exception();
} }
TEST(Run_WasmModule_Global_init) {
v8::internal::AccountingAllocator allocator;
Zone zone(&allocator);
TestSignatures sigs;
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
uint32_t global1 =
builder->AddGlobal(kAstI32, false, false, WasmInitExpr(777777));
uint32_t global2 =
builder->AddGlobal(kAstI32, false, false, WasmInitExpr(222222));
WasmFunctionBuilder* f1 = builder->AddFunction(sigs.i_v());
byte code[] = {
WASM_I32_ADD(WASM_GET_GLOBAL(global1), WASM_GET_GLOBAL(global2))};
f1->EmitCode(code, sizeof(code));
ExportAsMain(f1);
TestModule(&zone, builder, 999999);
}
template <typename CType>
static void RunWasmModuleGlobalInitTest(LocalType type, CType expected) {
v8::internal::AccountingAllocator allocator;
Zone zone(&allocator);
TestSignatures sigs;
LocalType types[] = {type};
FunctionSig sig(1, 0, types);
for (int padding = 0; padding < 5; padding++) {
// Test with a simple initializer
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
for (int i = 0; i < padding; i++) { // pad global before
builder->AddGlobal(kAstI32, false, false, WasmInitExpr(i + 20000));
}
uint32_t global =
builder->AddGlobal(type, false, false, WasmInitExpr(expected));
for (int i = 0; i < padding; i++) { // pad global after
builder->AddGlobal(kAstI32, false, false, WasmInitExpr(i + 30000));
}
WasmFunctionBuilder* f1 = builder->AddFunction(&sig);
byte code[] = {WASM_GET_GLOBAL(global)};
f1->EmitCode(code, sizeof(code));
ExportAsMain(f1);
TestModule(&zone, builder, expected);
}
for (int padding = 0; padding < 5; padding++) {
// Test with a global index
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
for (int i = 0; i < padding; i++) { // pad global before
builder->AddGlobal(kAstI32, false, false, WasmInitExpr(i + 40000));
}
uint32_t global1 =
builder->AddGlobal(type, false, false, WasmInitExpr(expected));
for (int i = 0; i < padding; i++) { // pad global middle
builder->AddGlobal(kAstI32, false, false, WasmInitExpr(i + 50000));
}
uint32_t global2 = builder->AddGlobal(
type, false, false, WasmInitExpr(WasmInitExpr::kGlobalIndex, global1));
for (int i = 0; i < padding; i++) { // pad global after
builder->AddGlobal(kAstI32, false, false, WasmInitExpr(i + 60000));
}
WasmFunctionBuilder* f1 = builder->AddFunction(&sig);
byte code[] = {WASM_GET_GLOBAL(global2)};
f1->EmitCode(code, sizeof(code));
ExportAsMain(f1);
TestModule(&zone, builder, expected);
}
}
TEST(Run_WasmModule_Global_i32) {
RunWasmModuleGlobalInitTest<int32_t>(kAstI32, -983489);
RunWasmModuleGlobalInitTest<int32_t>(kAstI32, 11223344);
}
TEST(Run_WasmModule_Global_f32) {
RunWasmModuleGlobalInitTest<float>(kAstF32, -983.9f);
RunWasmModuleGlobalInitTest<float>(kAstF32, 1122.99f);
}
TEST(Run_WasmModule_Global_f64) {
RunWasmModuleGlobalInitTest<double>(kAstF64, -833.9);
RunWasmModuleGlobalInitTest<double>(kAstF64, 86374.25);
}

View File

@ -268,7 +268,7 @@ class TestingModule : public ModuleEnv {
byte size = WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(type)); byte size = WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(type));
global_offset = (global_offset + size - 1) & ~(size - 1); // align global_offset = (global_offset + size - 1) & ~(size - 1); // align
module_.globals.push_back( module_.globals.push_back(
{type, true, NO_INIT, global_offset, false, false}); {type, true, WasmInitExpr(), global_offset, false, false});
global_offset += size; global_offset += size;
// limit number of globals. // limit number of globals.
CHECK_LT(global_offset, kMaxGlobalsSize); CHECK_LT(global_offset, kMaxGlobalsSize);

View File

@ -14,8 +14,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addMemory(1,1, true); builder.addMemory(1,1, true);
builder.addImport("getValue", kSig_i); builder.addImport("getValue", kSig_i_v);
builder.addFunction("f", kSig_i) builder.addFunction("f", kSig_i_v)
.addBody([ .addBody([
kExprCallFunction, 0 kExprCallFunction, 0
]).exportFunc(); ]).exportFunc();

View File

@ -12,7 +12,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
builder.addMemory(1,1, true); builder.addMemory(1,1, true);
var kSig_v_i = makeSig([kAstI32], []); var kSig_v_i = makeSig([kAstI32], []);
var signature = builder.addType(kSig_v_i); var signature = builder.addType(kSig_v_i);
builder.addImport("some_value", kSig_i); builder.addImport("some_value", kSig_i_v);
builder.addImport("writer", signature); builder.addImport("writer", signature);
builder.addFunction("main", kSig_i_i) builder.addFunction("main", kSig_i_i)
@ -65,7 +65,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function RelationBetweenModuleAndClone() { (function RelationBetweenModuleAndClone() {
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i) builder.addFunction("main", kSig_i_v)
.addBody([kExprI8Const, 42]) .addBody([kExprI8Const, 42])
.exportFunc(); .exportFunc();
@ -81,7 +81,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function SerializeAfterInstantiation() { (function SerializeAfterInstantiation() {
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i) builder.addFunction("main", kSig_i_v)
.addBody([kExprI8Const, 42]) .addBody([kExprI8Const, 42])
.exportFunc(); .exportFunc();

View File

@ -11,7 +11,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var kReturnValue = 88; var kReturnValue = 88;
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i) builder.addFunction("main", kSig_i_v)
.addBody([ .addBody([
kExprI8Const, kExprI8Const,
kReturnValue, kReturnValue,
@ -32,7 +32,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i) builder.addFunction("main", kSig_i_v)
.addBody([ .addBody([
kExprI8Const, kExprI8Const,
kReturnValue, kReturnValue,
@ -57,7 +57,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i) builder.addFunction("main", kSig_i_v)
.addBody([ .addBody([
kExprI8Const, kExprI8Const,
kReturnValue, kReturnValue,

View File

@ -94,7 +94,7 @@ print("Native function");
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
var sig_index = builder.addType(kSig_d); var sig_index = builder.addType(kSig_d_v);
builder.addImport("func", sig_index); builder.addImport("func", sig_index);
builder.addFunction("main", sig_index) builder.addFunction("main", sig_index)
.addBody([ .addBody([

View File

@ -10,7 +10,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function TestFunctionPrototype() { (function TestFunctionPrototype() {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addFunction("nine", kSig_i) builder.addFunction("nine", kSig_i_v)
.addBody([kExprI8Const, 9]) .addBody([kExprI8Const, 9])
.exportFunc(); .exportFunc();

View File

@ -0,0 +1,66 @@
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --expose-wasm
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
function TestImported(type, val, expected) {
print("TestImported " + type + "(" + val +")" + " = " + expected);
var builder = new WasmModuleBuilder();
var sig = makeSig([], [type]);
var g = builder.addImportedGlobal("foo", undefined, type);
builder.addFunction("main", sig)
.addBody([kExprGetGlobal, g.index])
.exportAs("main");
builder.addGlobal(kAstI32); // pad
var instance = builder.instantiate({foo: val});
assertEquals(expected, instance.exports.main());
}
TestImported(kAstI32, 300.1, 300);
TestImported(kAstF32, 87234.87238, Math.fround(87234.87238));
TestImported(kAstF64, 77777.88888, 77777.88888);
TestImported(kAstF64, "89", 89);
function TestExported(type, val, expected) {
print("TestExported " + type + "(" + val +")" + " = " + expected);
var builder = new WasmModuleBuilder();
var sig = makeSig([type], []);
builder.addGlobal(kAstI32); // pad
var g = builder.addGlobal(type, false)
.exportAs("foo");
g.init = val;
builder.addGlobal(kAstI32); // pad
var instance = builder.instantiate();
assertEquals(expected, instance.exports.foo);
}
TestExported(kAstI32, 455.5, 455);
TestExported(kAstF32, -999.34343, Math.fround(-999.34343));
TestExported(kAstF64, 87347.66666, 87347.66666);
function TestImportedExported(type, val, expected) {
print("TestImportedExported " + type + "(" + val +")" + " = " + expected);
var builder = new WasmModuleBuilder();
var sig = makeSig([type], []);
var i = builder.addImportedGlobal("foo", undefined, type);
builder.addGlobal(kAstI32); // pad
var o = builder.addGlobal(type, false)
.exportAs("bar");
o.init_index = i;
builder.addGlobal(kAstI32); // pad
var instance = builder.instantiate({foo: val});
assertEquals(expected, instance.exports.bar);
}
TestImportedExported(kAstI32, 415.5, 415);
TestImportedExported(kAstF32, -979.34343, Math.fround(-979.34343));
TestImportedExported(kAstF64, 81347.66666, 81347.66666);

View File

@ -266,9 +266,9 @@ testCallPrint();
function testCallImport2(foo, bar, expected) { function testCallImport2(foo, bar, expected) {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addImport("foo", kSig_i); builder.addImport("foo", kSig_i_v);
builder.addImport("bar", kSig_i); builder.addImport("bar", kSig_i_v);
builder.addFunction("main", kSig_i) builder.addFunction("main", kSig_i_v)
.addBody([ .addBody([
kExprCallFunction, 0, // -- kExprCallFunction, 0, // --
kExprCallFunction, 1, // -- kExprCallFunction, 1, // --

View File

@ -12,7 +12,7 @@ let nogc = () => {};
function newModule() { function newModule() {
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true); builder.addMemory(1, 1, true);
builder.addFunction("main", kSig_i) builder.addFunction("main", kSig_i_v)
.addBody([kExprI32Const, 0, kExprI32LoadMem, 0, 0]) .addBody([kExprI32Const, 0, kExprI32LoadMem, 0, 0])
.exportFunc(); .exportFunc();

View File

@ -12,7 +12,7 @@ let kReturnValue = 117;
let buffer = (() => { let buffer = (() => {
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true); builder.addMemory(1, 1, true);
builder.addFunction("main", kSig_i) builder.addFunction("main", kSig_i_v)
.addBody([kExprI8Const, kReturnValue]) .addBody([kExprI8Const, kReturnValue])
.exportFunc(); .exportFunc();
@ -119,7 +119,7 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
builder.addMemory(1,1, true); builder.addMemory(1,1, true);
var kSig_v_i = makeSig([kAstI32], []); var kSig_v_i = makeSig([kAstI32], []);
var signature = builder.addType(kSig_v_i); var signature = builder.addType(kSig_v_i);
builder.addImport("some_value", kSig_i); builder.addImport("some_value", kSig_i_v);
builder.addImport("writer", signature); builder.addImport("writer", signature);
builder.addFunction("main", kSig_i_i) builder.addFunction("main", kSig_i_i)
@ -169,7 +169,7 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
(function GlobalsArePrivateToTheInstance() { (function GlobalsArePrivateToTheInstance() {
print("GlobalsArePrivateToTheInstance..."); print("GlobalsArePrivateToTheInstance...");
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addGlobal(kAstI32); builder.addGlobal(kAstI32, true);
builder.addFunction("read", kSig_i_v) builder.addFunction("read", kSig_i_v)
.addBody([ .addBody([
kExprGetGlobal, 0]) kExprGetGlobal, 0])
@ -196,7 +196,7 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addMemory(1,1, true); builder.addMemory(1,1, true);
builder.addFunction("f", kSig_i) builder.addFunction("f", kSig_i_v)
.addBody([ .addBody([
kExprI32Const, 0, kExprI32Const, 0,
kExprI32LoadMem, 0, 0 kExprI32LoadMem, 0, 0

View File

@ -38,7 +38,7 @@ function assertVerifies(sig, body) {
} }
assertVerifies(kSig_v_v, [kExprNop]); assertVerifies(kSig_v_v, [kExprNop]);
assertVerifies(kSig_i, [kExprI8Const, 0]); assertVerifies(kSig_i_v, [kExprI8Const, 0]);
// Arguments aren't allow to start functions. // Arguments aren't allow to start functions.
assertFails(kSig_i_i, [kExprGetLocal, 0]); assertFails(kSig_i_i, [kExprGetLocal, 0]);

View File

@ -12,7 +12,7 @@ var debug = true;
(function BasicTest() { (function BasicTest() {
var module = new WasmModuleBuilder(); var module = new WasmModuleBuilder();
module.addMemory(1, 2, false); module.addMemory(1, 2, false);
module.addFunction("foo", kSig_i) module.addFunction("foo", kSig_i_v)
.addBody([kExprI8Const, 11]) .addBody([kExprI8Const, 11])
.exportAs("blarg"); .exportAs("blarg");
@ -116,7 +116,7 @@ var debug = true;
(function BasicTestWithUint8Array() { (function BasicTestWithUint8Array() {
var module = new WasmModuleBuilder(); var module = new WasmModuleBuilder();
module.addMemory(1, 2, false); module.addMemory(1, 2, false);
module.addFunction("foo", kSig_i) module.addFunction("foo", kSig_i_v)
.addBody([kExprI8Const, 17]) .addBody([kExprI8Const, 17])
.exportAs("blarg"); .exportAs("blarg");

View File

@ -89,8 +89,6 @@ var kExternalMemory = 2;
var kExternalGlobal = 3; var kExternalGlobal = 3;
// Useful signatures // Useful signatures
var kSig_i = makeSig([], [kAstI32]);
var kSig_d = makeSig([], [kAstF64]);
var kSig_i_i = makeSig([kAstI32], [kAstI32]); var kSig_i_i = makeSig([kAstI32], [kAstI32]);
var kSig_i_l = makeSig([kAstI64], [kAstI32]); var kSig_i_l = makeSig([kAstI64], [kAstI32]);
var kSig_i_ii = makeSig([kAstI32, kAstI32], [kAstI32]); var kSig_i_ii = makeSig([kAstI32, kAstI32], [kAstI32]);
@ -100,6 +98,8 @@ var kSig_l_ll = makeSig([kAstI64, kAstI64], [kAstI64]);
var kSig_i_dd = makeSig([kAstF64, kAstF64], [kAstI32]); var kSig_i_dd = makeSig([kAstF64, kAstF64], [kAstI32]);
var kSig_v_v = makeSig([], []); var kSig_v_v = makeSig([], []);
var kSig_i_v = makeSig([], [kAstI32]); var kSig_i_v = makeSig([], [kAstI32]);
var kSig_f_v = makeSig([], [kAstF64]);
var kSig_d_v = makeSig([], [kAstF64]);
var kSig_v_i = makeSig([kAstI32], []); var kSig_v_i = makeSig([kAstI32], []);
var kSig_v_ii = makeSig([kAstI32, kAstI32], []); var kSig_v_ii = makeSig([kAstI32, kAstI32], []);
var kSig_v_iii = makeSig([kAstI32, kAstI32, kAstI32], []); var kSig_v_iii = makeSig([kAstI32, kAstI32, kAstI32], []);

View File

@ -2,6 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Used for encoding f32 and double constants to bits.
let __buffer = new ArrayBuffer(8);
let byte_view = new Int8Array(__buffer);
let f32_view = new Float32Array(__buffer);
let f64_view = new Float64Array(__buffer);
class Binary extends Array { class Binary extends Array {
emit_u8(val) { emit_u8(val) {
this.push(val); this.push(val);
@ -19,7 +25,7 @@ class Binary extends Array {
this.push((val >> 24) & 0xff); this.push((val >> 24) & 0xff);
} }
emit_varint(val) { emit_u32v(val) {
while (true) { while (true) {
let v = val & 0xff; let v = val & 0xff;
val = val >>> 7; val = val >>> 7;
@ -40,7 +46,7 @@ class Binary extends Array {
emit_string(string) { emit_string(string) {
// When testing illegal names, we pass a byte array directly. // When testing illegal names, we pass a byte array directly.
if (string instanceof Array) { if (string instanceof Array) {
this.emit_varint(string.length); this.emit_u32v(string.length);
this.emit_bytes(string); this.emit_bytes(string);
return; return;
} }
@ -48,7 +54,7 @@ class Binary extends Array {
// This is the hacky way to convert a JavaScript string to a UTF8 encoded // This is the hacky way to convert a JavaScript string to a UTF8 encoded
// string only containing single-byte characters. // string only containing single-byte characters.
let string_utf8 = unescape(encodeURIComponent(string)); let string_utf8 = unescape(encodeURIComponent(string));
this.emit_varint(string_utf8.length); this.emit_u32v(string_utf8.length);
for (let i = 0; i < string_utf8.length; i++) { for (let i = 0; i < string_utf8.length; i++) {
this.emit_u8(string_utf8.charCodeAt(i)); this.emit_u8(string_utf8.charCodeAt(i));
} }
@ -66,26 +72,26 @@ class Binary extends Array {
let section = new Binary; let section = new Binary;
content_generator(section); content_generator(section);
// Emit section length. // Emit section length.
this.emit_varint(section.length); this.emit_u32v(section.length);
// Copy the temporary buffer. // Copy the temporary buffer.
this.push(...section); this.push(...section);
} }
} }
class WasmFunctionBuilder { class WasmFunctionBuilder {
constructor(name, type_index) { constructor(module, name, type_index) {
this.module = module;
this.name = name; this.name = name;
this.type_index = type_index; this.type_index = type_index;
this.exports = [];
} }
exportAs(name) { exportAs(name) {
this.exports.push(name); this.module.exports.push({name: name, kind: kExternalFunction, index: this.index});
return this; return this;
} }
exportFunc() { exportFunc() {
this.exports.push(this.name); this.exportAs(this.name);
return this; return this;
} }
@ -100,17 +106,33 @@ class WasmFunctionBuilder {
} }
} }
class WasmGlobalBuilder {
constructor(module, type, mutable) {
this.module = module;
this.type = type;
this.mutable = mutable;
this.init = 0;
}
exportAs(name) {
this.module.exports.push({name: name, kind: kExternalGlobal, index: this.index});
return this;
}
}
class WasmModuleBuilder { class WasmModuleBuilder {
constructor() { constructor() {
this.types = []; this.types = [];
this.imports = []; this.imports = [];
this.exports = [];
this.globals = []; this.globals = [];
this.functions = []; this.functions = [];
this.exports = [];
this.table = []; this.table = [];
this.segments = []; this.segments = [];
this.explicit = []; this.explicit = [];
this.pad = null; this.pad = null;
this.num_imported_funcs = 0;
this.num_imported_globals = 0;
return this; return this;
} }
@ -139,29 +161,39 @@ class WasmModuleBuilder {
return this.types.length - 1; return this.types.length - 1;
} }
addGlobal(local_type) { addGlobal(local_type, mutable) {
this.globals.push(local_type); let glob = new WasmGlobalBuilder(this, local_type, mutable);
return this.globals.length - 1; glob.index = this.globals.length + this.num_imported_globals;
this.globals.push(glob);
return glob;
} }
addFunction(name, type) { addFunction(name, type) {
let type_index = (typeof type) == "number" ? type : this.addType(type); let type_index = (typeof type) == "number" ? type : this.addType(type);
let func = new WasmFunctionBuilder(name, type_index); let func = new WasmFunctionBuilder(this, name, type_index);
func.index = this.functions.length + this.imports.length; func.index = this.functions.length + this.num_imported_funcs;
this.functions.push(func); this.functions.push(func);
return func; return func;
} }
addImportWithModule(module, name, type) { addImportWithModule(module, name, type) {
let type_index = (typeof type) == "number" ? type : this.addType(type); let type_index = (typeof type) == "number" ? type : this.addType(type);
this.imports.push({module: module, name: name, type: type_index}); this.imports.push({module: module, name: name, kind: kExternalFunction,
return this.imports.length - 1; type: type_index});
return this.num_imported_funcs++;
} }
addImport(name, type) { addImport(name, type) {
return this.addImportWithModule(name, undefined, type); return this.addImportWithModule(name, undefined, type);
} }
addImportedGlobal(module, name, type) {
let o = {module: module, name: name, kind: kExternalGlobal, type: type,
mutable: false}
this.imports.push(o);
return this.num_imported_globals++;
}
addDataSegment(addr, data, init) { addDataSegment(addr, data, init) {
this.segments.push({addr: addr, data: data, init: init}); this.segments.push({addr: addr, data: data, init: init});
return this.segments.length - 1; return this.segments.length - 1;
@ -183,14 +215,14 @@ class WasmModuleBuilder {
if (wasm.types.length > 0) { if (wasm.types.length > 0) {
if (debug) print("emitting types @ " + binary.length); if (debug) print("emitting types @ " + binary.length);
binary.emit_section(kTypeSectionCode, section => { binary.emit_section(kTypeSectionCode, section => {
section.emit_varint(wasm.types.length); section.emit_u32v(wasm.types.length);
for (let type of wasm.types) { for (let type of wasm.types) {
section.emit_u8(kWasmFunctionTypeForm); section.emit_u8(kWasmFunctionTypeForm);
section.emit_varint(type.params.length); section.emit_u32v(type.params.length);
for (let param of type.params) { for (let param of type.params) {
section.emit_u8(param); section.emit_u8(param);
} }
section.emit_varint(type.results.length); section.emit_u32v(type.results.length);
for (let result of type.results) { for (let result of type.results) {
section.emit_u8(result); section.emit_u8(result);
} }
@ -202,12 +234,19 @@ class WasmModuleBuilder {
if (wasm.imports.length > 0) { if (wasm.imports.length > 0) {
if (debug) print("emitting imports @ " + binary.length); if (debug) print("emitting imports @ " + binary.length);
binary.emit_section(kImportSectionCode, section => { binary.emit_section(kImportSectionCode, section => {
section.emit_varint(wasm.imports.length); section.emit_u32v(wasm.imports.length);
for (let imp of wasm.imports) { for (let imp of wasm.imports) {
section.emit_string(imp.module); section.emit_string(imp.module);
section.emit_string(imp.name || ''); section.emit_string(imp.name || '');
section.emit_u8(kExternalFunction); section.emit_u8(imp.kind);
section.emit_varint(imp.type); if (imp.kind == kExternalFunction) {
section.emit_u32v(imp.type);
} else if (imp.kind == kExternalGlobal) {
section.emit_u32v(imp.type);
section.emit_u8(imp.mutable);
} else {
throw new Error("unknown/unsupported import kind " + imp.kind);
}
} }
}); });
} }
@ -215,16 +254,14 @@ class WasmModuleBuilder {
// Add functions declarations // Add functions declarations
let has_names = false; let has_names = false;
let names = false; let names = false;
let exports = 0;
if (wasm.functions.length > 0) { if (wasm.functions.length > 0) {
if (debug) print("emitting function decls @ " + binary.length); if (debug) print("emitting function decls @ " + binary.length);
binary.emit_section(kFunctionSectionCode, section => { binary.emit_section(kFunctionSectionCode, section => {
section.emit_varint(wasm.functions.length); section.emit_u32v(wasm.functions.length);
for (let func of wasm.functions) { for (let func of wasm.functions) {
has_names = has_names || (func.name != undefined && has_names = has_names || (func.name != undefined &&
func.name.length > 0); func.name.length > 0);
exports += func.exports.length; section.emit_u32v(func.type_index);
section.emit_varint(func.type_index);
} }
}); });
} }
@ -236,8 +273,8 @@ class WasmModuleBuilder {
section.emit_u8(1); // one table entry section.emit_u8(1); // one table entry
section.emit_u8(kWasmAnyFunctionTypeForm); section.emit_u8(kWasmAnyFunctionTypeForm);
section.emit_u8(1); section.emit_u8(1);
section.emit_varint(wasm.table.length); section.emit_u32v(wasm.table.length);
section.emit_varint(wasm.table.length); section.emit_u32v(wasm.table.length);
}); });
} }
@ -246,9 +283,9 @@ class WasmModuleBuilder {
if (debug) print("emitting memory @ " + binary.length); if (debug) print("emitting memory @ " + binary.length);
binary.emit_section(kMemorySectionCode, section => { binary.emit_section(kMemorySectionCode, section => {
section.emit_u8(1); // one memory entry section.emit_u8(1); // one memory entry
section.emit_varint(kResizableMaximumFlag); section.emit_u32v(kResizableMaximumFlag);
section.emit_varint(wasm.memory.min); section.emit_u32v(wasm.memory.min);
section.emit_varint(wasm.memory.max); section.emit_u32v(wasm.memory.max);
}); });
} }
@ -256,28 +293,46 @@ class WasmModuleBuilder {
if (wasm.globals.length > 0) { if (wasm.globals.length > 0) {
if (debug) print ("emitting globals @ " + binary.length); if (debug) print ("emitting globals @ " + binary.length);
binary.emit_section(kGlobalSectionCode, section => { binary.emit_section(kGlobalSectionCode, section => {
section.emit_varint(wasm.globals.length); section.emit_u32v(wasm.globals.length);
for (let global_type of wasm.globals) { for (let global of wasm.globals) {
section.emit_u8(global_type); section.emit_u8(global.type);
section.emit_u8(true); // mutable section.emit_u8(global.mutable);
switch (global_type) { if ((typeof global.init_index) == "undefined") {
// Emit a constant initializer.
switch (global.type) {
case kAstI32: case kAstI32:
section.emit_u8(kExprI32Const); section.emit_u8(kExprI32Const);
section.emit_u8(0); section.emit_u32v(global.init);
break; break;
case kAstI64: case kAstI64:
section.emit_u8(kExprI64Const); section.emit_u8(kExprI64Const);
section.emit_u8(0); section.emit_u8(global.init);
break; break;
case kAstF32: case kAstF32:
section.emit_u8(kExprF32Const); section.emit_u8(kExprF32Const);
section.emit_u32(0); f32_view[0] = global.init;
section.emit_u8(byte_view[0]);
section.emit_u8(byte_view[1]);
section.emit_u8(byte_view[2]);
section.emit_u8(byte_view[3]);
break; break;
case kAstF64: case kAstF64:
section.emit_u8(kExprI32Const); section.emit_u8(kExprF64Const);
section.emit_u32(0); f64_view[0] = global.init;
section.emit_u32(0); section.emit_u8(byte_view[0]);
section.emit_u8(byte_view[1]);
section.emit_u8(byte_view[2]);
section.emit_u8(byte_view[3]);
section.emit_u8(byte_view[4]);
section.emit_u8(byte_view[5]);
section.emit_u8(byte_view[6]);
section.emit_u8(byte_view[7]);
break; break;
}
} else {
// Emit a global-index initializer.
section.emit_u8(kExprGetGlobal);
section.emit_u32v(global.init_index);
} }
section.emit_u8(kExprEnd); // end of init expression section.emit_u8(kExprEnd); // end of init expression
} }
@ -286,16 +341,15 @@ class WasmModuleBuilder {
// Add export table. // Add export table.
var mem_export = (wasm.memory != undefined && wasm.memory.exp); var mem_export = (wasm.memory != undefined && wasm.memory.exp);
if (exports > 0 || mem_export) { var exports_count = wasm.exports.length + (mem_export ? 1 : 0);
if (exports_count > 0) {
if (debug) print("emitting exports @ " + binary.length); if (debug) print("emitting exports @ " + binary.length);
binary.emit_section(kExportSectionCode, section => { binary.emit_section(kExportSectionCode, section => {
section.emit_varint(exports + (mem_export ? 1 : 0)); section.emit_u32v(exports_count);
for (let func of wasm.functions) { for (let exp of wasm.exports) {
for (let exp of func.exports) { section.emit_string(exp.name);
section.emit_string(exp); section.emit_u8(exp.kind);
section.emit_u8(kExternalFunction); section.emit_u32v(exp.index);
section.emit_varint(func.index);
}
} }
if (mem_export) { if (mem_export) {
section.emit_string("memory"); section.emit_string("memory");
@ -309,7 +363,7 @@ class WasmModuleBuilder {
if (wasm.start_index != undefined) { if (wasm.start_index != undefined) {
if (debug) print("emitting start function @ " + binary.length); if (debug) print("emitting start function @ " + binary.length);
binary.emit_section(kStartSectionCode, section => { binary.emit_section(kStartSectionCode, section => {
section.emit_varint(wasm.start_index); section.emit_u32v(wasm.start_index);
}); });
} }
@ -322,9 +376,9 @@ class WasmModuleBuilder {
section.emit_u8(kExprI32Const); section.emit_u8(kExprI32Const);
section.emit_u8(0); section.emit_u8(0);
section.emit_u8(kExprEnd); section.emit_u8(kExprEnd);
section.emit_varint(wasm.table.length); section.emit_u32v(wasm.table.length);
for (let index of wasm.table) { for (let index of wasm.table) {
section.emit_varint(index); section.emit_u32v(index);
} }
}); });
} }
@ -334,7 +388,7 @@ class WasmModuleBuilder {
// emit function bodies // emit function bodies
if (debug) print("emitting code @ " + binary.length); if (debug) print("emitting code @ " + binary.length);
binary.emit_section(kCodeSectionCode, section => { binary.emit_section(kCodeSectionCode, section => {
section.emit_varint(wasm.functions.length); section.emit_u32v(wasm.functions.length);
for (let func of wasm.functions) { for (let func of wasm.functions) {
// Function body length will be patched later. // Function body length will be patched later.
let local_decls = []; let local_decls = [];
@ -356,13 +410,13 @@ class WasmModuleBuilder {
} }
let header = new Binary; let header = new Binary;
header.emit_varint(local_decls.length); header.emit_u32v(local_decls.length);
for (let decl of local_decls) { for (let decl of local_decls) {
header.emit_varint(decl.count); header.emit_u32v(decl.count);
header.emit_u8(decl.type); header.emit_u8(decl.type);
} }
section.emit_varint(header.length + func.body.length); section.emit_u32v(header.length + func.body.length);
section.emit_bytes(header); section.emit_bytes(header);
section.emit_bytes(func.body); section.emit_bytes(func.body);
} }
@ -373,13 +427,13 @@ class WasmModuleBuilder {
if (wasm.segments.length > 0) { if (wasm.segments.length > 0) {
if (debug) print("emitting data segments @ " + binary.length); if (debug) print("emitting data segments @ " + binary.length);
binary.emit_section(kDataSectionCode, section => { binary.emit_section(kDataSectionCode, section => {
section.emit_varint(wasm.segments.length); section.emit_u32v(wasm.segments.length);
for (let seg of wasm.segments) { for (let seg of wasm.segments) {
section.emit_u8(0); // linear memory index 0 section.emit_u8(0); // linear memory index 0
section.emit_u8(kExprI32Const); section.emit_u8(kExprI32Const);
section.emit_varint(seg.addr); section.emit_u32v(seg.addr);
section.emit_u8(kExprEnd); section.emit_u8(kExprEnd);
section.emit_varint(seg.data.length); section.emit_u32v(seg.data.length);
section.emit_bytes(seg.data); section.emit_bytes(seg.data);
} }
}); });
@ -396,7 +450,7 @@ class WasmModuleBuilder {
if (debug) print("emitting names @ " + binary.length); if (debug) print("emitting names @ " + binary.length);
binary.emit_section(kUnknownSectionCode, section => { binary.emit_section(kUnknownSectionCode, section => {
section.emit_string("name"); section.emit_string("name");
section.emit_varint(wasm.functions.length); section.emit_u32v(wasm.functions.length);
for (let func of wasm.functions) { for (let func of wasm.functions) {
var name = func.name == undefined ? "" : func.name; var name = func.name == undefined ? "" : func.name;
section.emit_string(name); section.emit_string(name);

View File

@ -1283,7 +1283,7 @@ class TestModuleEnv : public ModuleEnv {
module = &mod; module = &mod;
} }
byte AddGlobal(LocalType type, bool mutability = true) { byte AddGlobal(LocalType type, bool mutability = true) {
mod.globals.push_back({type, mutability, NO_INIT, 0, false, false}); mod.globals.push_back({type, mutability, WasmInitExpr(), 0, false, false});
CHECK(mod.globals.size() <= 127); CHECK(mod.globals.size() <= 127);
return static_cast<byte>(mod.globals.size() - 1); return static_cast<byte>(mod.globals.size() - 1);
} }