[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);
}
void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<WeakCell> weak_instance,
wasm::WasmCode* wasm_code) {
Node* WasmGraphBuilder::BuildLoadInstanceFromExportedFunction(Node* closure) {
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 count =
wasm_count + 4; // wasm_code, instance_node, effect, and control.
@ -3016,25 +3034,20 @@ void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<WeakCell> weak_instance,
*control_ = 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(
jsgraph()->common()->Parameter(
Linkage::GetJSCallContextParamIndex(wasm_count + 1), "%context"),
graph()->start());
// Create the instance_node node to pass as parameter. This is either
// an actual reference to an instance or a placeholder reference,
// since JSToWasm wrappers can be compiled at module compile time and
// patched at instance build time.
// Create the instance_node node to pass as parameter. It is loaded from the
// called {WasmExportedFunction} via the {WasmExportedFunctionData} structure.
DCHECK_NULL(instance_node_);
// TODO(titzer): JSToWasmWrappers should load the instance from the
// 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_);
instance_node_ = BuildLoadInstanceFromExportedFunction(js_closure);
Address instr_start =
wasm_code == nullptr ? kNullAddress : wasm_code->instruction_start();
@ -4638,7 +4651,6 @@ void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
} // namespace
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
Handle<WeakCell> weak_instance,
wasm::WasmCode* wasm_code, uint32_t index,
wasm::UseTrapHandler use_trap_handler) {
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);
builder.set_control_ptr(&control);
builder.set_effect_ptr(&effect);
builder.BuildJSToWasmWrapper(weak_instance, wasm_code);
builder.BuildJSToWasmWrapper(wasm_code);
//----------------------------------------------------------------------------
// Run the compilation pipeline.

View File

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

View File

@ -211,7 +211,7 @@ class JSToWasmWrapperCache {
}
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);
DCHECK_EQ(code_cache_.size(), new_cache_idx);
USE(new_cache_idx);
@ -219,15 +219,10 @@ class JSToWasmWrapperCache {
return code;
}
void SetWeakInstance(Handle<WeakCell> weak_instance) {
weak_instance_ = weak_instance;
}
private:
// sig_map_ maps signatures to an index in code_cache_.
wasm::SignatureMap sig_map_;
std::vector<Handle<Code>> code_cache_;
Handle<WeakCell> weak_instance_;
};
// A helper class to simplify instantiating a module from a compiled module.
@ -1617,9 +1612,9 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
MaybeHandle<WasmInstanceObject> old_instance;
TRACE("Starting new module instantiation\n");
{
Handle<WasmCompiledModule> original =
handle(module_object_->compiled_module());
{
if (original->has_instance()) {
old_instance = handle(original->owning_instance());
// 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);
}
}
base::Optional<wasm::NativeModuleModificationScope>
native_module_modification_scope;
if (native_module != nullptr) {
native_module_modification_scope.emplace(native_module);
}
DCHECK_NOT_NULL(native_module);
wasm::NativeModuleModificationScope native_modification_scope(native_module);
//--------------------------------------------------------------------------
// Create the WebAssembly.Instance object.
//--------------------------------------------------------------------------
CodeSpecialization code_specialization;
Handle<WasmInstanceObject> instance =
WasmInstanceObject::New(isolate_, module_object_, compiled_module_);
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.
@ -1729,6 +1715,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
//--------------------------------------------------------------------------
// Initialize the indirect tables.
//--------------------------------------------------------------------------
CodeSpecialization code_specialization;
if (function_table_count > 0) {
InitializeTables(instance, &code_specialization);
}
@ -3688,9 +3675,6 @@ void CompileJsToWasmWrappers(Isolate* isolate,
Handle<WasmCompiledModule> compiled_module,
Counters* counters) {
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;
Handle<FixedArray> export_wrappers(compiled_module->export_wrappers(),
isolate);

View File

@ -62,14 +62,6 @@ 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) {
DCHECK_NULL(relocate_direct_calls_module_);
DCHECK_NOT_NULL(native_module);
@ -101,9 +93,6 @@ bool CodeSpecialization::ApplyToWholeModule(
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).
int reloc_mode = 0;
// 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_);
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;
int wrapper_index = 0;
for (auto exp : module->export_table) {
@ -134,15 +119,6 @@ bool CodeSpecialization::ApplyToWholeModule(
it.rinfo()->set_js_to_wasm_address(new_code->instruction_start(),
icache_flush_mode);
} 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:
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
// 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* /
// Patch* methods, then apply all changes in one step using the Apply* methods.
@ -27,10 +25,6 @@ class 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.
void RelocateDirectCalls(NativeModule* module);
// Apply all relocations and patching to all code in the instance (wasm code
@ -42,8 +36,6 @@ class CodeSpecialization {
ICacheFlushMode = FLUSH_ICACHE_IF_NEEDED);
private:
Handle<WeakCell> old_weak_instance_;
Handle<WeakCell> new_weak_instance_;
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.
Link();
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(
isolate_, test_module_ptr_, weak_instance, code, index,
isolate_, test_module_ptr_, code, index,
trap_handler::IsTrapHandlerEnabled() ? kUseTrapHandler : kNoTrapHandler);
Handle<JSFunction> ret = WasmExportedFunction::New(
isolate_, instance_object(), MaybeHandle<String>(),
@ -134,6 +129,8 @@ Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
ret_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> new_arr =
isolate_->factory()->NewFixedArray(old_arr->length() + 1);