[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:
parent
94c8170a88
commit
599f8a8342
@ -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});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
@ -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);
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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([
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
66
test/mjsunit/wasm/globals.js
Normal file
66
test/mjsunit/wasm/globals.js
Normal 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);
|
@ -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, // --
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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]);
|
||||||
|
@ -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");
|
||||||
|
|
||||||
|
@ -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], []);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user