Reland "[wasm] Unify deoptimization data"
This is a reland of 236298acbf
.
Original change's description:
> [wasm] Unify deoptimization data
>
> Add methods to add deoptimization data and use them from all the places
> where we currently add them manually. Also add them to wasm-to-wasm
> wrappers compiled on table set, which was missing before, leading to
> the referenced bug.
>
> R=ahaas@chromium.org
>
> Bug: chromium:779292
> Change-Id: Ib9132d9faeb1092c46e22dd8196d201ce5c0942f
> Reviewed-on: https://chromium-review.googlesource.com/774838
> Reviewed-by: Andreas Haas <ahaas@chromium.org>
> Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#49452}
Bug: chromium:779292
Change-Id: I8219305fc894c50904db57e51245733f6613dcd3
Reviewed-on: https://chromium-review.googlesource.com/778159
Reviewed-by: Mircea Trofin <mtrofin@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49508}
This commit is contained in:
parent
b5bdb762ac
commit
3380e9a4d9
@ -4277,6 +4277,8 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
|
|||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
void ValidateImportWrapperReferencesImmovables(Handle<Code> wrapper) {
|
void ValidateImportWrapperReferencesImmovables(Handle<Code> wrapper) {
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
return;
|
return;
|
||||||
@ -4315,6 +4317,36 @@ void ValidateImportWrapperReferencesImmovables(Handle<Code> wrapper) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void AttachWasmFunctionInfo(Isolate* isolate, Handle<Code> code,
|
||||||
|
MaybeHandle<WeakCell> weak_instance,
|
||||||
|
int func_index) {
|
||||||
|
DCHECK(weak_instance.is_null() ||
|
||||||
|
weak_instance.ToHandleChecked()->value()->IsWasmInstanceObject());
|
||||||
|
Handle<FixedArray> deopt_data = isolate->factory()->NewFixedArray(2, TENURED);
|
||||||
|
if (!weak_instance.is_null()) {
|
||||||
|
// TODO(wasm): Introduce constants for the indexes in wasm deopt data.
|
||||||
|
deopt_data->set(0, *weak_instance.ToHandleChecked());
|
||||||
|
}
|
||||||
|
deopt_data->set(1, Smi::FromInt(func_index));
|
||||||
|
|
||||||
|
// TODO(6792): No longer needed once WebAssembly code is off heap.
|
||||||
|
CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
|
||||||
|
|
||||||
|
code->set_deoptimization_data(*deopt_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AttachWasmFunctionInfo(Isolate* isolate, Handle<Code> code,
|
||||||
|
MaybeHandle<WasmInstanceObject> instance,
|
||||||
|
int func_index) {
|
||||||
|
MaybeHandle<WeakCell> weak_instance;
|
||||||
|
if (!instance.is_null()) {
|
||||||
|
weak_instance = isolate->factory()->NewWeakCell(instance.ToHandleChecked());
|
||||||
|
}
|
||||||
|
AttachWasmFunctionInfo(isolate, code, weak_instance, func_index);
|
||||||
|
}
|
||||||
|
|
||||||
Handle<Code> CompileWasmToJSWrapper(
|
Handle<Code> CompileWasmToJSWrapper(
|
||||||
Isolate* isolate, Handle<JSReceiver> target, wasm::FunctionSig* sig,
|
Isolate* isolate, Handle<JSReceiver> target, wasm::FunctionSig* sig,
|
||||||
uint32_t index, wasm::ModuleOrigin origin,
|
uint32_t index, wasm::ModuleOrigin origin,
|
||||||
|
@ -183,6 +183,21 @@ Handle<Code> CompileWasmInterpreterEntry(Isolate* isolate, uint32_t func_index,
|
|||||||
wasm::FunctionSig* sig,
|
wasm::FunctionSig* sig,
|
||||||
Handle<WasmInstanceObject> instance);
|
Handle<WasmInstanceObject> instance);
|
||||||
|
|
||||||
|
// Attach function information in the form of deoptimization data to the given
|
||||||
|
// code object. This information will be used for generating stack traces,
|
||||||
|
// calling imported functions in the interpreter, knowing which function to
|
||||||
|
// compile in a lazy compile stub, and more. The deopt data will be a newly
|
||||||
|
// allocated FixedArray of length 2, where the first element is a WeakCell
|
||||||
|
// containing the WasmInstanceObject, and the second element is the function
|
||||||
|
// index.
|
||||||
|
// If calling this method repeatedly for the same instance, pass a WeakCell
|
||||||
|
// directly in order to avoid creating many cells pointing to the same instance.
|
||||||
|
void AttachWasmFunctionInfo(Isolate*, Handle<Code>,
|
||||||
|
MaybeHandle<WeakCell> weak_instance,
|
||||||
|
int func_index);
|
||||||
|
void AttachWasmFunctionInfo(Isolate*, Handle<Code>,
|
||||||
|
MaybeHandle<WasmInstanceObject>, int func_index);
|
||||||
|
|
||||||
enum CWasmEntryParameters {
|
enum CWasmEntryParameters {
|
||||||
kCodeObject,
|
kCodeObject,
|
||||||
kArgumentsBuffer,
|
kArgumentsBuffer,
|
||||||
|
@ -218,6 +218,8 @@ class ModuleCompiler {
|
|||||||
Handle<Code> centry_stub_;
|
Handle<Code> centry_stub_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
class JSToWasmWrapperCache {
|
class JSToWasmWrapperCache {
|
||||||
public:
|
public:
|
||||||
void SetContextAddress(Address context_address) {
|
void SetContextAddress(Address context_address) {
|
||||||
@ -391,7 +393,7 @@ class InstanceBuilder {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// TODO(titzer): move to wasm-objects.cc
|
// TODO(titzer): move to wasm-objects.cc
|
||||||
static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
|
void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
|
||||||
DisallowHeapAllocation no_gc;
|
DisallowHeapAllocation no_gc;
|
||||||
JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter());
|
JSObject** p = reinterpret_cast<JSObject**>(data.GetParameter());
|
||||||
WasmInstanceObject* owner = reinterpret_cast<WasmInstanceObject*>(*p);
|
WasmInstanceObject* owner = reinterpret_cast<WasmInstanceObject*>(*p);
|
||||||
@ -465,6 +467,8 @@ static void InstanceFinalizer(const v8::WeakCallbackInfo<void>& data) {
|
|||||||
TRACE("}\n");
|
TRACE("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
bool SyncValidate(Isolate* isolate, const ModuleWireBytes& bytes) {
|
bool SyncValidate(Isolate* isolate, const ModuleWireBytes& bytes) {
|
||||||
if (bytes.start() == nullptr || bytes.length() == 0) return false;
|
if (bytes.start() == nullptr || bytes.length() == 0) return false;
|
||||||
ModuleResult result = SyncDecodeWasmModule(isolate, bytes.start(),
|
ModuleResult result = SyncDecodeWasmModule(isolate, bytes.start(),
|
||||||
@ -749,15 +753,7 @@ void LazyCompilationOrchestrator::CompileFunction(
|
|||||||
CHECK(!thrower.error());
|
CHECK(!thrower.error());
|
||||||
Handle<Code> code = maybe_code.ToHandleChecked();
|
Handle<Code> code = maybe_code.ToHandleChecked();
|
||||||
|
|
||||||
// TODO(6792): No longer needed once WebAssembly code is off heap.
|
compiler::AttachWasmFunctionInfo(isolate, code, instance, func_index);
|
||||||
CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
|
|
||||||
|
|
||||||
Handle<FixedArray> deopt_data = isolate->factory()->NewFixedArray(2, TENURED);
|
|
||||||
Handle<WeakCell> weak_instance = isolate->factory()->NewWeakCell(instance);
|
|
||||||
// TODO(wasm): Introduce constants for the indexes in wasm deopt data.
|
|
||||||
deopt_data->set(0, *weak_instance);
|
|
||||||
deopt_data->set(1, Smi::FromInt(func_index));
|
|
||||||
code->set_deoptimization_data(*deopt_data);
|
|
||||||
|
|
||||||
DCHECK_EQ(Builtins::kWasmCompileLazy,
|
DCHECK_EQ(Builtins::kWasmCompileLazy,
|
||||||
Code::cast(compiled_module->code_table()->get(func_index))
|
Code::cast(compiled_module->code_table()->get(func_index))
|
||||||
@ -1263,21 +1259,11 @@ Handle<Code> EnsureExportedLazyDeoptData(Isolate* isolate,
|
|||||||
// #1: func_index
|
// #1: func_index
|
||||||
// might be extended later for table exports (see
|
// might be extended later for table exports (see
|
||||||
// EnsureTableExportLazyDeoptData).
|
// EnsureTableExportLazyDeoptData).
|
||||||
Handle<FixedArray> deopt_data(code->deoptimization_data());
|
DCHECK_EQ(0, code->deoptimization_data()->length() % 2);
|
||||||
DCHECK_EQ(0, deopt_data->length() % 2);
|
if (code->deoptimization_data()->length() == 0) {
|
||||||
if (deopt_data->length() == 0) {
|
|
||||||
code = isolate->factory()->CopyCode(code);
|
code = isolate->factory()->CopyCode(code);
|
||||||
code_table->set(func_index, *code);
|
code_table->set(func_index, *code);
|
||||||
deopt_data = isolate->factory()->NewFixedArray(2, TENURED);
|
compiler::AttachWasmFunctionInfo(isolate, code, instance, func_index);
|
||||||
// TODO(6792): No longer needed once WebAssembly code is off heap.
|
|
||||||
CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
|
|
||||||
code->set_deoptimization_data(*deopt_data);
|
|
||||||
if (!instance.is_null()) {
|
|
||||||
Handle<WeakCell> weak_instance =
|
|
||||||
isolate->factory()->NewWeakCell(instance);
|
|
||||||
deopt_data->set(0, *weak_instance);
|
|
||||||
}
|
|
||||||
deopt_data->set(1, Smi::FromInt(func_index));
|
|
||||||
}
|
}
|
||||||
DCHECK_IMPLIES(!instance.is_null(),
|
DCHECK_IMPLIES(!instance.is_null(),
|
||||||
WeakCell::cast(code->deoptimization_data()->get(0))->value() ==
|
WeakCell::cast(code->deoptimization_data()->get(0))->value() ==
|
||||||
@ -1361,18 +1347,11 @@ Handle<Code> MakeWasmToWasmWrapper(
|
|||||||
Handle<Code> wrapper_code = compiler::CompileWasmToWasmWrapper(
|
Handle<Code> wrapper_code = compiler::CompileWasmToWasmWrapper(
|
||||||
isolate, wasm_code, *sig, imported_function->function_index(),
|
isolate, wasm_code, *sig, imported_function->function_index(),
|
||||||
new_wasm_context_address);
|
new_wasm_context_address);
|
||||||
// TODO(6792): No longer needed once WebAssembly code is off heap.
|
|
||||||
CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
|
|
||||||
// Set the deoptimization data for the WasmToWasm wrapper. This is
|
// Set the deoptimization data for the WasmToWasm wrapper. This is
|
||||||
// needed by the interpreter to find the imported instance for
|
// needed by the interpreter to find the imported instance for
|
||||||
// a cross-instance call.
|
// a cross-instance call.
|
||||||
Factory* factory = isolate->factory();
|
compiler::AttachWasmFunctionInfo(isolate, wrapper_code, imported_instance,
|
||||||
Handle<WeakCell> weak_link = factory->NewWeakCell(imported_instance);
|
imported_function->function_index());
|
||||||
Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED);
|
|
||||||
deopt_data->set(0, *weak_link);
|
|
||||||
auto function_index = Smi::FromInt(imported_function->function_index());
|
|
||||||
deopt_data->set(1, function_index);
|
|
||||||
wrapper_code->set_deoptimization_data(*deopt_data);
|
|
||||||
return wrapper_code;
|
return wrapper_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1684,15 +1663,8 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
|||||||
// unique copy to attach updated deoptimization data.
|
// unique copy to attach updated deoptimization data.
|
||||||
if (orig_code->deoptimization_data()->length() > 0) {
|
if (orig_code->deoptimization_data()->length() > 0) {
|
||||||
Handle<Code> code = factory->CopyCode(orig_code);
|
Handle<Code> code = factory->CopyCode(orig_code);
|
||||||
Handle<FixedArray> deopt_data =
|
compiler::AttachWasmFunctionInfo(isolate_, code,
|
||||||
factory->NewFixedArray(2, TENURED);
|
Handle<WasmInstanceObject>(), i);
|
||||||
deopt_data->set(1, Smi::FromInt(i));
|
|
||||||
// TODO(6792): No longer needed once WebAssembly code is off heap.
|
|
||||||
{
|
|
||||||
CodeSpaceMemoryModificationScope modification_scope(
|
|
||||||
isolate_->heap());
|
|
||||||
code->set_deoptimization_data(*deopt_data);
|
|
||||||
}
|
|
||||||
code_table->set(i, *code);
|
code_table->set(i, *code);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1870,12 +1842,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
|||||||
i < num_functions; ++i) {
|
i < num_functions; ++i) {
|
||||||
Handle<Code> code = handle(Code::cast(code_table->get(i)), isolate_);
|
Handle<Code> code = handle(Code::cast(code_table->get(i)), isolate_);
|
||||||
if (code->kind() == Code::WASM_FUNCTION) {
|
if (code->kind() == Code::WASM_FUNCTION) {
|
||||||
Handle<FixedArray> deopt_data = factory->NewFixedArray(2, TENURED);
|
compiler::AttachWasmFunctionInfo(isolate_, code, weak_link, i);
|
||||||
deopt_data->set(0, *weak_link);
|
|
||||||
deopt_data->set(1, Smi::FromInt(i));
|
|
||||||
// TODO(6792): No longer needed once WebAssembly code is off heap.
|
|
||||||
CodeSpaceMemoryModificationScope modification_scope(isolate_->heap());
|
|
||||||
code->set_deoptimization_data(*deopt_data);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DCHECK_EQ(Builtins::kWasmCompileLazy, code->builtin_index());
|
DCHECK_EQ(Builtins::kWasmCompileLazy, code->builtin_index());
|
||||||
|
@ -298,11 +298,14 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
|
|||||||
value = function;
|
value = function;
|
||||||
// TODO(titzer): Make JSToWasm wrappers just call the WASM to WASM wrapper,
|
// TODO(titzer): Make JSToWasm wrappers just call the WASM to WASM wrapper,
|
||||||
// and then we can just reuse the WASM to WASM wrapper.
|
// and then we can just reuse the WASM to WASM wrapper.
|
||||||
Address new_context_address = reinterpret_cast<Address>(
|
Handle<WasmInstanceObject> instance(exported_function->instance(), isolate);
|
||||||
exported_function->instance()->wasm_context()->get());
|
int func_index = exported_function->function_index();
|
||||||
|
Address new_context_address =
|
||||||
|
reinterpret_cast<Address>(instance->wasm_context()->get());
|
||||||
code = compiler::CompileWasmToWasmWrapper(
|
code = compiler::CompileWasmToWasmWrapper(
|
||||||
isolate, exported_function->GetWasmCode(), wasm_function->sig,
|
isolate, exported_function->GetWasmCode(), wasm_function->sig,
|
||||||
exported_function->function_index(), new_context_address);
|
func_index, new_context_address);
|
||||||
|
compiler::AttachWasmFunctionInfo(isolate, code, instance, func_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateDispatchTables(isolate, dispatch_tables, index, wasm_function, code);
|
UpdateDispatchTables(isolate, dispatch_tables, index, wasm_function, code);
|
||||||
|
@ -449,3 +449,21 @@ function checkStack(stack, expected_lines) {
|
|||||||
const instance = builder2.instantiate({imp: {func: exp}});
|
const instance = builder2.instantiate({imp: {func: exp}});
|
||||||
assertEquals(23, instance.exports.main());
|
assertEquals(23, instance.exports.main());
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
(function testTableCall() {
|
||||||
|
print(arguments.callee.name);
|
||||||
|
const builder1 = new WasmModuleBuilder();
|
||||||
|
builder1.addFunction('func', kSig_v_v).addBody([]).exportFunc();
|
||||||
|
const instance1 = builder1.instantiate();
|
||||||
|
const table = new WebAssembly.Table({element: 'anyfunc', initial: 2});
|
||||||
|
|
||||||
|
const builder2 = new WasmModuleBuilder()
|
||||||
|
builder2.addImportedTable('m', 'table');
|
||||||
|
const sig = builder2.addType(kSig_v_v);
|
||||||
|
builder2.addFunction('call_func', kSig_v_v)
|
||||||
|
.addBody([kExprI32Const, 0, kExprCallIndirect, sig, kTableZero])
|
||||||
|
.exportFunc();
|
||||||
|
const instance2 = builder2.instantiate({m: {table: table}});
|
||||||
|
table.set(0, instance1.exports.func);
|
||||||
|
instance2.exports.call_func();
|
||||||
|
})();
|
||||||
|
Loading…
Reference in New Issue
Block a user