Commit de330e13 authored by hablich's avatar hablich Committed by Commit bot

Revert of [wasm] WebAssembly.Memory object can be referenced by multiple...

Revert of [wasm] WebAssembly.Memory object can be referenced by multiple Instance objects. (patchset #13 id:240001 of https://codereview.chromium.org/2471883003/ )

Reason for revert:
Test crashes after an unrelated revert: https://chromegw.corp.google.com/i/client.v8/builders/V8%20Linux%20-%20gc%20stress/builds/7189

Reverting because of recommendation from WASM team.

Original issue's description:
> [wasm] WebAssembly.Memory object can be referenced by multiple Instance objects.
>
> Add support for WebAssembly.Memory objects to be simultaneously referenced by multiple Instance objects. GrowingMemory should maintain a consistent view of memory across instances.
>  - Store a link to instances that share WebAssembly.Memory in the WasmMemoryObject, updated on instantiate.
>  - Implement WasmInstanceWrapper as a wrapper around the instance object to keep track of previous/next instances, instance object is stored as a WeakCell that can be garbage collected.
>  - MemoryInstanceFinalizer maintains a valid list of instances when an instance is garbage collected.
>  - Refactor GrowInstanceMemory to GrowMemoryBuffer that allocates a new buffer, and UncheckedUpdateInstanceMemory that updates memory references for an instance.
>
>  R=titzer@chromium.org, mtrofin@chromium.org, bradnelson@chromium.org
>
> Committed: https://crrev.com/30ef8e33f3a199a27ca8512bcee314c9522d03f6
> Committed: https://crrev.com/3c98e339599b068f1ed630afb7601ff942424d31
> Cr-Original-Commit-Position: refs/heads/master@{#41121}
> Cr-Commit-Position: refs/heads/master@{#41198}

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

Review-Url: https://codereview.chromium.org/2529573002
Cr-Commit-Position: refs/heads/master@{#41208}
parent e3f5c515
......@@ -58,7 +58,7 @@ RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
instance = handle(owning_instance, isolate);
}
return *isolate->factory()->NewNumberFromInt(
wasm::GrowMemory(isolate, instance, delta_pages));
wasm::GrowInstanceMemory(isolate, instance, delta_pages));
}
RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) {
......
......@@ -28,6 +28,12 @@ using v8::internal::wasm::ErrorThrower;
namespace v8 {
enum WasmMemoryObjectData {
kWasmMemoryBuffer,
kWasmMemoryMaximum,
kWasmMemoryInstanceObject
};
namespace {
i::Handle<i::String> v8_str(i::Isolate* isolate, const char* str) {
return isolate->factory()->NewStringFromAsciiChecked(str);
......@@ -224,7 +230,6 @@ void WebAssemblyInstance(const v8::FunctionCallbackInfo<v8::Value>& args) {
i_isolate);
} else {
thrower.TypeError("Argument 2 must be a WebAssembly.Memory");
return;
}
}
i::MaybeHandle<i::JSObject> instance =
......@@ -528,15 +533,31 @@ void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
uint32_t delta = args[0]->Uint32Value(context).FromJust();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Handle<i::Object> receiver =
i::Handle<i::Object>::cast(Utils::OpenHandle(*args.This()));
int32_t ret = i::wasm::GrowWebAssemblyMemory(i_isolate, receiver, delta);
i::Handle<i::JSObject> receiver =
i::Handle<i::JSObject>::cast(Utils::OpenHandle(*args.This()));
i::Handle<i::Object> instance_object(
receiver->GetInternalField(kWasmMemoryInstanceObject), i_isolate);
i::Handle<i::WasmInstanceObject> instance(
i::Handle<i::WasmInstanceObject>::cast(instance_object));
// TODO(gdeepti) Implement growing memory when shared by different
// instances.
int32_t ret = internal::wasm::GrowInstanceMemory(i_isolate, instance, delta);
if (ret == -1) {
v8::Local<v8::Value> e = v8::Exception::Error(
v8_str(isolate, "Unable to grow instance memory."));
isolate->ThrowException(e);
return;
}
i::MaybeHandle<i::JSArrayBuffer> buffer =
internal::wasm::GetInstanceMemory(i_isolate, instance);
if (buffer.is_null()) {
v8::Local<v8::Value> e = v8::Exception::Error(
v8_str(isolate, "WebAssembly.Memory buffer object not set."));
isolate->ThrowException(e);
return;
}
receiver->SetInternalField(kWasmMemoryBuffer, *buffer.ToHandleChecked());
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(ret);
}
......@@ -552,9 +573,10 @@ void WebAssemblyMemoryGetBuffer(
return;
}
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Handle<i::WasmMemoryObject> receiver =
i::Handle<i::WasmMemoryObject>::cast(Utils::OpenHandle(*args.This()));
i::Handle<i::Object> buffer(receiver->get_buffer(), i_isolate);
i::Handle<i::JSObject> receiver =
i::Handle<i::JSObject>::cast(Utils::OpenHandle(*args.This()));
i::Handle<i::Object> buffer(receiver->GetInternalField(kWasmMemoryBuffer),
i_isolate);
DCHECK(buffer->IsJSArrayBuffer());
v8::ReturnValue<v8::Value> return_value = args.GetReturnValue();
return_value.Set(Utils::ToLocal(buffer));
......
......@@ -556,56 +556,12 @@ static void ResetCompiledModule(Isolate* isolate, WasmInstanceObject* owner,
compiled_module->reset_memory();
}
static void MemoryInstanceFinalizer(Isolate* isolate,
WasmInstanceObject* instance) {
// If the memory object is destroyed, nothing needs to be done here.
if (!instance->has_memory_object()) return;
Handle<WasmInstanceWrapper> instance_wrapper =
handle(instance->get_instance_wrapper());
DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper));
DCHECK(instance_wrapper->has_instance());
bool has_prev = instance_wrapper->has_previous();
bool has_next = instance_wrapper->has_next();
Handle<WasmMemoryObject> memory_object(instance->get_memory_object());
if (!has_prev && !has_next) {
memory_object->ResetInstancesLink(isolate);
return;
} else {
Handle<WasmInstanceWrapper> next_wrapper, prev_wrapper;
if (!has_prev) {
Handle<WasmInstanceWrapper> next_wrapper =
instance_wrapper->next_wrapper();
next_wrapper->reset_previous_wrapper();
// As this is the first link in the memory object, destroying
// without updating memory object would corrupt the instance chain in
// the memory object.
memory_object->set_instances_link(*next_wrapper);
} else if (!has_next) {
instance_wrapper->previous_wrapper()->reset_next_wrapper();
} else {
DCHECK(has_next && has_prev);
Handle<WasmInstanceWrapper> prev_wrapper =
instance_wrapper->previous_wrapper();
Handle<WasmInstanceWrapper> next_wrapper =
instance_wrapper->next_wrapper();
prev_wrapper->set_next_wrapper(*next_wrapper);
next_wrapper->set_previous_wrapper(*prev_wrapper);
}
// Reset to avoid dangling pointers
instance_wrapper->reset();
}
}
static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter());
WasmInstanceObject* owner = reinterpret_cast<WasmInstanceObject*>(*p);
Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate());
// Is a link to shared memory instances exists, update the list of memory
// instances before the instance is destroyed.
if (owner->has_instance_wrapper()) MemoryInstanceFinalizer(isolate, owner);
WasmCompiledModule* compiled_module = owner->get_compiled_module();
TRACE("Finalizing %d {\n", compiled_module->instance_id());
Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate());
DCHECK(compiled_module->has_weak_wasm_module());
WeakCell* weak_wasm_module = compiled_module->ptr_to_weak_wasm_module();
......@@ -1227,11 +1183,6 @@ class WasmInstanceBuilder {
LoadDataSegments(nullptr, 0);
}
DCHECK(wasm::IsWasmInstance(*instance));
if (instance->has_memory_object()) {
instance->get_memory_object()->AddInstance(isolate_, instance);
}
//--------------------------------------------------------------------------
// Set up the runtime support for the new instance.
//--------------------------------------------------------------------------
......@@ -1302,6 +1253,12 @@ class WasmInstanceBuilder {
v8::WeakCallbackType::kFinalizer);
}
}
DCHECK(wasm::IsWasmInstance(*instance));
if (instance->has_memory_object()) {
instance->get_memory_object()->AddInstance(*instance);
}
//--------------------------------------------------------------------------
// Run the start function if one was specified.
//--------------------------------------------------------------------------
......@@ -1596,7 +1553,6 @@ class WasmInstanceBuilder {
return -1;
}
auto memory = Handle<WasmMemoryObject>::cast(object);
DCHECK(WasmJs::IsWasmMemoryObject(isolate_, memory));
instance->set_memory_object(*memory);
memory_ = Handle<JSArrayBuffer>(memory->get_buffer(), isolate_);
break;
......@@ -1778,8 +1734,6 @@ class WasmInstanceBuilder {
} else {
memory_object = Handle<WasmMemoryObject>(
instance->get_memory_object(), isolate_);
DCHECK(WasmJs::IsWasmMemoryObject(isolate_, memory_object));
memory_object->ResetInstancesLink(isolate_);
}
desc.set_value(memory_object);
......@@ -2115,8 +2069,7 @@ bool wasm::ValidateModuleBytes(Isolate* isolate, const byte* start,
}
MaybeHandle<JSArrayBuffer> wasm::GetInstanceMemory(
Isolate* isolate, Handle<WasmInstanceObject> object) {
auto instance = Handle<WasmInstanceObject>::cast(object);
Isolate* isolate, Handle<WasmInstanceObject> instance) {
if (instance->has_memory_buffer()) {
return Handle<JSArrayBuffer>(instance->get_memory_buffer(), isolate);
}
......@@ -2132,7 +2085,6 @@ void SetInstanceMemory(Handle<WasmInstanceObject> instance,
int32_t wasm::GetInstanceMemorySize(Isolate* isolate,
Handle<WasmInstanceObject> instance) {
DCHECK(IsWasmInstance(*instance));
MaybeHandle<JSArrayBuffer> maybe_mem_buffer =
GetInstanceMemory(isolate, instance);
Handle<JSArrayBuffer> buffer;
......@@ -2160,26 +2112,42 @@ uint32_t GetMaxInstanceMemorySize(Isolate* isolate,
return WasmModule::kV8MaxPages;
}
Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
MaybeHandle<JSArrayBuffer> buffer,
uint32_t pages, uint32_t max_pages) {
Handle<JSArrayBuffer> old_buffer;
int32_t wasm::GrowInstanceMemory(Isolate* isolate,
Handle<WasmInstanceObject> instance,
uint32_t pages) {
if (pages == 0) return GetInstanceMemorySize(isolate, instance);
uint32_t max_pages = GetMaxInstanceMemorySize(isolate, instance);
Address old_mem_start = nullptr;
uint32_t old_size = 0;
if (buffer.ToHandle(&old_buffer) && old_buffer->backing_store() != nullptr) {
uint32_t old_size = 0, new_size = 0;
MaybeHandle<JSArrayBuffer> maybe_mem_buffer =
GetInstanceMemory(isolate, instance);
Handle<JSArrayBuffer> old_buffer;
if (!maybe_mem_buffer.ToHandle(&old_buffer) ||
old_buffer->backing_store() == nullptr) {
// If module object does not have linear memory associated with it,
// Allocate new array buffer of given size.
new_size = pages * WasmModule::kPageSize;
if (max_pages < pages) return -1;
} else {
old_mem_start = static_cast<Address>(old_buffer->backing_store());
DCHECK_NOT_NULL(old_mem_start);
old_size = old_buffer->byte_length()->Number();
// If the old memory was zero-sized, we should have been in the
// "undefined" case above.
DCHECK_NOT_NULL(old_mem_start);
DCHECK(old_size + pages * WasmModule::kPageSize <=
std::numeric_limits<uint32_t>::max());
new_size = old_size + pages * WasmModule::kPageSize;
}
DCHECK(old_size + pages * WasmModule::kPageSize <=
std::numeric_limits<uint32_t>::max());
uint32_t new_size = old_size + pages * WasmModule::kPageSize;
if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size ||
WasmModule::kV8MaxPages * WasmModule::kPageSize < new_size) {
return Handle<JSArrayBuffer>::null();
return -1;
}
Handle<JSArrayBuffer> new_buffer;
Handle<JSArrayBuffer> buffer;
if (!old_buffer.is_null() && old_buffer->has_guard_region()) {
// We don't move the backing store, we simply change the protection to make
// more of it accessible.
......@@ -2189,107 +2157,37 @@ Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
Handle<Object> new_size_object =
isolate->factory()->NewNumberFromSize(new_size);
old_buffer->set_byte_length(*new_size_object);
new_buffer = old_buffer;
SetInstanceMemory(instance, *old_buffer);
Handle<FixedArray> code_table =
instance->get_compiled_module()->code_table();
RelocateMemoryReferencesInCode(code_table, old_mem_start, old_mem_start,
old_size, new_size);
buffer = old_buffer;
} else {
const bool enable_guard_regions = false;
new_buffer = NewArrayBuffer(isolate, new_size, enable_guard_regions);
if (new_buffer.is_null()) return new_buffer;
Address new_mem_start = static_cast<Address>(new_buffer->backing_store());
buffer = NewArrayBuffer(isolate, new_size, enable_guard_regions);
if (buffer.is_null()) return -1;
Address new_mem_start = static_cast<Address>(buffer->backing_store());
if (old_size != 0) {
memcpy(new_mem_start, old_mem_start, old_size);
}
SetInstanceMemory(instance, *buffer);
Handle<FixedArray> code_table =
instance->get_compiled_module()->code_table();
RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start,
old_size, new_size);
}
return new_buffer;
}
void UncheckedUpdateInstanceMemory(Isolate* isolate,
Handle<WasmInstanceObject> instance,
Address old_mem_start, uint32_t old_size) {
DCHECK(instance->has_memory_buffer());
Handle<JSArrayBuffer> new_buffer(instance->get_memory_buffer());
uint32_t new_size = new_buffer->byte_length()->Number();
DCHECK(new_size <= std::numeric_limits<uint32_t>::max());
Address new_mem_start = static_cast<Address>(new_buffer->backing_store());
DCHECK_NOT_NULL(new_mem_start);
Handle<FixedArray> code_table = instance->get_compiled_module()->code_table();
RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start,
old_size, new_size);
}
int32_t wasm::GrowWebAssemblyMemory(Isolate* isolate, Handle<Object> receiver,
uint32_t pages) {
DCHECK(WasmJs::IsWasmMemoryObject(isolate, receiver));
Handle<WasmMemoryObject> memory_object(WasmMemoryObject::cast(*receiver));
Handle<WasmInstanceWrapper> instance_wrapper(
memory_object->get_instances_link());
DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper));
DCHECK(instance_wrapper->has_instance());
Handle<WasmInstanceObject> instance = instance_wrapper->instance_object();
DCHECK(IsWasmInstance(*instance));
if (pages == 0) return GetInstanceMemorySize(isolate, instance);
uint32_t max_pages = GetMaxInstanceMemorySize(isolate, instance);
// Grow memory object buffer and update instances associated with it.
MaybeHandle<JSArrayBuffer> memory_buffer =
handle(memory_object->get_buffer());
Handle<JSArrayBuffer> old_buffer;
uint32_t old_size = 0;
Address old_mem_start = nullptr;
if (memory_buffer.ToHandle(&old_buffer) &&
old_buffer->backing_store() != nullptr) {
old_size = old_buffer->byte_length()->Number();
old_mem_start = static_cast<Address>(old_buffer->backing_store());
SetInstanceMemory(instance, *buffer);
if (instance->has_memory_object()) {
instance->get_memory_object()->set_buffer(*buffer);
}
Handle<JSArrayBuffer> new_buffer =
GrowMemoryBuffer(isolate, memory_buffer, pages, max_pages);
if (new_buffer.is_null()) return -1;
DCHECK(!instance_wrapper->has_previous());
SetInstanceMemory(instance, *new_buffer);
UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
while (instance_wrapper->has_next()) {
instance_wrapper = instance_wrapper->next_wrapper();
DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper));
Handle<WasmInstanceObject> instance = instance_wrapper->instance_object();
DCHECK(IsWasmInstance(*instance));
SetInstanceMemory(instance, *new_buffer);
UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
}
memory_object->set_buffer(*new_buffer);
DCHECK(old_size % WasmModule::kPageSize == 0);
return (old_size / WasmModule::kPageSize);
}
int32_t wasm::GrowMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
uint32_t pages) {
if (!IsWasmInstance(*instance)) return -1;
if (pages == 0) return GetInstanceMemorySize(isolate, instance);
Handle<WasmInstanceObject> instance_obj(WasmInstanceObject::cast(*instance));
if (!instance_obj->has_memory_object()) {
// No other instances to grow, grow just the one.
MaybeHandle<JSArrayBuffer> instance_buffer =
GetInstanceMemory(isolate, instance);
Handle<JSArrayBuffer> old_buffer;
uint32_t old_size = 0;
Address old_mem_start = nullptr;
if (instance_buffer.ToHandle(&old_buffer) &&
old_buffer->backing_store() != nullptr) {
old_size = old_buffer->byte_length()->Number();
old_mem_start = static_cast<Address>(old_buffer->backing_store());
}
uint32_t max_pages = GetMaxInstanceMemorySize(isolate, instance_obj);
Handle<JSArrayBuffer> buffer =
GrowMemoryBuffer(isolate, instance_buffer, pages, max_pages);
if (buffer.is_null()) return -1;
SetInstanceMemory(instance, *buffer);
UncheckedUpdateInstanceMemory(isolate, instance, old_mem_start, old_size);
DCHECK(old_size % WasmModule::kPageSize == 0);
return (old_size / WasmModule::kPageSize);
} else {
return GrowWebAssemblyMemory(
isolate, handle(instance_obj->get_memory_object()), pages);
}
}
void testing::ValidateInstancesChain(Isolate* isolate,
Handle<WasmModuleObject> module_obj,
int instance_count) {
......
......@@ -430,12 +430,6 @@ int32_t GrowInstanceMemory(Isolate* isolate,
Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size,
bool enable_guard_regions);
int32_t GrowWebAssemblyMemory(Isolate* isolate, Handle<Object> receiver,
uint32_t pages);
int32_t GrowMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
uint32_t pages);
void UpdateDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
int index, Handle<JSFunction> js_function);
......
......@@ -174,8 +174,7 @@ Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
int maximum) {
Handle<JSFunction> memory_ctor(
isolate->native_context()->wasm_memory_constructor());
Handle<JSObject> memory_obj =
isolate->factory()->NewJSObject(memory_ctor, TENURED);
Handle<JSObject> memory_obj = isolate->factory()->NewJSObject(memory_ctor);
memory_obj->SetInternalField(kArrayBuffer, *buffer);
memory_obj->SetInternalField(kMaximum,
static_cast<Object*>(Smi::FromInt(maximum)));
......@@ -185,8 +184,6 @@ Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
}
DEFINE_ACCESSORS(WasmMemoryObject, buffer, kArrayBuffer, JSArrayBuffer)
DEFINE_OPTIONAL_ACCESSORS(WasmMemoryObject, instances_link, kInstancesLink,
WasmInstanceWrapper)
uint32_t WasmMemoryObject::current_pages() {
return SafeUint32(get_buffer()->byte_length()) / wasm::WasmModule::kPageSize;
......@@ -202,26 +199,10 @@ WasmMemoryObject* WasmMemoryObject::cast(Object* object) {
return reinterpret_cast<WasmMemoryObject*>(object);
}
void WasmMemoryObject::AddInstance(Isolate* isolate,
Handle<WasmInstanceObject> instance) {
Handle<WasmInstanceWrapper> instance_wrapper;
if (has_instances_link()) {
Handle<WasmInstanceWrapper> current_wrapper(get_instances_link());
DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*current_wrapper));
DCHECK(!current_wrapper->has_previous());
instance_wrapper = WasmInstanceWrapper::New(isolate, instance);
instance_wrapper->set_next_wrapper(*current_wrapper);
current_wrapper->set_previous_wrapper(*instance_wrapper);
} else {
instance_wrapper = WasmInstanceWrapper::New(isolate, instance);
}
set_instances_link(*instance_wrapper);
instance->set_instance_wrapper(*instance_wrapper);
}
void WasmMemoryObject::ResetInstancesLink(Isolate* isolate) {
Handle<Object> undefined = isolate->factory()->undefined_value();
SetInternalField(kInstancesLink, *undefined);
void WasmMemoryObject::AddInstance(WasmInstanceObject* instance) {
// TODO(gdeepti): This should be a weak list of instance objects
// for instances that share memory.
SetInternalField(kInstance, instance);
}
DEFINE_ACCESSORS(WasmInstanceObject, compiled_module, kCompiledModule,
......@@ -234,8 +215,6 @@ DEFINE_OPTIONAL_ACCESSORS(WasmInstanceObject, memory_object, kMemoryObject,
WasmMemoryObject)
DEFINE_OPTIONAL_ACCESSORS(WasmInstanceObject, debug_info, kDebugInfo,
WasmDebugInfo)
DEFINE_OPTIONAL_ACCESSORS(WasmInstanceObject, instance_wrapper,
kWasmMemInstanceWrapper, WasmInstanceWrapper)
WasmModuleObject* WasmInstanceObject::module_object() {
return WasmModuleObject::cast(*get_compiled_module()->wasm_module());
......@@ -445,34 +424,3 @@ bool WasmCompiledModule::GetPositionInfo(uint32_t position,
info->line_end = function.code_end_offset;
return true;
}
Handle<WasmInstanceWrapper> WasmInstanceWrapper::New(
Isolate* isolate, Handle<WasmInstanceObject> instance) {
Handle<FixedArray> array =
isolate->factory()->NewFixedArray(kWrapperPropertyCount, TENURED);
Handle<WasmInstanceWrapper> instance_wrapper(
reinterpret_cast<WasmInstanceWrapper*>(*array), isolate);
instance_wrapper->set_instance_object(instance, isolate);
return instance_wrapper;
}
bool WasmInstanceWrapper::IsWasmInstanceWrapper(Object* obj) {
if (!obj->IsFixedArray()) return false;
FixedArray* array = FixedArray::cast(obj);
if (array->length() != kWrapperPropertyCount) return false;
if (!array->get(kWrapperInstanceObject)->IsWeakCell()) return false;
Isolate* isolate = array->GetIsolate();
if (!array->get(kNextInstanceWrapper)->IsUndefined(isolate) &&
!array->get(kNextInstanceWrapper)->IsFixedArray())
return false;
if (!array->get(kPreviousInstanceWrapper)->IsUndefined(isolate) &&
!array->get(kPreviousInstanceWrapper)->IsFixedArray())
return false;
return true;
}
void WasmInstanceWrapper::set_instance_object(Handle<JSObject> instance,
Isolate* isolate) {
Handle<WeakCell> cell = isolate->factory()->NewWeakCell(instance);
set(kWrapperInstanceObject, *cell);
}
......@@ -17,7 +17,6 @@ struct WasmModule;
class WasmCompiledModule;
class WasmDebugInfo;
class WasmInstanceObject;
class WasmInstanceWrapper;
#define DECLARE_CASTS(name) \
static bool Is##name(Object* object); \
......@@ -80,14 +79,12 @@ class WasmTableObject : public JSObject {
class WasmMemoryObject : public JSObject {
public:
// TODO(titzer): add the brand as an internal field instead of a property.
enum Fields : uint8_t { kArrayBuffer, kMaximum, kInstancesLink, kFieldCount };
enum Fields : uint8_t { kArrayBuffer, kMaximum, kInstance, kFieldCount };
DECLARE_CASTS(WasmMemoryObject);
DECLARE_ACCESSORS(buffer, JSArrayBuffer);
DECLARE_OPTIONAL_ACCESSORS(instances_link, WasmInstanceWrapper);
void AddInstance(Isolate* isolate, Handle<WasmInstanceObject> object);
void ResetInstancesLink(Isolate* isolate);
void AddInstance(WasmInstanceObject* object);
uint32_t current_pages();
int32_t maximum_pages(); // returns < 0 if there is no maximum
......@@ -108,7 +105,6 @@ class WasmInstanceObject : public JSObject {
kMemoryArrayBuffer,
kGlobalsArrayBuffer,
kDebugInfo,
kWasmMemInstanceWrapper,
kFieldCount
};
......@@ -119,7 +115,6 @@ class WasmInstanceObject : public JSObject {
DECLARE_OPTIONAL_ACCESSORS(memory_buffer, JSArrayBuffer);
DECLARE_OPTIONAL_ACCESSORS(memory_object, WasmMemoryObject);
DECLARE_OPTIONAL_ACCESSORS(debug_info, WasmDebugInfo);
DECLARE_OPTIONAL_ACCESSORS(instance_wrapper, WasmInstanceWrapper);
WasmModuleObject* module_object();
wasm::WasmModule* module();
......@@ -331,61 +326,6 @@ class WasmDebugInfo : public FixedArray {
int func_index, int byte_offset);
};
class WasmInstanceWrapper : public FixedArray {
public:
static Handle<WasmInstanceWrapper> New(Isolate* isolate,
Handle<WasmInstanceObject> instance);
static WasmInstanceWrapper* cast(Object* fixed_array) {
SLOW_DCHECK(IsWasmInstanceWrapper(fixed_array));
return reinterpret_cast<WasmInstanceWrapper*>(fixed_array);
}
static bool IsWasmInstanceWrapper(Object* obj);
bool has_instance() { return get(kWrapperInstanceObject)->IsWeakCell(); }
Handle<WasmInstanceObject> instance_object() {
Object* obj = get(kWrapperInstanceObject);
DCHECK(obj->IsWeakCell());
WeakCell* cell = WeakCell::cast(obj);
DCHECK(cell->value()->IsJSObject());
return handle(WasmInstanceObject::cast(cell->value()));
}
bool has_next() { return IsWasmInstanceWrapper(get(kNextInstanceWrapper)); }
bool has_previous() {
return IsWasmInstanceWrapper(get(kPreviousInstanceWrapper));
}
void set_instance_object(Handle<JSObject> instance, Isolate* isolate);
void set_next_wrapper(Object* obj) {
DCHECK(IsWasmInstanceWrapper(obj));
set(kNextInstanceWrapper, obj);
}
void set_previous_wrapper(Object* obj) {
DCHECK(IsWasmInstanceWrapper(obj));
set(kPreviousInstanceWrapper, obj);
}
Handle<WasmInstanceWrapper> next_wrapper() {
Object* obj = get(kNextInstanceWrapper);
DCHECK(IsWasmInstanceWrapper(obj));
return handle(WasmInstanceWrapper::cast(obj));
}
Handle<WasmInstanceWrapper> previous_wrapper() {
Object* obj = get(kPreviousInstanceWrapper);
DCHECK(IsWasmInstanceWrapper(obj));
return handle(WasmInstanceWrapper::cast(obj));
}
void reset_next_wrapper() { set_undefined(kNextInstanceWrapper); }
void reset_previous_wrapper() { set_undefined(kPreviousInstanceWrapper); }
void reset() {
for (int kID = 0; kID < kWrapperPropertyCount; kID++) set_undefined(kID);
}
private:
enum {
kWrapperInstanceObject,
kNextInstanceWrapper,
kPreviousInstanceWrapper,
kWrapperPropertyCount
};
};
#undef DECLARE_ACCESSORS
#undef DECLARE_OPTIONAL_ACCESSORS
......
......@@ -40,6 +40,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertSame(memory, instance.exports.daggle);
})();
(function TestImportExport() {
print("TestImportExport");
var i1;
......@@ -228,141 +229,3 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
}
assertEquals(-1, instance.exports.grow(1));
})();
(function TestMemoryGrowWebAssemblyInstances() {
print("TestMemoryGrowWebAssemblyInstances");
let memory = new WebAssembly.Memory({initial: 1, maximum: 15});
var builder = new WasmModuleBuilder();
builder.addImportedMemory("imported_mem");
builder.addFunction("mem_size", kSig_i_v)
.addBody([kExprMemorySize, kMemoryZero])
.exportAs("mem_size");
builder.addFunction("grow", kSig_i_i)
.addBody([kExprGetLocal, 0, kExprGrowMemory, kMemoryZero])
.exportFunc();
var module = new WebAssembly.Module(builder.toBuffer());
var instances = [];
for (var i = 0; i < 6; i++) {
instances.push(new WebAssembly.Instance(module, {imported_mem: memory}));
}
function verify_mem_size(expected_pages) {
assertEquals(expected_pages*kPageSize,
memory.buffer.byteLength);
for (var i = 0; i < 6; i++) {
assertEquals(expected_pages, instances[i].exports.mem_size());
}
}
// Verify initial memory size
verify_mem_size(1);
// Verify memory size with interleaving calls to Memory.grow,
// GrowMemory opcode.
var current_mem_size = 1;
for (var i = 0; i < 5; i++) {
function grow(pages) { return instances[i].exports.grow(pages); }
assertEquals(current_mem_size, memory.grow(1));
verify_mem_size(++current_mem_size);
assertEquals(current_mem_size, instances[i].exports.grow(1));
verify_mem_size(++current_mem_size);
}
assertThrows(() => memory.grow(5));
})();
(function TestImportedMemoryGrowMultipleInstances() {
print("TestImportMemoryMultipleInstances");
let memory = new WebAssembly.Memory({initial: 5, maximum: 100});
var builder = new WasmModuleBuilder();
builder.addImportedMemory("imported_mem");
builder.addFunction("mem_size", kSig_i_v)
.addBody([kExprMemorySize, kMemoryZero])
.exportFunc();
builder.addFunction("grow", kSig_i_i)
.addBody([kExprGetLocal, 0, kExprGrowMemory, kMemoryZero])
.exportFunc();
var instances = [];
for (var i = 0; i < 5; i++) {
instances.push(builder.instantiate({imported_mem: memory}));
}
function grow_instance_0(pages) { return instances[0].exports.grow(pages); }
function grow_instance_1(pages) { return instances[1].exports.grow(pages); }
function grow_instance_2(pages) { return instances[2].exports.grow(pages); }
function grow_instance_3(pages) { return instances[3].exports.grow(pages); }
function grow_instance_4(pages) { return instances[4].exports.grow(pages); }
function verify_mem_size(expected_pages) {
assertEquals(expected_pages*kPageSize, memory.buffer.byteLength);
for (var i = 0; i < 5; i++) {
assertEquals(expected_pages, instances[i].exports.mem_size());
}
}
// Verify initial memory size
verify_mem_size(5);
// Grow instance memory and buffer memory out of order and verify memory is
// updated correctly.
assertEquals(5, grow_instance_0(7));
verify_mem_size(12);
assertEquals(12, memory.grow(4));
verify_mem_size(16);
assertEquals(16, grow_instance_4(1));
verify_mem_size(17);
assertEquals(17, grow_instance_1(6));
verify_mem_size(23);
assertEquals(23, grow_instance_3(2));
verify_mem_size(25);
assertEquals(25, memory.grow(10));
verify_mem_size(35);
assertEquals(35, grow_instance_2(15));
verify_mem_size(50);
assertThrows(() => memory.grow(51));
})();
(function TestExportImportedMemoryGrowMultipleInstances() {
// TODO(gdeepti):Exported memory objects currently do not take max_size
// into account so this can grow past the maximum specified in the exported
// memory object. Assert that growing past maximum for exported objects fails.
print("TestExportImportedMemoryGrowMultipleInstances");
var instance;
{
let builder = new WasmModuleBuilder();
builder.addMemory(1, 11, true);
builder.exportMemoryAs("exported_mem");
builder.addFunction("mem_size", kSig_i_v)
.addBody([kExprMemorySize, kMemoryZero])
.exportFunc();
instance = builder.instantiate();
}
var builder = new WasmModuleBuilder();
builder.addImportedMemory("imported_mem");
builder.addFunction("mem_size", kSig_i_v)
.addBody([kExprMemorySize, kMemoryZero])
.exportFunc();
builder.addFunction("grow", kSig_i_i)
.addBody([kExprGetLocal, 0, kExprGrowMemory, kMemoryZero])
.exportFunc();
var instances = [];
for (var i = 0; i < 10; i++) {
instances.push(builder.instantiate({
imported_mem: instance.exports.exported_mem}));
}
function verify_mem_size(expected_pages) {
for (var i = 0; i < 10; i++) {
assertEquals(expected_pages, instances[i].exports.mem_size());
}
}
var current_mem_size = 1;
for (var i = 0; i < 10; i++) {
function grow(pages) { return instances[i].exports.grow(pages); }
assertEquals(current_mem_size, instances[i].exports.grow(1));
verify_mem_size(++current_mem_size);
}
})();
......@@ -215,7 +215,6 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
})();
(function MustBeMemory() {
print("MustBeMemory...");
var memory = new ArrayBuffer(65536);
var module = new WebAssembly.Module(buffer);
assertThrows(() => new WebAssembly.Instance(module, null, memory), TypeError);
......
// 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 --expose-gc
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
// This test verifies that when instances are exported, Gc'ed, the other
// instances in the chain still maintain a consistent view of the memory.
(function ValidateSharedInstanceMemory() {
print("ValidateSharedInstanceMemory");
let memory = new WebAssembly.Memory({initial: 5, maximum: 100});
var builder = new WasmModuleBuilder();
builder.addImportedMemory("imported_mem");
builder.addFunction("mem_size", kSig_i_v)
.addBody([kExprMemorySize, kMemoryZero])
.exportFunc();
builder.addFunction("grow", kSig_i_i)
.addBody([kExprGetLocal, 0, kExprGrowMemory, kMemoryZero])
.exportFunc();
var instances = [];
for (var i = 0; i < 5; i++) {
instances.push(builder.instantiate({imported_mem: memory}));
}
function grow_instance_0(pages) { return instances[0].exports.grow(pages); }
function grow_instance_1(pages) { return instances[1].exports.grow(pages); }
function grow_instance_2(pages) { return instances[2].exports.grow(pages); }
function grow_instance_3(pages) { return instances[3].exports.grow(pages); }
function grow_instance_4(pages) { return instances[4].exports.grow(pages); }
var start_index = 0;
var end_index = 5;
function verify_mem_size(expected_pages) {
assertEquals(expected_pages*kPageSize, memory.buffer.byteLength);
for (var i = start_index; i < end_index; i++) {
assertEquals(expected_pages, instances[i].exports.mem_size());
}
}
// Verify initial memory size of all instances, grow and verify that all
// instances are updated correctly.
verify_mem_size(5);
assertEquals(5, memory.grow(6));
verify_mem_size(11);
instances[1] = null;
gc();
// i[0] - i[2] - i[3] - i[4]
start_index = 2;
verify_mem_size(11);
assertEquals(11, instances[0].exports.mem_size());
assertEquals(11, grow_instance_2(10));
assertEquals(21*kPageSize, memory.buffer.byteLength);
verify_mem_size(21);
assertEquals(21, instances[0].exports.mem_size());
instances[4] = null;
gc();
// i[0] - i[2] - i[3]
assertEquals(21, instances[0].exports.mem_size());
assertEquals(21, instances[2].exports.mem_size());
assertEquals(21, instances[3].exports.mem_size());
assertEquals(21, memory.grow(2));
assertEquals(23*kPageSize, memory.buffer.byteLength);
assertEquals(23, instances[0].exports.mem_size());
assertEquals(23, instances[2].exports.mem_size());
assertEquals(23, instances[3].exports.mem_size());
instances[0] = null;
gc();
// i[2] - i[3]
assertEquals(23, instances[2].exports.mem_size());
assertEquals(23, instances[3].exports.mem_size());
assertEquals(23, grow_instance_3(5));
assertEquals(28*kPageSize, memory.buffer.byteLength);
assertEquals(28, instances[2].exports.mem_size());
assertEquals(28, instances[3].exports.mem_size());
// Instantiate a new instance and verify that it can be grown correctly.
instances.push(builder.instantiate({imported_mem: memory}));
function grow_instance_5(pages) { return instances[5].exports.grow(pages); }
// i[2] - i[3] - i[5]
assertEquals(28, instances[2].exports.mem_size());
assertEquals(28, instances[3].exports.mem_size());
assertEquals(28, instances[5].exports.mem_size());
assertEquals(28, grow_instance_5(2));
assertEquals(30*kPageSize, memory.buffer.byteLength);
assertEquals(30, instances[2].exports.mem_size());
assertEquals(30, instances[3].exports.mem_size());
assertEquals(30, instances[5].exports.mem_size());
assertEquals(30, memory.grow(5));
assertEquals(35*kPageSize, memory.buffer.byteLength);
assertEquals(35, instances[2].exports.mem_size());
assertEquals(35, instances[3].exports.mem_size());
assertEquals(35, instances[5].exports.mem_size());
})();
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