Commit 68975751 authored by Ben L. Titzer's avatar Ben L. Titzer Committed by Commit Bot

[wasm] Simplify init by adding SetRawMemory() to WasmContext.

Bug: 
Change-Id: I1f4a9d06e91a0523e590a77f8073800d6f1994d6
Reviewed-on: https://chromium-review.googlesource.com/830393
Commit-Queue: Ben Titzer <titzer@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50140}
parent a449f09f
......@@ -387,7 +387,7 @@ class InstanceBuilder {
uint32_t EvalUint32InitExpr(const WasmInitExpr& expr);
// Load data segments into the memory.
void LoadDataSegments(Address mem_addr, size_t mem_size);
void LoadDataSegments(WasmContext* wasm_context);
void WriteGlobalValue(WasmGlobal& global, Handle<Object> value);
......@@ -2378,7 +2378,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
}
//--------------------------------------------------------------------------
// Allocate the instance object.
// Create the WebAssembly.Instance object.
//--------------------------------------------------------------------------
Zone instantiation_zone(isolate_->allocator(), ZONE_NAME);
CodeSpecialization code_specialization(isolate_, &instantiation_zone);
......@@ -2388,6 +2388,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
//--------------------------------------------------------------------------
// Set up the globals for the new instance.
//--------------------------------------------------------------------------
WasmContext* wasm_context = instance->wasm_context()->get();
MaybeHandle<JSArrayBuffer> old_globals;
uint32_t globals_size = module_->globals_size;
if (globals_size > 0) {
......@@ -2399,13 +2400,13 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
thrower_->RangeError("Out of memory: wasm globals");
return {};
}
instance->wasm_context()->get()->globals_start =
wasm_context->globals_start =
reinterpret_cast<byte*>(global_buffer->backing_store());
instance->set_globals_buffer(*global_buffer);
}
//--------------------------------------------------------------------------
// Prepare for initialization of function tables.
// Reserve the metadata for indirect function tables.
//--------------------------------------------------------------------------
int function_table_count = static_cast<int>(module_->function_tables.size());
table_instances_.reserve(module_->function_tables.size());
......@@ -2427,13 +2428,14 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
InitGlobals();
//--------------------------------------------------------------------------
// Set up the indirect function tables for the new instance.
// Initialize the indirect tables.
//--------------------------------------------------------------------------
if (function_table_count > 0)
if (function_table_count > 0) {
InitializeTables(instance, &code_specialization);
}
//--------------------------------------------------------------------------
// Set up the memory for the new instance.
// Allocate the memory array buffer.
//--------------------------------------------------------------------------
uint32_t initial_pages = module_->initial_pages;
(module_->is_wasm() ? counters()->wasm_wasm_min_mem_pages_count()
......@@ -2441,17 +2443,44 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
->AddSample(initial_pages);
if (!memory_.is_null()) {
Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
// Set externally passed ArrayBuffer non neuterable.
Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
memory->set_is_neuterable(false);
DCHECK_IMPLIES(use_trap_handler(),
module_->is_asm_js() || memory->has_guard_region());
} else if (initial_pages > 0) {
// Allocate memory if the initial size is more than 0 pages.
memory_ = AllocateMemory(initial_pages);
if (memory_.is_null()) return {}; // failed to allocate memory
}
//--------------------------------------------------------------------------
// Create the WebAssembly.Memory object.
//--------------------------------------------------------------------------
if (module_->has_memory) {
if (!instance->has_memory_object()) {
// No memory object exists. Create one.
Handle<WasmMemoryObject> memory_object = WasmMemoryObject::New(
isolate_, memory_,
module_->maximum_pages != 0 ? module_->maximum_pages : -1);
instance->set_memory_object(*memory_object);
}
// Add the instance object to the list of instances for this memory.
Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate_);
WasmMemoryObject::AddInstance(isolate_, memory_object, instance);
if (!memory_.is_null()) {
// Double-check the {memory} array buffer matches the context.
Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
uint32_t mem_size = 0;
CHECK(memory->byte_length()->ToUint32(&mem_size));
CHECK_EQ(wasm_context->mem_size, mem_size);
CHECK_EQ(wasm_context->mem_start, memory->backing_store());
}
}
//--------------------------------------------------------------------------
// Check that indirect function table segments are within bounds.
//--------------------------------------------------------------------------
......@@ -2472,42 +2501,15 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
//--------------------------------------------------------------------------
for (WasmDataSegment& seg : module_->data_segments) {
uint32_t base = EvalUint32InitExpr(seg.dest_addr);
uint32_t mem_size = 0;
if (!memory_.is_null()) {
CHECK(memory_.ToHandleChecked()->byte_length()->ToUint32(&mem_size));
}
if (!in_bounds(base, seg.source.length(), mem_size)) {
if (!in_bounds(base, seg.source.length(), wasm_context->mem_size)) {
thrower_->LinkError("data segment is out of bounds");
return {};
}
}
//--------------------------------------------------------------------------
// Initialize memory.
//--------------------------------------------------------------------------
Address mem_start = nullptr;
uint32_t mem_size = 0;
if (!memory_.is_null()) {
Handle<JSArrayBuffer> memory = memory_.ToHandleChecked();
mem_start = static_cast<Address>(memory->backing_store());
CHECK(memory->byte_length()->ToUint32(&mem_size));
LoadDataSegments(mem_start, mem_size);
}
//--------------------------------------------------------------------------
// Create a memory object if there is not already one.
//--------------------------------------------------------------------------
if (module_->has_memory && !instance->has_memory_object()) {
Handle<WasmMemoryObject> memory_object = WasmMemoryObject::New(
isolate_, memory_,
module_->maximum_pages != 0 ? module_->maximum_pages : -1);
instance->set_memory_object(*memory_object);
}
// Set the WasmContext address in wrappers.
// TODO(wasm): the wasm context should only appear as a constant in wrappers;
// this code specialization is applied to the whole instance.
WasmContext* wasm_context = instance->wasm_context()->get();
Address wasm_context_address = reinterpret_cast<Address>(wasm_context);
code_specialization.RelocateWasmContextReferences(wasm_context_address);
js_to_wasm_cache_.SetContextAddress(wasm_context_address);
......@@ -2547,17 +2549,18 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
if (thrower_->error()) return {};
//--------------------------------------------------------------------------
// Add instance to Memory object
// Initialize the indirect function tables.
//--------------------------------------------------------------------------
if (instance->has_memory_object()) {
Handle<WasmMemoryObject> memory(instance->memory_object(), isolate_);
WasmMemoryObject::AddInstance(isolate_, memory, instance);
if (function_table_count > 0) {
LoadTableSegments(code_table, instance);
}
//--------------------------------------------------------------------------
// Initialize the indirect function tables.
// Initialize the memory by loading data segments.
//--------------------------------------------------------------------------
if (function_table_count > 0) LoadTableSegments(code_table, instance);
if (module_->data_segments.size() > 0) {
LoadDataSegments(wasm_context);
}
// Patch all code with the relocations registered in code_specialization.
code_specialization.RelocateDirectCalls(instance);
......@@ -2582,7 +2585,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
}
//--------------------------------------------------------------------------
// Set up and link the new instance.
// Insert the compiled module into the weak list of compiled modules.
//--------------------------------------------------------------------------
{
Handle<Object> global_handle =
......@@ -2622,7 +2625,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
}
//--------------------------------------------------------------------------
// Run the start function if one was specified.
// Execute the start function if one was specified.
//--------------------------------------------------------------------------
if (module_->start_function_index >= 0) {
HandleScope scope(isolate_);
......@@ -2755,7 +2758,7 @@ uint32_t InstanceBuilder::EvalUint32InitExpr(const WasmInitExpr& expr) {
}
// Load data segments into the memory.
void InstanceBuilder::LoadDataSegments(Address mem_addr, size_t mem_size) {
void InstanceBuilder::LoadDataSegments(WasmContext* wasm_context) {
Handle<SeqOneByteString> module_bytes(compiled_module_->module_bytes(),
isolate_);
for (const WasmDataSegment& segment : module_->data_segments) {
......@@ -2763,9 +2766,8 @@ void InstanceBuilder::LoadDataSegments(Address mem_addr, size_t mem_size) {
// Segments of size == 0 are just nops.
if (source_size == 0) continue;
uint32_t dest_offset = EvalUint32InitExpr(segment.dest_addr);
DCHECK(
in_bounds(dest_offset, source_size, static_cast<uint32_t>(mem_size)));
byte* dest = mem_addr + dest_offset;
DCHECK(in_bounds(dest_offset, source_size, wasm_context->mem_size));
byte* dest = wasm_context->mem_start + dest_offset;
const byte* src = reinterpret_cast<const byte*>(
module_bytes->GetCharsAddress() + segment.source.offset());
memcpy(dest, src, source_size);
......
......@@ -399,8 +399,8 @@ Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
void SetInstanceMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
Handle<JSArrayBuffer> buffer) {
auto wasm_context = instance->wasm_context()->get();
wasm_context->mem_start = reinterpret_cast<byte*>(buffer->backing_store());
wasm_context->mem_size = buffer->byte_length()->Number();
wasm_context->SetRawMemory(reinterpret_cast<byte*>(buffer->backing_store()),
buffer->byte_length()->Number());
#if DEBUG
// To flush out bugs earlier, in DEBUG mode, check that all pages of the
// memory are accessible by reading and writing one byte on each page.
......@@ -563,8 +563,7 @@ Handle<WasmInstanceObject> WasmInstanceObject::New(
reinterpret_cast<WasmInstanceObject*>(*instance_object), isolate);
auto wasm_context = Managed<WasmContext>::Allocate(isolate);
wasm_context->get()->mem_start = nullptr;
wasm_context->get()->mem_size = 0;
wasm_context->get()->SetRawMemory(nullptr, 0);
wasm_context->get()->globals_start = nullptr;
instance->set_wasm_context(*wasm_context);
......
......@@ -59,10 +59,18 @@ class WasmInstanceObject;
// grow_memory). The address of the WasmContext is provided to the wasm entry
// functions using a RelocatableIntPtrConstant, then the address is passed as
// parameter to the other wasm functions.
// Note that generated code can directly read from instances of this struct.
struct WasmContext {
byte* mem_start;
uint32_t mem_size;
byte* globals_start;
byte* mem_start = nullptr;
uint32_t mem_size = 0; // TODO(titzer): uintptr_t?
byte* globals_start = nullptr;
inline void SetRawMemory(void* mem_start, size_t mem_size) {
DCHECK_LE(mem_size,
wasm::kV8MaxWasmMemoryPages * wasm::kSpecMaxWasmMemoryPages);
this->mem_start = static_cast<byte*>(mem_start);
this->mem_size = static_cast<uint32_t>(mem_size);
}
};
// Representation of a WebAssembly.Module JavaScript-level object.
......
......@@ -50,7 +50,8 @@ static void RunLoadStoreRelocation(MachineType rep) {
CType new_buffer[kNumElems];
byte* raw = reinterpret_cast<byte*>(buffer);
byte* new_raw = reinterpret_cast<byte*>(new_buffer);
WasmContext wasm_context = {raw, sizeof(buffer), nullptr};
WasmContext wasm_context;
wasm_context.SetRawMemory(raw, sizeof(buffer));
for (size_t i = 0; i < sizeof(buffer); i++) {
raw[i] = static_cast<byte>((i + sizeof(CType)) ^ 0xAA);
new_raw[i] = static_cast<byte>((i + sizeof(CType)) ^ 0xAA);
......@@ -70,8 +71,7 @@ static void RunLoadStoreRelocation(MachineType rep) {
CHECK(buffer[0] != buffer[1]);
CHECK_EQ(OK, m.Call());
CHECK(buffer[0] == buffer[1]);
wasm_context.mem_size = sizeof(new_buffer);
wasm_context.mem_start = new_raw;
wasm_context.SetRawMemory(new_raw, sizeof(new_buffer));
CHECK(new_buffer[0] != new_buffer[1]);
CHECK_EQ(OK, m.Call());
CHECK(new_buffer[0] == new_buffer[1]);
......@@ -101,7 +101,7 @@ static void RunLoadStoreRelocationOffset(MachineType rep) {
int32_t y = kNumElems - x - 1;
// initialize the buffer with raw data.
byte* raw = reinterpret_cast<byte*>(buffer);
wasm_context = {raw, sizeof(buffer), nullptr};
wasm_context.SetRawMemory(raw, sizeof(buffer));
for (size_t i = 0; i < sizeof(buffer); i++) {
raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA);
}
......@@ -130,8 +130,7 @@ static void RunLoadStoreRelocationOffset(MachineType rep) {
new_raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA);
}
wasm_context.mem_size = sizeof(new_buffer);
wasm_context.mem_start = new_raw;
wasm_context.SetRawMemory(new_raw, sizeof(new_buffer));
CHECK(new_buffer[x] != new_buffer[y]);
CHECK_EQ(OK, m.Call());
......@@ -154,7 +153,8 @@ TEST(RunLoadStoreRelocationOffset) {
TEST(Uint32LessThanMemoryRelocation) {
RawMachineAssemblerTester<uint32_t> m;
RawMachineLabel within_bounds, out_of_bounds;
WasmContext wasm_context = {reinterpret_cast<Address>(1234), 0x200, nullptr};
WasmContext wasm_context;
wasm_context.SetRawMemory(reinterpret_cast<void*>(1234), 0x200);
Node* index = m.Int32Constant(0x200);
Node* wasm_context_node =
m.RelocatableIntPtrConstant(reinterpret_cast<uintptr_t>(&wasm_context),
......@@ -169,7 +169,7 @@ TEST(Uint32LessThanMemoryRelocation) {
m.Return(m.Int32Constant(0xDEADBEEF));
// Check that index is out of bounds with current size
CHECK_EQ(0xDEADBEEF, m.Call());
wasm_context.mem_size = 0x400;
wasm_context.SetRawMemory(wasm_context.mem_start, 0x400);
// Check that after limit is increased, index is within bounds.
CHECK_EQ(0xACEDu, m.Call());
}
......
......@@ -36,8 +36,8 @@ WASM_COMPILED_EXEC_TEST(RunPatchWasmContext) {
reinterpret_cast<Address>(old_wasm_context);
uint32_t new_global_data[3] = {0, 0, 0};
WasmContext new_wasm_context = {0, 0,
reinterpret_cast<byte*>(new_global_data)};
WasmContext new_wasm_context;
new_wasm_context.globals_start = reinterpret_cast<byte*>(new_global_data);
{
// TODO(6792): No longer needed once WebAssembly code is off heap.
......
......@@ -61,8 +61,7 @@ byte* TestingModuleBuilder::AddMemory(uint32_t size) {
// TODO(wasm): Delete the following two lines when test-run-wasm will use a
// multiple of kPageSize as memory size. At the moment, the effect of these
// two lines is used to shrink the memory for testing purposes.
instance_object_->wasm_context()->get()->mem_start = mem_start_;
instance_object_->wasm_context()->get()->mem_size = mem_size_;
instance_object_->wasm_context()->get()->SetRawMemory(mem_start_, mem_size_);
return mem_start_;
}
......
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