[wasm] Factor out WasmModuleInstance from ModuleEnv.
R=ahaas@chromium.org,bradnelson@chromium.org BUG= Review URL: https://codereview.chromium.org/1637923002 Cr-Commit-Position: refs/heads/master@{#33541}
This commit is contained in:
parent
49fda47c5f
commit
1e1f72f3a6
@ -197,7 +197,7 @@ class WasmTrapHelper : public ZoneObject {
|
||||
*effect_ptr = effects_[reason] =
|
||||
graph()->NewNode(common()->EffectPhi(1), *effect_ptr, *control_ptr);
|
||||
|
||||
if (module && !module->context.is_null()) {
|
||||
if (module && !module->instance->context.is_null()) {
|
||||
// Use the module context to call the runtime to throw an exception.
|
||||
Runtime::FunctionId f = Runtime::kThrow;
|
||||
const Runtime::Function* fun = Runtime::FunctionForId(f);
|
||||
@ -210,7 +210,7 @@ class WasmTrapHelper : public ZoneObject {
|
||||
jsgraph()->ExternalConstant(
|
||||
ExternalReference(f, jsgraph()->isolate())), // ref
|
||||
jsgraph()->Int32Constant(fun->nargs), // arity
|
||||
jsgraph()->Constant(module->context), // context
|
||||
jsgraph()->Constant(module->instance->context), // context
|
||||
*effect_ptr,
|
||||
*control_ptr};
|
||||
|
||||
@ -1701,18 +1701,23 @@ void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSFunction> function,
|
||||
|
||||
|
||||
Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
|
||||
DCHECK(module_ && module_->instance);
|
||||
if (offset == 0) {
|
||||
if (!mem_buffer_)
|
||||
mem_buffer_ = jsgraph()->IntPtrConstant(module_->mem_start);
|
||||
if (!mem_buffer_) {
|
||||
mem_buffer_ = jsgraph()->IntPtrConstant(
|
||||
reinterpret_cast<uintptr_t>(module_->instance->mem_start));
|
||||
}
|
||||
return mem_buffer_;
|
||||
} else {
|
||||
return jsgraph()->IntPtrConstant(module_->mem_start + offset);
|
||||
return jsgraph()->IntPtrConstant(
|
||||
reinterpret_cast<uintptr_t>(module_->instance->mem_start + offset));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Node* WasmGraphBuilder::MemSize(uint32_t offset) {
|
||||
int32_t size = static_cast<int>(module_->mem_end - module_->mem_start);
|
||||
DCHECK(module_ && module_->instance);
|
||||
uint32_t size = static_cast<uint32_t>(module_->instance->mem_size);
|
||||
if (offset == 0) {
|
||||
if (!mem_size_) mem_size_ = jsgraph()->Int32Constant(size);
|
||||
return mem_size_;
|
||||
@ -1723,18 +1728,21 @@ Node* WasmGraphBuilder::MemSize(uint32_t offset) {
|
||||
|
||||
|
||||
Node* WasmGraphBuilder::FunctionTable() {
|
||||
DCHECK(module_ && module_->instance &&
|
||||
!module_->instance->function_table.is_null());
|
||||
if (!function_table_) {
|
||||
DCHECK(!module_->function_table.is_null());
|
||||
function_table_ = jsgraph()->Constant(module_->function_table);
|
||||
function_table_ = jsgraph()->Constant(module_->instance->function_table);
|
||||
}
|
||||
return function_table_;
|
||||
}
|
||||
|
||||
|
||||
Node* WasmGraphBuilder::LoadGlobal(uint32_t index) {
|
||||
DCHECK(module_ && module_->instance && module_->instance->globals_start);
|
||||
MachineType mem_type = module_->GetGlobalType(index);
|
||||
Node* addr = jsgraph()->IntPtrConstant(
|
||||
module_->globals_area + module_->module->globals->at(index).offset);
|
||||
reinterpret_cast<uintptr_t>(module_->instance->globals_start +
|
||||
module_->module->globals->at(index).offset));
|
||||
const Operator* op = jsgraph()->machine()->Load(mem_type);
|
||||
Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), *effect_,
|
||||
*control_);
|
||||
@ -1744,9 +1752,11 @@ Node* WasmGraphBuilder::LoadGlobal(uint32_t index) {
|
||||
|
||||
|
||||
Node* WasmGraphBuilder::StoreGlobal(uint32_t index, Node* val) {
|
||||
DCHECK(module_ && module_->instance && module_->instance->globals_start);
|
||||
MachineType mem_type = module_->GetGlobalType(index);
|
||||
Node* addr = jsgraph()->IntPtrConstant(
|
||||
module_->globals_area + module_->module->globals->at(index).offset);
|
||||
reinterpret_cast<uintptr_t>(module_->instance->globals_start +
|
||||
module_->module->globals->at(index).offset));
|
||||
const Operator* op = jsgraph()->machine()->Store(
|
||||
StoreRepresentation(mem_type.representation(), kNoWriteBarrier));
|
||||
Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), val,
|
||||
@ -1759,12 +1769,11 @@ Node* WasmGraphBuilder::StoreGlobal(uint32_t index, Node* val) {
|
||||
void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
|
||||
uint32_t offset) {
|
||||
// TODO(turbofan): fold bounds checks for constant indexes.
|
||||
CHECK_GE(module_->mem_end, module_->mem_start);
|
||||
ptrdiff_t size = module_->mem_end - module_->mem_start;
|
||||
DCHECK(module_ && module_->instance);
|
||||
size_t size = module_->instance->mem_size;
|
||||
byte memsize = wasm::WasmOpcodes::MemSize(memtype);
|
||||
Node* cond;
|
||||
if (static_cast<ptrdiff_t>(offset) >= size ||
|
||||
static_cast<ptrdiff_t>(offset + memsize) > size) {
|
||||
if (offset >= size || (static_cast<uint64_t>(offset) + memsize) > size) {
|
||||
// The access will always throw.
|
||||
cond = jsgraph()->Int32Constant(0);
|
||||
} else {
|
||||
|
@ -102,10 +102,7 @@ class ModuleDecoder : public Decoder {
|
||||
// Set up module environment for verification.
|
||||
ModuleEnv menv;
|
||||
menv.module = module;
|
||||
menv.globals_area = 0;
|
||||
menv.mem_start = 0;
|
||||
menv.mem_end = 0;
|
||||
menv.function_code = nullptr;
|
||||
menv.instance = nullptr;
|
||||
menv.asm_js = asm_js_;
|
||||
// Decode functions.
|
||||
for (uint32_t i = 0; i < functions_count; i++) {
|
||||
|
@ -183,25 +183,81 @@ Handle<FixedArray> BuildFunctionTable(Isolate* isolate, WasmModule* module) {
|
||||
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
|
||||
|
||||
|
||||
@ -232,90 +288,63 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
|
||||
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);
|
||||
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>();
|
||||
}
|
||||
|
||||
module->SetInternalField(kWasmGlobalsArrayBuffer, *globals_buffer);
|
||||
} else {
|
||||
module->SetInternalField(kWasmGlobalsArrayBuffer, Smi::FromInt(0));
|
||||
if (!AllocateGlobals(&thrower, isolate, &instance)) {
|
||||
return MaybeHandle<JSObject>();
|
||||
}
|
||||
if (!instance.globals_buffer.is_null()) {
|
||||
instance.js_object->SetInternalField(kWasmGlobalsArrayBuffer,
|
||||
*instance.globals_buffer);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Compile all functions in the module.
|
||||
//-------------------------------------------------------------------------
|
||||
instance.function_table = BuildFunctionTable(isolate, this);
|
||||
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.instance = &instance;
|
||||
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.
|
||||
@ -358,8 +387,8 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
|
||||
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()) {
|
||||
@ -369,24 +398,25 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
|
||||
}
|
||||
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);
|
||||
|
||||
module->SetInternalField(kWasmModuleFunctionTable, Smi::FromInt(0));
|
||||
module->SetInternalField(kWasmModuleCodeTable, *code_table);
|
||||
return module;
|
||||
linker.Link(instance.function_table, this->function_table);
|
||||
instance.js_object->SetInternalField(kWasmModuleFunctionTable,
|
||||
Smi::FromInt(0));
|
||||
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();
|
||||
}
|
||||
|
||||
@ -426,33 +456,30 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
|
||||
|
||||
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;
|
||||
@ -479,7 +506,7 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
linker.Link(module_env.function_table, module->function_table);
|
||||
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");
|
||||
|
@ -121,22 +121,41 @@ struct WasmModule {
|
||||
Handle<JSArrayBuffer> memory);
|
||||
};
|
||||
|
||||
// An instantiated WASM module, including memory, function table, etc.
|
||||
struct WasmModuleInstance {
|
||||
WasmModule* module; // static representation of the module.
|
||||
// -- Heap allocated --------------------------------------------------------
|
||||
Handle<JSObject> js_object; // JavaScript module object.
|
||||
Handle<Context> context; // JavaScript native context.
|
||||
Handle<JSArrayBuffer> mem_buffer; // Handle to array buffer of memory.
|
||||
Handle<JSArrayBuffer> globals_buffer; // Handle to array buffer of globals.
|
||||
Handle<FixedArray> function_table; // indirect function table.
|
||||
std::vector<Handle<Code>>* function_code; // code objects for each function.
|
||||
// -- raw memory ------------------------------------------------------------
|
||||
byte* mem_start; // start of linear memory.
|
||||
size_t mem_size; // size of the linear memory.
|
||||
// -- raw globals -----------------------------------------------------------
|
||||
byte* globals_start; // start of the globals area.
|
||||
size_t globals_size; // size of the globals area.
|
||||
|
||||
explicit WasmModuleInstance(WasmModule* m)
|
||||
: module(m),
|
||||
function_code(nullptr),
|
||||
mem_start(nullptr),
|
||||
mem_size(0),
|
||||
globals_start(nullptr),
|
||||
globals_size(0) {}
|
||||
};
|
||||
|
||||
// forward declaration.
|
||||
class WasmLinker;
|
||||
|
||||
// Interface provided to the decoder/graph builder which contains only
|
||||
// minimal information about the globals, functions, and function tables.
|
||||
struct ModuleEnv {
|
||||
uintptr_t globals_area; // address of the globals area.
|
||||
uintptr_t mem_start; // address of the start of linear memory.
|
||||
uintptr_t mem_end; // address of the end of linear memory.
|
||||
|
||||
WasmModule* module;
|
||||
WasmModuleInstance* instance;
|
||||
WasmLinker* linker;
|
||||
std::vector<Handle<Code>>* function_code;
|
||||
Handle<FixedArray> function_table;
|
||||
Handle<JSArrayBuffer> memory;
|
||||
Handle<Context> context;
|
||||
bool asm_js; // true if the module originated from asm.js.
|
||||
|
||||
bool IsValidGlobal(uint32_t index) {
|
||||
|
@ -56,7 +56,7 @@ uint32_t AddJsFunction(TestingModule* module, FunctionSig* sig,
|
||||
uint32_t index = static_cast<uint32_t>(module->module->functions->size() - 1);
|
||||
Isolate* isolate = CcTest::InitIsolateOnce();
|
||||
Handle<Code> code = CompileWasmToJSWrapper(isolate, module, jsfunc, index);
|
||||
module->function_code->at(index) = code;
|
||||
module->instance->function_code->at(index) = code;
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ Handle<JSFunction> WrapCode(ModuleEnv* module, uint32_t index) {
|
||||
// Wrap the 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<Code> code = module->function_code->at(index);
|
||||
Handle<Code> code = module->instance->function_code->at(index);
|
||||
WasmJs::InstallWasmFunctionMap(isolate, isolate->native_context());
|
||||
return compiler::CompileJSToWasmWrapper(isolate, module, name, code,
|
||||
module_object, index);
|
||||
|
@ -60,37 +60,37 @@ inline void init_env(FunctionEnv* env, FunctionSig* sig) {
|
||||
const uint32_t kMaxGlobalsSize = 128;
|
||||
|
||||
// A helper for module environments that adds the ability to allocate memory
|
||||
// and global variables.
|
||||
// and global variables. Contains a built-in {WasmModuleInstance}.
|
||||
class TestingModule : public ModuleEnv {
|
||||
public:
|
||||
TestingModule() : mem_size(0), global_offset(0) {
|
||||
globals_area = 0;
|
||||
mem_start = 0;
|
||||
mem_end = 0;
|
||||
TestingModule() : instance_(nullptr), global_offset(0) {
|
||||
instance = &instance_;
|
||||
instance->globals_start = global_data;
|
||||
instance->globals_size = kMaxGlobalsSize;
|
||||
instance->mem_start = nullptr;
|
||||
instance->mem_size = 0;
|
||||
instance->function_code = nullptr;
|
||||
module = nullptr;
|
||||
linker = nullptr;
|
||||
function_code = nullptr;
|
||||
asm_js = false;
|
||||
memset(global_data, 0, sizeof(global_data));
|
||||
}
|
||||
|
||||
~TestingModule() {
|
||||
if (mem_start) {
|
||||
free(raw_mem_start<byte>());
|
||||
if (instance->mem_start) {
|
||||
free(instance->mem_start);
|
||||
}
|
||||
if (function_code) delete function_code;
|
||||
if (instance->function_code) delete instance->function_code;
|
||||
if (module) delete module;
|
||||
}
|
||||
|
||||
byte* AddMemory(size_t size) {
|
||||
CHECK_EQ(0, mem_start);
|
||||
CHECK_EQ(0, mem_size);
|
||||
mem_start = reinterpret_cast<uintptr_t>(malloc(size));
|
||||
CHECK(mem_start);
|
||||
byte* raw = raw_mem_start<byte>();
|
||||
memset(raw, 0, size);
|
||||
mem_end = mem_start + size;
|
||||
mem_size = size;
|
||||
CHECK_NULL(instance->mem_start);
|
||||
CHECK_EQ(0, instance->mem_size);
|
||||
instance->mem_start = reinterpret_cast<byte*>(malloc(size));
|
||||
CHECK(instance->mem_start);
|
||||
memset(instance->mem_start, 0, size);
|
||||
instance->mem_size = size;
|
||||
return raw_mem_start<byte>();
|
||||
}
|
||||
|
||||
@ -103,7 +103,7 @@ class TestingModule : public ModuleEnv {
|
||||
template <typename T>
|
||||
T* AddGlobal(MachineType mem_type) {
|
||||
WasmGlobal* global = AddGlobal(mem_type);
|
||||
return reinterpret_cast<T*>(globals_area + global->offset);
|
||||
return reinterpret_cast<T*>(instance->globals_start + global->offset);
|
||||
}
|
||||
|
||||
byte AddSignature(FunctionSig* sig) {
|
||||
@ -119,33 +119,33 @@ class TestingModule : public ModuleEnv {
|
||||
|
||||
template <typename T>
|
||||
T* raw_mem_start() {
|
||||
DCHECK(mem_start);
|
||||
return reinterpret_cast<T*>(mem_start);
|
||||
DCHECK(instance->mem_start);
|
||||
return reinterpret_cast<T*>(instance->mem_start);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* raw_mem_end() {
|
||||
DCHECK(mem_end);
|
||||
return reinterpret_cast<T*>(mem_end);
|
||||
DCHECK(instance->mem_start);
|
||||
return reinterpret_cast<T*>(instance->mem_start + instance->mem_size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T raw_mem_at(int i) {
|
||||
DCHECK(mem_start);
|
||||
return reinterpret_cast<T*>(mem_start)[i];
|
||||
DCHECK(instance->mem_start);
|
||||
return reinterpret_cast<T*>(instance->mem_start)[i];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T raw_val_at(int i) {
|
||||
T val;
|
||||
memcpy(&val, reinterpret_cast<void*>(mem_start + i), sizeof(T));
|
||||
memcpy(&val, reinterpret_cast<void*>(instance->mem_start + i), sizeof(T));
|
||||
return val;
|
||||
}
|
||||
|
||||
// Zero-initialize the memory.
|
||||
void BlankMemory() {
|
||||
byte* raw = raw_mem_start<byte>();
|
||||
memset(raw, 0, mem_size);
|
||||
memset(raw, 0, instance->mem_size);
|
||||
}
|
||||
|
||||
// Pseudo-randomly intialize the memory.
|
||||
@ -161,10 +161,10 @@ class TestingModule : public ModuleEnv {
|
||||
AllocModule();
|
||||
if (module->functions == nullptr) {
|
||||
module->functions = new std::vector<WasmFunction>();
|
||||
function_code = new std::vector<Handle<Code>>();
|
||||
instance->function_code = new std::vector<Handle<Code>>();
|
||||
}
|
||||
module->functions->push_back({sig, 0, 0, 0, 0, 0, 0, 0, false, false});
|
||||
function_code->push_back(code);
|
||||
instance->function_code->push_back(code);
|
||||
return &module->functions->back();
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ class TestingModule : public ModuleEnv {
|
||||
Isolate* isolate = module->shared_isolate;
|
||||
Handle<FixedArray> fixed =
|
||||
isolate->factory()->NewFixedArray(2 * table_size);
|
||||
function_table = fixed;
|
||||
instance->function_table = fixed;
|
||||
module->function_table = new std::vector<uint16_t>();
|
||||
for (int i = 0; i < table_size; i++) {
|
||||
module->function_table->push_back(functions[i]);
|
||||
@ -181,26 +181,26 @@ class TestingModule : public ModuleEnv {
|
||||
}
|
||||
|
||||
void PopulateIndirectFunctionTable() {
|
||||
if (function_table.is_null()) return;
|
||||
if (instance->function_table.is_null()) return;
|
||||
int table_size = static_cast<int>(module->function_table->size());
|
||||
for (int i = 0; i < table_size; i++) {
|
||||
int function_index = module->function_table->at(i);
|
||||
WasmFunction* function = &module->functions->at(function_index);
|
||||
function_table->set(i, Smi::FromInt(function->sig_index));
|
||||
function_table->set(i + table_size, *function_code->at(function_index));
|
||||
instance->function_table->set(i, Smi::FromInt(function->sig_index));
|
||||
instance->function_table->set(
|
||||
i + table_size, *instance->function_code->at(function_index));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
size_t mem_size;
|
||||
WasmModuleInstance instance_;
|
||||
uint32_t global_offset;
|
||||
byte global_data[kMaxGlobalsSize];
|
||||
byte global_data[kMaxGlobalsSize]; // preallocated global data.
|
||||
|
||||
WasmGlobal* AddGlobal(MachineType mem_type) {
|
||||
AllocModule();
|
||||
if (globals_area == 0) {
|
||||
globals_area = reinterpret_cast<uintptr_t>(global_data);
|
||||
if (!module->globals) {
|
||||
module->globals = new std::vector<WasmGlobal>();
|
||||
}
|
||||
byte size = WasmOpcodes::MemSize(mem_type);
|
||||
|
@ -1204,11 +1204,9 @@ namespace {
|
||||
class TestModuleEnv : public ModuleEnv {
|
||||
public:
|
||||
TestModuleEnv() {
|
||||
mem_start = 0;
|
||||
mem_end = 0;
|
||||
instance = nullptr;
|
||||
module = &mod;
|
||||
linker = nullptr;
|
||||
function_code = nullptr;
|
||||
mod.globals = new std::vector<WasmGlobal>;
|
||||
mod.signatures = new std::vector<FunctionSig*>;
|
||||
mod.functions = new std::vector<WasmFunction>;
|
||||
|
Loading…
Reference in New Issue
Block a user