Revert "Revert "[wasm] Reference indirect tables as addresses of global handles""
This reverts commitaf37f6b970
. Reason for revert: Reverted dependency fixed. Original change's description: > Revert "[wasm] Reference indirect tables as addresses of global handles" > > This reverts commit186099d49f
. > > Reason for revert: Need to revert: > https://chromium-review.googlesource.com/c/613880 > > Original change's description: > > [wasm] Reference indirect tables as addresses of global handles > > > > This sets us up for getting the wasm code generation off the GC heap. > > We reference tables as global handles, which have a stable address. This > > requires an extra instruction when attempting to make an indirect call, > > per table (i.e. one for the signature table and one for the function > > table). > > > > Bug: > > Change-Id: I83743ba0f1dfdeba9aee5d27232f8823981288f8 > > Reviewed-on: https://chromium-review.googlesource.com/612322 > > Commit-Queue: Mircea Trofin <mtrofin@chromium.org> > > Reviewed-by: Brad Nelson <bradnelson@chromium.org> > > Cr-Commit-Position: refs/heads/master@{#47444} > > TBR=bradnelson@chromium.org,titzer@chromium.org,mtrofin@chromium.org > > Change-Id: Ic3dff87410a51a2072ddc16cfc83a230526d4c56 > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Reviewed-on: https://chromium-review.googlesource.com/622568 > Reviewed-by: Michael Achenbach <machenbach@chromium.org> > Commit-Queue: Michael Achenbach <machenbach@chromium.org> > Cr-Commit-Position: refs/heads/master@{#47450} TBR=bradnelson@chromium.org,machenbach@chromium.org,titzer@chromium.org,mtrofin@chromium.org Change-Id: I3dc5dc8be26b5462703edac954cbedbb8f504c1e No-Presubmit: true No-Tree-Checks: true No-Try: true Reviewed-on: https://chromium-review.googlesource.com/622035 Reviewed-by: Mircea Trofin <mtrofin@chromium.org> Commit-Queue: Mircea Trofin <mtrofin@chromium.org> Cr-Commit-Position: refs/heads/master@{#47455}
This commit is contained in:
parent
5eb1aa488e
commit
b22fb03a49
@ -313,6 +313,17 @@ void RelocInfo::update_wasm_memory_reference(
|
||||
set_embedded_address(isolate, updated_reference, icache_flush_mode);
|
||||
}
|
||||
|
||||
void RelocInfo::set_global_handle(Isolate* isolate, Address address,
|
||||
ICacheFlushMode icache_flush_mode) {
|
||||
DCHECK_EQ(rmode_, WASM_GLOBAL_HANDLE);
|
||||
set_embedded_address(isolate, address, icache_flush_mode);
|
||||
}
|
||||
|
||||
Address RelocInfo::global_handle() const {
|
||||
DCHECK_EQ(rmode_, WASM_GLOBAL_HANDLE);
|
||||
return embedded_address();
|
||||
}
|
||||
|
||||
void RelocInfo::update_wasm_memory_size(Isolate* isolate, uint32_t old_size,
|
||||
uint32_t new_size,
|
||||
ICacheFlushMode icache_flush_mode) {
|
||||
@ -698,6 +709,8 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
|
||||
return "wasm function table size reference";
|
||||
case WASM_PROTECTED_INSTRUCTION_LANDING:
|
||||
return "wasm protected instruction landing";
|
||||
case WASM_GLOBAL_HANDLE:
|
||||
return "global handle";
|
||||
case NUMBER_OF_MODES:
|
||||
case PC_JUMP:
|
||||
UNREACHABLE();
|
||||
@ -783,6 +796,7 @@ void RelocInfo::Verify(Isolate* isolate) {
|
||||
case WASM_MEMORY_SIZE_REFERENCE:
|
||||
case WASM_GLOBAL_REFERENCE:
|
||||
case WASM_FUNCTION_TABLE_SIZE_REFERENCE:
|
||||
case WASM_GLOBAL_HANDLE:
|
||||
case WASM_PROTECTED_INSTRUCTION_LANDING:
|
||||
// TODO(eholk): make sure the protected instruction is in range.
|
||||
case NONE32:
|
||||
|
@ -339,6 +339,7 @@ class RelocInfo {
|
||||
WASM_MEMORY_SIZE_REFERENCE,
|
||||
WASM_FUNCTION_TABLE_SIZE_REFERENCE,
|
||||
WASM_PROTECTED_INSTRUCTION_LANDING,
|
||||
WASM_GLOBAL_HANDLE,
|
||||
|
||||
RUNTIME_ENTRY,
|
||||
COMMENT,
|
||||
@ -446,16 +447,15 @@ class RelocInfo {
|
||||
return mode == WASM_FUNCTION_TABLE_SIZE_REFERENCE;
|
||||
}
|
||||
static inline bool IsWasmReference(Mode mode) {
|
||||
return mode == WASM_MEMORY_REFERENCE || mode == WASM_GLOBAL_REFERENCE ||
|
||||
mode == WASM_MEMORY_SIZE_REFERENCE ||
|
||||
mode == WASM_FUNCTION_TABLE_SIZE_REFERENCE;
|
||||
return IsWasmPtrReference(mode) || IsWasmSizeReference(mode);
|
||||
}
|
||||
static inline bool IsWasmSizeReference(Mode mode) {
|
||||
return mode == WASM_MEMORY_SIZE_REFERENCE ||
|
||||
mode == WASM_FUNCTION_TABLE_SIZE_REFERENCE;
|
||||
}
|
||||
static inline bool IsWasmPtrReference(Mode mode) {
|
||||
return mode == WASM_MEMORY_REFERENCE || mode == WASM_GLOBAL_REFERENCE;
|
||||
return mode == WASM_MEMORY_REFERENCE || mode == WASM_GLOBAL_REFERENCE ||
|
||||
mode == WASM_GLOBAL_HANDLE;
|
||||
}
|
||||
static inline bool IsWasmProtectedLanding(Mode mode) {
|
||||
return mode == WASM_PROTECTED_INSTRUCTION_LANDING;
|
||||
@ -490,6 +490,8 @@ class RelocInfo {
|
||||
Address wasm_global_reference() const;
|
||||
uint32_t wasm_function_table_size_reference() const;
|
||||
uint32_t wasm_memory_size_reference() const;
|
||||
Address global_handle() const;
|
||||
|
||||
void update_wasm_memory_reference(
|
||||
Isolate* isolate, Address old_base, Address new_base,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
@ -507,6 +509,10 @@ class RelocInfo {
|
||||
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
|
||||
void set_global_handle(
|
||||
Isolate* isolate, Address address,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
|
||||
// this relocation applies to;
|
||||
// can only be called if IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
|
||||
INLINE(Address target_address());
|
||||
|
@ -849,6 +849,8 @@ void PipelineWasmCompilationJob::ValidateImmovableEmbeddedObjects() const {
|
||||
Object* target = nullptr;
|
||||
switch (mode) {
|
||||
case RelocInfo::CODE_TARGET:
|
||||
// this would be either one of the stubs or builtins, because
|
||||
// we didn't link yet.
|
||||
target = reinterpret_cast<Object*>(it.rinfo()->target_address());
|
||||
break;
|
||||
case RelocInfo::EMBEDDED_OBJECT:
|
||||
@ -860,9 +862,7 @@ void PipelineWasmCompilationJob::ValidateImmovableEmbeddedObjects() const {
|
||||
CHECK_NOT_NULL(target);
|
||||
bool is_immovable =
|
||||
target->IsSmi() || Heap::IsImmovable(HeapObject::cast(target));
|
||||
// TODO(mtrofin): remove the fixed array part when WebAssembly.Table
|
||||
// is backed by native object, rather than a FixedArray
|
||||
CHECK(is_immovable || target->IsFixedArray());
|
||||
CHECK(is_immovable);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2254,9 +2254,14 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t sig_index, Node** args,
|
||||
Node* size = function_table_sizes_[table_index];
|
||||
Node* in_bounds = graph()->NewNode(machine->Uint32LessThan(), key, size);
|
||||
TrapIfFalse(wasm::kTrapFuncInvalid, in_bounds, position);
|
||||
Node* table = function_tables_[table_index];
|
||||
Node* signatures = signature_tables_[table_index];
|
||||
|
||||
Node* table_address = function_tables_[table_index];
|
||||
Node* table = graph()->NewNode(
|
||||
jsgraph()->machine()->Load(MachineType::AnyTagged()), table_address,
|
||||
jsgraph()->IntPtrConstant(0), *effect_, *control_);
|
||||
Node* signatures_address = signature_tables_[table_index];
|
||||
Node* signatures = graph()->NewNode(
|
||||
jsgraph()->machine()->Load(MachineType::AnyTagged()), signatures_address,
|
||||
jsgraph()->IntPtrConstant(0), *effect_, *control_);
|
||||
// Load signature from the table and check.
|
||||
// The table is a FixedArray; signatures are encoded as SMIs.
|
||||
// [sig1, sig2, sig3, ...., code1, code2, code3 ...]
|
||||
@ -2988,10 +2993,16 @@ void WasmGraphBuilder::EnsureFunctionTableNodes() {
|
||||
if (function_tables_.size() > 0) return;
|
||||
size_t tables_size = env_->function_tables.size();
|
||||
for (size_t i = 0; i < tables_size; ++i) {
|
||||
auto function_handle = env_->function_tables[i];
|
||||
auto signature_handle = env_->signature_tables[i];
|
||||
function_tables_.push_back(HeapConstant(function_handle));
|
||||
signature_tables_.push_back(HeapConstant(signature_handle));
|
||||
wasm::GlobalHandleAddress function_handle_address =
|
||||
env_->function_tables[i];
|
||||
wasm::GlobalHandleAddress signature_handle_address =
|
||||
env_->signature_tables[i];
|
||||
function_tables_.push_back(jsgraph()->RelocatableIntPtrConstant(
|
||||
reinterpret_cast<intptr_t>(function_handle_address),
|
||||
RelocInfo::WASM_GLOBAL_HANDLE));
|
||||
signature_tables_.push_back(jsgraph()->RelocatableIntPtrConstant(
|
||||
reinterpret_cast<intptr_t>(signature_handle_address),
|
||||
RelocInfo::WASM_GLOBAL_HANDLE));
|
||||
uint32_t table_size = env_->module->function_tables[i].initial_size;
|
||||
function_table_sizes_.push_back(jsgraph()->RelocatableInt32Constant(
|
||||
static_cast<uint32_t>(table_size),
|
||||
@ -3819,8 +3830,8 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
|
||||
|
||||
// TODO(titzer): compile JS to WASM wrappers without a {ModuleEnv}.
|
||||
ModuleEnv env = {module,
|
||||
std::vector<Handle<FixedArray>>(), // function_tables
|
||||
std::vector<Handle<FixedArray>>(), // signature_tables
|
||||
std::vector<Address>(), // function_tables
|
||||
std::vector<Address>(), // signature_tables
|
||||
std::vector<wasm::SignatureMap*>(), // signature_maps
|
||||
std::vector<Handle<Code>>(), // function_code
|
||||
BUILTIN_CODE(isolate, Illegal), // default_function_code
|
||||
|
@ -52,12 +52,14 @@ struct ModuleEnv {
|
||||
// A pointer to the decoded module's static representation.
|
||||
const wasm::WasmModule* module;
|
||||
// The function tables are FixedArrays of code used to dispatch indirect
|
||||
// calls. (the same length as module.function_tables)
|
||||
const std::vector<Handle<FixedArray>> function_tables;
|
||||
// calls. (the same length as module.function_tables). We use the address
|
||||
// to a global handle to the FixedArray.
|
||||
const std::vector<Address> function_tables;
|
||||
// The signatures tables are FixedArrays of SMIs used to check signatures
|
||||
// match at runtime.
|
||||
// (the same length as module.function_tables)
|
||||
const std::vector<Handle<FixedArray>> signature_tables;
|
||||
// We use the address to a global handle to the FixedArray.
|
||||
const std::vector<Address> signature_tables;
|
||||
// Signature maps canonicalize {FunctionSig*} to indexes. New entries can be
|
||||
// added to a signature map during graph building.
|
||||
// Normally, these signature maps correspond to the signature maps in the
|
||||
|
@ -327,13 +327,12 @@ MaybeHandle<WasmModuleObject> ModuleCompiler::CompileToModuleObject(
|
||||
ErrorThrower* thrower, const ModuleWireBytes& wire_bytes,
|
||||
Handle<Script> asm_js_script,
|
||||
Vector<const byte> asm_js_offset_table_bytes) {
|
||||
Factory* factory = isolate_->factory();
|
||||
|
||||
TimedHistogramScope wasm_compile_module_time_scope(
|
||||
module_->is_wasm() ? counters()->wasm_compile_wasm_module_time()
|
||||
: counters()->wasm_compile_asm_module_time());
|
||||
return CompileToModuleObjectInternal(thrower, wire_bytes, asm_js_script,
|
||||
asm_js_offset_table_bytes, factory);
|
||||
return CompileToModuleObjectInternal(
|
||||
isolate_, thrower, wire_bytes, asm_js_script, asm_js_offset_table_bytes);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -519,16 +518,25 @@ double MonotonicallyIncreasingTimeInMs() {
|
||||
}
|
||||
|
||||
std::unique_ptr<compiler::ModuleEnv> CreateDefaultModuleEnv(
|
||||
Factory* factory, WasmModule* module, Handle<Code> illegal_builtin) {
|
||||
std::vector<Handle<FixedArray>> function_tables;
|
||||
std::vector<Handle<FixedArray>> signature_tables;
|
||||
Isolate* isolate, WasmModule* module, Handle<Code> illegal_builtin,
|
||||
GlobalHandleLifetimeManager* lifetime_manager) {
|
||||
std::vector<GlobalHandleAddress> function_tables;
|
||||
std::vector<GlobalHandleAddress> signature_tables;
|
||||
std::vector<SignatureMap*> signature_maps;
|
||||
|
||||
for (size_t i = 0; i < module->function_tables.size(); i++) {
|
||||
auto& function_table = module->function_tables[i];
|
||||
function_tables.push_back(factory->NewFixedArray(1, TENURED));
|
||||
signature_tables.push_back(factory->NewFixedArray(1, TENURED));
|
||||
signature_maps.push_back(&function_table.map);
|
||||
// We need *some* value for each table. We'll reuse this value when
|
||||
// we want to reset a {WasmCompiledModule}. We could just insert
|
||||
// bogus values (e.g. 0, 1, etc), but to keep things consistent, we'll
|
||||
// create a valid global handle for the undefined value.
|
||||
// These global handles are deleted when finalizing the module object.
|
||||
Handle<Object> func_table =
|
||||
isolate->global_handles()->Create(isolate->heap()->undefined_value());
|
||||
Handle<Object> sig_table =
|
||||
isolate->global_handles()->Create(isolate->heap()->undefined_value());
|
||||
function_tables.push_back(func_table.address());
|
||||
signature_tables.push_back(sig_table.address());
|
||||
signature_maps.push_back(&module->function_tables[i].map);
|
||||
}
|
||||
|
||||
std::vector<Handle<Code>> empty_code;
|
||||
@ -566,9 +574,10 @@ void ReopenHandles(Isolate* isolate, const std::vector<Handle<T>>& vec) {
|
||||
} // namespace
|
||||
|
||||
MaybeHandle<WasmModuleObject> ModuleCompiler::CompileToModuleObjectInternal(
|
||||
ErrorThrower* thrower, const ModuleWireBytes& wire_bytes,
|
||||
Handle<Script> asm_js_script, Vector<const byte> asm_js_offset_table_bytes,
|
||||
Factory* factory) {
|
||||
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& wire_bytes,
|
||||
Handle<Script> asm_js_script,
|
||||
Vector<const byte> asm_js_offset_table_bytes) {
|
||||
Factory* factory = isolate->factory();
|
||||
// Check whether lazy compilation is enabled for this module.
|
||||
bool lazy_compile = compile_lazy(module_.get());
|
||||
|
||||
@ -579,7 +588,9 @@ MaybeHandle<WasmModuleObject> ModuleCompiler::CompileToModuleObjectInternal(
|
||||
? BUILTIN_CODE(isolate_, WasmCompileLazy)
|
||||
: BUILTIN_CODE(isolate_, Illegal);
|
||||
|
||||
auto env = CreateDefaultModuleEnv(factory, module_.get(), init_builtin);
|
||||
GlobalHandleLifetimeManager globals_manager;
|
||||
auto env = CreateDefaultModuleEnv(isolate, module_.get(), init_builtin,
|
||||
&globals_manager);
|
||||
|
||||
// The {code_table} array contains import wrappers and functions (which
|
||||
// are both included in {functions.size()}, and export wrappers).
|
||||
@ -695,6 +706,10 @@ MaybeHandle<WasmModuleObject> ModuleCompiler::CompileToModuleObjectInternal(
|
||||
func_index++;
|
||||
}
|
||||
|
||||
// Now we can relinquish control to the global handles, because the
|
||||
// {WasmModuleObject} will take care of them in its finalizer, which it'll
|
||||
// setup in {New}.
|
||||
globals_manager.ReleaseWithoutDestroying();
|
||||
return WasmModuleObject::New(isolate_, compiled_module);
|
||||
}
|
||||
|
||||
@ -1134,6 +1149,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
||||
DCHECK(!isolate_->has_pending_exception());
|
||||
TRACE("Finishing instance %d\n", compiled_module_->instance_id());
|
||||
TRACE_CHAIN(module_object_->compiled_module());
|
||||
globals_manager_.ReleaseWithoutDestroying();
|
||||
return instance;
|
||||
}
|
||||
|
||||
@ -1725,9 +1741,16 @@ void InstanceBuilder::InitializeTables(
|
||||
CodeSpecialization* code_specialization) {
|
||||
int function_table_count = static_cast<int>(module_->function_tables.size());
|
||||
Handle<FixedArray> new_function_tables =
|
||||
isolate_->factory()->NewFixedArray(function_table_count);
|
||||
isolate_->factory()->NewFixedArray(function_table_count, TENURED);
|
||||
Handle<FixedArray> new_signature_tables =
|
||||
isolate_->factory()->NewFixedArray(function_table_count);
|
||||
isolate_->factory()->NewFixedArray(function_table_count, TENURED);
|
||||
Handle<FixedArray> old_function_tables = compiled_module_->function_tables();
|
||||
Handle<FixedArray> old_signature_tables =
|
||||
compiled_module_->signature_tables();
|
||||
|
||||
DCHECK_EQ(old_function_tables->length(), new_function_tables->length());
|
||||
DCHECK_EQ(old_signature_tables->length(), new_signature_tables->length());
|
||||
|
||||
for (int index = 0; index < function_table_count; ++index) {
|
||||
WasmIndirectFunctionTable& table = module_->function_tables[index];
|
||||
TableInstance& table_instance = table_instances_[index];
|
||||
@ -1752,27 +1775,36 @@ void InstanceBuilder::InitializeTables(
|
||||
table_size, table_instance.function_table->length());
|
||||
}
|
||||
}
|
||||
int int_index = static_cast<int>(index);
|
||||
|
||||
new_function_tables->set(static_cast<int>(index),
|
||||
*table_instance.function_table);
|
||||
new_signature_tables->set(static_cast<int>(index),
|
||||
*table_instance.signature_table);
|
||||
}
|
||||
// We create a global handle here and delete it when finalizing the
|
||||
// instance. Even if the same table is shared accross many instances, each
|
||||
// will have its own private global handle to it. Meanwhile, we the global
|
||||
// handles root the respective objects (the tables).
|
||||
Handle<FixedArray> global_func_table =
|
||||
isolate_->global_handles()->Create(*table_instance.function_table);
|
||||
Handle<FixedArray> global_sig_table =
|
||||
isolate_->global_handles()->Create(*table_instance.signature_table);
|
||||
|
||||
FixedArray* old_function_tables = compiled_module_->ptr_to_function_tables();
|
||||
DCHECK_EQ(old_function_tables->length(), new_function_tables->length());
|
||||
for (int i = 0, e = new_function_tables->length(); i < e; ++i) {
|
||||
code_specialization->RelocateObject(
|
||||
handle(old_function_tables->get(i), isolate_),
|
||||
handle(new_function_tables->get(i), isolate_));
|
||||
}
|
||||
FixedArray* old_signature_tables =
|
||||
compiled_module_->ptr_to_signature_tables();
|
||||
DCHECK_EQ(old_signature_tables->length(), new_signature_tables->length());
|
||||
for (int i = 0, e = new_signature_tables->length(); i < e; ++i) {
|
||||
code_specialization->RelocateObject(
|
||||
handle(old_signature_tables->get(i), isolate_),
|
||||
handle(new_signature_tables->get(i), isolate_));
|
||||
GlobalHandleAddress new_func_table_addr = global_func_table.address();
|
||||
GlobalHandleAddress new_sig_table_addr = global_sig_table.address();
|
||||
globals_manager_.Add(new_func_table_addr);
|
||||
globals_manager_.Add(new_sig_table_addr);
|
||||
|
||||
WasmCompiledModule::SetTableValue(isolate_, new_function_tables, int_index,
|
||||
new_func_table_addr);
|
||||
WasmCompiledModule::SetTableValue(isolate_, new_signature_tables, int_index,
|
||||
new_sig_table_addr);
|
||||
|
||||
GlobalHandleAddress old_func_table_addr =
|
||||
WasmCompiledModule::GetTableValue(*old_function_tables, int_index);
|
||||
GlobalHandleAddress old_sig_table_addr =
|
||||
WasmCompiledModule::GetTableValue(*old_signature_tables, int_index);
|
||||
|
||||
code_specialization->RelocatePointer(old_func_table_addr,
|
||||
new_func_table_addr);
|
||||
code_specialization->RelocatePointer(old_sig_table_addr,
|
||||
new_sig_table_addr);
|
||||
}
|
||||
|
||||
compiled_module_->set_function_tables(new_function_tables);
|
||||
@ -2058,8 +2090,8 @@ class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
|
||||
|
||||
Factory* factory = isolate->factory();
|
||||
Handle<Code> illegal_builtin = BUILTIN_CODE(isolate, Illegal);
|
||||
job_->module_env_ =
|
||||
CreateDefaultModuleEnv(factory, module_.get(), illegal_builtin);
|
||||
job_->module_env_ = CreateDefaultModuleEnv(
|
||||
isolate, module_.get(), illegal_builtin, &job_->globals_manager_);
|
||||
|
||||
// The {code_table} array contains import wrappers and functions (which
|
||||
// are both included in {functions.size()}, and export wrappers.
|
||||
@ -2083,8 +2115,6 @@ class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
|
||||
centry_stub = Handle<Code>(*centry_stub, isolate);
|
||||
job_->code_table_ = Handle<FixedArray>(*job_->code_table_, isolate);
|
||||
compiler::ModuleEnv* env = job_->module_env_.get();
|
||||
ReopenHandles(isolate, env->function_tables);
|
||||
ReopenHandles(isolate, env->signature_tables);
|
||||
ReopenHandles(isolate, env->function_code);
|
||||
Handle<Code>* mut =
|
||||
const_cast<Handle<Code>*>(&env->default_function_code);
|
||||
@ -2328,6 +2358,7 @@ class AsyncCompileJob::FinishModule : public CompileStep {
|
||||
Handle<WasmModuleObject> result =
|
||||
WasmModuleObject::New(job_->isolate_, job_->compiled_module_);
|
||||
// {job_} is deleted in AsyncCompileSucceeded, therefore the {return}.
|
||||
job_->globals_manager_.ReleaseWithoutDestroying();
|
||||
return job_->AsyncCompileSucceeded(result);
|
||||
}
|
||||
};
|
||||
|
@ -164,9 +164,9 @@ class ModuleCompiler {
|
||||
|
||||
private:
|
||||
MaybeHandle<WasmModuleObject> CompileToModuleObjectInternal(
|
||||
ErrorThrower* thrower, const ModuleWireBytes& wire_bytes,
|
||||
Handle<Script> asm_js_script,
|
||||
Vector<const byte> asm_js_offset_table_bytes, Factory* factory);
|
||||
Isolate* isolate, ErrorThrower* thrower,
|
||||
const ModuleWireBytes& wire_bytes, Handle<Script> asm_js_script,
|
||||
Vector<const byte> asm_js_offset_table_bytes);
|
||||
|
||||
Isolate* isolate_;
|
||||
std::unique_ptr<WasmModule> module_;
|
||||
@ -234,6 +234,7 @@ class InstanceBuilder {
|
||||
std::vector<Handle<JSFunction>> js_wrappers_;
|
||||
JSToWasmWrapperCache js_to_wasm_cache_;
|
||||
WeakCallbackInfo<void>::Callback instance_finalizer_callback_;
|
||||
GlobalHandleLifetimeManager globals_manager_;
|
||||
|
||||
const std::shared_ptr<Counters>& async_counters() const {
|
||||
return async_counters_;
|
||||
@ -347,6 +348,7 @@ class AsyncCompileJob {
|
||||
Handle<JSPromise> module_promise_;
|
||||
std::unique_ptr<ModuleCompiler> compiler_;
|
||||
std::unique_ptr<compiler::ModuleEnv> module_env_;
|
||||
GlobalHandleLifetimeManager globals_manager_;
|
||||
|
||||
std::vector<DeferredHandles*> deferred_handles_;
|
||||
Handle<WasmModuleObject> module_object_;
|
||||
|
@ -84,8 +84,7 @@ bool IsAtWasmDirectCallTarget(RelocIterator& it) {
|
||||
|
||||
} // namespace
|
||||
|
||||
CodeSpecialization::CodeSpecialization(Isolate* isolate, Zone* zone)
|
||||
: objects_to_relocate(isolate->heap(), ZoneAllocationPolicy(zone)) {}
|
||||
CodeSpecialization::CodeSpecialization(Isolate* isolate, Zone* zone) {}
|
||||
|
||||
CodeSpecialization::~CodeSpecialization() {}
|
||||
|
||||
@ -120,11 +119,8 @@ void CodeSpecialization::RelocateDirectCalls(
|
||||
relocate_direct_calls_instance = instance;
|
||||
}
|
||||
|
||||
void CodeSpecialization::RelocateObject(Handle<Object> old_obj,
|
||||
Handle<Object> new_obj) {
|
||||
DCHECK(!old_obj.is_null() && !new_obj.is_null());
|
||||
has_objects_to_relocate = true;
|
||||
objects_to_relocate.Set(*old_obj, new_obj);
|
||||
void CodeSpecialization::RelocatePointer(Address old_ptr, Address new_ptr) {
|
||||
pointers_to_relocate.insert(std::make_pair(old_ptr, new_ptr));
|
||||
}
|
||||
|
||||
bool CodeSpecialization::ApplyToWholeInstance(
|
||||
@ -191,7 +187,7 @@ bool CodeSpecialization::ApplyToWasmCode(Code* code,
|
||||
bool reloc_globals = old_globals_start || new_globals_start;
|
||||
bool patch_table_size = old_function_table_size || new_function_table_size;
|
||||
bool reloc_direct_calls = !relocate_direct_calls_instance.is_null();
|
||||
bool reloc_objects = has_objects_to_relocate;
|
||||
bool reloc_pointers = pointers_to_relocate.size() > 0;
|
||||
|
||||
int reloc_mode = 0;
|
||||
auto add_mode = [&reloc_mode](bool cond, RelocInfo::Mode mode) {
|
||||
@ -202,7 +198,7 @@ bool CodeSpecialization::ApplyToWasmCode(Code* code,
|
||||
add_mode(reloc_globals, RelocInfo::WASM_GLOBAL_REFERENCE);
|
||||
add_mode(patch_table_size, RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE);
|
||||
add_mode(reloc_direct_calls, RelocInfo::CODE_TARGET);
|
||||
add_mode(reloc_objects, RelocInfo::EMBEDDED_OBJECT);
|
||||
add_mode(reloc_pointers, RelocInfo::WASM_GLOBAL_HANDLE);
|
||||
|
||||
std::unique_ptr<PatchDirectCallsHelper> patch_direct_calls_helper;
|
||||
bool changed = false;
|
||||
@ -258,13 +254,12 @@ bool CodeSpecialization::ApplyToWasmCode(Code* code,
|
||||
UPDATE_WRITE_BARRIER, icache_flush_mode);
|
||||
changed = true;
|
||||
} break;
|
||||
case RelocInfo::EMBEDDED_OBJECT: {
|
||||
DCHECK(reloc_objects);
|
||||
Object* old = it.rinfo()->target_object();
|
||||
Handle<Object>* new_obj = objects_to_relocate.Find(old);
|
||||
if (new_obj) {
|
||||
it.rinfo()->set_target_object(HeapObject::cast(**new_obj),
|
||||
UPDATE_WRITE_BARRIER,
|
||||
case RelocInfo::WASM_GLOBAL_HANDLE: {
|
||||
DCHECK(reloc_pointers);
|
||||
Address old_ptr = it.rinfo()->global_handle();
|
||||
if (pointers_to_relocate.count(old_ptr) == 1) {
|
||||
Address new_ptr = pointers_to_relocate[old_ptr];
|
||||
it.rinfo()->set_global_handle(code->GetIsolate(), new_ptr,
|
||||
icache_flush_mode);
|
||||
changed = true;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ class CodeSpecialization {
|
||||
// Update all direct call sites based on the code table in the given instance.
|
||||
void RelocateDirectCalls(Handle<WasmInstanceObject> instance);
|
||||
// Relocate an arbitrary object (e.g. function table).
|
||||
void RelocateObject(Handle<Object> old_obj, Handle<Object> new_obj);
|
||||
void RelocatePointer(Address old_obj, Address new_obj);
|
||||
|
||||
// Apply all relocations and patching to all code in the instance (wasm code
|
||||
// and exported functions).
|
||||
@ -62,8 +62,7 @@ class CodeSpecialization {
|
||||
|
||||
Handle<WasmInstanceObject> relocate_direct_calls_instance;
|
||||
|
||||
bool has_objects_to_relocate = false;
|
||||
IdentityMap<Handle<Object>, ZoneAllocationPolicy> objects_to_relocate;
|
||||
std::map<Address, Address> pointers_to_relocate;
|
||||
};
|
||||
|
||||
} // namespace wasm
|
||||
|
@ -2328,8 +2328,12 @@ class ThreadImpl {
|
||||
if (table_index >= static_cast<uint32_t>(sig_tables->length())) {
|
||||
return {ExternalCallResult::INVALID_FUNC};
|
||||
}
|
||||
FixedArray* sig_table =
|
||||
FixedArray::cast(sig_tables->get(static_cast<int>(table_index)));
|
||||
// Reconstitute the global handle to sig_table, and, further below,
|
||||
// to the function table, from the address stored in the
|
||||
// respective table of tables.
|
||||
int table_index_as_int = static_cast<int>(table_index);
|
||||
Handle<FixedArray> sig_table(reinterpret_cast<FixedArray**>(
|
||||
WasmCompiledModule::GetTableValue(sig_tables, table_index_as_int)));
|
||||
if (entry_index >= static_cast<uint32_t>(sig_table->length())) {
|
||||
return {ExternalCallResult::INVALID_FUNC};
|
||||
}
|
||||
@ -2341,8 +2345,8 @@ class ThreadImpl {
|
||||
// Get code object.
|
||||
FixedArray* fun_tables = compiled_module->ptr_to_function_tables();
|
||||
DCHECK_EQ(sig_tables->length(), fun_tables->length());
|
||||
FixedArray* fun_table =
|
||||
FixedArray::cast(fun_tables->get(static_cast<int>(table_index)));
|
||||
Handle<FixedArray> fun_table(reinterpret_cast<FixedArray**>(
|
||||
WasmCompiledModule::GetTableValue(fun_tables, table_index_as_int)));
|
||||
DCHECK_EQ(sig_table->length(), fun_table->length());
|
||||
target = Code::cast(fun_table->get(static_cast<int>(entry_index)));
|
||||
}
|
||||
|
@ -217,18 +217,18 @@ compiler::ModuleEnv CreateModuleEnvFromCompiledModule(
|
||||
DisallowHeapAllocation no_gc;
|
||||
WasmModule* module = compiled_module->module();
|
||||
|
||||
std::vector<Handle<FixedArray>> function_tables;
|
||||
std::vector<Handle<FixedArray>> signature_tables;
|
||||
std::vector<GlobalHandleAddress> function_tables;
|
||||
std::vector<GlobalHandleAddress> signature_tables;
|
||||
std::vector<SignatureMap*> signature_maps;
|
||||
|
||||
int num_function_tables = static_cast<int>(module->function_tables.size());
|
||||
for (int i = 0; i < num_function_tables; i++) {
|
||||
for (int i = 0; i < num_function_tables; ++i) {
|
||||
FixedArray* ft = compiled_module->ptr_to_function_tables();
|
||||
FixedArray* st = compiled_module->ptr_to_signature_tables();
|
||||
|
||||
// TODO(clemensh): defer these handles for concurrent compilation.
|
||||
function_tables.push_back(handle(FixedArray::cast(ft->get(i))));
|
||||
signature_tables.push_back(handle(FixedArray::cast(st->get(i))));
|
||||
function_tables.push_back(WasmCompiledModule::GetTableValue(ft, i));
|
||||
signature_tables.push_back(WasmCompiledModule::GetTableValue(st, i));
|
||||
signature_maps.push_back(&module->function_tables[i].map);
|
||||
}
|
||||
|
||||
|
@ -177,9 +177,33 @@ Handle<WasmModuleObject> WasmModuleObject::New(
|
||||
Handle<WeakCell> link_to_module =
|
||||
isolate->factory()->NewWeakCell(module_object);
|
||||
compiled_module->set_weak_wasm_module(link_to_module);
|
||||
Handle<Object> global_handle =
|
||||
isolate->global_handles()->Create(*module_object);
|
||||
GlobalHandles::MakeWeak(global_handle.location(), global_handle.location(),
|
||||
&Finalizer, v8::WeakCallbackType::kFinalizer);
|
||||
return module_object;
|
||||
}
|
||||
|
||||
void WasmModuleObject::Finalizer(const v8::WeakCallbackInfo<void>& data) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter());
|
||||
WasmModuleObject* module = reinterpret_cast<WasmModuleObject*>(*p);
|
||||
WasmCompiledModule* compiled_module = module->compiled_module();
|
||||
if (compiled_module->has_empty_function_tables()) {
|
||||
DCHECK(compiled_module->has_empty_signature_tables());
|
||||
for (int i = 0, e = compiled_module->empty_function_tables()->length();
|
||||
i < e; ++i) {
|
||||
GlobalHandles::Destroy(
|
||||
reinterpret_cast<Object**>(WasmCompiledModule::GetTableValue(
|
||||
compiled_module->ptr_to_empty_function_tables(), i)));
|
||||
GlobalHandles::Destroy(
|
||||
reinterpret_cast<Object**>(WasmCompiledModule::GetTableValue(
|
||||
compiled_module->ptr_to_empty_signature_tables(), i)));
|
||||
}
|
||||
}
|
||||
GlobalHandles::Destroy(reinterpret_cast<Object**>(p));
|
||||
}
|
||||
|
||||
Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial,
|
||||
int64_t maximum,
|
||||
Handle<FixedArray>* js_functions) {
|
||||
@ -239,23 +263,52 @@ void WasmTableObject::grow(Isolate* isolate, uint32_t count) {
|
||||
FixedArray::cast(dispatch_tables->get(i + 2)));
|
||||
Handle<FixedArray> old_signature_table(
|
||||
FixedArray::cast(dispatch_tables->get(i + 3)));
|
||||
Handle<FixedArray> new_function_table =
|
||||
isolate->factory()->CopyFixedArrayAndGrow(old_function_table, count);
|
||||
Handle<FixedArray> new_signature_table =
|
||||
isolate->factory()->CopyFixedArrayAndGrow(old_signature_table, count);
|
||||
Handle<FixedArray> new_function_table = isolate->global_handles()->Create(
|
||||
*isolate->factory()->CopyFixedArrayAndGrow(old_function_table, count));
|
||||
Handle<FixedArray> new_signature_table = isolate->global_handles()->Create(
|
||||
*isolate->factory()->CopyFixedArrayAndGrow(old_signature_table, count));
|
||||
|
||||
GlobalHandleAddress new_function_table_addr = new_function_table.address();
|
||||
GlobalHandleAddress new_signature_table_addr =
|
||||
new_signature_table.address();
|
||||
|
||||
int table_index = Smi::cast(dispatch_tables->get(i + 1))->value();
|
||||
// Update dispatch tables with new function/signature tables
|
||||
dispatch_tables->set(i + 2, *new_function_table);
|
||||
dispatch_tables->set(i + 3, *new_signature_table);
|
||||
|
||||
// Patch the code of the respective instance.
|
||||
CodeSpecialization code_specialization(isolate, &specialization_zone);
|
||||
code_specialization.PatchTableSize(old_size, old_size + count);
|
||||
code_specialization.RelocateObject(old_function_table, new_function_table);
|
||||
code_specialization.RelocateObject(old_signature_table,
|
||||
new_signature_table);
|
||||
code_specialization.ApplyToWholeInstance(
|
||||
WasmInstanceObject::cast(dispatch_tables->get(i)));
|
||||
{
|
||||
DisallowHeapAllocation no_gc;
|
||||
CodeSpecialization code_specialization(isolate, &specialization_zone);
|
||||
WasmInstanceObject* instance =
|
||||
WasmInstanceObject::cast(dispatch_tables->get(i));
|
||||
WasmCompiledModule* compiled_module = instance->compiled_module();
|
||||
GlobalHandleAddress old_function_table_addr =
|
||||
WasmCompiledModule::GetTableValue(
|
||||
compiled_module->ptr_to_function_tables(), table_index);
|
||||
GlobalHandleAddress old_signature_table_addr =
|
||||
WasmCompiledModule::GetTableValue(
|
||||
compiled_module->ptr_to_signature_tables(), table_index);
|
||||
code_specialization.PatchTableSize(old_size, old_size + count);
|
||||
code_specialization.RelocatePointer(old_function_table_addr,
|
||||
new_function_table_addr);
|
||||
code_specialization.RelocatePointer(old_signature_table_addr,
|
||||
new_signature_table_addr);
|
||||
code_specialization.ApplyToWholeInstance(instance);
|
||||
WasmCompiledModule::UpdateTableValue(
|
||||
compiled_module->ptr_to_function_tables(), table_index,
|
||||
new_function_table_addr);
|
||||
WasmCompiledModule::UpdateTableValue(
|
||||
compiled_module->ptr_to_signature_tables(), table_index,
|
||||
new_signature_table_addr);
|
||||
// We need to destroy the global handles this instance held to the
|
||||
// old tables now, otherwise we'd leak global handles.
|
||||
GlobalHandles::Destroy(
|
||||
reinterpret_cast<Object**>(old_function_table_addr));
|
||||
GlobalHandles::Destroy(
|
||||
reinterpret_cast<Object**>(old_signature_table_addr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -797,8 +850,8 @@ void WasmSharedModuleData::PrepareForLazyCompilation(
|
||||
Handle<WasmCompiledModule> WasmCompiledModule::New(
|
||||
Isolate* isolate, Handle<WasmSharedModuleData> shared,
|
||||
Handle<FixedArray> code_table,
|
||||
const std::vector<Handle<FixedArray>>& function_tables,
|
||||
const std::vector<Handle<FixedArray>>& signature_tables) {
|
||||
const std::vector<wasm::GlobalHandleAddress>& function_tables,
|
||||
const std::vector<wasm::GlobalHandleAddress>& signature_tables) {
|
||||
DCHECK_EQ(function_tables.size(), signature_tables.size());
|
||||
Handle<FixedArray> ret =
|
||||
isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED);
|
||||
@ -824,12 +877,18 @@ Handle<WasmCompiledModule> WasmCompiledModule::New(
|
||||
Handle<FixedArray> ft =
|
||||
isolate->factory()->NewFixedArray(num_function_tables, TENURED);
|
||||
for (int i = 0; i < num_function_tables; ++i) {
|
||||
st->set(i, *(signature_tables[i]));
|
||||
ft->set(i, *(function_tables[i]));
|
||||
size_t index = static_cast<size_t>(i);
|
||||
SetTableValue(isolate, ft, i, function_tables[index]);
|
||||
SetTableValue(isolate, st, i, signature_tables[index]);
|
||||
}
|
||||
// TODO(wasm): setting the empty tables here this way is OK under the
|
||||
// assumption that we compile and then instantiate. It needs rework if we do
|
||||
// direct instantiation. The empty tables are used as a default when
|
||||
// resetting the compiled module.
|
||||
compiled_module->set_signature_tables(st);
|
||||
compiled_module->set_empty_function_tables(ft);
|
||||
compiled_module->set_empty_signature_tables(st);
|
||||
compiled_module->set_function_tables(ft);
|
||||
compiled_module->set_empty_function_tables(ft);
|
||||
}
|
||||
|
||||
// TODO(mtrofin): copy the rest of the specialization parameters over.
|
||||
@ -864,8 +923,30 @@ Handle<WasmCompiledModule> WasmCompiledModule::Clone(
|
||||
return ret;
|
||||
}
|
||||
|
||||
void WasmCompiledModule::SetTableValue(Isolate* isolate,
|
||||
Handle<FixedArray> table, int index,
|
||||
Address value) {
|
||||
Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(
|
||||
static_cast<double>(reinterpret_cast<size_t>(value)), MUTABLE, TENURED);
|
||||
table->set(index, *number);
|
||||
}
|
||||
|
||||
void WasmCompiledModule::UpdateTableValue(FixedArray* table, int index,
|
||||
Address value) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
HeapNumber::cast(table->get(index))
|
||||
->set_value(static_cast<double>(reinterpret_cast<size_t>(value)));
|
||||
}
|
||||
|
||||
Address WasmCompiledModule::GetTableValue(FixedArray* table, int index) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
double value = HeapNumber::cast(table->get(index))->value();
|
||||
return reinterpret_cast<Address>(static_cast<size_t>(value));
|
||||
}
|
||||
|
||||
void WasmCompiledModule::Reset(Isolate* isolate,
|
||||
WasmCompiledModule* compiled_module) {
|
||||
WasmCompiledModule* compiled_module,
|
||||
bool clear_global_handles) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
TRACE("Resetting %d\n", compiled_module->instance_id());
|
||||
Object* undefined = *isolate->factory()->undefined_value();
|
||||
@ -898,16 +979,36 @@ void WasmCompiledModule::Reset(Isolate* isolate,
|
||||
// Reset function tables.
|
||||
if (compiled_module->has_function_tables()) {
|
||||
FixedArray* function_tables = compiled_module->ptr_to_function_tables();
|
||||
FixedArray* signature_tables = compiled_module->ptr_to_signature_tables();
|
||||
FixedArray* empty_function_tables =
|
||||
compiled_module->ptr_to_empty_function_tables();
|
||||
FixedArray* empty_signature_tables =
|
||||
compiled_module->ptr_to_empty_signature_tables();
|
||||
if (function_tables != empty_function_tables) {
|
||||
DCHECK_EQ(function_tables->length(), empty_function_tables->length());
|
||||
for (int i = 0, e = function_tables->length(); i < e; ++i) {
|
||||
code_specialization.RelocateObject(
|
||||
handle(function_tables->get(i), isolate),
|
||||
handle(empty_function_tables->get(i), isolate));
|
||||
GlobalHandleAddress func_addr =
|
||||
WasmCompiledModule::GetTableValue(function_tables, i);
|
||||
GlobalHandleAddress sig_addr =
|
||||
WasmCompiledModule::GetTableValue(signature_tables, i);
|
||||
code_specialization.RelocatePointer(
|
||||
func_addr,
|
||||
WasmCompiledModule::GetTableValue(empty_function_tables, i));
|
||||
code_specialization.RelocatePointer(
|
||||
sig_addr,
|
||||
WasmCompiledModule::GetTableValue(empty_signature_tables, i));
|
||||
// We create a global handle per table per instance. When sharing
|
||||
// tables, to avoid accummulating global handles until the last
|
||||
// instance sharing the table is GC-ed, destroy the handles here.
|
||||
// Except if we call this post-deserialize - because maybe the
|
||||
// instance that originated the {WasmCompiledModule} is still alive.
|
||||
if (clear_global_handles) {
|
||||
GlobalHandles::Destroy(reinterpret_cast<Object**>(func_addr));
|
||||
GlobalHandles::Destroy(reinterpret_cast<Object**>(sig_addr));
|
||||
}
|
||||
}
|
||||
compiled_module->set_ptr_to_function_tables(empty_function_tables);
|
||||
compiled_module->set_ptr_to_signature_tables(empty_signature_tables);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1065,7 +1166,35 @@ void WasmCompiledModule::ReinitializeAfterDeserialization(
|
||||
isolate);
|
||||
DCHECK(!WasmSharedModuleData::IsWasmSharedModuleData(*shared));
|
||||
WasmSharedModuleData::ReinitializeAfterDeserialization(isolate, shared);
|
||||
WasmCompiledModule::Reset(isolate, *compiled_module);
|
||||
int function_table_count =
|
||||
static_cast<int>(compiled_module->module()->function_tables.size());
|
||||
if (function_table_count > 0) {
|
||||
// The tables are of the right size, but contain bogus global handle
|
||||
// addresses. Produce new global handles for the empty tables, then reset,
|
||||
// which will relocate the code. We end up with a WasmCompiledModule as-if
|
||||
// it were just compiled.
|
||||
DCHECK(compiled_module->has_function_tables());
|
||||
DCHECK(compiled_module->has_signature_tables());
|
||||
DCHECK(compiled_module->has_empty_signature_tables());
|
||||
DCHECK(compiled_module->has_empty_function_tables());
|
||||
|
||||
for (int i = 0; i < function_table_count; ++i) {
|
||||
Handle<Object> global_func_table_handle =
|
||||
isolate->global_handles()->Create(isolate->heap()->undefined_value());
|
||||
Handle<Object> global_sig_table_handle =
|
||||
isolate->global_handles()->Create(isolate->heap()->undefined_value());
|
||||
GlobalHandleAddress new_func_table = global_func_table_handle.address();
|
||||
GlobalHandleAddress new_sig_table = global_sig_table_handle.address();
|
||||
SetTableValue(isolate, compiled_module->empty_function_tables(), i,
|
||||
new_func_table);
|
||||
SetTableValue(isolate, compiled_module->empty_signature_tables(), i,
|
||||
new_sig_table);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset, but don't delete any global handles, because their owning instance
|
||||
// may still be active.
|
||||
WasmCompiledModule::Reset(isolate, *compiled_module, false);
|
||||
DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,34 @@ namespace internal {
|
||||
namespace wasm {
|
||||
class InterpretedFrame;
|
||||
class WasmInterpreter;
|
||||
}
|
||||
|
||||
// When we compile or instantiate, we need to create global handles
|
||||
// for function tables. Normally, these handles get destroyed when the
|
||||
// respective objects get GCed. If we fail to construct those objects,
|
||||
// we can leak global hanles. The exit path in these cases isn't unique,
|
||||
// and may grow.
|
||||
//
|
||||
// This type addresses that.
|
||||
|
||||
typedef Address GlobalHandleAddress;
|
||||
|
||||
class GlobalHandleLifetimeManager final {
|
||||
public:
|
||||
void Add(GlobalHandleAddress addr) { handles_.push_back(addr); }
|
||||
// Call this when compilation or instantiation has succeeded, and we've
|
||||
// passed the control to a JS object with a finalizer that'll destroy
|
||||
// the handles.
|
||||
void ReleaseWithoutDestroying() { handles_.clear(); }
|
||||
~GlobalHandleLifetimeManager() {
|
||||
for (auto& addr : handles_) {
|
||||
GlobalHandles::Destroy(reinterpret_cast<Object**>(addr));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Address> handles_;
|
||||
};
|
||||
} // namespace wasm
|
||||
|
||||
class WasmCompiledModule;
|
||||
class WasmDebugInfo;
|
||||
@ -65,6 +92,9 @@ class WasmModuleObject : public JSObject {
|
||||
|
||||
static Handle<WasmModuleObject> New(
|
||||
Isolate* isolate, Handle<WasmCompiledModule> compiled_module);
|
||||
|
||||
private:
|
||||
static void Finalizer(const v8::WeakCallbackInfo<void>& data);
|
||||
};
|
||||
|
||||
// Representation of a WebAssembly.Table JavaScript-level object.
|
||||
@ -386,7 +416,8 @@ class WasmCompiledModule : public FixedArray {
|
||||
MACRO(OBJECT, FixedArray, weak_exported_functions) \
|
||||
MACRO(OBJECT, FixedArray, function_tables) \
|
||||
MACRO(OBJECT, FixedArray, signature_tables) \
|
||||
MACRO(OBJECT, FixedArray, empty_function_tables) \
|
||||
MACRO(CONST_OBJECT, FixedArray, empty_function_tables) \
|
||||
MACRO(CONST_OBJECT, FixedArray, empty_signature_tables) \
|
||||
MACRO(LARGE_NUMBER, size_t, embedded_mem_start) \
|
||||
MACRO(LARGE_NUMBER, size_t, globals_start) \
|
||||
MACRO(LARGE_NUMBER, uint32_t, embedded_mem_size) \
|
||||
@ -420,12 +451,13 @@ class WasmCompiledModule : public FixedArray {
|
||||
static Handle<WasmCompiledModule> New(
|
||||
Isolate* isolate, Handle<WasmSharedModuleData> shared,
|
||||
Handle<FixedArray> code_table,
|
||||
const std::vector<Handle<FixedArray>>& function_tables,
|
||||
const std::vector<Handle<FixedArray>>& signature_tables);
|
||||
const std::vector<wasm::GlobalHandleAddress>& function_tables,
|
||||
const std::vector<wasm::GlobalHandleAddress>& signature_tables);
|
||||
|
||||
static Handle<WasmCompiledModule> Clone(Isolate* isolate,
|
||||
Handle<WasmCompiledModule> module);
|
||||
static void Reset(Isolate* isolate, WasmCompiledModule* module);
|
||||
static void Reset(Isolate* isolate, WasmCompiledModule* module,
|
||||
bool clear_global_handles = true);
|
||||
|
||||
Address GetEmbeddedMemStartOrNull() const {
|
||||
return has_embedded_mem_start()
|
||||
@ -565,6 +597,11 @@ class WasmCompiledModule : public FixedArray {
|
||||
set_code_table(testing_table);
|
||||
}
|
||||
|
||||
static void SetTableValue(Isolate* isolate, Handle<FixedArray> table,
|
||||
int index, Address value);
|
||||
static void UpdateTableValue(FixedArray* table, int index, Address value);
|
||||
static Address GetTableValue(FixedArray* table, int index);
|
||||
|
||||
private:
|
||||
void InitId();
|
||||
|
||||
|
@ -276,8 +276,14 @@ class TestingModuleBuilder {
|
||||
table.map.FindOrInsert(test_module_.functions[function_indexes[i]].sig);
|
||||
}
|
||||
|
||||
function_tables_.push_back(isolate_->factory()->NewFixedArray(table_size));
|
||||
signature_tables_.push_back(isolate_->factory()->NewFixedArray(table_size));
|
||||
function_tables_.push_back(
|
||||
isolate_->global_handles()
|
||||
->Create(*isolate_->factory()->NewFixedArray(table_size))
|
||||
.address());
|
||||
signature_tables_.push_back(
|
||||
isolate_->global_handles()
|
||||
->Create(*isolate_->factory()->NewFixedArray(table_size))
|
||||
.address());
|
||||
}
|
||||
|
||||
void PopulateIndirectFunctionTable() {
|
||||
@ -285,8 +291,10 @@ class TestingModuleBuilder {
|
||||
// Initialize the fixed arrays in instance->function_tables.
|
||||
for (uint32_t i = 0; i < function_tables_.size(); i++) {
|
||||
WasmIndirectFunctionTable& table = test_module_.function_tables[i];
|
||||
Handle<FixedArray> function_table = function_tables_[i];
|
||||
Handle<FixedArray> signature_table = signature_tables_[i];
|
||||
Handle<FixedArray> function_table(
|
||||
reinterpret_cast<FixedArray**>(function_tables_[i]));
|
||||
Handle<FixedArray> signature_table(
|
||||
reinterpret_cast<FixedArray**>(signature_tables_[i]));
|
||||
int table_size = static_cast<int>(table.values.size());
|
||||
for (int j = 0; j < table_size; j++) {
|
||||
WasmFunction& function = test_module_.functions[table.values[j]];
|
||||
@ -354,8 +362,8 @@ class TestingModuleBuilder {
|
||||
byte* mem_start_;
|
||||
uint32_t mem_size_;
|
||||
std::vector<Handle<Code>> function_code_;
|
||||
std::vector<Handle<FixedArray>> function_tables_;
|
||||
std::vector<Handle<FixedArray>> signature_tables_;
|
||||
std::vector<GlobalHandleAddress> function_tables_;
|
||||
std::vector<GlobalHandleAddress> signature_tables_;
|
||||
V8_ALIGNED(8) byte globals_data_[kMaxGlobalsSize];
|
||||
WasmInterpreter* interpreter_;
|
||||
Handle<WasmInstanceObject> instance_object_;
|
||||
|
@ -67,5 +67,7 @@ gc();
|
||||
module = null;
|
||||
})();
|
||||
|
||||
gc();
|
||||
// the first GC will clear the module, the second the instance.
|
||||
gc();
|
||||
%ValidateWasmOrphanedInstance(instance4);
|
||||
|
Loading…
Reference in New Issue
Block a user