[wasm] Load instances from {WasmExportedFunction} objects.

This changes JS-to-Wasm wrappers to no longer embed a WeakCell with the
associated instance into the code, but load the instance object from the
passed {WasmExportedFunction} object instead.

R=titzer@chromium.org
BUG=v8:7424

Change-Id: I5403f882912eb23e760fabe70207440648754a69
Reviewed-on: https://chromium-review.googlesource.com/1028053
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Ben Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53057}
This commit is contained in:
Michael Starzinger 2018-05-08 10:33:30 +02:00 committed by Commit Bot
parent f5fda7c83a
commit 55b70e8686
6 changed files with 46 additions and 82 deletions

View File

@ -3004,8 +3004,26 @@ Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() {
return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag); return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag);
} }
void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<WeakCell> weak_instance, Node* WasmGraphBuilder::BuildLoadInstanceFromExportedFunction(Node* closure) {
wasm::WasmCode* wasm_code) { Node* shared = *effect_ = graph()->NewNode(
jsgraph()->machine()->Load(MachineType::AnyTagged()), closure,
jsgraph()->Int32Constant(JSFunction::kSharedFunctionInfoOffset -
kHeapObjectTag),
*effect_, *control_);
Node* function_data = *effect_ = graph()->NewNode(
jsgraph()->machine()->Load(MachineType::AnyTagged()), shared,
jsgraph()->Int32Constant(SharedFunctionInfo::kFunctionDataOffset -
kHeapObjectTag),
*effect_, *control_);
Node* instance = *effect_ = graph()->NewNode(
jsgraph()->machine()->Load(MachineType::AnyTagged()), function_data,
jsgraph()->Int32Constant(WasmExportedFunctionData::kInstanceOffset -
kHeapObjectTag),
*effect_, *control_);
return instance;
}
void WasmGraphBuilder::BuildJSToWasmWrapper(wasm::WasmCode* wasm_code) {
const int wasm_count = static_cast<int>(sig_->parameter_count()); const int wasm_count = static_cast<int>(sig_->parameter_count());
const int count = const int count =
wasm_count + 4; // wasm_code, instance_node, effect, and control. wasm_count + 4; // wasm_code, instance_node, effect, and control.
@ -3016,25 +3034,20 @@ void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<WeakCell> weak_instance,
*control_ = start; *control_ = start;
*effect_ = start; *effect_ = start;
// Create the js_context parameter // Create the js_closure and js_context parameters.
Node* js_closure =
graph()->NewNode(jsgraph()->common()->Parameter(
Linkage::kJSCallClosureParamIndex, "%closure"),
graph()->start());
Node* js_context = graph()->NewNode( Node* js_context = graph()->NewNode(
jsgraph()->common()->Parameter( jsgraph()->common()->Parameter(
Linkage::GetJSCallContextParamIndex(wasm_count + 1), "%context"), Linkage::GetJSCallContextParamIndex(wasm_count + 1), "%context"),
graph()->start()); graph()->start());
// Create the instance_node node to pass as parameter. This is either // Create the instance_node node to pass as parameter. It is loaded from the
// an actual reference to an instance or a placeholder reference, // called {WasmExportedFunction} via the {WasmExportedFunctionData} structure.
// since JSToWasm wrappers can be compiled at module compile time and
// patched at instance build time.
DCHECK_NULL(instance_node_); DCHECK_NULL(instance_node_);
// TODO(titzer): JSToWasmWrappers should load the instance from the instance_node_ = BuildLoadInstanceFromExportedFunction(js_closure);
// incoming JSFunction, but this is currently too slow/too complex because
// we use a regular JS property with a private symbol.
instance_node_ = graph()->NewNode(
jsgraph()->machine()->Load(MachineType::TaggedPointer()),
jsgraph()->HeapConstant(weak_instance),
jsgraph()->Int32Constant(WeakCell::kValueOffset - kHeapObjectTag),
*effect_, *control_);
Address instr_start = Address instr_start =
wasm_code == nullptr ? kNullAddress : wasm_code->instruction_start(); wasm_code == nullptr ? kNullAddress : wasm_code->instruction_start();
@ -4638,7 +4651,6 @@ void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
} // namespace } // namespace
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module, Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
Handle<WeakCell> weak_instance,
wasm::WasmCode* wasm_code, uint32_t index, wasm::WasmCode* wasm_code, uint32_t index,
wasm::UseTrapHandler use_trap_handler) { wasm::UseTrapHandler use_trap_handler) {
const wasm::WasmFunction* func = &module->functions[index]; const wasm::WasmFunction* func = &module->functions[index];
@ -4665,7 +4677,7 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
isolate->factory()->null_value(), func->sig); isolate->factory()->null_value(), func->sig);
builder.set_control_ptr(&control); builder.set_control_ptr(&control);
builder.set_effect_ptr(&effect); builder.set_effect_ptr(&effect);
builder.BuildJSToWasmWrapper(weak_instance, wasm_code); builder.BuildJSToWasmWrapper(wasm_code);
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// Run the compilation pipeline. // Run the compilation pipeline.

View File

@ -108,9 +108,11 @@ Handle<Code> CompileWasmToJSWrapper(Isolate*, Handle<JSReceiver> target,
wasm::ModuleOrigin, wasm::UseTrapHandler); wasm::ModuleOrigin, wasm::UseTrapHandler);
// Wraps a given wasm code object, producing a code object. // Wraps a given wasm code object, producing a code object.
V8_EXPORT_PRIVATE Handle<Code> CompileJSToWasmWrapper( V8_EXPORT_PRIVATE Handle<Code> CompileJSToWasmWrapper(Isolate*,
Isolate*, wasm::WasmModule*, Handle<WeakCell> weak_instance, wasm::WasmModule*,
wasm::WasmCode*, uint32_t index, wasm::UseTrapHandler); wasm::WasmCode*,
uint32_t index,
wasm::UseTrapHandler);
// Compiles a stub that redirects a call to a wasm function to the wasm // Compiles a stub that redirects a call to a wasm function to the wasm
// interpreter. It's ABI compatible with the compiled wasm function. // interpreter. It's ABI compatible with the compiled wasm function.
@ -251,8 +253,7 @@ class WasmGraphBuilder {
Node* CallIndirect(uint32_t index, Node** args, Node*** rets, Node* CallIndirect(uint32_t index, Node** args, Node*** rets,
wasm::WasmCodePosition position); wasm::WasmCodePosition position);
void BuildJSToWasmWrapper(Handle<WeakCell> weak_instance, void BuildJSToWasmWrapper(wasm::WasmCode* wasm_code);
wasm::WasmCode* wasm_code);
bool BuildWasmToJSWrapper(Handle<JSReceiver> target, bool BuildWasmToJSWrapper(Handle<JSReceiver> target,
int index); int index);
void BuildWasmInterpreterEntry(uint32_t func_index); void BuildWasmInterpreterEntry(uint32_t func_index);
@ -466,6 +467,8 @@ class WasmGraphBuilder {
Node* BuildLoadHeapNumberValue(Node* value, Node* control); Node* BuildLoadHeapNumberValue(Node* value, Node* control);
Node* BuildHeapNumberValueIndexConstant(); Node* BuildHeapNumberValueIndexConstant();
Node* BuildLoadInstanceFromExportedFunction(Node* closure);
// Asm.js specific functionality. // Asm.js specific functionality.
Node* BuildI32AsmjsSConvertF32(Node* input); Node* BuildI32AsmjsSConvertF32(Node* input);
Node* BuildI32AsmjsSConvertF64(Node* input); Node* BuildI32AsmjsSConvertF64(Node* input);

View File

@ -211,7 +211,7 @@ class JSToWasmWrapperCache {
} }
Handle<Code> code = compiler::CompileJSToWasmWrapper( Handle<Code> code = compiler::CompileJSToWasmWrapper(
isolate, module, weak_instance_, wasm_code, index, use_trap_handler); isolate, module, wasm_code, index, use_trap_handler);
uint32_t new_cache_idx = sig_map_.FindOrInsert(func->sig); uint32_t new_cache_idx = sig_map_.FindOrInsert(func->sig);
DCHECK_EQ(code_cache_.size(), new_cache_idx); DCHECK_EQ(code_cache_.size(), new_cache_idx);
USE(new_cache_idx); USE(new_cache_idx);
@ -219,15 +219,10 @@ class JSToWasmWrapperCache {
return code; return code;
} }
void SetWeakInstance(Handle<WeakCell> weak_instance) {
weak_instance_ = weak_instance;
}
private: private:
// sig_map_ maps signatures to an index in code_cache_. // sig_map_ maps signatures to an index in code_cache_.
wasm::SignatureMap sig_map_; wasm::SignatureMap sig_map_;
std::vector<Handle<Code>> code_cache_; std::vector<Handle<Code>> code_cache_;
Handle<WeakCell> weak_instance_;
}; };
// A helper class to simplify instantiating a module from a compiled module. // A helper class to simplify instantiating a module from a compiled module.
@ -1617,9 +1612,9 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
MaybeHandle<WasmInstanceObject> old_instance; MaybeHandle<WasmInstanceObject> old_instance;
TRACE("Starting new module instantiation\n"); TRACE("Starting new module instantiation\n");
Handle<WasmCompiledModule> original =
handle(module_object_->compiled_module());
{ {
Handle<WasmCompiledModule> original =
handle(module_object_->compiled_module());
if (original->has_instance()) { if (original->has_instance()) {
old_instance = handle(original->owning_instance()); old_instance = handle(original->owning_instance());
// Clone, but don't insert yet the clone in the instances chain. // Clone, but don't insert yet the clone in the instances chain.
@ -1647,24 +1642,15 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
compiled_module_->GetNativeModule()->instance_id); compiled_module_->GetNativeModule()->instance_id);
} }
} }
base::Optional<wasm::NativeModuleModificationScope> DCHECK_NOT_NULL(native_module);
native_module_modification_scope; wasm::NativeModuleModificationScope native_modification_scope(native_module);
if (native_module != nullptr) {
native_module_modification_scope.emplace(native_module);
}
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Create the WebAssembly.Instance object. // Create the WebAssembly.Instance object.
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
CodeSpecialization code_specialization;
Handle<WasmInstanceObject> instance = Handle<WasmInstanceObject> instance =
WasmInstanceObject::New(isolate_, module_object_, compiled_module_); WasmInstanceObject::New(isolate_, module_object_, compiled_module_);
Handle<WeakCell> weak_instance = factory->NewWeakCell(instance); Handle<WeakCell> weak_instance = factory->NewWeakCell(instance);
Handle<WeakCell> old_weak_instance(original->weak_owning_instance(),
isolate_);
code_specialization.UpdateInstanceReferences(old_weak_instance,
weak_instance);
js_to_wasm_cache_.SetWeakInstance(weak_instance);
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Set up the globals for the new instance. // Set up the globals for the new instance.
@ -1729,6 +1715,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Initialize the indirect tables. // Initialize the indirect tables.
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
CodeSpecialization code_specialization;
if (function_table_count > 0) { if (function_table_count > 0) {
InitializeTables(instance, &code_specialization); InitializeTables(instance, &code_specialization);
} }
@ -3688,9 +3675,6 @@ void CompileJsToWasmWrappers(Isolate* isolate,
Handle<WasmCompiledModule> compiled_module, Handle<WasmCompiledModule> compiled_module,
Counters* counters) { Counters* counters) {
JSToWasmWrapperCache js_to_wasm_cache; JSToWasmWrapperCache js_to_wasm_cache;
Handle<WeakCell> weak_instance(compiled_module->weak_owning_instance(),
isolate);
js_to_wasm_cache.SetWeakInstance(weak_instance);
int wrapper_index = 0; int wrapper_index = 0;
Handle<FixedArray> export_wrappers(compiled_module->export_wrappers(), Handle<FixedArray> export_wrappers(compiled_module->export_wrappers(),
isolate); isolate);

View File

@ -62,14 +62,6 @@ CodeSpecialization::CodeSpecialization() {}
CodeSpecialization::~CodeSpecialization() {} CodeSpecialization::~CodeSpecialization() {}
void CodeSpecialization::UpdateInstanceReferences(
Handle<WeakCell> old_weak_instance, Handle<WeakCell> new_weak_instance) {
DCHECK(!old_weak_instance.is_null());
DCHECK(!new_weak_instance.is_null());
old_weak_instance_ = old_weak_instance;
new_weak_instance_ = new_weak_instance;
}
void CodeSpecialization::RelocateDirectCalls(NativeModule* native_module) { void CodeSpecialization::RelocateDirectCalls(NativeModule* native_module) {
DCHECK_NULL(relocate_direct_calls_module_); DCHECK_NULL(relocate_direct_calls_module_);
DCHECK_NOT_NULL(native_module); DCHECK_NOT_NULL(native_module);
@ -101,9 +93,6 @@ bool CodeSpecialization::ApplyToWholeModule(
changed |= ApplyToWasmCode(wasm_function, icache_flush_mode); changed |= ApplyToWasmCode(wasm_function, icache_flush_mode);
} }
bool patch_wasm_weak_instances =
!old_weak_instance_.is_identical_to(new_weak_instance_);
// Patch all exported functions (JS_TO_WASM_FUNCTION). // Patch all exported functions (JS_TO_WASM_FUNCTION).
int reloc_mode = 0; int reloc_mode = 0;
// Patch CODE_TARGET if we shall relocate direct calls. If we patch direct // Patch CODE_TARGET if we shall relocate direct calls. If we patch direct
@ -113,10 +102,6 @@ bool CodeSpecialization::ApplyToWholeModule(
DCHECK_EQ(native_module, relocate_direct_calls_module_); DCHECK_EQ(native_module, relocate_direct_calls_module_);
reloc_mode |= RelocInfo::ModeMask(RelocInfo::JS_TO_WASM_CALL); reloc_mode |= RelocInfo::ModeMask(RelocInfo::JS_TO_WASM_CALL);
} }
// Instance references are simply embedded objects.
if (patch_wasm_weak_instances) {
reloc_mode |= RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
}
if (!reloc_mode) return changed; if (!reloc_mode) return changed;
int wrapper_index = 0; int wrapper_index = 0;
for (auto exp : module->export_table) { for (auto exp : module->export_table) {
@ -134,15 +119,6 @@ bool CodeSpecialization::ApplyToWholeModule(
it.rinfo()->set_js_to_wasm_address(new_code->instruction_start(), it.rinfo()->set_js_to_wasm_address(new_code->instruction_start(),
icache_flush_mode); icache_flush_mode);
} break; } break;
case RelocInfo::EMBEDDED_OBJECT: {
changed = true;
const HeapObject* old = it.rinfo()->target_object();
if (*old_weak_instance_ == old) {
it.rinfo()->set_target_object(
*new_weak_instance_, WriteBarrierMode::UPDATE_WRITE_BARRIER,
icache_flush_mode);
}
} break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }

View File

@ -17,8 +17,6 @@ uint32_t ExtractDirectCallIndex(wasm::Decoder& decoder, const byte* pc);
// Helper class to specialize wasm code for a specific instance, or to update // Helper class to specialize wasm code for a specific instance, or to update
// code when memory / globals / tables change. // code when memory / globals / tables change.
// This class in unhandlified, and contains a DisallowHeapAllocation field to
// ensure that no allocations happen while it is alive.
// //
// Set up all relocations / patching that should be performed by the Relocate* / // Set up all relocations / patching that should be performed by the Relocate* /
// Patch* methods, then apply all changes in one step using the Apply* methods. // Patch* methods, then apply all changes in one step using the Apply* methods.
@ -27,10 +25,6 @@ class CodeSpecialization {
CodeSpecialization(); CodeSpecialization();
~CodeSpecialization(); ~CodeSpecialization();
// Update instance references in code. Instance references should only
// appear in export wrappers.
void UpdateInstanceReferences(Handle<WeakCell> old_weak_instance,
Handle<WeakCell> new_weak_instance);
// Update all direct call sites based on the code table in the given instance. // Update all direct call sites based on the code table in the given instance.
void RelocateDirectCalls(NativeModule* module); void RelocateDirectCalls(NativeModule* module);
// Apply all relocations and patching to all code in the instance (wasm code // Apply all relocations and patching to all code in the instance (wasm code
@ -42,8 +36,6 @@ class CodeSpecialization {
ICacheFlushMode = FLUSH_ICACHE_IF_NEEDED); ICacheFlushMode = FLUSH_ICACHE_IF_NEEDED);
private: private:
Handle<WeakCell> old_weak_instance_;
Handle<WeakCell> new_weak_instance_;
NativeModule* relocate_direct_calls_module_ = nullptr; NativeModule* relocate_direct_calls_module_ = nullptr;
}; };

View File

@ -119,13 +119,8 @@ Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
// Wrap the code so it can be called as a JS function. // Wrap the code so it can be called as a JS function.
Link(); Link();
wasm::WasmCode* code = native_module_->code(index); wasm::WasmCode* code = native_module_->code(index);
Handle<WasmCompiledModule> compiled_module(
instance_object()->compiled_module(), isolate_);
Handle<WeakCell> weak_instance(compiled_module->weak_owning_instance(),
isolate_);
Handle<Code> ret_code = compiler::CompileJSToWasmWrapper( Handle<Code> ret_code = compiler::CompileJSToWasmWrapper(
isolate_, test_module_ptr_, weak_instance, code, index, isolate_, test_module_ptr_, code, index,
trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler : kNoTrapHandler); trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler : kNoTrapHandler);
Handle<JSFunction> ret = WasmExportedFunction::New( Handle<JSFunction> ret = WasmExportedFunction::New(
isolate_, instance_object(), MaybeHandle<String>(), isolate_, instance_object(), MaybeHandle<String>(),
@ -134,6 +129,8 @@ Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
ret_code); ret_code);
// Add reference to the exported wrapper code. // Add reference to the exported wrapper code.
Handle<WasmCompiledModule> compiled_module(
instance_object()->compiled_module(), isolate_);
Handle<FixedArray> old_arr(compiled_module->export_wrappers(), isolate_); Handle<FixedArray> old_arr(compiled_module->export_wrappers(), isolate_);
Handle<FixedArray> new_arr = Handle<FixedArray> new_arr =
isolate_->factory()->NewFixedArray(old_arr->length() + 1); isolate_->factory()->NewFixedArray(old_arr->length() + 1);