Revert of [wasm] reuse the first compiled module (patchset #12 id:220001 of https://codereview.chromium.org/2305903002/ )

Reason for revert:
mac gc stress failures:
https://build.chromium.org/p/client.v8/builders/V8%20Mac%20GC%20Stress/builds/8341

Original issue's description:
> [wasm] reuse the first compiled module.
>
> This change avoids needing to keep around an unused compiled
> module. Instead, the result of compiling the wasm bytes is
> given to the first instance. The module object and that instance object
> point to the same compiled module. Instances are, then, cloned from
> the compiled module the module object points to. When an instance is
> collected, we make sure that the module object still has a clone
> available, and, if the last instance is GC-ed, we also reset the compiled
> module so that it does not reference its heap, so that it (==heap) may
> be collected.
>
> This is achieved by linking the clones in a double-linked list and
> registering a finalizer for each. When we create an instance, we tie it
> in the front of the list, making the module object point to it (O(1)). When
> the finalizer is called, we relink the list over the dying object (O(1)). The
> costliest operation is finalizing the last instance, since we need to visit
> all wasm functions and reset heap references.
>
> BUG=v8:5316
>
> Committed: https://crrev.com/01f5af515728aebe6c5246f4f7dd6c573e8748af
> Cr-Commit-Position: refs/heads/master@{#39153}

TBR=bradnelson@chromium.org,verwaest@chromium.org,vogelheim@chromium.org,yangguo@chromium.org,mtrofin@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:5316

Review-Url: https://codereview.chromium.org/2306403002
Cr-Commit-Position: refs/heads/master@{#39154}
This commit is contained in:
machenbach 2016-09-05 03:49:33 -07:00 committed by Commit bot
parent 01f5af5157
commit 359a00bf6f
9 changed files with 145 additions and 565 deletions

View File

@ -773,31 +773,5 @@ RUNTIME_FUNCTION(Runtime_DeserializeWasmModule) {
wasm::ModuleOrigin::kWasmOrigin);
}
RUNTIME_FUNCTION(Runtime_ValidateWasmInstancesChain) {
HandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_HANDLE_CHECKED(JSObject, module_obj, 0);
CONVERT_ARG_HANDLE_CHECKED(Smi, instance_count, 1);
wasm::testing::ValidateInstancesChain(isolate, module_obj,
instance_count->value());
return isolate->heap()->ToBoolean(true);
}
RUNTIME_FUNCTION(Runtime_ValidateWasmModuleState) {
HandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, module_obj, 0);
wasm::testing::ValidateModuleState(isolate, module_obj);
return isolate->heap()->ToBoolean(true);
}
RUNTIME_FUNCTION(Runtime_ValidateWasmOrphanedInstance) {
HandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, instance_obj, 0);
wasm::testing::ValidateOrphanedInstance(isolate, instance_obj);
return isolate->heap()->ToBoolean(true);
}
} // namespace internal
} // namespace v8

View File

@ -18,12 +18,16 @@
namespace v8 {
namespace internal {
namespace {
const int kWasmMemArrayBuffer = 2;
}
RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
uint32_t delta_pages = 0;
CHECK(args[0]->ToUint32(&delta_pages));
Handle<JSObject> module_instance;
Handle<JSObject> module_object;
{
// Get the module JSObject
@ -37,17 +41,17 @@ RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
Object* owning_instance = wasm::GetOwningWasmInstance(undefined, code);
CHECK_NOT_NULL(owning_instance);
CHECK_NE(owning_instance, undefined);
module_instance = handle(JSObject::cast(owning_instance), isolate);
module_object = handle(JSObject::cast(owning_instance), isolate);
}
Address old_mem_start, new_mem_start;
uint32_t old_size, new_size;
// Get mem buffer associated with module object
MaybeHandle<JSArrayBuffer> maybe_mem_buffer =
wasm::GetInstanceMemory(isolate, module_instance);
Handle<JSArrayBuffer> old_buffer;
if (!maybe_mem_buffer.ToHandle(&old_buffer)) {
Handle<Object> obj(module_object->GetInternalField(kWasmMemArrayBuffer),
isolate);
if (obj->IsUndefined(isolate)) {
// If module object does not have linear memory associated with it,
// Allocate new array buffer of given size.
old_mem_start = nullptr;
@ -69,6 +73,7 @@ RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
}
#endif
} else {
Handle<JSArrayBuffer> old_buffer = Handle<JSArrayBuffer>::cast(obj);
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
@ -96,10 +101,9 @@ RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
buffer->set_is_neuterable(false);
// Set new buffer to be wasm memory
module_object->SetInternalField(kWasmMemArrayBuffer, *buffer);
wasm::SetInstanceMemory(module_instance, *buffer);
CHECK(wasm::UpdateWasmModuleMemory(module_instance, old_mem_start,
CHECK(wasm::UpdateWasmModuleMemory(module_object, old_mem_start,
new_mem_start, old_size, new_size));
return *isolate->factory()->NewNumberFromInt(old_size /

View File

@ -887,10 +887,7 @@ namespace internal {
F(SerializeWasmModule, 1, 1) \
F(DeserializeWasmModule, 1, 1) \
F(IsAsmWasmCode, 1, 1) \
F(IsNotAsmWasmCode, 1, 1) \
F(ValidateWasmInstancesChain, 2, 1) \
F(ValidateWasmModuleState, 1, 1) \
F(ValidateWasmOrphanedInstance, 1, 1)
F(IsNotAsmWasmCode, 1, 1)
#define FOR_EACH_INTRINSIC_TYPEDARRAY(F) \
F(ArrayBufferGetByteLength, 1, 1) \

View File

@ -98,10 +98,6 @@ void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
UNREACHABLE();
}
if (SkipOver(obj)) {
return SerializeObject(*isolate()->factory()->undefined_value(),
how_to_code, where_to_point, skip);
}
// Past this point we should not see any (context-specific) maps anymore.
CHECK(!obj->IsMap());
// There should be no references to the global object embedded.

View File

@ -36,7 +36,6 @@ class CodeSerializer : public Serializer {
UNREACHABLE();
}
virtual bool SkipOver(Object* obj) { return false; }
void SerializeGeneric(HeapObject* heap_object, HowToCode how_to_code,
WhereToPoint where_to_point);
@ -74,8 +73,6 @@ class WasmCompiledModuleSerializer : public CodeSerializer {
}
}
bool SkipOver(Object* obj) override { return obj->IsWeakCell(); };
private:
WasmCompiledModuleSerializer(Isolate* isolate, uint32_t source_hash)
: CodeSerializer(isolate, source_hash) {}

View File

@ -158,19 +158,15 @@ Object* GetOwningWasmInstance(Object* undefined, Code* code) {
namespace {
// Internal constants for the layout of the module object.
enum WasmInstanceFields {
kWasmCompiledModule = 0,
kWasmModuleFunctionTable,
kWasmModuleCodeTable,
kWasmMemArrayBuffer,
kWasmGlobalsArrayBuffer,
// TODO(clemensh): Remove function name array, extract names from module
// bytes.
kWasmFunctionNamesArray,
kWasmModuleBytesString,
kWasmDebugInfo,
kWasmModuleInternalFieldCount
};
const int kWasmModuleFunctionTable = 0;
const int kWasmModuleCodeTable = 1;
const int kWasmMemArrayBuffer = 2;
const int kWasmGlobalsArrayBuffer = 3;
// TODO(clemensh): Remove function name array, extract names from module bytes.
const int kWasmFunctionNamesArray = 4;
const int kWasmModuleBytesString = 5;
const int kWasmDebugInfo = 6;
const int kWasmModuleInternalFieldCount = 7;
// TODO(mtrofin): Unnecessary once we stop using JS Heap for wasm code.
// For now, each field is expected to have the type commented by its side.
@ -198,14 +194,8 @@ enum CompiledWasmObjectFields {
kDataSegments, // maybe ByteArray.
kGlobalsSize, // Smi. an uint32_t
kMemSize, // Smi.an uint32_t
kMemStart, // MaybeHandle<ArrayBuffer>
kExportMem, // Smi. bool
kOrigin, // Smi. ModuleOrigin
kNextInstance, // WeakCell. See compiled code cloning.
kPrevInstance, // WeakCell. See compiled code cloning.
kOwningInstance, // WeakCell, pointing to the owning instance.
kModuleObject, // WeakCell, pointing to the module object.
kCompiledWasmObjectTableSize // Sentinel value.
};
@ -339,9 +329,8 @@ Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size) {
return buffer;
}
void RelocateInstanceCode(Handle<JSObject> instance, Address old_start,
Address start, uint32_t prev_size,
uint32_t new_size) {
void RelocateInstanceCode(Handle<JSObject> instance, Address start,
uint32_t prev_size, uint32_t new_size) {
Handle<FixedArray> functions = Handle<FixedArray>(
FixedArray::cast(instance->GetInternalField(kWasmModuleCodeTable)));
for (int i = 0; i < functions->length(); ++i) {
@ -350,7 +339,7 @@ void RelocateInstanceCode(Handle<JSObject> instance, Address old_start,
int mask = (1 << RelocInfo::WASM_MEMORY_REFERENCE) |
(1 << RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
for (RelocIterator it(*function, mask); !it.done(); it.next()) {
it.rinfo()->update_wasm_memory_reference(old_start, start, prev_size,
it.rinfo()->update_wasm_memory_reference(nullptr, start, prev_size,
new_size);
}
}
@ -372,8 +361,7 @@ Handle<JSArrayBuffer> AllocateMemory(ErrorThrower* thrower, Isolate* isolate,
return mem_buffer;
}
void RelocateGlobals(Handle<JSObject> instance, Address old_start,
Address globals_start) {
void RelocateGlobals(Handle<JSObject> instance, Address globals_start) {
Handle<FixedArray> functions = Handle<FixedArray>(
FixedArray::cast(instance->GetInternalField(kWasmModuleCodeTable)));
uint32_t function_count = static_cast<uint32_t>(functions->length());
@ -382,7 +370,7 @@ void RelocateGlobals(Handle<JSObject> instance, Address old_start,
AllowDeferredHandleDereference embedding_raw_address;
int mask = 1 << RelocInfo::WASM_GLOBAL_REFERENCE;
for (RelocIterator it(*function, mask); !it.done(); it.next()) {
it.rinfo()->update_wasm_global_reference(old_start, globals_start);
it.rinfo()->update_wasm_global_reference(nullptr, globals_start);
}
}
}
@ -413,35 +401,40 @@ void InitializePlaceholders(Factory* factory,
}
}
bool LinkFunction(Isolate* isolate, Handle<Code> unlinked,
Handle<FixedArray> code_targets,
Code::Kind kind = Code::WASM_FUNCTION) {
bool LinkFunction(Handle<Code> unlinked,
const std::vector<Handle<Code>>& code_targets,
Code::Kind kind) {
bool modified = false;
int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
int mode_mask = RelocInfo::kCodeTargetMask;
AllowDeferredHandleDereference embedding_raw_address;
for (RelocIterator it(*unlinked, mode_mask); !it.done(); it.next()) {
Code* target = Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
if (target->kind() == kind &&
target->constant_pool_offset() >= kPlaceholderMarker) {
// Patch direct calls to placeholder code objects.
uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
CHECK(index < static_cast<uint32_t>(code_targets->length()));
Handle<Code> new_target =
code_targets->GetValueChecked<Code>(isolate, index);
if (target != *new_target) {
it.rinfo()->set_target_address(new_target->instruction_start(),
UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
modified = true;
RelocInfo::Mode mode = it.rinfo()->rmode();
if (RelocInfo::IsCodeTarget(mode)) {
Code* target =
Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
if (target->kind() == kind &&
target->constant_pool_offset() >= kPlaceholderMarker) {
// Patch direct calls to placeholder code objects.
uint32_t index = target->constant_pool_offset() - kPlaceholderMarker;
CHECK(index < code_targets.size());
Handle<Code> new_target = code_targets[index];
if (target != *new_target) {
it.rinfo()->set_target_address(new_target->instruction_start(),
UPDATE_WRITE_BARRIER,
SKIP_ICACHE_FLUSH);
modified = true;
}
}
}
}
return modified;
}
void LinkModuleFunctions(Isolate* isolate, Handle<FixedArray> functions) {
for (int i = 0; i < functions->length(); ++i) {
Handle<Code> code = functions->GetValueChecked<Code>(isolate, i);
LinkFunction(isolate, code, functions);
void LinkModuleFunctions(Isolate* isolate,
std::vector<Handle<Code>>& functions) {
for (size_t i = 0; i < functions.size(); ++i) {
Handle<Code> code = functions[i];
LinkFunction(code, functions, Code::WASM_FUNCTION);
}
}
@ -460,6 +453,8 @@ void SetRuntimeSupport(Isolate* isolate, Handle<JSObject> js_object) {
for (int i = FLAG_skip_compiling_wasm_funcs; i < functions->length(); ++i) {
Handle<Code> code = functions->GetValueChecked<Code>(isolate, i);
DCHECK(code->deoptimization_data() == nullptr ||
code->deoptimization_data()->length() == 0);
Handle<FixedArray> deopt_data =
isolate->factory()->NewFixedArray(2, TENURED);
deopt_data->set(0, *weak_link);
@ -626,17 +621,6 @@ static void RecordStats(Isolate* isolate, Handle<FixedArray> functions) {
}
}
Address GetGlobalStartAddressFromCodeTemplate(Object* undefined,
JSObject* owner) {
Address old_address = nullptr;
Object* stored_value = owner->GetInternalField(kWasmGlobalsArrayBuffer);
if (stored_value != undefined) {
old_address = static_cast<Address>(
JSArrayBuffer::cast(stored_value)->backing_store());
}
return old_address;
}
Handle<FixedArray> GetImportsMetadata(Factory* factory,
const WasmModule* module) {
Handle<FixedArray> ret = factory->NewFixedArray(
@ -928,9 +912,8 @@ void SetDebugSupport(Factory* factory, Handle<FixedArray> compiled_module,
}
}
bool SetupGlobals(Isolate* isolate, MaybeHandle<JSObject> template_owner,
Handle<FixedArray> compiled_module, Handle<JSObject> instance,
ErrorThrower* thrower) {
bool SetupGlobals(Isolate* isolate, Handle<FixedArray> compiled_module,
Handle<JSObject> instance, ErrorThrower* thrower) {
uint32_t globals_size = static_cast<uint32_t>(
Smi::cast(compiled_module->get(kGlobalsSize))->value());
if (globals_size > 0) {
@ -940,13 +923,7 @@ bool SetupGlobals(Isolate* isolate, MaybeHandle<JSObject> template_owner,
thrower->Error("Out of memory: wasm globals");
return false;
}
Address old_address =
template_owner.is_null()
? nullptr
: GetGlobalStartAddressFromCodeTemplate(
*isolate->factory()->undefined_value(),
JSObject::cast(*template_owner.ToHandleChecked()));
RelocateGlobals(instance, old_address,
RelocateGlobals(instance,
static_cast<Address>(globals_buffer->backing_store()));
instance->SetInternalField(kWasmGlobalsArrayBuffer, *globals_buffer);
}
@ -972,72 +949,13 @@ bool SetupInstanceHeap(Isolate* isolate, Handle<FixedArray> compiled_module,
instance->SetInternalField(kWasmMemArrayBuffer, *memory);
Address mem_start = static_cast<Address>(memory->backing_store());
uint32_t mem_size = static_cast<uint32_t>(memory->byte_length()->Number());
uint32_t old_mem_size = static_cast<uint32_t>(
compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize)
->value());
MaybeHandle<JSArrayBuffer> old_mem =
compiled_module->GetValue<JSArrayBuffer>(isolate, kMemStart);
Address old_mem_start =
old_mem.is_null()
? nullptr
: static_cast<Address>(old_mem.ToHandleChecked()->backing_store());
RelocateInstanceCode(instance, old_mem_start, mem_start, old_mem_size,
mem_size);
RelocateInstanceCode(instance, mem_start,
WasmModule::kPageSize * min_mem_pages, mem_size);
LoadDataSegments(compiled_module, mem_start, mem_size);
compiled_module->GetValueChecked<HeapNumber>(isolate, kMemSize)
->set_value(static_cast<double>(mem_size));
compiled_module->set(kMemStart, *memory);
}
return true;
}
void FixupFunctionsAndImports(Handle<FixedArray> old_functions,
Handle<FixedArray> new_functions,
MaybeHandle<FixedArray> maybe_old_imports,
MaybeHandle<FixedArray> maybe_new_imports) {
DCHECK_EQ(new_functions->length(), old_functions->length());
DisallowHeapAllocation no_gc;
std::map<Code*, Code*> old_to_new_code;
for (int i = 0; i < new_functions->length(); ++i) {
old_to_new_code.insert(std::make_pair(Code::cast(old_functions->get(i)),
Code::cast(new_functions->get(i))));
}
DCHECK_EQ(maybe_old_imports.is_null(), maybe_new_imports.is_null());
if (!maybe_old_imports.is_null()) {
Handle<FixedArray> old_imports = maybe_old_imports.ToHandleChecked();
Handle<FixedArray> new_imports = maybe_new_imports.ToHandleChecked();
DCHECK_EQ(new_imports->length(), old_imports->length());
for (int i = 0; i < new_imports->length(); ++i) {
old_to_new_code.insert(std::make_pair(Code::cast(old_imports->get(i)),
Code::cast(new_imports->get(i))));
}
}
int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
AllowDeferredHandleDereference embedding_raw_address;
for (int i = 0; i < new_functions->length(); ++i) {
Code* wasm_function = Code::cast(new_functions->get(i));
for (RelocIterator it(wasm_function, mode_mask); !it.done(); it.next()) {
Code* old_code =
Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
if (old_code->kind() == Code::WASM_TO_JS_FUNCTION ||
old_code->kind() == Code::WASM_FUNCTION) {
auto found = old_to_new_code.find(old_code);
DCHECK(found != old_to_new_code.end());
Code* new_code = found->second;
// Avoid redundant updates, expected for wasm functions, if we're at the
// first instance.
if (new_code == old_code) {
DCHECK(new_code->kind() == Code::WASM_FUNCTION);
continue;
}
it.rinfo()->set_target_address(new_code->instruction_start(),
UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
}
}
}
}
bool SetupImports(Isolate* isolate, Handle<FixedArray> compiled_module,
Handle<JSObject> instance, ErrorThrower* thrower,
Handle<JSReceiver> ffi) {
@ -1056,14 +974,49 @@ bool SetupImports(Isolate* isolate, Handle<FixedArray> compiled_module,
}
RecordStats(isolate, import_code);
if (import_code.empty()) return true;
Handle<FixedArray> new_imports =
isolate->factory()->NewFixedArray(static_cast<int>(import_code.size()));
for (int i = 0; i < new_imports->length(); ++i) {
new_imports->set(i, *import_code[i]);
{
DisallowHeapAllocation no_gc;
std::map<Code*, int> import_to_index;
Handle<FixedArray> mapping =
compiled_module->GetValueChecked<FixedArray>(isolate, kImportMap);
for (int i = 0; i < mapping->length(); ++i) {
import_to_index.insert(std::make_pair(Code::cast(mapping->get(i)), i));
}
Handle<FixedArray> code_table = Handle<FixedArray>(
FixedArray::cast(instance->GetInternalField(kWasmModuleCodeTable)));
int mode_mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
AllowDeferredHandleDereference embedding_raw_address;
for (int i = 0; i < code_table->length(); ++i) {
Handle<Code> wasm_function =
code_table->GetValueChecked<Code>(isolate, i);
for (RelocIterator it(*wasm_function, mode_mask); !it.done(); it.next()) {
Code* target =
Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
if (target->kind() == Code::WASM_TO_JS_FUNCTION) {
auto found_index = import_to_index.find(target);
CHECK(found_index != import_to_index.end());
int index = found_index->second;
CHECK(index < static_cast<int>(import_code.size()));
Handle<Code> new_target = import_code[index];
it.rinfo()->set_target_address(new_target->instruction_start(),
UPDATE_WRITE_BARRIER,
SKIP_ICACHE_FLUSH);
}
}
}
}
compiled_module->set(kImportMap, *new_imports);
Handle<FixedArray> new_mapping =
isolate->factory()->NewFixedArray(static_cast<int>(import_code.size()));
for (int i = 0; i < new_mapping->length(); ++i) {
new_mapping->set(i, *import_code[i]);
}
compiled_module->set(kImportMap, *new_mapping);
return true;
}
@ -1128,122 +1081,6 @@ bool SetupExportsObject(Handle<FixedArray> compiled_module, Isolate* isolate,
return true;
}
#define GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(Field) \
WeakCell* Get##Field(const FixedArray* compiled_module) { \
Object* obj = compiled_module->get(k##Field); \
DCHECK_NOT_NULL(obj); \
if (obj->IsWeakCell()) { \
return WeakCell::cast(obj); \
} else { \
return nullptr; \
} \
}
GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(NextInstance)
GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(PrevInstance)
GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(OwningInstance)
GET_COMPILED_MODULE_WEAK_RELATION_OR_NULL(ModuleObject)
static void ResetCompiledModule(Isolate* isolate, JSObject* owner,
FixedArray* compiled_module) {
Object* undefined = *isolate->factory()->undefined_value();
Object* mem_size_obj = compiled_module->get(kMemSize);
DCHECK(mem_size_obj->IsMutableHeapNumber());
uint32_t old_mem_size =
static_cast<uint32_t>(HeapNumber::cast(mem_size_obj)->value());
Object* mem_start = compiled_module->get(kMemStart);
Address old_mem_address = nullptr;
Address globals_start =
GetGlobalStartAddressFromCodeTemplate(undefined, owner);
if (old_mem_size > 0) {
CHECK_NE(mem_start, undefined);
old_mem_address =
static_cast<Address>(JSArrayBuffer::cast(mem_start)->backing_store());
}
int mode_mask = RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_REFERENCE) |
RelocInfo::ModeMask(RelocInfo::WASM_MEMORY_SIZE_REFERENCE) |
RelocInfo::ModeMask(RelocInfo::WASM_GLOBAL_REFERENCE);
Object* fct_obj = compiled_module->get(kFunctions);
if (fct_obj != nullptr && fct_obj != undefined &&
(old_mem_size > 0 || globals_start != nullptr)) {
FixedArray* functions = FixedArray::cast(fct_obj);
for (int i = 0; i < functions->length(); ++i) {
Code* code = Code::cast(functions->get(i));
bool changed = false;
for (RelocIterator it(code, mode_mask); !it.done(); it.next()) {
RelocInfo::Mode mode = it.rinfo()->rmode();
if (RelocInfo::IsWasmMemoryReference(mode) ||
RelocInfo::IsWasmMemorySizeReference(mode)) {
it.rinfo()->update_wasm_memory_reference(old_mem_address, nullptr,
old_mem_size, old_mem_size);
changed = true;
} else {
CHECK(RelocInfo::IsWasmGlobalReference(mode));
it.rinfo()->update_wasm_global_reference(globals_start, nullptr);
changed = true;
}
}
if (changed) {
Assembler::FlushICache(isolate, code->instruction_start(),
code->instruction_size());
}
}
}
compiled_module->set(kOwningInstance, undefined);
compiled_module->set(kMemStart, undefined);
}
static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter());
JSObject* owner = *p;
FixedArray* compiled_module =
FixedArray::cast(owner->GetInternalField(kWasmCompiledModule));
Isolate* isolate = reinterpret_cast<Isolate*>(data.GetIsolate());
Object* undefined = *isolate->factory()->undefined_value();
WeakCell* weak_module_obj = GetModuleObject(compiled_module);
DCHECK_NOT_NULL(weak_module_obj);
// weak_module_obj may have been cleared, meaning the module object
// was GC-ed. In that case, there won't be any new instances created,
// and we don't need to maintain the links between instances.
if (!weak_module_obj->cleared()) {
JSObject* module_obj = JSObject::cast(weak_module_obj->value());
FixedArray* current_template =
FixedArray::cast(module_obj->GetInternalField(0));
DCHECK_NULL(GetPrevInstance(current_template));
WeakCell* next = GetNextInstance(compiled_module);
WeakCell* prev = GetPrevInstance(compiled_module);
if (current_template == compiled_module) {
if (next == nullptr) {
ResetCompiledModule(isolate, owner, compiled_module);
} else {
DCHECK(next->value()->IsFixedArray());
module_obj->SetInternalField(0, next->value());
DCHECK_NULL(prev);
FixedArray::cast(next->value())->set(kPrevInstance, undefined);
}
} else {
DCHECK(!(prev == nullptr && next == nullptr));
// the only reason prev or next would be cleared is if the
// respective objects got collected, but if that happened,
// we would have relinked the list.
if (prev != nullptr) {
DCHECK(!prev->cleared());
FixedArray::cast(prev->value())
->set(kNextInstance, next == nullptr ? undefined : next);
}
if (next != nullptr) {
DCHECK(!next->cleared());
FixedArray::cast(next->value())
->set(kPrevInstance, prev == nullptr ? undefined : prev);
}
}
}
GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
}
} // namespace
MaybeHandle<FixedArray> WasmModule::CompileFunctions(
@ -1319,11 +1156,6 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
compiled_functions->set(static_cast<int>(i), code);
}
LinkModuleFunctions(isolate, compiled_functions);
// TODO(mtrofin): do we need to flush the cache here?
FlushAssemblyCache(isolate, compiled_functions);
// Create the compiled module object, and populate with compiled functions
// and information needed at instantiation time. This object needs to be
// serializable. Instantiation may occur off a deserialized version of this
@ -1419,10 +1251,6 @@ MaybeHandle<FixedArray> WasmModule::CompileFunctions(
ret->set(kGlobalsSize, Smi::FromInt(globals_size));
ret->set(kExportMem, Smi::FromInt(mem_export));
ret->set(kOrigin, Smi::FromInt(origin));
Handle<HeapNumber> size_as_object = factory->NewHeapNumber(
static_cast<double>(temp_instance_for_compilation.mem_size), MUTABLE,
TENURED);
ret->set(kMemSize, *size_as_object);
return ret;
}
@ -1447,8 +1275,7 @@ void PatchJSWrapper(Isolate* isolate, Handle<Code> wrapper,
Handle<FixedArray> SetupIndirectFunctionTable(
Isolate* isolate, Handle<FixedArray> wasm_functions,
Handle<FixedArray> indirect_table_template,
Handle<FixedArray> tables_to_replace) {
Handle<FixedArray> indirect_table_template) {
Factory* factory = isolate->factory();
Handle<FixedArray> cloned_indirect_tables =
factory->CopyFixedArray(indirect_table_template);
@ -1463,13 +1290,10 @@ Handle<FixedArray> SetupIndirectFunctionTable(
Handle<FixedArray> cloned_table = factory->CopyFixedArray(orig_table);
cloned_metadata->set(kTable, *cloned_table);
// Patch the cloned code to refer to the cloned kTable.
Handle<FixedArray> table_to_replace =
tables_to_replace->GetValueChecked<FixedArray>(isolate, i)
->GetValueChecked<FixedArray>(isolate, kTable);
for (int fct_index = 0; fct_index < wasm_functions->length(); ++fct_index) {
for (int i = 0; i < wasm_functions->length(); ++i) {
Handle<Code> wasm_function =
wasm_functions->GetValueChecked<Code>(isolate, fct_index);
PatchFunctionTable(wasm_function, table_to_replace, cloned_table);
wasm_functions->GetValueChecked<Code>(isolate, i);
PatchFunctionTable(wasm_function, orig_table, cloned_table);
}
}
return cloned_indirect_tables;
@ -1478,24 +1302,7 @@ Handle<FixedArray> SetupIndirectFunctionTable(
Handle<FixedArray> CloneModuleForInstance(Isolate* isolate,
Handle<FixedArray> original) {
Factory* factory = isolate->factory();
bool is_first =
original->GetValue<WeakCell>(isolate, kOwningInstance).is_null();
if (is_first) {
return original;
}
// We insert the latest clone in front.
Handle<FixedArray> clone = factory->CopyFixedArray(original);
Handle<WeakCell> weak_link_to_wasm_obj =
original->GetValueChecked<WeakCell>(isolate, kModuleObject);
clone->set(kModuleObject, *weak_link_to_wasm_obj);
Handle<WeakCell> link_to_original = factory->NewWeakCell(original);
clone->set(kNextInstance, *link_to_original);
Handle<WeakCell> link_to_clone = factory->NewWeakCell(clone);
original->set(kPrevInstance, *link_to_clone);
JSObject::cast(weak_link_to_wasm_obj->value())->SetInternalField(0, *clone);
// Clone each wasm code object.
Handle<FixedArray> orig_wasm_functions =
@ -1556,7 +1363,6 @@ Handle<FixedArray> CloneModuleForInstance(Isolate* isolate,
clone_wasm_functions->GetValueChecked<Code>(isolate, startup_fct_index);
PatchJSWrapper(isolate, startup_fct_clone, new_target);
}
clone->set(kImportMap, *isolate->factory()->undefined_value());
return clone;
}
@ -1566,30 +1372,27 @@ Handle<FixedArray> CloneModuleForInstance(Isolate* isolate,
// * installs named properties on the object for exported functions
// * compiles wasm code to machine code
MaybeHandle<JSObject> WasmModule::Instantiate(
Isolate* isolate, Handle<FixedArray> compiled_module_template,
Isolate* isolate, Handle<FixedArray> compiled_module,
Handle<JSReceiver> ffi, Handle<JSArrayBuffer> memory) {
HistogramTimerScope wasm_instantiate_module_time_scope(
isolate->counters()->wasm_instantiate_module_time());
ErrorThrower thrower(isolate, "WasmModule::Instantiate()");
Factory* factory = isolate->factory();
Handle<FixedArray> compiled_module =
CloneModuleForInstance(isolate, compiled_module_template);
compiled_module = CloneModuleForInstance(isolate, compiled_module);
bool template_is_owned =
GetOwningInstance(*compiled_module_template) != nullptr;
MaybeHandle<JSObject> template_owner;
if (template_is_owned) {
Handle<WeakCell> weak_owner =
compiled_module_template->GetValueChecked<WeakCell>(isolate,
kOwningInstance);
template_owner = handle(JSObject::cast(weak_owner->value()));
}
// These fields are compulsory.
Handle<FixedArray> code_table =
compiled_module->GetValueChecked<FixedArray>(isolate, kFunctions);
std::vector<Handle<Code>> functions(
static_cast<size_t>(code_table->length()));
for (int i = 0; i < code_table->length(); ++i) {
functions[static_cast<size_t>(i)] =
code_table->GetValueChecked<Code>(isolate, i);
}
LinkModuleFunctions(isolate, functions);
RecordStats(isolate, code_table);
MaybeHandle<JSObject> nothing;
@ -1600,61 +1403,35 @@ MaybeHandle<JSObject> WasmModule::Instantiate(
Handle<JSObject> js_object = factory->NewJSObjectFromMap(map, TENURED);
js_object->SetInternalField(kWasmModuleCodeTable, *code_table);
// Remember the old imports, for the case when we are at the first instance -
// they will be replaced with the instance's actual imports in SetupImports.
MaybeHandle<FixedArray> old_imports =
compiled_module_template->GetValue<FixedArray>(isolate, kImportMap);
if (!(SetupInstanceHeap(isolate, compiled_module, js_object, memory,
&thrower) &&
SetupGlobals(isolate, template_owner, compiled_module, js_object,
&thrower) &&
SetupGlobals(isolate, compiled_module, js_object, &thrower) &&
SetupImports(isolate, compiled_module, js_object, &thrower, ffi) &&
SetupExportsObject(compiled_module, isolate, js_object, &thrower))) {
return nothing;
}
FixupFunctionsAndImports(
compiled_module_template->GetValueChecked<FixedArray>(isolate,
kFunctions),
code_table, old_imports,
compiled_module->GetValue<FixedArray>(isolate, kImportMap));
SetDebugSupport(factory, compiled_module, js_object);
SetRuntimeSupport(isolate, js_object);
FlushAssemblyCache(isolate, code_table);
{
std::vector<Handle<Code>> functions(
static_cast<size_t>(code_table->length()));
for (int i = 0; i < code_table->length(); ++i) {
functions[static_cast<size_t>(i)] =
code_table->GetValueChecked<Code>(isolate, i);
}
MaybeHandle<FixedArray> maybe_indirect_tables =
compiled_module->GetValue<FixedArray>(isolate,
kTableOfIndirectFunctionTables);
Handle<FixedArray> indirect_tables_template;
if (maybe_indirect_tables.ToHandle(&indirect_tables_template)) {
Handle<FixedArray> to_replace =
template_owner.is_null()
? indirect_tables_template
: handle(FixedArray::cast(
template_owner.ToHandleChecked()->GetInternalField(
kWasmModuleFunctionTable)));
Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable(
isolate, code_table, indirect_tables_template, to_replace);
for (int i = 0; i < indirect_tables->length(); ++i) {
Handle<FixedArray> metadata =
indirect_tables->GetValueChecked<FixedArray>(isolate, i);
uint32_t size = Smi::cast(metadata->get(kSize))->value();
Handle<FixedArray> table =
metadata->GetValueChecked<FixedArray>(isolate, kTable);
wasm::PopulateFunctionTable(table, size, &functions);
}
js_object->SetInternalField(kWasmModuleFunctionTable, *indirect_tables);
MaybeHandle<FixedArray> maybe_indirect_tables =
compiled_module->GetValue<FixedArray>(isolate,
kTableOfIndirectFunctionTables);
Handle<FixedArray> indirect_tables_template;
if (maybe_indirect_tables.ToHandle(&indirect_tables_template)) {
Handle<FixedArray> indirect_tables = SetupIndirectFunctionTable(
isolate, code_table, indirect_tables_template);
for (int i = 0; i < indirect_tables->length(); ++i) {
Handle<FixedArray> metadata =
indirect_tables->GetValueChecked<FixedArray>(isolate, i);
uint32_t size = Smi::cast(metadata->get(kSize))->value();
Handle<FixedArray> table =
metadata->GetValueChecked<FixedArray>(isolate, kTable);
wasm::PopulateFunctionTable(table, size, &functions);
}
js_object->SetInternalField(kWasmModuleFunctionTable, *indirect_tables);
}
// Run the start function if one was specified.
@ -1684,19 +1461,6 @@ MaybeHandle<JSObject> WasmModule::Instantiate(
}
DCHECK(wasm::IsWasmObject(*js_object));
if (!compiled_module->GetValue<WeakCell>(isolate, kModuleObject).is_null()) {
js_object->SetInternalField(kWasmCompiledModule, *compiled_module);
Handle<WeakCell> link_to_owner = factory->NewWeakCell(js_object);
compiled_module->set(kOwningInstance, *link_to_owner);
Handle<Object> global_handle =
isolate->global_handles()->Create(*js_object);
GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
&InstanceFinalizer,
v8::WeakCallbackType::kFinalizer);
}
return js_object;
}
@ -1884,8 +1648,6 @@ Handle<JSObject> CreateCompiledModuleObject(Isolate* isolate,
Handle<Symbol> module_sym(isolate->native_context()->wasm_module_sym());
Object::SetProperty(module_obj, module_sym, module_obj, STRICT).Check();
}
Handle<WeakCell> link_to_module = isolate->factory()->NewWeakCell(module_obj);
compiled_module->set(kModuleObject, *link_to_module);
return module_obj;
}
@ -1911,25 +1673,6 @@ MaybeHandle<JSObject> CreateModuleObjectFromBytes(Isolate* isolate,
origin);
}
MaybeHandle<JSArrayBuffer> GetInstanceMemory(Isolate* isolate,
Handle<JSObject> instance) {
Object* mem = instance->GetInternalField(kWasmMemArrayBuffer);
DCHECK(IsWasmObject(*instance));
if (mem->IsUndefined(isolate)) return MaybeHandle<JSArrayBuffer>();
return Handle<JSArrayBuffer>(JSArrayBuffer::cast(mem));
}
void SetInstanceMemory(Handle<JSObject> instance, JSArrayBuffer* buffer) {
DisallowHeapAllocation no_gc;
DCHECK(IsWasmObject(*instance));
instance->SetInternalField(kWasmMemArrayBuffer, buffer);
Object* module = instance->GetInternalField(kWasmCompiledModule);
if (module->IsFixedArray()) {
HeapNumber::cast(FixedArray::cast(module)->get(kMemSize))
->set_value(buffer->byte_length()->Number());
}
}
namespace testing {
int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
@ -2014,51 +1757,6 @@ int32_t CallFunction(Isolate* isolate, Handle<JSObject> instance,
return -1;
}
void ValidateInstancesChain(Isolate* isolate, Handle<JSObject> module_obj,
int instance_count) {
CHECK_GE(instance_count, 0);
DisallowHeapAllocation no_gc;
FixedArray* compiled_module =
FixedArray::cast(module_obj->GetInternalField(0));
CHECK_EQ(JSObject::cast(GetModuleObject(compiled_module)->value()),
*module_obj);
Object* prev = nullptr;
int found_instances = GetOwningInstance(compiled_module) == nullptr ? 0 : 1;
FixedArray* current_instance = compiled_module;
while (GetNextInstance(current_instance) != nullptr) {
CHECK((prev == nullptr && GetPrevInstance(current_instance) == nullptr) ||
GetPrevInstance(current_instance)->value() == prev);
CHECK_EQ(GetModuleObject(current_instance)->value(), *module_obj);
CHECK(IsWasmObject(GetOwningInstance(current_instance)->value()));
prev = current_instance;
current_instance =
FixedArray::cast(GetNextInstance(current_instance)->value());
++found_instances;
CHECK_LE(found_instances, instance_count);
}
CHECK_EQ(found_instances, instance_count);
}
void ValidateModuleState(Isolate* isolate, Handle<JSObject> module_obj) {
DisallowHeapAllocation no_gc;
FixedArray* compiled_module =
FixedArray::cast(module_obj->GetInternalField(0));
CHECK_NOT_NULL(GetModuleObject(compiled_module));
CHECK_EQ(GetModuleObject(compiled_module)->value(), *module_obj);
CHECK_NULL(GetPrevInstance(compiled_module));
CHECK_NULL(GetNextInstance(compiled_module));
CHECK_NULL(GetOwningInstance(compiled_module));
}
void ValidateOrphanedInstance(Isolate* isolate, Handle<JSObject> instance) {
DisallowHeapAllocation no_gc;
CHECK(IsWasmObject(*instance));
FixedArray* compiled_module =
FixedArray::cast(instance->GetInternalField(kWasmCompiledModule));
CHECK_NOT_NULL(GetModuleObject(compiled_module));
CHECK(GetModuleObject(compiled_module)->cleared());
}
} // namespace testing
} // namespace wasm
} // namespace internal

View File

@ -415,10 +415,6 @@ MaybeHandle<JSObject> CreateModuleObjectFromBytes(Isolate* isolate,
// was collected, or the instance object owning the Code object
Object* GetOwningWasmInstance(Object* undefined, Code* code);
MaybeHandle<JSArrayBuffer> GetInstanceMemory(Isolate* isolate,
Handle<JSObject> instance);
void SetInstanceMemory(Handle<JSObject> instance, JSArrayBuffer* buffer);
namespace testing {
// Decode, verify, and run the function labeled "main" in the
@ -429,12 +425,6 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
int32_t CallFunction(Isolate* isolate, Handle<JSObject> instance,
ErrorThrower* thrower, const char* name, int argc,
Handle<Object> argv[], bool asm_js = false);
void ValidateInstancesChain(Isolate* isolate, Handle<JSObject> module_obj,
int instance_count);
void ValidateModuleState(Isolate* isolate, Handle<JSObject> module_obj);
void ValidateOrphanedInstance(Isolate* isolate, Handle<JSObject> instance);
} // namespace testing
} // namespace wasm
} // namespace internal

View File

@ -1,50 +0,0 @@
// 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.
// TODO (mtrofin): re-enable ignition (v8:5345)
// Flags: --no-ignition --no-ignition-staging
// Flags: --expose-wasm --expose-gc --allow-natives-syntax
load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js");
(function CompiledModuleInstancesAreGCed() {
var builder = new WasmModuleBuilder();
builder.addMemory(1,1, true);
builder.addImport("getValue", kSig_i);
builder.addFunction("f", kSig_i)
.addBody([
kExprCallImport, kArity0, 0
]).exportFunc();
var module = new WebAssembly.Module(builder.toBuffer());
%ValidateWasmModuleState(module);
%ValidateWasmInstancesChain(module, 0);
var i1 = new WebAssembly.Instance(module, {getValue: () => 1});
%ValidateWasmInstancesChain(module, 1);
var i2 = new WebAssembly.Instance(module, {getValue: () => 2});
%ValidateWasmInstancesChain(module, 2);
var i3 = new WebAssembly.Instance(module, {getValue: () => 3});
%ValidateWasmInstancesChain(module, 3);
assertEquals(1, i1.exports.f());
i1 = null;
gc();
%ValidateWasmInstancesChain(module, 2);
assertEquals(3, i3.exports.f());
i3 = null;
gc();
%ValidateWasmInstancesChain(module, 1);
assertEquals(2, i2.exports.f());
i2 = null;
gc();
%ValidateWasmModuleState(module);
var i4 = new WebAssembly.Instance(module, {getValue: () => 4});
assertEquals(4, i4.exports.f());
module = null;
gc();
%ValidateWasmOrphanedInstance(i4);
})();

View File

@ -155,50 +155,24 @@ promise.then(module => CheckInstance(new WebAssembly.Instance(module)));
})();
(function GlobalsArePrivateToTheInstance() {
var builder = new WasmModuleBuilder();
builder.addGlobal(kAstI32);
builder.addFunction("read", kSig_i_v)
.addBody([
kExprGetGlobal, 0])
.exportFunc();
builder.addFunction("write", kSig_v_i)
.addBody([
kExprGetLocal, 0,
kExprSetGlobal, 0])
.exportFunc();
var module = new WebAssembly.Module(builder.toBuffer());
var i1 = new WebAssembly.Instance(module);
var i2 = new WebAssembly.Instance(module);
i1.exports.write(1);
i2.exports.write(2);
assertEquals(1, i1.exports.read());
assertEquals(2, i2.exports.read());
})();
(function InstanceMemoryIsIsolated() {
var builder = new WasmModuleBuilder();
builder.addMemory(1,1, true);
builder.addFunction("f", kSig_i)
builder.addGlobal(kAstI32);
builder.addFunction("read", kSig_i_v)
.addBody([
kExprI32Const, 0,
kExprI32LoadMem, 0, 0
]).exportFunc();
kExprGetGlobal, 0])
.exportFunc();
var mem_1 = new ArrayBuffer(65536);
var mem_2 = new ArrayBuffer(65536);
var view_1 = new Int32Array(mem_1);
var view_2 = new Int32Array(mem_2);
view_1[0] = 1;
view_2[0] = 1000;
builder.addFunction("write", kSig_v_i)
.addBody([
kExprGetLocal, 0,
kExprSetGlobal, 0])
.exportFunc();
var module = new WebAssembly.Module(builder.toBuffer());
var i1 = new WebAssembly.Instance(module, null, mem_1);
var i2 = new WebAssembly.Instance(module, null, mem_2);
assertEquals(1, i1.exports.f());
assertEquals(1000, i2.exports.f());
var i1 = new WebAssembly.Instance(module);
var i2 = new WebAssembly.Instance(module);
i1.exports.write(1);
i2.exports.write(2);
assertEquals(1, i1.exports.read());
assertEquals(2, i2.exports.read());
})();