Index: src/wasm/wasm-module.cc |
diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc |
index aa385f824e6917b38815aadf8d047c4fa5964ea4..4f6dbac5d2855832052ec923119592565d8541bd 100644 |
--- a/src/wasm/wasm-module.cc |
+++ b/src/wasm/wasm-module.cc |
@@ -81,6 +81,7 @@ enum WasmInstanceObjectFields { |
kWasmMemArrayBuffer, |
kWasmGlobalsArrayBuffer, |
kWasmDebugInfo, |
+ kWasmMemInstanceWrapper, |
kWasmInstanceInternalFieldCount |
}; |
@@ -1223,11 +1224,6 @@ class WasmInstanceBuilder { |
} |
} |
- DCHECK(wasm::IsWasmInstance(*instance)); |
- Handle<Object> memory_object(instance->GetInternalField(kWasmMemObject), |
- isolate_); |
- WasmJs::SetWasmMemoryInstance(isolate_, memory_object, instance); |
- |
//-------------------------------------------------------------------------- |
// Run the start function if one was specified. |
//-------------------------------------------------------------------------- |
@@ -1504,6 +1500,7 @@ class WasmInstanceBuilder { |
} |
instance->SetInternalField(kWasmMemObject, *object); |
memory_ = WasmJs::GetWasmMemoryArrayBuffer(isolate_, object); |
+ WasmJs::SetWasmMemoryInstance(isolate_, object, instance); |
break; |
} |
case kExternalGlobal: { |
@@ -1679,6 +1676,9 @@ class WasmInstanceBuilder { |
memory_object = |
WasmJs::CreateWasmMemoryObject(isolate_, buffer, false, 0); |
instance->SetInternalField(kWasmMemObject, *memory_object); |
+ } else { |
+ DCHECK(WasmJs::IsWasmMemoryObject(isolate_, memory_object)); |
+ WasmJs::ResetWasmMemoryInstance(isolate_, memory_object); |
} |
desc.set_value(memory_object); |
@@ -2072,6 +2072,12 @@ bool wasm::ValidateModuleBytes(Isolate* isolate, const byte* start, |
return false; |
} |
+void wasm::SetInstanceMemoryObject(Handle<JSObject> instance, |
+ Handle<Object> mem_object) { |
+ DCHECK(IsWasmInstance(*instance)); |
+ instance->SetInternalField(kWasmMemObject, *mem_object); |
+} |
+ |
MaybeHandle<JSArrayBuffer> wasm::GetInstanceMemory(Isolate* isolate, |
Handle<JSObject> instance) { |
Object* mem = instance->GetInternalField(kWasmMemArrayBuffer); |
@@ -2090,6 +2096,7 @@ void SetInstanceMemory(Handle<JSObject> instance, JSArrayBuffer* buffer) { |
int32_t wasm::GetInstanceMemorySize(Isolate* isolate, |
Handle<JSObject> instance) { |
+ DCHECK(IsWasmInstance(*instance)); |
MaybeHandle<JSArrayBuffer> maybe_mem_buffer = |
GetInstanceMemory(isolate, instance); |
Handle<JSArrayBuffer> buffer; |
@@ -2108,59 +2115,110 @@ uint32_t GetMaxInstanceMemorySize(Isolate* isolate, Handle<JSObject> instance) { |
return WasmJs::GetWasmMemoryMaximumSize(isolate, memory_object); |
} |
-int32_t wasm::GrowInstanceMemory(Isolate* isolate, Handle<JSObject> instance, |
- uint32_t pages) { |
- if (!IsWasmInstance(*instance)) return -1; |
- if (pages == 0) return GetInstanceMemorySize(isolate, instance); |
- uint32_t max_pages = GetMaxInstanceMemorySize(isolate, instance); |
- if (WasmModule::kV8MaxPages < max_pages) return -1; |
- |
+Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate, |
+ MaybeHandle<JSArrayBuffer> buffer, |
+ uint32_t pages, uint32_t max_pages) { |
+ Handle<JSArrayBuffer> old_buffer; |
Address old_mem_start = nullptr; |
- uint32_t old_size = 0, new_size = 0; |
+ uint32_t old_size = 0; |
+ if (buffer.ToHandle(&old_buffer) && old_buffer->backing_store() != nullptr) { |
+ old_mem_start = static_cast<Address>(old_buffer->backing_store()); |
+ DCHECK_NOT_NULL(old_mem_start); |
+ old_size = old_buffer->byte_length()->Number(); |
+ } |
+ 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) { |
+ return Handle<JSArrayBuffer>::null(); |
+ } |
+ Handle<JSArrayBuffer> new_buffer = NewArrayBuffer(isolate, new_size); |
+ Address new_mem_start = static_cast<Address>(new_buffer->backing_store()); |
+ if (new_buffer.is_null() || new_mem_start == nullptr) { |
+ return Handle<JSArrayBuffer>::null(); |
+ } |
+ if (old_size != 0) memcpy(new_mem_start, old_mem_start, old_size); |
+ return new_buffer; |
+} |
+int32_t UncheckedUpdateInstanceMemory(Isolate* isolate, |
+ Handle<JSObject> instance, |
+ Handle<JSArrayBuffer> buffer) { |
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 { |
+ Address old_mem_start = nullptr; |
+ uint32_t old_size = 0; |
+ if (maybe_mem_buffer.ToHandle(&old_buffer) && |
+ old_buffer->backing_store() != nullptr) { |
old_mem_start = static_cast<Address>(old_buffer->backing_store()); |
- 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; |
- } |
- |
- if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size) { |
- return -1; |
+ old_size = old_buffer->byte_length()->Number(); |
} |
- Handle<JSArrayBuffer> buffer = NewArrayBuffer(isolate, new_size); |
- if (buffer.is_null()) return -1; |
+ uint32_t new_size = buffer->byte_length()->Number(); |
+ DCHECK(new_size <= std::numeric_limits<uint32_t>::max()); |
Address new_mem_start = static_cast<Address>(buffer->backing_store()); |
- if (old_size != 0) { |
- memcpy(new_mem_start, old_mem_start, old_size); |
- } |
+ DCHECK_NOT_NULL(new_mem_start); |
SetInstanceMemory(instance, *buffer); |
Handle<FixedArray> code_table = GetCompiledModule(*instance)->code_table(); |
RelocateMemoryReferencesInCode(code_table, old_mem_start, new_mem_start, |
old_size, new_size); |
- Handle<Object> memory_object(instance->GetInternalField(kWasmMemObject), |
- isolate); |
- if (!memory_object->IsUndefined(isolate)) { |
- WasmJs::SetWasmMemoryArrayBuffer(isolate, memory_object, buffer); |
- } |
- |
DCHECK(old_size % WasmModule::kPageSize == 0); |
return (old_size / WasmModule::kPageSize); |
} |
+int32_t wasm::GrowWebAssemblyMemory(Isolate* isolate, |
Mircea Trofin
2016/11/09 18:57:10
please add comment explaining what the return is.
gdeepti
2016/11/16 05:34:10
This is as per Spec for GrowMemory - Return the pr
|
+ Handle<Object> memory_object, |
+ uint32_t pages) { |
+ DCHECK(WasmJs::IsWasmMemoryObject(isolate, memory_object)); |
+ uint32_t max_pages = WasmJs::GetWasmMemoryMaximumSize(isolate, memory_object); |
+ if (WasmModule::kV8MaxPages < max_pages) return -1; |
Mircea Trofin
2016/11/09 18:57:10
Should this be a DCHECK rather, and have the calle
gdeepti
2016/11/16 05:34:10
As per the spec, grow_memory should return -1 for
|
+ Handle<WasmInstanceWrapper> instance_wrapper = |
+ Handle<WasmInstanceWrapper>::cast( |
+ WasmJs::GetWasmMemoryInstanceWrapper(isolate, memory_object)); |
+ DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper)); |
+ DCHECK(instance_wrapper->has_instance()); |
+ Handle<JSObject> instance = instance_wrapper->instance_object(); |
+ DCHECK(IsWasmInstance(*instance)); |
+ if (pages == 0) return GetInstanceMemorySize(isolate, instance); |
Mircea Trofin
2016/11/09 18:57:09
why support pages == 0? Should this be an early DC
gdeepti
2016/11/16 05:34:10
The Spec says - "Return the previous memory size i
|
+ |
+ // Grow memory object buffer and update instances associated with it. |
+ MaybeHandle<JSArrayBuffer> old_buffer = |
+ WasmJs::GetWasmMemoryArrayBuffer(isolate, memory_object); |
+ Handle<JSArrayBuffer> new_buffer = |
+ GrowMemoryBuffer(isolate, old_buffer, pages, max_pages); |
+ if (new_buffer.is_null()) return -1; |
+ DCHECK(!instance_wrapper->has_previous()); |
+ int32_t ret = UncheckedUpdateInstanceMemory(isolate, instance, new_buffer); |
+ while (instance_wrapper->has_next()) { |
Mircea Trofin
2016/11/09 18:57:09
nit: perhaps paranoia, but you could do this in a
gdeepti
2016/11/16 05:34:10
I would prefer to leave this as is, as this seems
|
+ instance_wrapper = instance_wrapper->next_wrapper(); |
+ DCHECK(WasmInstanceWrapper::IsWasmInstanceWrapper(*instance_wrapper)); |
+ Handle<JSObject> instance = instance_wrapper->instance_object(); |
+ DCHECK(IsWasmInstance(*instance)); |
+ CHECK_EQ(ret, UncheckedUpdateInstanceMemory(isolate, instance, new_buffer)); |
+ } |
+ WasmJs::SetWasmMemoryArrayBuffer(isolate, memory_object, new_buffer); |
+ return ret; |
+} |
+ |
+int32_t wasm::GrowMemory(Isolate* isolate, Handle<JSObject> instance, |
+ uint32_t pages) { |
+ if (!IsWasmInstance(*instance)) return -1; |
+ if (pages == 0) return GetInstanceMemorySize(isolate, instance); |
+ Handle<Object> obj(instance->GetInternalField(kWasmMemObject), isolate); |
+ if (obj->IsUndefined(isolate)) { |
+ // No other instances to grow, grow just the one. |
+ MaybeHandle<JSArrayBuffer> old_buffer = |
+ GetInstanceMemory(isolate, instance); |
+ Handle<JSArrayBuffer> buffer = |
+ GrowMemoryBuffer(isolate, old_buffer, pages, WasmModule::kV8MaxPages); |
+ if (buffer.is_null()) return -1; |
+ return UncheckedUpdateInstanceMemory(isolate, instance, buffer); |
+ } else { |
+ return GrowWebAssemblyMemory(isolate, obj, pages); |
+ } |
+} |
+ |
void testing::ValidateInstancesChain(Isolate* isolate, |
Handle<JSObject> wasm_module, |
int instance_count) { |
@@ -2239,3 +2297,88 @@ void WasmCompiledModule::RecreateModuleWrapper(Isolate* isolate, |
compiled_module->set_module_wrapper(module_wrapper); |
DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module)); |
} |
+ |
+static void MemoryInstanceFinalizer(const v8::WeakCallbackInfo<void>& data) { |
Mircea Trofin
2016/11/09 18:57:10
I'd piggy-back on the existing finalizer registrat
gdeepti
2016/11/16 05:34:10
The MemoryInstanceFinalizer is optional, i.e, only
|
+ JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter()); |
+ JSObject* instance = *p; |
+ Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate()); |
+ Handle<WasmInstanceWrapper> instance_wrapper = |
+ handle(WasmInstanceWrapper::cast( |
+ instance->GetInternalField(kWasmMemInstanceWrapper))); |
+ |
+ 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<Object> memory_object(instance->GetInternalField(kWasmMemObject), |
+ isolate); |
+ |
+ if (!has_prev && !has_next) { |
+ if (!memory_object->IsUndefined(isolate)) { |
+ WasmJs::ResetWasmMemoryInstance(isolate, memory_object); |
+ } |
+ GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); |
+ 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. |
Mircea Trofin
2016/11/09 18:57:10
This comment makes me believe even moreso that we
gdeepti
2016/11/16 05:34:10
Agreed, Done.
|
+ const int kWasmMemObjectInstancesLink = 2; |
Mircea Trofin
2016/11/09 18:57:10
please see my earlier comment about fragility. Ple
gdeepti
2016/11/16 05:34:10
Done.
|
+ JSObject::cast(*memory_object) |
+ ->SetInternalField(kWasmMemObjectInstancesLink, *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(); |
+ GlobalHandles::Destroy(reinterpret_cast<Object**>(p)); |
+ } |
+} |
+ |
+Handle<WasmInstanceWrapper> WasmInstanceWrapper::New( |
+ Isolate* isolate, Handle<JSObject> 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<Object> global_handle = isolate->global_handles()->Create(*instance); |
+ Handle<WeakCell> cell = isolate->factory()->NewWeakCell(instance); |
+ set(kWrapperInstanceObject, *cell); |
+ GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(), |
+ &MemoryInstanceFinalizer, |
bradnelson
2016/11/09 01:40:11
You should be able to piggy-back this on the exist
gdeepti
2016/11/16 05:34:10
Done.
|
+ v8::WeakCallbackType::kFinalizer); |
+} |