Revert "Revert "Upgrade to 5.0.71.48"" DO NOT MERGE
This reverts commit f2e3994fa5148cc3d9946666f0b0596290192b0e,
and updates the x64 makefile properly so it doesn't break that
build.
FPIIM-449
Change-Id: Ib83e35bfbae6af627451c926a9650ec57c045605
(cherry picked from commit 109988c7ccb6f3fd1a58574fa3dfb88beaef6632)
diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc
index fd24280..02d197c 100644
--- a/src/wasm/wasm-module.cc
+++ b/src/wasm/wasm-module.cc
@@ -31,33 +31,32 @@
std::ostream& operator<<(std::ostream& os, const WasmFunction& function) {
- os << "WASM function with signature ";
+ os << "WASM function with signature " << *function.sig;
- // TODO(titzer): factor out rendering of signatures.
- if (function.sig->return_count() == 0) os << "v";
- for (size_t i = 0; i < function.sig->return_count(); i++) {
- os << WasmOpcodes::ShortNameOf(function.sig->GetReturn(i));
- }
- os << "_";
- if (function.sig->parameter_count() == 0) os << "v";
- for (size_t i = 0; i < function.sig->parameter_count(); i++) {
- os << WasmOpcodes::ShortNameOf(function.sig->GetParam(i));
- }
os << " locals: ";
- if (function.local_int32_count)
- os << function.local_int32_count << " int32s ";
- if (function.local_int64_count)
- os << function.local_int64_count << " int64s ";
- if (function.local_float32_count)
- os << function.local_float32_count << " float32s ";
- if (function.local_float64_count)
- os << function.local_float64_count << " float64s ";
+ if (function.local_i32_count) os << function.local_i32_count << " i32s ";
+ if (function.local_i64_count) os << function.local_i64_count << " i64s ";
+ if (function.local_f32_count) os << function.local_f32_count << " f32s ";
+ if (function.local_f64_count) os << function.local_f64_count << " f64s ";
os << " code bytes: "
<< (function.code_end_offset - function.code_start_offset);
return os;
}
+std::ostream& operator<<(std::ostream& os, const WasmFunctionName& pair) {
+ os << "#" << pair.function_->func_index << ":";
+ if (pair.function_->name_offset > 0) {
+ if (pair.module_) {
+ os << pair.module_->GetName(pair.function_->name_offset);
+ } else {
+ os << "+" << pair.function_->func_index;
+ }
+ } else {
+ os << "?";
+ }
+ return os;
+}
// A helper class for compiling multiple wasm functions that offers
// placeholder code objects for calling functions that are not yet compiled.
@@ -193,35 +192,98 @@
return fixed;
}
-
-Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, int size,
+Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size,
byte** backing_store) {
- void* memory = isolate->array_buffer_allocator()->Allocate(size);
- if (!memory) return Handle<JSArrayBuffer>::null();
+ if (size > (1 << WasmModule::kMaxMemSize)) {
+ // TODO(titzer): lift restriction on maximum memory allocated here.
+ *backing_store = nullptr;
+ return Handle<JSArrayBuffer>::null();
+ }
+ void* memory =
+ isolate->array_buffer_allocator()->Allocate(static_cast<int>(size));
+ if (!memory) {
+ *backing_store = nullptr;
+ return Handle<JSArrayBuffer>::null();
+ }
+
*backing_store = reinterpret_cast<byte*>(memory);
#if DEBUG
// Double check the API allocator actually zero-initialized the memory.
- for (int i = 0; i < size; i++) {
- DCHECK_EQ(0, (*backing_store)[i]);
+ byte* bytes = reinterpret_cast<byte*>(*backing_store);
+ for (size_t i = 0; i < size; i++) {
+ DCHECK_EQ(0, bytes[i]);
}
#endif
Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
- JSArrayBuffer::Setup(buffer, isolate, false, memory, size);
+ JSArrayBuffer::Setup(buffer, isolate, false, memory, static_cast<int>(size));
buffer->set_is_neuterable(false);
return buffer;
}
+
+// Set the memory for a module instance to be the {memory} array buffer.
+void SetMemory(WasmModuleInstance* instance, Handle<JSArrayBuffer> memory) {
+ memory->set_is_neuterable(false);
+ instance->mem_start = reinterpret_cast<byte*>(memory->backing_store());
+ instance->mem_size = memory->byte_length()->Number();
+ instance->mem_buffer = memory;
+}
+
+// Allocate memory for a module instance as a new JSArrayBuffer.
+bool AllocateMemory(ErrorThrower* thrower, Isolate* isolate,
+ WasmModuleInstance* instance) {
+ DCHECK(instance->module);
+ DCHECK(instance->mem_buffer.is_null());
+
+ if (instance->module->min_mem_size_log2 > WasmModule::kMaxMemSize) {
+ thrower->Error("Out of memory: wasm memory too large");
+ return false;
+ }
+ instance->mem_size = static_cast<size_t>(1)
+ << instance->module->min_mem_size_log2;
+ instance->mem_buffer =
+ NewArrayBuffer(isolate, instance->mem_size, &instance->mem_start);
+ if (!instance->mem_start) {
+ thrower->Error("Out of memory: wasm memory");
+ instance->mem_size = 0;
+ return false;
+ }
+ return true;
+}
+
+bool AllocateGlobals(ErrorThrower* thrower, Isolate* isolate,
+ WasmModuleInstance* instance) {
+ instance->globals_size = AllocateGlobalsOffsets(instance->module->globals);
+
+ if (instance->globals_size > 0) {
+ instance->globals_buffer = NewArrayBuffer(isolate, instance->globals_size,
+ &instance->globals_start);
+ if (!instance->globals_start) {
+ // Not enough space for backing store of globals.
+ thrower->Error("Out of memory: wasm globals");
+ return false;
+ }
+ }
+ return true;
+}
} // namespace
-
WasmModule::WasmModule()
- : globals(nullptr),
+ : shared_isolate(nullptr),
+ module_start(nullptr),
+ module_end(nullptr),
+ min_mem_size_log2(0),
+ max_mem_size_log2(0),
+ mem_export(false),
+ mem_external(false),
+ start_function_index(-1),
+ globals(nullptr),
signatures(nullptr),
functions(nullptr),
data_segments(nullptr),
- function_table(nullptr) {}
-
+ function_table(nullptr),
+ import_table(nullptr) {}
WasmModule::~WasmModule() {
if (globals) delete globals;
@@ -229,8 +291,33 @@
if (functions) delete functions;
if (data_segments) delete data_segments;
if (function_table) delete function_table;
+ if (import_table) delete import_table;
}
+static MaybeHandle<JSFunction> LookupFunction(ErrorThrower& thrower,
+ Handle<JSObject> ffi,
+ uint32_t index,
+ Handle<String> name,
+ const char* cstr) {
+ if (!ffi.is_null()) {
+ MaybeHandle<Object> result = Object::GetProperty(ffi, name);
+ if (!result.is_null()) {
+ Handle<Object> obj = result.ToHandleChecked();
+ if (obj->IsJSFunction()) {
+ return Handle<JSFunction>::cast(obj);
+ } else {
+ thrower.Error("FFI function #%d:%s is not a JSFunction.", index, cstr);
+ return MaybeHandle<JSFunction>();
+ }
+ } else {
+ thrower.Error("FFI function #%d:%s not found.", index, cstr);
+ return MaybeHandle<JSFunction>();
+ }
+ } else {
+ thrower.Error("FFI table is not an object.");
+ return MaybeHandle<JSFunction>();
+ }
+}
// Instantiates a wasm module as a JSObject.
// * allocates a backing store of {mem_size} bytes.
@@ -242,95 +329,91 @@
Handle<JSArrayBuffer> memory) {
this->shared_isolate = isolate; // TODO(titzer): have a real shared isolate.
ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
-
Factory* factory = isolate->factory();
- // Memory is bigger than maximum supported size.
- if (memory.is_null() && min_mem_size_log2 > kMaxMemSize) {
- thrower.Error("Out of memory: wasm memory too large");
- return MaybeHandle<JSObject>();
- }
+ //-------------------------------------------------------------------------
+ // Allocate the instance and its JS counterpart.
+ //-------------------------------------------------------------------------
Handle<Map> map = factory->NewMap(
JS_OBJECT_TYPE,
JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize);
-
- //-------------------------------------------------------------------------
- // Allocate the module object.
- //-------------------------------------------------------------------------
- Handle<JSObject> module = factory->NewJSObjectFromMap(map, TENURED);
+ WasmModuleInstance instance(this);
+ std::vector<Handle<Code>> import_code;
+ instance.context = isolate->native_context();
+ instance.js_object = factory->NewJSObjectFromMap(map, TENURED);
Handle<FixedArray> code_table =
factory->NewFixedArray(static_cast<int>(functions->size()), TENURED);
+ instance.js_object->SetInternalField(kWasmModuleCodeTable, *code_table);
//-------------------------------------------------------------------------
- // Allocate the linear memory.
+ // Allocate and initialize the linear memory.
//-------------------------------------------------------------------------
- uint32_t mem_size = 1 << min_mem_size_log2;
- byte* mem_addr = nullptr;
- Handle<JSArrayBuffer> mem_buffer;
- if (!memory.is_null()) {
- memory->set_is_neuterable(false);
- mem_addr = reinterpret_cast<byte*>(memory->backing_store());
- mem_size = memory->byte_length()->Number();
- mem_buffer = memory;
- } else {
- mem_buffer = NewArrayBuffer(isolate, mem_size, &mem_addr);
- if (!mem_addr) {
- // Not enough space for backing store of memory
- thrower.Error("Out of memory: wasm memory");
+ if (memory.is_null()) {
+ if (!AllocateMemory(&thrower, isolate, &instance)) {
return MaybeHandle<JSObject>();
}
+ } else {
+ SetMemory(&instance, memory);
}
-
- // Load initialized data segments.
- LoadDataSegments(this, mem_addr, mem_size);
-
- module->SetInternalField(kWasmMemArrayBuffer, *mem_buffer);
+ instance.js_object->SetInternalField(kWasmMemArrayBuffer,
+ *instance.mem_buffer);
+ LoadDataSegments(this, instance.mem_start, instance.mem_size);
if (mem_export) {
// Export the memory as a named property.
Handle<String> name = factory->InternalizeUtf8String("memory");
- JSObject::AddProperty(module, name, mem_buffer, READ_ONLY);
+ JSObject::AddProperty(instance.js_object, name, instance.mem_buffer,
+ READ_ONLY);
}
//-------------------------------------------------------------------------
// Allocate the globals area if necessary.
//-------------------------------------------------------------------------
- size_t globals_size = AllocateGlobalsOffsets(globals);
- byte* globals_addr = nullptr;
- if (globals_size > 0) {
- Handle<JSArrayBuffer> globals_buffer =
- NewArrayBuffer(isolate, mem_size, &globals_addr);
- if (!globals_addr) {
- // Not enough space for backing store of globals.
- thrower.Error("Out of memory: wasm globals");
- return MaybeHandle<JSObject>();
- }
+ if (!AllocateGlobals(&thrower, isolate, &instance)) {
+ return MaybeHandle<JSObject>();
+ }
+ if (!instance.globals_buffer.is_null()) {
+ instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer,
+ *instance.globals_buffer);
+ }
- module->SetInternalField(kWasmGlobalsArrayBuffer, *globals_buffer);
- } else {
- module->SetInternalField(kWasmGlobalsArrayBuffer, Smi::FromInt(0));
+ //-------------------------------------------------------------------------
+ // Compile wrappers to imported functions.
+ //-------------------------------------------------------------------------
+ uint32_t index = 0;
+ instance.function_table = BuildFunctionTable(isolate, this);
+ WasmLinker linker(isolate, functions->size());
+ ModuleEnv module_env;
+ module_env.module = this;
+ module_env.instance = &instance;
+ module_env.linker = &linker;
+ module_env.asm_js = false;
+
+ if (import_table->size() > 0) {
+ instance.import_code = &import_code;
+ instance.import_code->reserve(import_table->size());
+ for (const WasmImport& import : *import_table) {
+ const char* cstr = GetName(import.function_name_offset);
+ Handle<String> name = factory->InternalizeUtf8String(cstr);
+ MaybeHandle<JSFunction> function =
+ LookupFunction(thrower, ffi, index, name, cstr);
+ if (function.is_null()) return MaybeHandle<JSObject>();
+ Handle<Code> code = compiler::CompileWasmToJSWrapper(
+ isolate, &module_env, function.ToHandleChecked(), import.sig, cstr);
+ instance.import_code->push_back(code);
+ index++;
+ }
}
//-------------------------------------------------------------------------
// Compile all functions in the module.
//-------------------------------------------------------------------------
- int index = 0;
- WasmLinker linker(isolate, functions->size());
- ModuleEnv module_env;
- module_env.module = this;
- module_env.mem_start = reinterpret_cast<uintptr_t>(mem_addr);
- module_env.mem_end = reinterpret_cast<uintptr_t>(mem_addr) + mem_size;
- module_env.globals_area = reinterpret_cast<uintptr_t>(globals_addr);
- module_env.linker = &linker;
- module_env.function_code = nullptr;
- module_env.function_table = BuildFunctionTable(isolate, this);
- module_env.memory = memory;
- module_env.context = isolate->native_context();
- module_env.asm_js = false;
// First pass: compile each function and initialize the code table.
+ index = 0;
for (const WasmFunction& func : *functions) {
if (thrower.error()) break;
+ DCHECK_EQ(index, func.func_index);
const char* cstr = GetName(func.name_offset);
Handle<String> name = factory->InternalizeUtf8String(cstr);
@@ -338,38 +421,21 @@
Handle<JSFunction> function = Handle<JSFunction>::null();
if (func.external) {
// Lookup external function in FFI object.
- if (!ffi.is_null()) {
- MaybeHandle<Object> result = Object::GetProperty(ffi, name);
- if (!result.is_null()) {
- Handle<Object> obj = result.ToHandleChecked();
- if (obj->IsJSFunction()) {
- function = Handle<JSFunction>::cast(obj);
- code = compiler::CompileWasmToJSWrapper(isolate, &module_env,
- function, index);
- } else {
- thrower.Error("FFI function #%d:%s is not a JSFunction.", index,
- cstr);
- return MaybeHandle<JSObject>();
- }
- } else {
- thrower.Error("FFI function #%d:%s not found.", index, cstr);
- return MaybeHandle<JSObject>();
- }
- } else {
- thrower.Error("FFI table is not an object.");
- return MaybeHandle<JSObject>();
- }
+ MaybeHandle<JSFunction> function =
+ LookupFunction(thrower, ffi, index, name, cstr);
+ if (function.is_null()) return MaybeHandle<JSObject>();
+ code = compiler::CompileWasmToJSWrapper(
+ isolate, &module_env, function.ToHandleChecked(), func.sig, cstr);
} else {
// Compile the function.
- code = compiler::CompileWasmFunction(thrower, isolate, &module_env, func,
- index);
+ code = compiler::CompileWasmFunction(thrower, isolate, &module_env, func);
if (code.is_null()) {
thrower.Error("Compilation of #%d:%s failed.", index, cstr);
return MaybeHandle<JSObject>();
}
if (func.exported) {
- function = compiler::CompileJSToWasmWrapper(isolate, &module_env, name,
- code, module, index);
+ function = compiler::CompileJSToWasmWrapper(
+ isolate, &module_env, name, code, instance.js_object, index);
}
}
if (!code.is_null()) {
@@ -379,27 +445,54 @@
}
if (func.exported) {
// Exported functions are installed as read-only properties on the module.
- JSObject::AddProperty(module, name, function, READ_ONLY);
+ JSObject::AddProperty(instance.js_object, name, function, READ_ONLY);
}
index++;
}
// Second pass: patch all direct call sites.
- linker.Link(module_env.function_table, this->function_table);
+ linker.Link(instance.function_table, this->function_table);
+ instance.js_object->SetInternalField(kWasmModuleFunctionTable,
+ Smi::FromInt(0));
- module->SetInternalField(kWasmModuleFunctionTable, Smi::FromInt(0));
- module->SetInternalField(kWasmModuleCodeTable, *code_table);
- return module;
+ // Run the start function if one was specified.
+ if (this->start_function_index >= 0) {
+ HandleScope scope(isolate);
+ uint32_t index = static_cast<uint32_t>(this->start_function_index);
+ Handle<String> name = isolate->factory()->NewStringFromStaticChars("start");
+ Handle<Code> code = linker.GetFunctionCode(index);
+ Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
+ isolate, &module_env, name, code, instance.js_object, index);
+
+ // Call the JS function.
+ Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
+ MaybeHandle<Object> retval =
+ Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
+
+ if (retval.is_null()) {
+ thrower.Error("WASM.instantiateModule(): start function failed");
+ }
+ }
+ return instance.js_object;
}
Handle<Code> ModuleEnv::GetFunctionCode(uint32_t index) {
DCHECK(IsValidFunction(index));
if (linker) return linker->GetFunctionCode(index);
- if (function_code) return function_code->at(index);
+ if (instance && instance->function_code) {
+ return instance->function_code->at(index);
+ }
return Handle<Code>::null();
}
+Handle<Code> ModuleEnv::GetImportCode(uint32_t index) {
+ DCHECK(IsValidImport(index));
+ if (instance && instance->import_code) {
+ return instance->import_code->at(index);
+ }
+ return Handle<Code>::null();
+}
compiler::CallDescriptor* ModuleEnv::GetCallDescriptor(Zone* zone,
uint32_t index) {
@@ -436,43 +529,45 @@
int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
ErrorThrower thrower(isolate, "CompileAndRunWasmModule");
+ WasmModuleInstance instance(module);
- // Allocate temporary linear memory and globals.
- size_t mem_size = 1 << module->min_mem_size_log2;
- size_t globals_size = AllocateGlobalsOffsets(module->globals);
+ // Allocate and initialize the linear memory.
+ if (!AllocateMemory(&thrower, isolate, &instance)) {
+ return -1;
+ }
+ LoadDataSegments(module, instance.mem_start, instance.mem_size);
- base::SmartArrayPointer<byte> mem_addr(new byte[mem_size]);
- base::SmartArrayPointer<byte> globals_addr(new byte[globals_size]);
+ // Allocate the globals area if necessary.
+ if (!AllocateGlobals(&thrower, isolate, &instance)) {
+ return -1;
+ }
- memset(mem_addr.get(), 0, mem_size);
- memset(globals_addr.get(), 0, globals_size);
+ // Build the function table.
+ instance.function_table = BuildFunctionTable(isolate, module);
// Create module environment.
WasmLinker linker(isolate, module->functions->size());
ModuleEnv module_env;
module_env.module = module;
- module_env.mem_start = reinterpret_cast<uintptr_t>(mem_addr.get());
- module_env.mem_end = reinterpret_cast<uintptr_t>(mem_addr.get()) + mem_size;
- module_env.globals_area = reinterpret_cast<uintptr_t>(globals_addr.get());
+ module_env.instance = &instance;
module_env.linker = &linker;
- module_env.function_code = nullptr;
- module_env.function_table = BuildFunctionTable(isolate, module);
module_env.asm_js = false;
- // Load data segments.
- // TODO(titzer): throw instead of crashing if segments don't fit in memory?
- LoadDataSegments(module, mem_addr.get(), mem_size);
-
// Compile all functions.
Handle<Code> main_code = Handle<Code>::null(); // record last code.
- int index = 0;
+ uint32_t index = 0;
+ int main_index = 0;
for (const WasmFunction& func : *module->functions) {
+ DCHECK_EQ(index, func.func_index);
if (!func.external) {
// Compile the function and install it in the code table.
- Handle<Code> code = compiler::CompileWasmFunction(
- thrower, isolate, &module_env, func, index);
+ Handle<Code> code =
+ compiler::CompileWasmFunction(thrower, isolate, &module_env, func);
if (!code.is_null()) {
- if (func.exported) main_code = code;
+ if (func.exported) {
+ main_code = code;
+ main_index = index;
+ }
linker.Finish(index, code);
}
if (thrower.error()) return -1;
@@ -480,30 +575,37 @@
index++;
}
- if (!main_code.is_null()) {
- linker.Link(module_env.function_table, module->function_table);
-#if USE_SIMULATOR && V8_TARGET_ARCH_ARM64
- // Run the main code on arm64 simulator.
- Simulator* simulator = Simulator::current(isolate);
- Simulator::CallArgument args[] = {Simulator::CallArgument(0),
- Simulator::CallArgument::End()};
- return static_cast<int32_t>(simulator->CallInt64(main_code->entry(), args));
-#elif USE_SIMULATOR
- // Run the main code on simulator.
- Simulator* simulator = Simulator::current(isolate);
- return static_cast<int32_t>(
- simulator->Call(main_code->entry(), 4, 0, 0, 0, 0));
-#else
- // Run the main code as raw machine code.
- int32_t (*raw_func)() = reinterpret_cast<int32_t (*)()>(
- reinterpret_cast<uintptr_t>(main_code->entry()));
- return raw_func();
-#endif
- } else {
- // No main code was found.
- isolate->Throw(*isolate->factory()->NewStringFromStaticChars(
- "WASM.compileRun() failed: no valid main code produced."));
+ if (main_code.is_null()) {
+ thrower.Error("WASM.compileRun() failed: no main code found");
+ return -1;
}
+
+ linker.Link(instance.function_table, instance.module->function_table);
+
+ // Wrap the main code so it can be called as a JS function.
+ Handle<String> name = isolate->factory()->NewStringFromStaticChars("main");
+ Handle<JSObject> module_object = Handle<JSObject>(0, isolate);
+ Handle<JSFunction> jsfunc = compiler::CompileJSToWasmWrapper(
+ isolate, &module_env, name, main_code, module_object, main_index);
+
+ // Call the JS function.
+ Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
+ MaybeHandle<Object> retval =
+ Execution::Call(isolate, jsfunc, undefined, 0, nullptr);
+
+ // The result should be a number.
+ if (retval.is_null()) {
+ thrower.Error("WASM.compileRun() failed: Invocation was null");
+ return -1;
+ }
+ Handle<Object> result = retval.ToHandleChecked();
+ if (result->IsSmi()) {
+ return Smi::cast(*result)->value();
+ }
+ if (result->IsHeapNumber()) {
+ return static_cast<int32_t>(HeapNumber::cast(*result)->value());
+ }
+ thrower.Error("WASM.compileRun() failed: Return value should be number");
return -1;
}
} // namespace wasm