Commit 3b1b544c authored by hablich's avatar hablich Committed by Commit bot

Revert of [wasm] Refactor import handling for 0xC. (patchset #10 id:180001 of...

Revert of [wasm] Refactor import handling for 0xC. (patchset #10 id:180001 of https://codereview.chromium.org/2390113003/ )

Reason for revert:
Failes a few GC stress tests.https://chromegw.corp.google.com/i/client.v8/builders/V8%20Linux%20-%20gc%20stress/builds/6253

Original issue's description:
> [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=
>
> Committed: https://crrev.com/599f8a83420346d9cba5ff97bd2a7520468207b6
> Cr-Commit-Position: refs/heads/master@{#40033}

TBR=mtrofin@chromium.org,ahaas@chromium.org,bradnelson@chromium.org,titzer@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=

Review-Url: https://codereview.chromium.org/2395133002
Cr-Commit-Position: refs/heads/master@{#40038}
parent eeaa2398
......@@ -3151,8 +3151,8 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module,
Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
wasm::FunctionSig* sig, uint32_t index,
Handle<String> module_name,
MaybeHandle<String> import_name) {
Handle<String> import_module,
MaybeHandle<String> import_function) {
//----------------------------------------------------------------------------
// 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()) {
const char* function_name = nullptr;
int function_name_size = 0;
if (!import_name.is_null()) {
Handle<String> handle = import_name.ToHandleChecked();
if (!import_function.is_null()) {
Handle<String> handle = import_function.ToHandleChecked();
function_name = handle->ToCString().get();
function_name_size = handle->length();
}
RecordFunctionCompilation(
CodeEventListener::FUNCTION_TAG, isolate, code, "wasm-to-js", index,
{module_name->ToCString().get(), module_name->length()},
{import_module->ToCString().get(), import_module->length()},
{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.
Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
wasm::FunctionSig* sig, uint32_t index,
Handle<String> module_name,
MaybeHandle<String> import_name);
Handle<String> import_module,
MaybeHandle<String> import_function);
// Wraps a given wasm code object, producing a code object.
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module,
......
......@@ -318,7 +318,7 @@ class ModuleDecoder : public Decoder {
// ===== Imported global =========================================
import->index = static_cast<uint32_t>(module->globals.size());
module->globals.push_back(
{kAstStmt, false, WasmInitExpr(), 0, true, false});
{kAstStmt, false, NO_INIT, 0, true, false});
WasmGlobal* global = &module->globals.back();
global->type = consume_value_type();
global->mutability = consume_u8("mutability") != 0;
......@@ -399,8 +399,7 @@ class ModuleDecoder : public Decoder {
TRACE("DecodeGlobal[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
// Add an uninitialized global and pass a pointer to it.
module->globals.push_back(
{kAstStmt, false, WasmInitExpr(), 0, false, false});
module->globals.push_back({kAstStmt, false, NO_INIT, 0, false, false});
WasmGlobal* global = &module->globals.back();
DecodeGlobalInModule(module, i, global);
}
......@@ -546,9 +545,9 @@ class ModuleDecoder : public Decoder {
TRACE("DecodeDataSegment[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
module->data_segments.push_back({
WasmInitExpr(), // dest_addr
0, // source_offset
0 // source_size
NO_INIT, // dest_addr
0, // source_offset
0 // source_size
});
WasmDataSegment* segment = &module->data_segments.back();
DecodeDataSegmentInModule(module, segment);
......@@ -648,19 +647,13 @@ class ModuleDecoder : public Decoder {
const byte* pos = pc();
global->init = consume_init_expr(module, kAstStmt);
switch (global->init.kind) {
case WasmInitExpr::kGlobalIndex: {
uint32_t other_index = global->init.val.global_index;
if (other_index >= index) {
case WasmInitExpr::kGlobalIndex:
if (global->init.val.global_index >= index) {
error("invalid global index in init expression");
} else if (module->globals[other_index].type != global->type) {
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));
} else if (module->globals[index].type != global->type) {
error("type mismatch in global initialization");
}
break;
}
default:
if (global->type != TypeOf(module, global->init)) {
error(pos, pos,
......
......@@ -255,9 +255,8 @@ void WasmModuleBuilder::MarkStartFunction(WasmFunctionBuilder* function) {
}
uint32_t WasmModuleBuilder::AddGlobal(LocalType type, bool exported,
bool mutability,
const WasmInitExpr& init) {
globals_.push_back({type, exported, mutability, init});
bool mutability) {
globals_.push_back({type, exported, mutability});
return static_cast<uint32_t>(globals_.size() - 1);
}
......@@ -345,64 +344,29 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer& buffer) const {
for (auto global : globals_) {
buffer.write_u8(WasmOpcodes::LocalTypeCodeFor(global.type));
buffer.write_u8(global.mutability ? 1 : 0);
switch (global.init.kind) {
case WasmInitExpr::kI32Const: {
DCHECK_EQ(kAstI32, global.type);
const byte code[] = {WASM_I32V_5(global.init.val.i32_const)};
switch (global.type) {
case kAstI32: {
static const byte code[] = {WASM_I32V_1(0)};
buffer.write(code, sizeof(code));
break;
}
case WasmInitExpr::kI64Const: {
DCHECK_EQ(kAstI64, global.type);
const byte code[] = {WASM_I64V_10(global.init.val.i64_const)};
case kAstF32: {
static const byte code[] = {WASM_F32(0)};
buffer.write(code, sizeof(code));
break;
}
case WasmInitExpr::kF32Const: {
DCHECK_EQ(kAstF32, global.type);
const byte code[] = {WASM_F32(global.init.val.f32_const)};
case kAstI64: {
static const byte code[] = {WASM_I64V_1(0)};
buffer.write(code, sizeof(code));
break;
}
case WasmInitExpr::kF64Const: {
DCHECK_EQ(kAstF64, global.type);
const byte code[] = {WASM_F64(global.init.val.f64_const)};
case kAstF64: {
static const byte code[] = {WASM_F64(0.0)};
buffer.write(code, sizeof(code));
break;
}
case WasmInitExpr::kGlobalIndex: {
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();
}
}
default:
UNREACHABLE();
}
buffer.write_u8(kExprEnd);
}
......
......@@ -212,8 +212,7 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
imports_[index].name_length = name_length;
}
WasmFunctionBuilder* AddFunction(FunctionSig* sig = nullptr);
uint32_t AddGlobal(LocalType type, bool exported, bool mutability = true,
const WasmInitExpr& init = WasmInitExpr());
uint32_t AddGlobal(LocalType type, bool exported, bool mutability = true);
void AddDataSegment(const byte* data, uint32_t size, uint32_t dest);
uint32_t AddSignature(FunctionSig* sig);
void AddIndirectFunction(uint32_t index);
......@@ -242,7 +241,6 @@ class V8_EXPORT_PRIVATE WasmModuleBuilder : public ZoneObject {
LocalType type;
bool exported;
bool mutability;
WasmInitExpr init;
};
struct WasmDataSegment {
......
......@@ -65,9 +65,6 @@ enum WasmInstanceObjectFields {
};
enum WasmImportData {
kImportKind, // Smi. an ExternalKind
kImportGlobalType, // Smi. Type for globals.
kImportIndex, // Smi. index for the import.
kModuleName, // String
kFunctionName, // maybe String
kOutputCount, // Smi. an uint32_t
......@@ -76,26 +73,15 @@ enum WasmImportData {
};
enum WasmExportData {
kExportKind, // Smi. an ExternalKind
kExportGlobalType, // Smi. Type for globals.
kExportName, // String
kExportArity, // Smi, an int
kExportIndex, // Smi, an uint32_t
kExportedSignature, // ByteArray. A copy of the data in FunctionSig
kWasmExportDataSize // Sentinel value.
};
enum WasmGlobalInitData {
kGlobalInitKind, // 0 = constant, 1 = global index
kGlobalInitType, // Smi. Type for globals.
kGlobalInitIndex, // Smi, an uint32_t
kGlobalInitValue, // Number.
kWasmGlobalInitDataSize
kExportName, // String
kExportArity, // Smi, an int
kExportedFunctionIndex, // Smi, an uint32_t
kExportedSignature, // ByteArray. A copy of the data in FunctionSig
kWasmExportDataSize // Sentinel value.
};
enum WasmSegmentInfo {
kDestInitKind, // 0 = constant, 1 = global index
kDestAddrValue, // Smi. an uint32_t
kDestAddr, // Smi. an uint32_t
kSourceSize, // Smi. an uint32_t
kWasmSegmentInfoSize // Sentinel value.
};
......@@ -106,14 +92,36 @@ enum WasmIndirectFunctionTableData {
kWasmIndirectFunctionTableDataSize // Sentinel value.
};
byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) {
return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset;
}
uint32_t GetMinModuleMemSize(const WasmModule* module) {
return WasmModule::kPageSize * module->min_mem_pages;
}
void LoadDataSegments(Handle<WasmCompiledModule> compiled_module,
Address mem_addr, size_t mem_size) {
CHECK(compiled_module->has_data_segments() ==
compiled_module->has_data_segments_info());
// If we have neither, we're done.
if (!compiled_module->has_data_segments()) return;
Handle<ByteArray> data = compiled_module->data_segments();
Handle<FixedArray> segments = compiled_module->data_segments_info();
uint32_t last_extraction_pos = 0;
for (int i = 0; i < segments->length(); ++i) {
Handle<ByteArray> segment =
Handle<ByteArray>(ByteArray::cast(segments->get(i)));
uint32_t dest_addr = static_cast<uint32_t>(segment->get_int(kDestAddr));
uint32_t source_size = static_cast<uint32_t>(segment->get_int(kSourceSize));
CHECK_LT(dest_addr, mem_size);
CHECK_LE(source_size, mem_size);
CHECK_LE(dest_addr, mem_size - source_size);
byte* addr = mem_addr + dest_addr;
data->copy_out(last_extraction_pos, addr, source_size);
last_extraction_pos += source_size;
}
}
void SaveDataSegmentInfo(Factory* factory, const WasmModule* module,
Handle<WasmCompiledModule> compiled_module) {
Handle<FixedArray> segments = factory->NewFixedArray(
......@@ -133,7 +141,7 @@ void SaveDataSegmentInfo(Factory* factory, const WasmModule* module,
factory->NewByteArray(kWasmSegmentInfoSize * sizeof(uint32_t), TENURED);
// TODO(titzer): add support for global offsets for dest_addr
CHECK_EQ(WasmInitExpr::kI32Const, segment.dest_addr.kind);
js_segment->set_int(kDestAddrValue, segment.dest_addr.val.i32_const);
js_segment->set_int(kDestAddr, segment.dest_addr.val.i32_const);
js_segment->set_int(kSourceSize, segment.source_size);
segments->set(i, *js_segment);
data->copy_in(last_insertion_pos,
......@@ -197,6 +205,22 @@ void RelocateInstanceCode(Handle<JSObject> instance, Address old_start,
}
}
// Allocate memory for a module instance as a new JSArrayBuffer.
Handle<JSArrayBuffer> AllocateMemory(ErrorThrower* thrower, Isolate* isolate,
uint32_t min_mem_pages) {
if (min_mem_pages > WasmModule::kMaxMemPages) {
thrower->Error("Out of memory: wasm memory too large");
return Handle<JSArrayBuffer>::null();
}
Handle<JSArrayBuffer> mem_buffer =
NewArrayBuffer(isolate, min_mem_pages * WasmModule::kPageSize);
if (mem_buffer.is_null()) {
thrower->Error("Out of memory: wasm memory");
}
return mem_buffer;
}
void RelocateGlobals(Handle<JSObject> instance, Address old_start,
Address globals_start) {
Handle<FixedArray> functions = Handle<FixedArray>(
......@@ -351,18 +375,12 @@ Address GetGlobalStartAddressFromCodeTemplate(Object* undefined,
return old_address;
}
Handle<FixedArray> EncodeImports(Factory* factory, const WasmModule* module) {
Handle<FixedArray> GetImportsData(Factory* factory, const WasmModule* module) {
Handle<FixedArray> ret = factory->NewFixedArray(
static_cast<int>(module->import_table.size()), TENURED);
for (size_t i = 0; i < module->import_table.size(); ++i) {
const WasmImport& import = module->import_table[i];
Handle<FixedArray> encoded_import =
factory->NewFixedArray(kWasmImportDataSize, TENURED);
encoded_import->set(kImportKind, Smi::FromInt(import.kind));
encoded_import->set(kImportIndex, Smi::FromInt(import.index));
// Add the module and function name.
if (import.kind != kExternalFunction) continue;
WasmName module_name = module->GetNameOrNull(import.module_name_offset,
import.module_name_length);
WasmName function_name = module->GetNameOrNull(import.field_name_offset,
......@@ -370,47 +388,165 @@ Handle<FixedArray> EncodeImports(Factory* factory, const WasmModule* module) {
Handle<String> module_name_string =
factory->InternalizeUtf8String(module_name);
Handle<String> function_name_string =
function_name.is_empty()
? Handle<String>::null()
: factory->InternalizeUtf8String(function_name);
FunctionSig* fsig = module->functions[import.index].sig;
Handle<ByteArray> sig = factory->NewByteArray(
static_cast<int>(fsig->parameter_count() + fsig->return_count()),
TENURED);
sig->copy_in(0, reinterpret_cast<const byte*>(fsig->raw_data()),
sig->length());
Handle<FixedArray> encoded_import =
factory->NewFixedArray(kWasmImportDataSize, TENURED);
encoded_import->set(kModuleName, *module_name_string);
if (!function_name.is_empty()) {
Handle<String> function_name_string =
factory->InternalizeUtf8String(function_name);
if (!function_name_string.is_null()) {
encoded_import->set(kFunctionName, *function_name_string);
}
encoded_import->set(kOutputCount,
Smi::FromInt(static_cast<int>(fsig->return_count())));
encoded_import->set(kSignature, *sig);
ret->set(static_cast<int>(i), *encoded_import);
}
return ret;
}
switch (import.kind) {
case kExternalFunction: {
// Encode the signature into the import.
FunctionSig* fsig = module->functions[import.index].sig;
Handle<ByteArray> sig = factory->NewByteArray(
static_cast<int>(fsig->parameter_count() + fsig->return_count()),
TENURED);
sig->copy_in(0, reinterpret_cast<const byte*>(fsig->raw_data()),
sig->length());
encoded_import->set(
kOutputCount, Smi::FromInt(static_cast<int>(fsig->return_count())));
encoded_import->set(kSignature, *sig);
break;
static MaybeHandle<JSFunction> ReportFFIError(
ErrorThrower* thrower, const char* error, uint32_t index,
Handle<String> module_name, MaybeHandle<String> function_name) {
Handle<String> function_name_handle;
if (function_name.ToHandle(&function_name_handle)) {
thrower->Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s",
index, module_name->length(), module_name->ToCString().get(),
function_name_handle->length(),
function_name_handle->ToCString().get(), error);
} else {
thrower->Error("Import #%d module=\"%.*s\" error: %s", index,
module_name->length(), module_name->ToCString().get(),
error);
}
thrower->Error("Import ");
return MaybeHandle<JSFunction>();
}
static MaybeHandle<JSReceiver> LookupFunction(
ErrorThrower* thrower, Factory* factory, Handle<JSReceiver> ffi,
uint32_t index, Handle<String> module_name,
MaybeHandle<String> function_name) {
if (ffi.is_null()) {
return ReportFFIError(thrower, "FFI is not an object", index, module_name,
function_name);
}
// Look up the module first.
MaybeHandle<Object> result = Object::GetProperty(ffi, module_name);
if (result.is_null()) {
return ReportFFIError(thrower, "module not found", index, module_name,
function_name);
}
Handle<Object> module = result.ToHandleChecked();
if (!module->IsJSReceiver()) {
return ReportFFIError(thrower, "module is not an object or function", index,
module_name, function_name);
}
Handle<Object> function;
if (!function_name.is_null()) {
// Look up the function in the module.
MaybeHandle<Object> result =
Object::GetProperty(module, function_name.ToHandleChecked());
if (result.is_null()) {
return ReportFFIError(thrower, "function not found", index, module_name,
function_name);
}
function = result.ToHandleChecked();
} else {
// No function specified. Use the "default export".
function = module;
}
if (!function->IsCallable()) {
return ReportFFIError(thrower, "not a callable", index, module_name,
function_name);
}
return Handle<JSReceiver>::cast(function);
}
Handle<Code> CompileImportWrapper(Isolate* isolate,
const Handle<JSReceiver> ffi, int index,
Handle<FixedArray> import_data,
ErrorThrower* thrower) {
Handle<FixedArray> data =
import_data->GetValueChecked<FixedArray>(isolate, index);
Handle<String> module_name =
data->GetValueChecked<String>(isolate, kModuleName);
MaybeHandle<String> function_name =
data->GetValue<String>(isolate, kFunctionName);
// TODO(mtrofin): this is an uint32_t, actually. We should rationalize
// it when we rationalize signed/unsigned stuff.
int ret_count = Smi::cast(data->get(kOutputCount))->value();
CHECK_GE(ret_count, 0);
Handle<ByteArray> sig_data =
data->GetValueChecked<ByteArray>(isolate, kSignature);
int sig_data_size = sig_data->length();
int param_count = sig_data_size - ret_count;
CHECK(param_count >= 0);
MaybeHandle<JSReceiver> function = LookupFunction(
thrower, isolate->factory(), ffi, index, module_name, function_name);
if (function.is_null()) return Handle<Code>::null();
Handle<Code> code;
Handle<JSReceiver> target = function.ToHandleChecked();
bool isMatch = false;
Handle<Code> export_wrapper_code;
if (target->IsJSFunction()) {
Handle<JSFunction> func = Handle<JSFunction>::cast(target);
export_wrapper_code = handle(func->code());
if (export_wrapper_code->kind() == Code::JS_TO_WASM_FUNCTION) {
int exported_param_count =
Smi::cast(func->GetInternalField(kInternalArity))->value();
Handle<ByteArray> exportedSig = Handle<ByteArray>(
ByteArray::cast(func->GetInternalField(kInternalSignature)));
if (exported_param_count == param_count &&
exportedSig->length() == sig_data->length() &&
memcmp(exportedSig->GetDataStartAddress(),
sig_data->GetDataStartAddress(), exportedSig->length()) == 0) {
isMatch = true;
}
case kExternalTable:
// Nothing extra required for imported tables.
break;
case kExternalMemory:
// Nothing extra required for imported memories.
break;
case kExternalGlobal: {
// Encode the offset and the global type into the import.
const WasmGlobal& global = module->globals[import.index];
TRACE("import[%zu].type = %s\n", i, WasmOpcodes::TypeName(global.type));
encoded_import->set(
kImportGlobalType,
Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type)));
encoded_import->set(kImportIndex, Smi::FromInt(global.offset));
break;
}
}
if (isMatch) {
int wasm_count = 0;
int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
for (RelocIterator it(*export_wrapper_code, mask); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
Address target_address = rinfo->target_address();
Code* target = Code::GetCodeFromTargetAddress(target_address);
if (target->kind() == Code::WASM_FUNCTION) {
++wasm_count;
code = handle(target);
}
}
ret->set(static_cast<int>(i), *encoded_import);
DCHECK(wasm_count == 1);
return code;
} else {
// Copy the signature to avoid a raw pointer into a heap object when
// GC can happen.
Zone zone(isolate->allocator());
MachineRepresentation* reps =
zone.NewArray<MachineRepresentation>(sig_data_size);
memcpy(reps, sig_data->GetDataStartAddress(),
sizeof(MachineRepresentation) * sig_data_size);
FunctionSig sig(ret_count, param_count, reps);
return compiler::CompileWasmToJSWrapper(isolate, target, &sig, index,
module_name, function_name);
}
return ret;
}
void InitializeParallelCompilation(
......@@ -872,42 +1008,6 @@ WasmModule::WasmModule(byte* module_start)
num_exported_functions(0),
pending_tasks(new base::Semaphore(0)) {}
void EncodeInit(const WasmModule* module, Factory* factory,
Handle<FixedArray> entry, int kind_index, int value_index,
const WasmInitExpr& expr) {
entry->set(kind_index, Smi::FromInt(0));
Handle<Object> value;
switch (expr.kind) {
case WasmInitExpr::kGlobalIndex: {
TRACE(" kind = 1, global index %u\n", expr.val.global_index);
entry->set(kind_index, Smi::FromInt(1));
uint32_t offset = module->globals[expr.val.global_index].offset;
entry->set(value_index, Smi::FromInt(offset));
return;
}
case WasmInitExpr::kI32Const:
TRACE(" kind = 0, i32 = %d\n", expr.val.i32_const);
value = factory->NewNumber(expr.val.i32_const);
break;
case WasmInitExpr::kI64Const:
// TODO(titzer): implement initializers for i64 globals.
UNREACHABLE();
break;
case WasmInitExpr::kF32Const:
TRACE(" kind = 0, f32 = %f\n", expr.val.f32_const);
value = factory->NewNumber(expr.val.f32_const);
break;
case WasmInitExpr::kF64Const:
TRACE(" kind = 0, f64 = %lf\n", expr.val.f64_const);
value = factory->NewNumber(expr.val.f64_const);
break;
default:
UNREACHABLE();
}
entry->set(value_index, *value);
}
MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
Isolate* isolate, ErrorThrower* thrower) const {
Factory* factory = isolate->factory();
......@@ -952,7 +1052,7 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
factory->NewFixedArray(static_cast<int>(code_table_size), TENURED);
// Initialize the code table with placeholders.
for (uint32_t i = 0; i < functions.size(); ++i) {
for (uint32_t i = 0; i < functions.size(); i++) {
Code::Kind kind = Code::WASM_FUNCTION;
if (i < num_imported_functions) kind = Code::WASM_TO_JS_FUNCTION;
Handle<Code> placeholder = CreatePlaceholder(factory, i, kind);
......@@ -966,12 +1066,12 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
// Avoid a race condition by collecting results into a second vector.
std::vector<Handle<Code>> results;
results.reserve(temp_instance.function_code.size());
for (size_t i = 0; i < temp_instance.function_code.size(); ++i) {
for (size_t i = 0; i < temp_instance.function_code.size(); i++) {
results.push_back(temp_instance.function_code[i]);
}
CompileInParallel(isolate, this, results, thrower, &module_env);
for (size_t i = 0; i < results.size(); ++i) {
for (size_t i = 0; i < results.size(); i++) {
temp_instance.function_code[i] = results[i];
}
} else {
......@@ -1003,116 +1103,62 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
// and information needed at instantiation time. This object needs to be
// serializable. Instantiation may occur off a deserialized version of this
// object.
Handle<WasmCompiledModule> ret =
WasmCompiledModule::New(isolate, min_mem_pages, globals_size, origin);
Handle<WasmCompiledModule> ret = WasmCompiledModule::New(
isolate, min_mem_pages, globals_size, mem_export, origin);
ret->set_code_table(code_table);
if (!indirect_table.is_null()) {
ret->set_indirect_function_tables(indirect_table.ToHandleChecked());
}
Handle<FixedArray> import_data = GetImportsData(factory, this);
ret->set_import_data(import_data);
// Create and set import data.
ret->set_imports(EncodeImports(factory, this));
// Create and set export data.
int export_size = static_cast<int>(export_table.size());
// Compile exported function wrappers.
int export_size = static_cast<int>(num_exported_functions);
if (export_size > 0) {
Handle<FixedArray> exports = factory->NewFixedArray(export_size, TENURED);
int index = 0;
int func_index = 0;
int index = -1;
for (const WasmExport& exp : export_table) {
if (thrower->error()) return nothing;
Handle<FixedArray> encoded_export =
if (exp.kind != kExternalFunction)
continue; // skip non-function exports.
index++;
Handle<FixedArray> export_data =
factory->NewFixedArray(kWasmExportDataSize, TENURED);
FunctionSig* funcSig = functions[exp.index].sig;
Handle<ByteArray> exportedSig =
factory->NewByteArray(static_cast<int>(funcSig->parameter_count() +
funcSig->return_count()),
TENURED);
exportedSig->copy_in(0,
reinterpret_cast<const byte*>(funcSig->raw_data()),
exportedSig->length());
export_data->set(kExportedSignature, *exportedSig);
WasmName str = GetName(exp.name_offset, exp.name_length);
Handle<String> name = factory->InternalizeUtf8String(str);
encoded_export->set(kExportKind, Smi::FromInt(exp.kind));
encoded_export->set(kExportName, *name);
encoded_export->set(kExportIndex,
Smi::FromInt(static_cast<int>(exp.index)));
exports->set(index, *encoded_export);
switch (exp.kind) {
case kExternalFunction: {
// Copy the signature and arity.
FunctionSig* funcSig = functions[exp.index].sig;
Handle<ByteArray> exportedSig = factory->NewByteArray(
static_cast<int>(funcSig->parameter_count() +
funcSig->return_count()),
TENURED);
exportedSig->copy_in(
0, reinterpret_cast<const byte*>(funcSig->raw_data()),
exportedSig->length());
encoded_export->set(kExportedSignature, *exportedSig);
encoded_export->set(
kExportArity,
Smi::FromInt(static_cast<int>(funcSig->parameter_count())));
// Compile a wrapper for an exported function.
Handle<Code> code =
code_table->GetValueChecked<Code>(isolate, exp.index);
Handle<Code> export_code = compiler::CompileJSToWasmWrapper(
isolate, &module_env, code, exp.index);
int code_table_index =
static_cast<int>(functions.size() + func_index);
code_table->set(code_table_index, *export_code);
encoded_export->set(kExportIndex, Smi::FromInt(code_table_index));
++func_index;
}
case kExternalTable:
// Nothing special about exported tables.
break;
case kExternalMemory:
// Nothing special about exported tables.
break;
case kExternalGlobal: {
// Encode the global type and the global offset.
const WasmGlobal& global = globals[exp.index];
encoded_export->set(
kExportGlobalType,
Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type)));
encoded_export->set(kExportIndex, Smi::FromInt(global.offset));
break;
}
}
++index;
Handle<Code> code = code_table->GetValueChecked<Code>(isolate, exp.index);
Handle<Code> export_code = compiler::CompileJSToWasmWrapper(
isolate, &module_env, code, exp.index);
if (thrower->error()) return nothing;
export_data->set(kExportName, *name);
export_data->set(kExportArity,
Smi::FromInt(static_cast<int>(
functions[exp.index].sig->parameter_count())));
export_data->set(kExportedFunctionIndex,
Smi::FromInt(static_cast<int>(exp.index)));
exports->set(index, *export_data);
code_table->set(static_cast<int>(functions.size() + index), *export_code);
}
ret->set_exports(exports);
}
// Create and set init data.
int init_size = static_cast<int>(globals.size());
if (init_size > 0) {
Handle<FixedArray> inits = factory->NewFixedArray(init_size, TENURED);
int index = 0;
for (const WasmGlobal& global : globals) {
// Skip globals that have no initializer (e.g. imported ones).
if (global.init.kind == WasmInitExpr::kNone) continue;
Handle<FixedArray> encoded_init =
factory->NewFixedArray(kWasmGlobalInitDataSize, TENURED);
inits->set(index, *encoded_init);
TRACE("init[%d].type = %s\n", index, WasmOpcodes::TypeName(global.type));
encoded_init->set(
kGlobalInitType,
Smi::FromInt(WasmOpcodes::LocalTypeCodeFor(global.type)));
encoded_init->set(kGlobalInitIndex, Smi::FromInt(global.offset));
EncodeInit(this, factory, encoded_init, kGlobalInitKind, kGlobalInitValue,
global.init);
++index;
}
inits->Shrink(index);
ret->set_inits(inits);
}
// Record data for startup function.
if (start_function_index >= 0) {
HandleScope scope(isolate);
Handle<FixedArray> startup_data =
factory->NewFixedArray(kWasmExportDataSize, TENURED);
startup_data->set(kExportArity, Smi::FromInt(0));
startup_data->set(kExportIndex, Smi::FromInt(start_function_index));
startup_data->set(kExportedFunctionIndex,
Smi::FromInt(start_function_index));
ret->set_startup_function(startup_data);
}
......@@ -1137,727 +1183,374 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
return ret;
}
// A helper class to simplify instantiating a module from a compiled module.
// It closes over the {Isolate}, the {ErrorThrower}, the {WasmCompiledModule},
// etc.
class WasmInstanceBuilder {
public:
WasmInstanceBuilder(Isolate* isolate, ErrorThrower* thrower,
Handle<JSObject> module_object, Handle<JSReceiver> ffi,
Handle<JSArrayBuffer> memory)
: isolate_(isolate),
thrower_(thrower),
module_object_(module_object),
ffi_(ffi),
memory_(memory) {}
// Build an instance, in all of its glory.
MaybeHandle<JSObject> Build() {
MaybeHandle<JSObject> nothing;
HistogramTimerScope wasm_instantiate_module_time_scope(
isolate_->counters()->wasm_instantiate_module_time());
Factory* factory = isolate_->factory();
//--------------------------------------------------------------------------
// Reuse the compiled module (if no owner), otherwise clone.
//--------------------------------------------------------------------------
Handle<FixedArray> code_table;
Handle<FixedArray> old_code_table;
Handle<JSObject> owner;
// If we don't clone, this will be null(). Otherwise, this will
// be a weak link to the original. If we lose the original to GC,
// this will be a cleared. We'll link the instances chain last.
MaybeHandle<WeakCell> link_to_original;
TRACE("Starting new module instantiation\n");
{
Handle<WasmCompiledModule> original(
WasmCompiledModule::cast(module_object_->GetInternalField(0)),
isolate_);
// Always make a new copy of the code_table, since the old_code_table
// may still have placeholders for imports.
old_code_table = original->code_table();
code_table = factory->CopyFixedArray(old_code_table);
if (original->has_weak_owning_instance()) {
WeakCell* tmp = original->ptr_to_weak_owning_instance();
DCHECK(!tmp->cleared());
// There is already an owner, clone everything.
owner = Handle<JSObject>(JSObject::cast(tmp->value()), isolate_);
// Insert the latest clone in front.
TRACE("Cloning from %d\n", original->instance_id());
compiled_module_ = WasmCompiledModule::Clone(isolate_, original);
// Replace the strong reference to point to the new instance here.
// This allows any of the other instances, including the original,
// to be collected.
module_object_->SetInternalField(0, *compiled_module_);
compiled_module_->set_weak_module_object(
original->weak_module_object());
link_to_original = factory->NewWeakCell(original);
// Don't link to original here. We remember the original
// as a weak link. If that link isn't clear by the time we finish
// instantiating this instance, then we link it at that time.
compiled_module_->reset_weak_next_instance();
// Clone the code for WASM functions and exports.
for (int i = 0; i < code_table->length(); ++i) {
Handle<Code> orig_code =
code_table->GetValueChecked<Code>(isolate_, i);
switch (orig_code->kind()) {
case Code::WASM_TO_JS_FUNCTION:
// Imports will be overwritten with newly compiled wrappers.
break;
case Code::JS_TO_WASM_FUNCTION:
case Code::WASM_FUNCTION: {
Handle<Code> code = factory->CopyCode(orig_code);
code_table->set(i, *code);
break;
}
default:
UNREACHABLE();
}
}
RecordStats(isolate_, code_table);
} else {
// There was no owner, so we can reuse the original.
compiled_module_ = original;
TRACE("Reusing existing instance %d\n",
compiled_module_->instance_id());
}
compiled_module_->set_code_table(code_table);
}
//--------------------------------------------------------------------------
// Allocate the instance object.
//--------------------------------------------------------------------------
Handle<Map> map = factory->NewMap(
JS_OBJECT_TYPE,
JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED);
instance->SetInternalField(kWasmModuleCodeTable, *code_table);
//--------------------------------------------------------------------------
// Set up the memory for the new instance.
//--------------------------------------------------------------------------
MaybeHandle<JSArrayBuffer> old_memory;
// TODO(titzer): handle imported memory properly.
uint32_t min_mem_pages = compiled_module_->min_memory_pages();
isolate_->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages);
// TODO(wasm): re-enable counter for max_mem_pages when we use that field.
if (memory_.is_null() && min_mem_pages > 0) {
memory_ = AllocateMemory(min_mem_pages);
if (memory_.is_null()) return nothing; // failed to allocate memory
}
if (!memory_.is_null()) {
instance->SetInternalField(kWasmMemArrayBuffer, *memory_);
Address mem_start = static_cast<Address>(memory_->backing_store());
uint32_t mem_size =
static_cast<uint32_t>(memory_->byte_length()->Number());
LoadDataSegments(mem_start, mem_size);
uint32_t old_mem_size = compiled_module_->has_heap()
? compiled_module_->mem_size()
: compiled_module_->default_mem_size();
Address old_mem_start =
compiled_module_->has_heap()
? static_cast<Address>(compiled_module_->heap()->backing_store())
: nullptr;
RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size,
mem_size);
compiled_module_->set_heap(memory_);
}
//--------------------------------------------------------------------------
// Set up the globals for the new instance.
//--------------------------------------------------------------------------
MaybeHandle<JSArrayBuffer> old_globals;
MaybeHandle<JSArrayBuffer> globals;
uint32_t globals_size = compiled_module_->globals_size();
if (globals_size > 0) {
Handle<JSArrayBuffer> global_buffer =
NewArrayBuffer(isolate_, globals_size);
globals = global_buffer;
if (globals.is_null()) {
thrower_->Error("Out of memory: wasm globals");
return nothing;
}
Address old_address =
owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate(
*factory->undefined_value(),
JSObject::cast(*owner));
RelocateGlobals(instance, old_address,
static_cast<Address>(global_buffer->backing_store()));
instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer);
}
//--------------------------------------------------------------------------
// Process the imports for the module.
//--------------------------------------------------------------------------
int num_imported_functions = ProcessImports(globals, code_table);
if (num_imported_functions < 0) return nothing;
//--------------------------------------------------------------------------
// Process the initialization for the module's globals.
//--------------------------------------------------------------------------
ProcessInits(globals);
//--------------------------------------------------------------------------
// Set up the debug support for the new instance.
//--------------------------------------------------------------------------
// TODO(wasm): avoid referencing this stuff from the instance, use it off
// the compiled module instead. See the following 3 assignments:
if (compiled_module_->has_module_bytes()) {
instance->SetInternalField(kWasmModuleBytesString,
compiled_module_->ptr_to_module_bytes());
}
if (compiled_module_->has_function_names()) {
instance->SetInternalField(kWasmFunctionNamesArray,
compiled_module_->ptr_to_function_names());
}
{
Handle<Object> handle = factory->NewNumber(num_imported_functions);
instance->SetInternalField(kWasmNumImportedFunctions, *handle);
}
//--------------------------------------------------------------------------
// Set up the runtime support for the new instance.
//--------------------------------------------------------------------------
Handle<WeakCell> weak_link = factory->NewWeakCell(instance);
for (int i = num_imported_functions + FLAG_skip_compiling_wasm_funcs;
i < code_table->length(); ++i) {
Handle<Code> code = code_table->GetValueChecked<Code>(isolate_, i);
if (code->kind() == Code::WASM_FUNCTION) {
Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED);
deopt_data->set(0, *weak_link);
deopt_data->set(1, Smi::FromInt(static_cast<int>(i)));
deopt_data->set_length(2);
code->set_deoptimization_data(*deopt_data);
}
}
// Instantiates a WASM module, creating a WebAssembly.Instance from a
// WebAssembly.Module.
MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
ErrorThrower* thrower,
Handle<JSObject> module_object,
Handle<JSReceiver> ffi,
Handle<JSArrayBuffer> memory) {
MaybeHandle<JSObject> nothing;
HistogramTimerScope wasm_instantiate_module_time_scope(
isolate->counters()->wasm_instantiate_module_time());
Factory* factory = isolate->factory();
//--------------------------------------------------------------------------
// Set up the indirect function tables for the new instance.
//--------------------------------------------------------------------------
{
std::vector<Handle<Code>> functions(
static_cast<size_t>(code_table->length()));
//--------------------------------------------------------------------------
// Reuse the compiled module (if no owner), otherwise clone.
//--------------------------------------------------------------------------
Handle<WasmCompiledModule> compiled_module;
Handle<FixedArray> code_table;
Handle<FixedArray> old_code_table;
Handle<JSObject> owner;
// If we don't clone, this will be null(). Otherwise, this will
// be a weak link to the original. If we lose the original to GC,
// this will be a cleared. We'll link the instances chain last.
MaybeHandle<WeakCell> link_to_original;
TRACE("Starting new module instantiation\n");
{
Handle<WasmCompiledModule> original(
WasmCompiledModule::cast(module_object->GetInternalField(0)), isolate);
// Always make a new copy of the code_table, since the old_code_table
// may still have placeholders for imports.
old_code_table = original->code_table();
code_table = factory->CopyFixedArray(old_code_table);
if (original->has_weak_owning_instance()) {
WeakCell* tmp = original->ptr_to_weak_owning_instance();
DCHECK(!tmp->cleared());
// There is already an owner, clone everything.
owner = Handle<JSObject>(JSObject::cast(tmp->value()), isolate);
// Insert the latest clone in front.
TRACE("Cloning from %d\n", original->instance_id());
compiled_module = WasmCompiledModule::Clone(isolate, original);
// Replace the strong reference to point to the new instance here.
// This allows any of the other instances, including the original,
// to be collected.
module_object->SetInternalField(0, *compiled_module);
compiled_module->set_weak_module_object(original->weak_module_object());
link_to_original = factory->NewWeakCell(original);
// Don't link to original here. We remember the original
// as a weak link. If that link isn't clear by the time we finish
// instantiating this instance, then we link it at that time.
compiled_module->reset_weak_next_instance();
// Clone the code for WASM functions and exports.
for (int i = 0; i < code_table->length(); ++i) {
functions[i] = code_table->GetValueChecked<Code>(isolate_, i);
}
if (compiled_module_->has_indirect_function_tables()) {
Handle<FixedArray> indirect_tables_template =
compiled_module_->indirect_function_tables();
Handle<FixedArray> to_replace =
owner.is_null() ? indirect_tables_template
: handle(FixedArray::cast(owner->GetInternalField(
kWasmModuleFunctionTable)));
Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable(
isolate_, code_table, indirect_tables_template, to_replace);
for (int i = 0; i < indirect_tables->length(); ++i) {
Handle<FixedArray> metadata =
indirect_tables->GetValueChecked<FixedArray>(isolate_, i);
uint32_t size = Smi::cast(metadata->get(kSize))->value();
Handle<FixedArray> table =
metadata->GetValueChecked<FixedArray>(isolate_, kTable);
PopulateFunctionTable(table, size, &functions);
Handle<Code> orig_code = code_table->GetValueChecked<Code>(isolate, i);
switch (orig_code->kind()) {
case Code::WASM_TO_JS_FUNCTION:
// Imports will be overwritten with newly compiled wrappers.
break;
case Code::JS_TO_WASM_FUNCTION:
case Code::WASM_FUNCTION: {
Handle<Code> code = factory->CopyCode(orig_code);
code_table->set(i, *code);
break;
}
default:
UNREACHABLE();
}
instance->SetInternalField(kWasmModuleFunctionTable, *indirect_tables);
}
RecordStats(isolate, code_table);
} else {
// There was no owner, so we can reuse the original.
compiled_module = original;
TRACE("Reusing existing instance %d\n", compiled_module->instance_id());
}
//--------------------------------------------------------------------------
// Set up the exports object for the new instance.
//--------------------------------------------------------------------------
ProcessExports(globals, code_table, instance);
if (num_imported_functions > 0 || !owner.is_null()) {
// If the code was cloned, or new imports were compiled, patch.
PatchDirectCalls(old_code_table, code_table, num_imported_functions);
compiled_module->set_code_table(code_table);
}
//--------------------------------------------------------------------------
// Allocate the instance object.
//--------------------------------------------------------------------------
Handle<Map> map = factory->NewMap(
JS_OBJECT_TYPE,
JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
Handle<JSObject> instance = factory->NewJSObjectFromMap(map, TENURED);
instance->SetInternalField(kWasmModuleCodeTable, *code_table);
//--------------------------------------------------------------------------
// Set up the memory for the new instance.
//--------------------------------------------------------------------------
MaybeHandle<JSArrayBuffer> old_memory;
// TODO(titzer): handle imported memory properly.
uint32_t min_mem_pages = compiled_module->min_memory_pages();
isolate->counters()->wasm_min_mem_pages_count()->AddSample(min_mem_pages);
// TODO(wasm): re-enable counter for max_mem_pages when we use that field.
if (memory.is_null() && min_mem_pages > 0) {
memory = AllocateMemory(thrower, isolate, min_mem_pages);
if (memory.is_null()) return nothing; // failed to allocate memory
}
if (!memory.is_null()) {
instance->SetInternalField(kWasmMemArrayBuffer, *memory);
Address mem_start = static_cast<Address>(memory->backing_store());
uint32_t mem_size = static_cast<uint32_t>(memory->byte_length()->Number());
LoadDataSegments(compiled_module, mem_start, mem_size);
uint32_t old_mem_size = compiled_module->has_heap()
? compiled_module->mem_size()
: compiled_module->default_mem_size();
Address old_mem_start =
compiled_module->has_heap()
? static_cast<Address>(compiled_module->heap()->backing_store())
: nullptr;
RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size,
mem_size);
compiled_module->set_heap(memory);
}
//--------------------------------------------------------------------------
// Set up the globals for the new instance.
//--------------------------------------------------------------------------
MaybeHandle<JSArrayBuffer> old_globals;
MaybeHandle<JSArrayBuffer> globals;
uint32_t globals_size = compiled_module->globals_size();
if (globals_size > 0) {
Handle<JSArrayBuffer> global_buffer = NewArrayBuffer(isolate, globals_size);
globals = global_buffer;
if (globals.is_null()) {
thrower->Error("Out of memory: wasm globals");
return nothing;
}
FlushICache(isolate_, code_table);
//--------------------------------------------------------------------------
// Run the start function if one was specified.
//--------------------------------------------------------------------------
if (compiled_module_->has_startup_function()) {
Handle<FixedArray> startup_data = compiled_module_->startup_function();
HandleScope scope(isolate_);
int32_t start_index =
startup_data->GetValueChecked<Smi>(isolate_, kExportIndex)->value();
Handle<Code> startup_code =
code_table->GetValueChecked<Code>(isolate_, start_index);
int arity = Smi::cast(startup_data->get(kExportArity))->value();
MaybeHandle<ByteArray> startup_signature =
startup_data->GetValue<ByteArray>(isolate_, kExportedSignature);
Handle<JSFunction> startup_fct = WrapExportCodeAsJSFunction(
isolate_, startup_code, factory->InternalizeUtf8String("start"),
arity, startup_signature, instance);
RecordStats(isolate_, *startup_code);
// Call the JS function.
Handle<Object> undefined = factory->undefined_value();
MaybeHandle<Object> retval =
Execution::Call(isolate_, startup_fct, undefined, 0, nullptr);
if (retval.is_null()) {
thrower_->Error("WASM.instantiateModule(): start function failed");
return nothing;
}
Address old_address =
owner.is_null() ? nullptr : GetGlobalStartAddressFromCodeTemplate(
*isolate->factory()->undefined_value(),
JSObject::cast(*owner));
RelocateGlobals(instance, old_address,
static_cast<Address>(global_buffer->backing_store()));
instance->SetInternalField(kWasmGlobalsArrayBuffer, *global_buffer);
}
//--------------------------------------------------------------------------
// Compile the import wrappers for the new instance.
//--------------------------------------------------------------------------
// TODO(titzer): handle imported globals and function tables.
int num_imported_functions = 0;
if (compiled_module->has_import_data()) {
Handle<FixedArray> import_data = compiled_module->import_data();
num_imported_functions = import_data->length();
for (int index = 0; index < num_imported_functions; index++) {
Handle<Code> import_wrapper =
CompileImportWrapper(isolate, ffi, index, import_data, thrower);
if (thrower->error()) return nothing;
code_table->set(index, *import_wrapper);
RecordStats(isolate, *import_wrapper);
}
}
DCHECK(wasm::IsWasmObject(*instance));
{
Handle<WeakCell> link_to_owner = factory->NewWeakCell(instance);
Handle<Object> global_handle =
isolate_->global_handles()->Create(*instance);
Handle<WeakCell> link_to_clone = factory->NewWeakCell(compiled_module_);
{
DisallowHeapAllocation no_gc;
compiled_module_->set_weak_owning_instance(link_to_owner);
Handle<WeakCell> next;
if (link_to_original.ToHandle(&next) && !next->cleared()) {
WasmCompiledModule* original =
WasmCompiledModule::cast(next->value());
DCHECK(original->has_weak_owning_instance());
DCHECK(!original->weak_owning_instance()->cleared());
compiled_module_->set_weak_next_instance(next);
original->set_weak_prev_instance(link_to_clone);
}
compiled_module_->set_weak_owning_instance(link_to_owner);
instance->SetInternalField(kWasmCompiledModule, *compiled_module_);
GlobalHandles::MakeWeak(global_handle.location(),
global_handle.location(), &InstanceFinalizer,
v8::WeakCallbackType::kFinalizer);
}
}
TRACE("Finishing instance %d\n", compiled_module_->instance_id());
TRACE_CHAIN(WasmCompiledModule::cast(module_object_->GetInternalField(0)));
return instance;
//--------------------------------------------------------------------------
// Set up the debug support for the new instance.
//--------------------------------------------------------------------------
// TODO(wasm): avoid referencing this stuff from the instance, use it off
// the compiled module instead. See the following 3 assignments:
if (compiled_module->has_module_bytes()) {
instance->SetInternalField(kWasmModuleBytesString,
compiled_module->ptr_to_module_bytes());
}
private:
Isolate* isolate_;
ErrorThrower* thrower_;
Handle<JSObject> module_object_;
Handle<JSReceiver> ffi_;
Handle<JSArrayBuffer> memory_;
Handle<WasmCompiledModule> compiled_module_;
// Helper routine to print out errors with imports (FFI).
MaybeHandle<JSFunction> ReportFFIError(const char* error, uint32_t index,
Handle<String> module_name,
MaybeHandle<String> function_name) {
Handle<String> function_name_handle;
if (function_name.ToHandle(&function_name_handle)) {
thrower_->Error("Import #%d module=\"%.*s\" function=\"%.*s\" error: %s",
index, module_name->length(),
module_name->ToCString().get(),
function_name_handle->length(),
function_name_handle->ToCString().get(), error);
} else {
thrower_->Error("Import #%d module=\"%.*s\" error: %s", index,
module_name->length(), module_name->ToCString().get(),
error);
}
thrower_->Error("Import ");
return MaybeHandle<JSFunction>();
if (compiled_module->has_function_names()) {
instance->SetInternalField(kWasmFunctionNamesArray,
compiled_module->ptr_to_function_names());
}
// Look up an import value in the {ffi_} object.
MaybeHandle<Object> LookupImport(uint32_t index, Handle<String> module_name,
MaybeHandle<String> import_name) {
if (ffi_.is_null()) {
return ReportFFIError("FFI is not an object", index, module_name,
import_name);
{
Handle<Object> handle = factory->NewNumber(num_imported_functions);
instance->SetInternalField(kWasmNumImportedFunctions, *handle);
}
//--------------------------------------------------------------------------
// Set up the runtime support for the new instance.
//--------------------------------------------------------------------------
Handle<WeakCell> weak_link = isolate->factory()->NewWeakCell(instance);
for (int i = num_imported_functions + FLAG_skip_compiling_wasm_funcs;
i < code_table->length(); ++i) {
Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
if (code->kind() == Code::WASM_FUNCTION) {
Handle<FixedArray> deopt_data =
isolate->factory()->NewFixedArray(2, TENURED);
deopt_data->set(0, *weak_link);
deopt_data->set(1, Smi::FromInt(static_cast<int>(i)));
deopt_data->set_length(2);
code->set_deoptimization_data(*deopt_data);
}
}
// Look up the module first.
MaybeHandle<Object> result = Object::GetProperty(ffi_, module_name);
if (result.is_null()) {
return ReportFFIError("module not found", index, module_name,
import_name);
//--------------------------------------------------------------------------
// Set up the indirect function tables for the new instance.
//--------------------------------------------------------------------------
{
std::vector<Handle<Code>> functions(
static_cast<size_t>(code_table->length()));
for (int i = 0; i < code_table->length(); ++i) {
functions[i] = code_table->GetValueChecked<Code>(isolate, i);
}
Handle<Object> module = result.ToHandleChecked();
if (!import_name.is_null()) {
// Look up the value in the module.
if (!module->IsJSReceiver()) {
return ReportFFIError("module is not an object or function", index,
module_name, import_name);
}
result = Object::GetProperty(module, import_name.ToHandleChecked());
if (result.is_null()) {
return ReportFFIError("import not found", index, module_name,
import_name);
if (compiled_module->has_indirect_function_tables()) {
Handle<FixedArray> indirect_tables_template =
compiled_module->indirect_function_tables();
Handle<FixedArray> to_replace =
owner.is_null() ? indirect_tables_template
: handle(FixedArray::cast(owner->GetInternalField(
kWasmModuleFunctionTable)));
Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable(
isolate, code_table, indirect_tables_template, to_replace);
for (int i = 0; i < indirect_tables->length(); ++i) {
Handle<FixedArray> metadata =
indirect_tables->GetValueChecked<FixedArray>(isolate, i);
uint32_t size = Smi::cast(metadata->get(kSize))->value();
Handle<FixedArray> table =
metadata->GetValueChecked<FixedArray>(isolate, kTable);
PopulateFunctionTable(table, size, &functions);
}
} else {
// No function specified. Use the "default export".
result = module;
}
return result;
}
// Load data segments into the memory.
void LoadDataSegments(Address mem_addr, size_t mem_size) {
CHECK(compiled_module_->has_data_segments() ==
compiled_module_->has_data_segments_info());
// If we have neither, we're done.
if (!compiled_module_->has_data_segments()) return;
Handle<ByteArray> data = compiled_module_->data_segments();
Handle<FixedArray> segments = compiled_module_->data_segments_info();
uint32_t last_extraction_pos = 0;
for (int i = 0; i < segments->length(); ++i) {
Handle<ByteArray> segment =
Handle<ByteArray>(ByteArray::cast(segments->get(i)));
uint32_t dest_addr =
static_cast<uint32_t>(segment->get_int(kDestAddrValue));
uint32_t source_size =
static_cast<uint32_t>(segment->get_int(kSourceSize));
CHECK_LT(dest_addr, mem_size);
CHECK_LE(source_size, mem_size);
CHECK_LE(dest_addr, mem_size - source_size);
byte* addr = mem_addr + dest_addr;
data->copy_out(last_extraction_pos, addr, source_size);
last_extraction_pos += source_size;
instance->SetInternalField(kWasmModuleFunctionTable, *indirect_tables);
}
}
Handle<Code> CompileImportWrapper(int index, Handle<FixedArray> data,
Handle<JSReceiver> target,
Handle<String> module_name,
MaybeHandle<String> import_name) {
// TODO(mtrofin): this is an uint32_t, actually. We should rationalize
// it when we rationalize signed/unsigned stuff.
int ret_count = Smi::cast(data->get(kOutputCount))->value();
CHECK_GE(ret_count, 0);
Handle<ByteArray> sig_data =
data->GetValueChecked<ByteArray>(isolate_, kSignature);
int sig_data_size = sig_data->length();
int param_count = sig_data_size - ret_count;
CHECK(param_count >= 0);
Handle<Code> code;
bool isMatch = false;
Handle<Code> export_wrapper_code;
if (target->IsJSFunction()) {
Handle<JSFunction> func = Handle<JSFunction>::cast(target);
export_wrapper_code = handle(func->code());
if (export_wrapper_code->kind() == Code::JS_TO_WASM_FUNCTION) {
int exported_param_count =
Smi::cast(func->GetInternalField(kInternalArity))->value();
Handle<ByteArray> exportedSig = Handle<ByteArray>(
ByteArray::cast(func->GetInternalField(kInternalSignature)));
if (exported_param_count == param_count &&
exportedSig->length() == sig_data->length() &&
memcmp(exportedSig->GetDataStartAddress(),
sig_data->GetDataStartAddress(),
exportedSig->length()) == 0) {
isMatch = true;
}
}
}
if (isMatch) {
int wasm_count = 0;
int const mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
for (RelocIterator it(*export_wrapper_code, mask); !it.done();
it.next()) {
RelocInfo* rinfo = it.rinfo();
Address target_address = rinfo->target_address();
Code* target = Code::GetCodeFromTargetAddress(target_address);
if (target->kind() == Code::WASM_FUNCTION) {
++wasm_count;
code = handle(target);
}
}
DCHECK(wasm_count == 1);
return code;
} else {
// Copy the signature to avoid a raw pointer into a heap object when
// GC can happen.
Zone zone(isolate_->allocator());
MachineRepresentation* reps =
zone.NewArray<MachineRepresentation>(sig_data_size);
memcpy(reps, sig_data->GetDataStartAddress(),
sizeof(MachineRepresentation) * sig_data_size);
FunctionSig sig(ret_count, param_count, reps);
return compiler::CompileWasmToJSWrapper(isolate_, target, &sig, index,
module_name, import_name);
}
}
//--------------------------------------------------------------------------
// Set up the exports object for the new instance.
//--------------------------------------------------------------------------
bool mem_export = compiled_module->export_memory();
ModuleOrigin origin = compiled_module->origin();
void WriteGlobalValue(MaybeHandle<JSArrayBuffer> globals, uint32_t offset,
Handle<Object> value, int type) {
double num = 0;
if (value->IsSmi()) {
num = Smi::cast(*value)->value();
} else if (value->IsHeapNumber()) {
num = HeapNumber::cast(*value)->value();
} else {
UNREACHABLE();
if (compiled_module->has_exports() || mem_export) {
PropertyDescriptor desc;
desc.set_writable(false);
Handle<JSObject> exports_object = instance;
if (origin == kWasmOrigin) {
// Create the "exports" object.
Handle<JSFunction> object_function = Handle<JSFunction>(
isolate->native_context()->object_function(), isolate);
exports_object = factory->NewJSObject(object_function, TENURED);
Handle<String> exports_name = factory->InternalizeUtf8String("exports");
JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY);
}
TRACE("init [globals+%u] = %lf, type = %d\n", offset, num, type);
byte* ptr = raw_buffer_ptr(globals, offset);
switch (type) {
case kLocalI32:
*reinterpret_cast<int32_t*>(ptr) = static_cast<int32_t>(num);
break;
case kLocalI64:
// TODO(titzer): initialization of imported i64 globals.
UNREACHABLE();
int first_export = -1;
// TODO(wasm): another iteration over the code objects.
for (int i = 0; i < code_table->length(); i++) {
Handle<Code> code = code_table->GetValueChecked<Code>(isolate, i);
if (code->kind() == Code::JS_TO_WASM_FUNCTION) {
first_export = i;
break;
case kLocalF32:
*reinterpret_cast<float*>(ptr) = static_cast<float>(num);
break;
case kLocalF64:
*reinterpret_cast<double*>(ptr) = num;
break;
default:
UNREACHABLE();
}
}
}
// Process the imports, including functions, tables, globals, and memory, in
// order, loading them from the {ffi_} object. Returns the number of imported
// functions.
int ProcessImports(MaybeHandle<JSArrayBuffer> globals,
Handle<FixedArray> code_table) {
int num_imported_functions = 0;
if (!compiled_module_->has_imports()) return num_imported_functions;
Handle<FixedArray> imports = compiled_module_->imports();
for (int index = 0; index < imports->length(); ++index) {
Handle<FixedArray> data =
imports->GetValueChecked<FixedArray>(isolate_, index);
Handle<String> module_name =
data->GetValueChecked<String>(isolate_, kModuleName);
MaybeHandle<String> function_name =
data->GetValue<String>(isolate_, kFunctionName);
MaybeHandle<Object> result =
LookupImport(index, module_name, function_name);
if (thrower_->error()) return -1;
WasmExternalKind kind = static_cast<WasmExternalKind>(
Smi::cast(data->get(kImportKind))->value());
switch (kind) {
case kExternalFunction: {
// Function imports must be callable.
Handle<Object> function = result.ToHandleChecked();
if (!function->IsCallable()) {
ReportFFIError("function import requires a callable", index,
module_name, function_name);
return -1;
}
Handle<Code> import_wrapper = CompileImportWrapper(
index, data, Handle<JSReceiver>::cast(function), module_name,
function_name);
int func_index = Smi::cast(data->get(kImportIndex))->value();
code_table->set(func_index, *import_wrapper);
RecordStats(isolate_, *import_wrapper);
num_imported_functions++;
break;
}
case kExternalTable:
// TODO(titzer): Table imports must be a WebAssembly.Table.
break;
case kExternalMemory:
// TODO(titzer): Memory imports must be a WebAssembly.Memory.
break;
case kExternalGlobal: {
// Global imports are converted to numbers and written into the
// {globals} array buffer.
Handle<Object> object = result.ToHandleChecked();
MaybeHandle<Object> number = Object::ToNumber(object);
if (number.is_null()) {
ReportFFIError("global import could not be converted to number",
index, module_name, function_name);
return -1;
}
Handle<Object> val = number.ToHandleChecked();
int offset = Smi::cast(data->get(kImportIndex))->value();
int type = Smi::cast(data->get(kImportGlobalType))->value();
WriteGlobalValue(globals, offset, val, type);
break;
if (compiled_module->has_exports()) {
Handle<FixedArray> exports = compiled_module->exports();
int export_size = exports->length();
for (int i = 0; i < export_size; ++i) {
Handle<FixedArray> export_data =
exports->GetValueChecked<FixedArray>(isolate, i);
Handle<String> name =
export_data->GetValueChecked<String>(isolate, kExportName);
int arity = Smi::cast(export_data->get(kExportArity))->value();
MaybeHandle<ByteArray> signature =
export_data->GetValue<ByteArray>(isolate, kExportedSignature);
Handle<Code> export_code =
code_table->GetValueChecked<Code>(isolate, first_export + i);
Handle<JSFunction> function = WrapExportCodeAsJSFunction(
isolate, export_code, name, arity, signature, instance);
desc.set_value(function);
Maybe<bool> status = JSReceiver::DefineOwnProperty(
isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
if (!status.IsJust()) {
thrower->Error("export of %.*s failed.", name->length(),
name->ToCString().get());
return nothing;
}
default:
UNREACHABLE();
break;
}
}
return num_imported_functions;
}
// Process initialization of globals.
void ProcessInits(MaybeHandle<JSArrayBuffer> globals) {
if (!compiled_module_->has_inits()) return;
Handle<FixedArray> inits = compiled_module_->inits();
for (int index = 0; index < inits->length(); ++index) {
Handle<FixedArray> data =
inits->GetValueChecked<FixedArray>(isolate_, index);
int offset = Smi::cast(data->get(kGlobalInitIndex))->value();
Handle<Object> val(data->get(kGlobalInitValue), isolate_);
int type = Smi::cast(data->get(kGlobalInitType))->value();
if (Smi::cast(data->get(kGlobalInitKind))->value() == 0) {
// Initialize with a constant.
WriteGlobalValue(globals, offset, val, type);
} else {
// Initialize with another global.
int old_offset = Smi::cast(*val)->value();
TRACE("init [globals+%u] = [globals+%d]\n", offset, old_offset);
int size = sizeof(int32_t);
if (type == kLocalI64 || type == kLocalF64) size = sizeof(double);
memcpy(raw_buffer_ptr(globals, offset),
raw_buffer_ptr(globals, old_offset), size);
}
if (mem_export) {
// Export the memory as a named property.
Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>(
JSArrayBuffer::cast(instance->GetInternalField(kWasmMemArrayBuffer)));
Handle<Object> memory_object =
WasmJs::CreateWasmMemoryObject(isolate, buffer, false, 0);
// TODO(titzer): export the memory with the correct name.
Handle<String> name = factory->InternalizeUtf8String("memory");
JSObject::AddProperty(exports_object, name, memory_object, READ_ONLY);
}
}
// Allocate memory for a module instance as a new JSArrayBuffer.
Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) {
if (min_mem_pages > WasmModule::kMaxMemPages) {
thrower_->Error("Out of memory: wasm memory too large");
return Handle<JSArrayBuffer>::null();
}
Handle<JSArrayBuffer> mem_buffer =
NewArrayBuffer(isolate_, min_mem_pages * WasmModule::kPageSize);
if (mem_buffer.is_null()) {
thrower_->Error("Out of memory: wasm memory");
}
return mem_buffer;
if (num_imported_functions > 0 || !owner.is_null()) {
// If the code was cloned, or new imports were compiled, patch.
PatchDirectCalls(old_code_table, code_table, num_imported_functions);
}
// Process the exports, creating wrappers for functions, tables, memories,
// and globals.
void ProcessExports(MaybeHandle<JSArrayBuffer> globals,
Handle<FixedArray> code_table,
Handle<JSObject> instance) {
if (!compiled_module_->has_exports()) return;
FlushICache(isolate, code_table);
Handle<JSObject> exports_object = instance;
if (compiled_module_->origin() == kWasmOrigin) {
// Create the "exports" object.
Handle<JSFunction> object_function = Handle<JSFunction>(
isolate_->native_context()->object_function(), isolate_);
exports_object =
isolate_->factory()->NewJSObject(object_function, TENURED);
Handle<String> exports_name =
isolate_->factory()->InternalizeUtf8String("exports");
JSObject::AddProperty(instance, exports_name, exports_object, READ_ONLY);
//--------------------------------------------------------------------------
// Run the start function if one was specified.
//--------------------------------------------------------------------------
if (compiled_module->has_startup_function()) {
Handle<FixedArray> startup_data = compiled_module->startup_function();
HandleScope scope(isolate);
int32_t start_index =
startup_data->GetValueChecked<Smi>(isolate, kExportedFunctionIndex)
->value();
Handle<Code> startup_code =
code_table->GetValueChecked<Code>(isolate, start_index);
int arity = Smi::cast(startup_data->get(kExportArity))->value();
MaybeHandle<ByteArray> startup_signature =
startup_data->GetValue<ByteArray>(isolate, kExportedSignature);
Handle<JSFunction> startup_fct = WrapExportCodeAsJSFunction(
isolate, startup_code, factory->InternalizeUtf8String("start"), arity,
startup_signature, instance);
RecordStats(isolate, *startup_code);
// Call the JS function.
Handle<Object> undefined = isolate->factory()->undefined_value();
MaybeHandle<Object> retval =
Execution::Call(isolate, startup_fct, undefined, 0, nullptr);
if (retval.is_null()) {
thrower->Error("WASM.instantiateModule(): start function failed");
return nothing;
}
}
PropertyDescriptor desc;
desc.set_writable(false);
DCHECK(wasm::IsWasmObject(*instance));
Handle<FixedArray> exports = compiled_module_->exports();
{
Handle<WeakCell> link_to_owner = factory->NewWeakCell(instance);
for (int i = 0; i < exports->length(); ++i) {
Handle<FixedArray> export_data =
exports->GetValueChecked<FixedArray>(isolate_, i);
Handle<String> name =
export_data->GetValueChecked<String>(isolate_, kExportName);
WasmExternalKind kind = static_cast<WasmExternalKind>(
Smi::cast(export_data->get(kExportKind))->value());
switch (kind) {
case kExternalFunction: {
// Wrap and export the code as a JSFunction.
int code_table_index =
Smi::cast(export_data->get(kExportIndex))->value();
Handle<Code> export_code =
code_table->GetValueChecked<Code>(isolate_, code_table_index);
int arity = Smi::cast(export_data->get(kExportArity))->value();
MaybeHandle<ByteArray> signature =
export_data->GetValue<ByteArray>(isolate_, kExportedSignature);
desc.set_value(WrapExportCodeAsJSFunction(
isolate_, export_code, name, arity, signature, instance));
break;
}
case kExternalTable:
// TODO(titzer): create a WebAssembly.Table instance.
// TODO(titzer): should it have the same identity as an import?
break;
case kExternalMemory: {
// TODO(titzer): should memory have the same identity as an
// import?
Handle<JSArrayBuffer> buffer =
Handle<JSArrayBuffer>(JSArrayBuffer::cast(
instance->GetInternalField(kWasmMemArrayBuffer)));
desc.set_value(
WasmJs::CreateWasmMemoryObject(isolate_, buffer, false, 0));
break;
}
case kExternalGlobal: {
// Export the value of the global variable as a number.
int offset = Smi::cast(export_data->get(kExportIndex))->value();
byte* ptr = raw_buffer_ptr(globals, offset);
double num = 0;
switch (Smi::cast(export_data->get(kExportGlobalType))->value()) {
case kLocalI32:
num = *reinterpret_cast<int32_t*>(ptr);
break;
case kLocalF32:
num = *reinterpret_cast<float*>(ptr);
break;
case kLocalF64:
num = *reinterpret_cast<double*>(ptr);
break;
default:
UNREACHABLE();
}
desc.set_value(isolate_->factory()->NewNumber(num));
break;
}
default:
UNREACHABLE();
break;
Handle<Object> global_handle = isolate->global_handles()->Create(*instance);
Handle<WeakCell> link_to_clone = factory->NewWeakCell(compiled_module);
{
DisallowHeapAllocation no_gc;
compiled_module->set_weak_owning_instance(link_to_owner);
Handle<WeakCell> next;
if (link_to_original.ToHandle(&next) && !next->cleared()) {
WasmCompiledModule* original = WasmCompiledModule::cast(next->value());
DCHECK(original->has_weak_owning_instance());
DCHECK(!original->weak_owning_instance()->cleared());
compiled_module->set_weak_next_instance(next);
original->set_weak_prev_instance(link_to_clone);
}
Maybe<bool> status = JSReceiver::DefineOwnProperty(
isolate_, exports_object, name, &desc, Object::THROW_ON_ERROR);
if (!status.IsJust()) {
thrower_->Error("export of %.*s failed.", name->length(),
name->ToCString().get());
return;
}
compiled_module->set_weak_owning_instance(link_to_owner);
instance->SetInternalField(kWasmCompiledModule, *compiled_module);
GlobalHandles::MakeWeak(global_handle.location(),
global_handle.location(), &InstanceFinalizer,
v8::WeakCallbackType::kFinalizer);
}
}
};
// Instantiates a WASM module, creating a WebAssembly.Instance from a
// WebAssembly.Module.
MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
ErrorThrower* thrower,
Handle<JSObject> module_object,
Handle<JSReceiver> ffi,
Handle<JSArrayBuffer> memory) {
WasmInstanceBuilder builder(isolate, thrower, module_object, ffi, memory);
return builder.Build();
TRACE("Finishing instance %d\n", compiled_module->instance_id());
TRACE_CHAIN(WasmCompiledModule::cast(module_object->GetInternalField(0)));
return instance;
}
#if DEBUG
uint32_t WasmCompiledModule::instance_id_counter_ = 0;
#endif
Handle<WasmCompiledModule> WasmCompiledModule::New(Isolate* isolate,
uint32_t min_memory_pages,
uint32_t globals_size,
bool export_memory,
ModuleOrigin origin) {
Handle<FixedArray> ret =
isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED);
......@@ -1869,6 +1562,7 @@ Handle<WasmCompiledModule> WasmCompiledModule::New(Isolate* isolate,
ret->set(kID_min_memory_pages,
Smi::FromInt(static_cast<int>(min_memory_pages)));
ret->set(kID_globals_size, Smi::FromInt(static_cast<int>(globals_size)));
ret->set(kID_export_memory, Smi::FromInt(static_cast<int>(export_memory)));
ret->set(kID_origin, Smi::FromInt(static_cast<int>(origin)));
WasmCompiledModule::cast(*ret)->Init();
return handle(WasmCompiledModule::cast(*ret));
......@@ -1876,8 +1570,7 @@ Handle<WasmCompiledModule> WasmCompiledModule::New(Isolate* isolate,
void WasmCompiledModule::Init() {
#if DEBUG
static uint32_t instance_id_counter = 0;
set(kID_instance_id, Smi::FromInt(instance_id_counter++));
set(kID_instance_id, Smi::FromInt(instance_id_counter_++));
TRACE("New compiled module id: %d\n", instance_id());
#endif
}
......@@ -1981,7 +1674,7 @@ bool UpdateWasmModuleMemory(Handle<JSObject> object, Address old_start,
// Iterate through the code objects in the code table and update relocation
// information
for (int i = 0; i < code_table->length(); ++i) {
for (int i = 0; i < code_table->length(); i++) {
obj = code_table->get(i);
Handle<Code> code(Code::cast(obj));
......@@ -2016,7 +1709,7 @@ Handle<FixedArray> BuildFunctionTable(Isolate* isolate, uint32_t index,
// platforms, it is possible to have the top bits of "undefined" take
// small integer values (or zero), which are more likely to be equal to
// the signature index we check against.
for (uint32_t i = table->size; i < table->max_size; ++i) {
for (uint32_t i = table->size; i < table->max_size; i++) {
values->set(i, Smi::FromInt(-1));
}
return values;
......
......@@ -86,16 +86,12 @@ struct WasmInitExpr {
double f64_const;
uint32_t global_index;
} val;
};
WasmInitExpr() : kind(kNone) {}
explicit WasmInitExpr(int32_t v) : kind(kI32Const) { val.i32_const = v; }
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;
#define NO_INIT \
{ \
WasmInitExpr::kNone, { 0u } \
}
};
// Static representation of a WASM function.
struct WasmFunction {
......@@ -388,9 +384,8 @@ class WasmCompiledModule : public FixedArray {
#define CORE_WCM_PROPERTY_TABLE(MACRO) \
MACRO(OBJECT, FixedArray, code_table) \
MACRO(OBJECT, FixedArray, imports) \
MACRO(OBJECT, FixedArray, import_data) \
MACRO(OBJECT, FixedArray, exports) \
MACRO(OBJECT, FixedArray, inits) \
MACRO(OBJECT, FixedArray, startup_function) \
MACRO(OBJECT, FixedArray, indirect_function_tables) \
MACRO(OBJECT, String, module_bytes) \
......@@ -400,6 +395,7 @@ class WasmCompiledModule : public FixedArray {
MACRO(OBJECT, ByteArray, data_segments) \
MACRO(SMALL_NUMBER, uint32_t, globals_size) \
MACRO(OBJECT, JSArrayBuffer, heap) \
MACRO(SMALL_NUMBER, bool, export_memory) \
MACRO(SMALL_NUMBER, ModuleOrigin, origin) \
MACRO(WEAK_LINK, WasmCompiledModule, next_instance) \
MACRO(WEAK_LINK, WasmCompiledModule, prev_instance) \
......@@ -428,6 +424,7 @@ class WasmCompiledModule : public FixedArray {
static Handle<WasmCompiledModule> New(Isolate* isolate,
uint32_t min_memory_pages,
uint32_t globals_size,
bool export_memory,
ModuleOrigin origin);
static Handle<WasmCompiledModule> Clone(Isolate* isolate,
......@@ -457,6 +454,9 @@ class WasmCompiledModule : public FixedArray {
void PrintInstancesChain();
private:
#if DEBUG
static uint32_t instance_id_counter_;
#endif
void Init();
DISALLOW_IMPLICIT_CONSTRUCTORS(WasmCompiledModule);
......
......@@ -429,94 +429,3 @@ TEST(Run_WasmModule_GrowMemOobVariableIndex) {
CHECK(try_catch.HasCaught());
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));
global_offset = (global_offset + size - 1) & ~(size - 1); // align
module_.globals.push_back(
{type, true, WasmInitExpr(), global_offset, false, false});
{type, true, NO_INIT, global_offset, false, false});
global_offset += size;
// limit number of globals.
CHECK_LT(global_offset, kMaxGlobalsSize);
......
......@@ -14,8 +14,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder();
builder.addMemory(1,1, true);
builder.addImport("getValue", kSig_i_v);
builder.addFunction("f", kSig_i_v)
builder.addImport("getValue", kSig_i);
builder.addFunction("f", kSig_i)
.addBody([
kExprCallFunction, 0
]).exportFunc();
......
......@@ -12,7 +12,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
builder.addMemory(1,1, true);
var kSig_v_i = makeSig([kAstI32], []);
var signature = builder.addType(kSig_v_i);
builder.addImport("some_value", kSig_i_v);
builder.addImport("some_value", kSig_i);
builder.addImport("writer", signature);
builder.addFunction("main", kSig_i_i)
......@@ -65,7 +65,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function RelationBetweenModuleAndClone() {
let builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i_v)
builder.addFunction("main", kSig_i)
.addBody([kExprI8Const, 42])
.exportFunc();
......@@ -81,7 +81,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function SerializeAfterInstantiation() {
let builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i_v)
builder.addFunction("main", kSig_i)
.addBody([kExprI8Const, 42])
.exportFunc();
......
......@@ -11,7 +11,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var kReturnValue = 88;
var builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i_v)
builder.addFunction("main", kSig_i)
.addBody([
kExprI8Const,
kReturnValue,
......@@ -32,7 +32,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i_v)
builder.addFunction("main", kSig_i)
.addBody([
kExprI8Const,
kReturnValue,
......@@ -57,7 +57,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var builder = new WasmModuleBuilder();
builder.addFunction("main", kSig_i_v)
builder.addFunction("main", kSig_i)
.addBody([
kExprI8Const,
kReturnValue,
......
......@@ -94,7 +94,7 @@ print("Native function");
var builder = new WasmModuleBuilder();
var sig_index = builder.addType(kSig_d_v);
var sig_index = builder.addType(kSig_d);
builder.addImport("func", sig_index);
builder.addFunction("main", sig_index)
.addBody([
......
......@@ -10,7 +10,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function TestFunctionPrototype() {
var builder = new WasmModuleBuilder();
builder.addFunction("nine", kSig_i_v)
builder.addFunction("nine", kSig_i)
.addBody([kExprI8Const, 9])
.exportFunc();
......
// 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) {
var builder = new WasmModuleBuilder();
builder.addImport("foo", kSig_i_v);
builder.addImport("bar", kSig_i_v);
builder.addFunction("main", kSig_i_v)
builder.addImport("foo", kSig_i);
builder.addImport("bar", kSig_i);
builder.addFunction("main", kSig_i)
.addBody([
kExprCallFunction, 0, // --
kExprCallFunction, 1, // --
......
......@@ -12,7 +12,7 @@ let nogc = () => {};
function newModule() {
let builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true);
builder.addFunction("main", kSig_i_v)
builder.addFunction("main", kSig_i)
.addBody([kExprI32Const, 0, kExprI32LoadMem, 0, 0])
.exportFunc();
......
......@@ -12,7 +12,7 @@ let kReturnValue = 117;
let buffer = (() => {
let builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true);
builder.addFunction("main", kSig_i_v)
builder.addFunction("main", kSig_i)
.addBody([kExprI8Const, kReturnValue])
.exportFunc();
......@@ -119,7 +119,7 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
builder.addMemory(1,1, true);
var kSig_v_i = makeSig([kAstI32], []);
var signature = builder.addType(kSig_v_i);
builder.addImport("some_value", kSig_i_v);
builder.addImport("some_value", kSig_i);
builder.addImport("writer", signature);
builder.addFunction("main", kSig_i_i)
......@@ -169,7 +169,7 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
(function GlobalsArePrivateToTheInstance() {
print("GlobalsArePrivateToTheInstance...");
var builder = new WasmModuleBuilder();
builder.addGlobal(kAstI32, true);
builder.addGlobal(kAstI32);
builder.addFunction("read", kSig_i_v)
.addBody([
kExprGetGlobal, 0])
......@@ -196,7 +196,7 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
var builder = new WasmModuleBuilder();
builder.addMemory(1,1, true);
builder.addFunction("f", kSig_i_v)
builder.addFunction("f", kSig_i)
.addBody([
kExprI32Const, 0,
kExprI32LoadMem, 0, 0
......
......@@ -38,7 +38,7 @@ function assertVerifies(sig, body) {
}
assertVerifies(kSig_v_v, [kExprNop]);
assertVerifies(kSig_i_v, [kExprI8Const, 0]);
assertVerifies(kSig_i, [kExprI8Const, 0]);
// Arguments aren't allow to start functions.
assertFails(kSig_i_i, [kExprGetLocal, 0]);
......
......@@ -12,7 +12,7 @@ var debug = true;
(function BasicTest() {
var module = new WasmModuleBuilder();
module.addMemory(1, 2, false);
module.addFunction("foo", kSig_i_v)
module.addFunction("foo", kSig_i)
.addBody([kExprI8Const, 11])
.exportAs("blarg");
......@@ -116,7 +116,7 @@ var debug = true;
(function BasicTestWithUint8Array() {
var module = new WasmModuleBuilder();
module.addMemory(1, 2, false);
module.addFunction("foo", kSig_i_v)
module.addFunction("foo", kSig_i)
.addBody([kExprI8Const, 17])
.exportAs("blarg");
......
......@@ -89,6 +89,8 @@ var kExternalMemory = 2;
var kExternalGlobal = 3;
// Useful signatures
var kSig_i = makeSig([], [kAstI32]);
var kSig_d = makeSig([], [kAstF64]);
var kSig_i_i = makeSig([kAstI32], [kAstI32]);
var kSig_i_l = makeSig([kAstI64], [kAstI32]);
var kSig_i_ii = makeSig([kAstI32, kAstI32], [kAstI32]);
......@@ -98,8 +100,6 @@ var kSig_l_ll = makeSig([kAstI64, kAstI64], [kAstI64]);
var kSig_i_dd = makeSig([kAstF64, kAstF64], [kAstI32]);
var kSig_v_v = makeSig([], []);
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_ii = makeSig([kAstI32, kAstI32], []);
var kSig_v_iii = makeSig([kAstI32, kAstI32, kAstI32], []);
......
......@@ -2,12 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// 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 {
emit_u8(val) {
this.push(val);
......@@ -25,7 +19,7 @@ class Binary extends Array {
this.push((val >> 24) & 0xff);
}
emit_u32v(val) {
emit_varint(val) {
while (true) {
let v = val & 0xff;
val = val >>> 7;
......@@ -46,7 +40,7 @@ class Binary extends Array {
emit_string(string) {
// When testing illegal names, we pass a byte array directly.
if (string instanceof Array) {
this.emit_u32v(string.length);
this.emit_varint(string.length);
this.emit_bytes(string);
return;
}
......@@ -54,7 +48,7 @@ class Binary extends Array {
// This is the hacky way to convert a JavaScript string to a UTF8 encoded
// string only containing single-byte characters.
let string_utf8 = unescape(encodeURIComponent(string));
this.emit_u32v(string_utf8.length);
this.emit_varint(string_utf8.length);
for (let i = 0; i < string_utf8.length; i++) {
this.emit_u8(string_utf8.charCodeAt(i));
}
......@@ -72,26 +66,26 @@ class Binary extends Array {
let section = new Binary;
content_generator(section);
// Emit section length.
this.emit_u32v(section.length);
this.emit_varint(section.length);
// Copy the temporary buffer.
this.push(...section);
}
}
class WasmFunctionBuilder {
constructor(module, name, type_index) {
this.module = module;
constructor(name, type_index) {
this.name = name;
this.type_index = type_index;
this.exports = [];
}
exportAs(name) {
this.module.exports.push({name: name, kind: kExternalFunction, index: this.index});
this.exports.push(name);
return this;
}
exportFunc() {
this.exportAs(this.name);
this.exports.push(this.name);
return this;
}
......@@ -106,33 +100,17 @@ 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 {
constructor() {
this.types = [];
this.imports = [];
this.exports = [];
this.globals = [];
this.functions = [];
this.exports = [];
this.table = [];
this.segments = [];
this.explicit = [];
this.pad = null;
this.num_imported_funcs = 0;
this.num_imported_globals = 0;
return this;
}
......@@ -161,39 +139,29 @@ class WasmModuleBuilder {
return this.types.length - 1;
}
addGlobal(local_type, mutable) {
let glob = new WasmGlobalBuilder(this, local_type, mutable);
glob.index = this.globals.length + this.num_imported_globals;
this.globals.push(glob);
return glob;
addGlobal(local_type) {
this.globals.push(local_type);
return this.globals.length - 1;
}
addFunction(name, type) {
let type_index = (typeof type) == "number" ? type : this.addType(type);
let func = new WasmFunctionBuilder(this, name, type_index);
func.index = this.functions.length + this.num_imported_funcs;
let func = new WasmFunctionBuilder(name, type_index);
func.index = this.functions.length + this.imports.length;
this.functions.push(func);
return func;
}
addImportWithModule(module, name, type) {
let type_index = (typeof type) == "number" ? type : this.addType(type);
this.imports.push({module: module, name: name, kind: kExternalFunction,
type: type_index});
return this.num_imported_funcs++;
this.imports.push({module: module, name: name, type: type_index});
return this.imports.length - 1;
}
addImport(name, 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) {
this.segments.push({addr: addr, data: data, init: init});
return this.segments.length - 1;
......@@ -215,14 +183,14 @@ class WasmModuleBuilder {
if (wasm.types.length > 0) {
if (debug) print("emitting types @ " + binary.length);
binary.emit_section(kTypeSectionCode, section => {
section.emit_u32v(wasm.types.length);
section.emit_varint(wasm.types.length);
for (let type of wasm.types) {
section.emit_u8(kWasmFunctionTypeForm);
section.emit_u32v(type.params.length);
section.emit_varint(type.params.length);
for (let param of type.params) {
section.emit_u8(param);
}
section.emit_u32v(type.results.length);
section.emit_varint(type.results.length);
for (let result of type.results) {
section.emit_u8(result);
}
......@@ -234,19 +202,12 @@ class WasmModuleBuilder {
if (wasm.imports.length > 0) {
if (debug) print("emitting imports @ " + binary.length);
binary.emit_section(kImportSectionCode, section => {
section.emit_u32v(wasm.imports.length);
section.emit_varint(wasm.imports.length);
for (let imp of wasm.imports) {
section.emit_string(imp.module);
section.emit_string(imp.name || '');
section.emit_u8(imp.kind);
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);
}
section.emit_u8(kExternalFunction);
section.emit_varint(imp.type);
}
});
}
......@@ -254,14 +215,16 @@ class WasmModuleBuilder {
// Add functions declarations
let has_names = false;
let names = false;
let exports = 0;
if (wasm.functions.length > 0) {
if (debug) print("emitting function decls @ " + binary.length);
binary.emit_section(kFunctionSectionCode, section => {
section.emit_u32v(wasm.functions.length);
section.emit_varint(wasm.functions.length);
for (let func of wasm.functions) {
has_names = has_names || (func.name != undefined &&
func.name.length > 0);
section.emit_u32v(func.type_index);
exports += func.exports.length;
section.emit_varint(func.type_index);
}
});
}
......@@ -273,8 +236,8 @@ class WasmModuleBuilder {
section.emit_u8(1); // one table entry
section.emit_u8(kWasmAnyFunctionTypeForm);
section.emit_u8(1);
section.emit_u32v(wasm.table.length);
section.emit_u32v(wasm.table.length);
section.emit_varint(wasm.table.length);
section.emit_varint(wasm.table.length);
});
}
......@@ -283,9 +246,9 @@ class WasmModuleBuilder {
if (debug) print("emitting memory @ " + binary.length);
binary.emit_section(kMemorySectionCode, section => {
section.emit_u8(1); // one memory entry
section.emit_u32v(kResizableMaximumFlag);
section.emit_u32v(wasm.memory.min);
section.emit_u32v(wasm.memory.max);
section.emit_varint(kResizableMaximumFlag);
section.emit_varint(wasm.memory.min);
section.emit_varint(wasm.memory.max);
});
}
......@@ -293,46 +256,28 @@ class WasmModuleBuilder {
if (wasm.globals.length > 0) {
if (debug) print ("emitting globals @ " + binary.length);
binary.emit_section(kGlobalSectionCode, section => {
section.emit_u32v(wasm.globals.length);
for (let global of wasm.globals) {
section.emit_u8(global.type);
section.emit_u8(global.mutable);
if ((typeof global.init_index) == "undefined") {
// Emit a constant initializer.
switch (global.type) {
section.emit_varint(wasm.globals.length);
for (let global_type of wasm.globals) {
section.emit_u8(global_type);
section.emit_u8(true); // mutable
switch (global_type) {
case kAstI32:
section.emit_u8(kExprI32Const);
section.emit_u32v(global.init);
section.emit_u8(0);
break;
case kAstI64:
section.emit_u8(kExprI64Const);
section.emit_u8(global.init);
section.emit_u8(0);
break;
case kAstF32:
section.emit_u8(kExprF32Const);
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]);
section.emit_u32(0);
break;
case kAstF64:
section.emit_u8(kExprF64Const);
f64_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]);
section.emit_u8(byte_view[4]);
section.emit_u8(byte_view[5]);
section.emit_u8(byte_view[6]);
section.emit_u8(byte_view[7]);
section.emit_u8(kExprI32Const);
section.emit_u32(0);
section.emit_u32(0);
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
}
......@@ -341,15 +286,16 @@ class WasmModuleBuilder {
// Add export table.
var mem_export = (wasm.memory != undefined && wasm.memory.exp);
var exports_count = wasm.exports.length + (mem_export ? 1 : 0);
if (exports_count > 0) {
if (exports > 0 || mem_export) {
if (debug) print("emitting exports @ " + binary.length);
binary.emit_section(kExportSectionCode, section => {
section.emit_u32v(exports_count);
for (let exp of wasm.exports) {
section.emit_string(exp.name);
section.emit_u8(exp.kind);
section.emit_u32v(exp.index);
section.emit_varint(exports + (mem_export ? 1 : 0));
for (let func of wasm.functions) {
for (let exp of func.exports) {
section.emit_string(exp);
section.emit_u8(kExternalFunction);
section.emit_varint(func.index);
}
}
if (mem_export) {
section.emit_string("memory");
......@@ -363,7 +309,7 @@ class WasmModuleBuilder {
if (wasm.start_index != undefined) {
if (debug) print("emitting start function @ " + binary.length);
binary.emit_section(kStartSectionCode, section => {
section.emit_u32v(wasm.start_index);
section.emit_varint(wasm.start_index);
});
}
......@@ -376,9 +322,9 @@ class WasmModuleBuilder {
section.emit_u8(kExprI32Const);
section.emit_u8(0);
section.emit_u8(kExprEnd);
section.emit_u32v(wasm.table.length);
section.emit_varint(wasm.table.length);
for (let index of wasm.table) {
section.emit_u32v(index);
section.emit_varint(index);
}
});
}
......@@ -388,7 +334,7 @@ class WasmModuleBuilder {
// emit function bodies
if (debug) print("emitting code @ " + binary.length);
binary.emit_section(kCodeSectionCode, section => {
section.emit_u32v(wasm.functions.length);
section.emit_varint(wasm.functions.length);
for (let func of wasm.functions) {
// Function body length will be patched later.
let local_decls = [];
......@@ -410,13 +356,13 @@ class WasmModuleBuilder {
}
let header = new Binary;
header.emit_u32v(local_decls.length);
header.emit_varint(local_decls.length);
for (let decl of local_decls) {
header.emit_u32v(decl.count);
header.emit_varint(decl.count);
header.emit_u8(decl.type);
}
section.emit_u32v(header.length + func.body.length);
section.emit_varint(header.length + func.body.length);
section.emit_bytes(header);
section.emit_bytes(func.body);
}
......@@ -427,13 +373,13 @@ class WasmModuleBuilder {
if (wasm.segments.length > 0) {
if (debug) print("emitting data segments @ " + binary.length);
binary.emit_section(kDataSectionCode, section => {
section.emit_u32v(wasm.segments.length);
section.emit_varint(wasm.segments.length);
for (let seg of wasm.segments) {
section.emit_u8(0); // linear memory index 0
section.emit_u8(kExprI32Const);
section.emit_u32v(seg.addr);
section.emit_varint(seg.addr);
section.emit_u8(kExprEnd);
section.emit_u32v(seg.data.length);
section.emit_varint(seg.data.length);
section.emit_bytes(seg.data);
}
});
......@@ -450,7 +396,7 @@ class WasmModuleBuilder {
if (debug) print("emitting names @ " + binary.length);
binary.emit_section(kUnknownSectionCode, section => {
section.emit_string("name");
section.emit_u32v(wasm.functions.length);
section.emit_varint(wasm.functions.length);
for (let func of wasm.functions) {
var name = func.name == undefined ? "" : func.name;
section.emit_string(name);
......
......@@ -1283,7 +1283,7 @@ class TestModuleEnv : public ModuleEnv {
module = &mod;
}
byte AddGlobal(LocalType type, bool mutability = true) {
mod.globals.push_back({type, mutability, WasmInitExpr(), 0, false, false});
mod.globals.push_back({type, mutability, NO_INIT, 0, false, false});
CHECK(mod.globals.size() <= 127);
return static_cast<byte>(mod.globals.size() - 1);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment