Commit 958b78a7 authored by Mircea Trofin's avatar Mircea Trofin Committed by Commit Bot

[wasm] Ensure indirect calls happen in the context of the owning instance

Bug: chromium:793714
Change-Id: I8c1ea8a2e27b5a7fe9cd1f8260873057a3bf9fd9
Reviewed-on: https://chromium-review.googlesource.com/826030
Commit-Queue: Mircea Trofin <mtrofin@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50136}
parent 8b4966e9
......@@ -3571,7 +3571,28 @@ void InstanceBuilder::LoadTableSegments(Handle<FixedArray> code_table,
}
table_instance.js_wrappers->set(table_index,
*js_wrappers_[func_index]);
// When updating dispatch tables, we need to provide a wasm-to-wasm
// wrapper for wasm_code - unless wasm_code is already a wrapper. If
// it's a wasm-to-js wrapper, we don't need to construct a
// wasm-to-wasm wrapper because there's no context switching required.
// The remaining case is that it's a wasm-to-wasm wrapper, in which
// case it's already doing "the right thing", and wrapping it again
// would be redundant.
if (func_index >= module_->num_imported_functions) {
value_to_update_with = GetOrCreateIndirectCallWrapper(
isolate_, instance, wasm_code, func_index, function->sig);
} else {
if (wasm_code.IsCodeObject()) {
DCHECK(wasm_code.GetCode()->kind() == Code::WASM_TO_JS_FUNCTION ||
wasm_code.GetCode()->kind() ==
Code::WASM_TO_WASM_FUNCTION);
} else {
DCHECK(wasm_code.GetWasmCode()->kind() ==
WasmCode::kWasmToJsWrapper ||
wasm_code.GetWasmCode()->kind() ==
WasmCode::kWasmToWasmWrapper);
}
}
UpdateDispatchTables(isolate_, all_dispatch_tables, table_index,
function, value_to_update_with);
}
......
......@@ -155,6 +155,39 @@ WasmFunction* GetWasmFunctionForExport(Isolate* isolate,
return nullptr;
}
Handle<Object> GetOrCreateIndirectCallWrapper(
Isolate* isolate, Handle<WasmInstanceObject> owning_instance,
WasmCodeWrapper wasm_code, uint32_t index, FunctionSig* sig) {
Address new_context_address =
reinterpret_cast<Address>(owning_instance->wasm_context()->get());
if (!wasm_code.IsCodeObject()) {
DCHECK_NE(wasm_code.GetWasmCode()->kind(),
wasm::WasmCode::kWasmToWasmWrapper);
wasm::NativeModule* native_module = wasm_code.GetWasmCode()->owner();
// The only reason we pass owning_instance is for the GC case. Check
// that the values match.
DCHECK_EQ(owning_instance->compiled_module()->GetNativeModule(),
native_module);
// We create the wrapper on the module exporting the function. This
// wrapper will only be called as indirect call.
wasm::WasmCode* exported_wrapper =
native_module->GetExportedWrapper(wasm_code.GetWasmCode()->index());
if (exported_wrapper == nullptr) {
Handle<Code> new_wrapper = compiler::CompileWasmToWasmWrapper(
isolate, wasm_code, sig, new_context_address);
exported_wrapper = native_module->AddExportedWrapper(
new_wrapper, wasm_code.GetWasmCode()->index());
}
Address target = exported_wrapper->instructions().start();
return isolate->factory()->NewForeign(target, TENURED);
}
Handle<Code> code = compiler::CompileWasmToWasmWrapper(
isolate, wasm_code, sig, new_context_address);
AttachWasmFunctionInfo(isolate, code, owning_instance,
static_cast<int>(index));
return code;
}
void UpdateDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
int index, const WasmFunction* function,
Handle<Object> code_or_foreign) {
......
......@@ -288,6 +288,10 @@ void UpdateDispatchTables(Isolate* isolate, Handle<FixedArray> dispatch_tables,
int index, const WasmFunction* function,
Handle<Object> code_or_foreign);
Handle<Object> GetOrCreateIndirectCallWrapper(
Isolate* isolate, Handle<WasmInstanceObject> owning_instance,
WasmCodeWrapper wasm_code, uint32_t index, FunctionSig* sig);
void UnpackAndRegisterProtectedInstructionsGC(Isolate* isolate,
Handle<FixedArray> code_table);
......
......@@ -333,35 +333,15 @@ void WasmTableObject::Set(Isolate* isolate, Handle<WasmTableObject> table,
value = function;
// TODO(titzer): Make JSToWasm wrappers just call the WASM to WASM wrapper,
// and then we can just reuse the WASM to WASM wrapper.
Address new_context_address = reinterpret_cast<Address>(
exported_function->instance()->wasm_context()->get());
WasmCodeWrapper wasm_code = exported_function->GetWasmCode();
if (!wasm_code.IsCodeObject()) {
wasm::NativeModule* native_module = wasm_code.GetWasmCode()->owner();
wasm::NativeModuleModificationScope modification_scope(native_module);
// we create the wrapper on the module exporting the function. This
// wrapper will only be called as indirect call.
wasm::WasmCode* exported_wrapper =
native_module->GetExportedWrapper(wasm_code.GetWasmCode()->index());
if (exported_wrapper == nullptr) {
Handle<Code> new_wrapper = compiler::CompileWasmToWasmWrapper(
isolate, wasm_code, wasm_function->sig, new_context_address);
exported_wrapper = native_module->AddExportedWrapper(
new_wrapper, wasm_code.GetWasmCode()->index());
}
Address target = exported_wrapper->instructions().start();
code = isolate->factory()->NewForeign(target, TENURED);
} else {
Handle<WasmInstanceObject> instance(exported_function->instance(),
isolate);
int func_index = exported_function->function_index();
code = compiler::CompileWasmToWasmWrapper(
isolate, wasm_code, wasm_function->sig, new_context_address);
// TODO(6792): No longer needed once WebAssembly code is off heap.
CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
AttachWasmFunctionInfo(isolate, Handle<Code>::cast(code), instance,
func_index);
}
wasm::NativeModule* native_module =
wasm_code.IsCodeObject() ? nullptr : wasm_code.GetWasmCode()->owner();
CodeSpaceMemoryModificationScope gc_modification_scope(isolate->heap());
wasm::NativeModuleModificationScope native_modification_scope(
native_module);
code = wasm::GetOrCreateIndirectCallWrapper(
isolate, handle(exported_function->instance()), wasm_code,
exported_function->function_index(), wasm_function->sig);
}
UpdateDispatchTables(isolate, dispatch_tables, index, wasm_function, code);
array->set(index, *value);
......
......@@ -601,3 +601,43 @@ function js_div(a, b) { return (a / b) | 0; }
() => instance0.exports.main(0), WebAssembly.RuntimeError,
/signature mismatch/);
})();
(function IndirectCallIntoOtherInstance() {
print("IndirectCallIntoOtherInstance...");
var mem_1 = new WebAssembly.Memory({initial: 1});
var mem_2 = new WebAssembly.Memory({initial: 1});
var view_1 = new Int32Array(mem_1.buffer);
var view_2 = new Int32Array(mem_2.buffer);
view_1[0] = 1;
view_2[0] = 1000;
let builder = new WasmModuleBuilder();
let sig = builder.addType(kSig_i_v);
builder.addFunction('main', kSig_i_i)
.addBody([kExprGetLocal, 0, kExprCallIndirect, sig, kTableZero])
.exportAs('main');
builder.addImportedMemory('', 'memory', 1);
builder.setFunctionTableBounds(1, 1);
builder.addExportOfKind('table', kExternalTable);
let module1 = new WebAssembly.Module(builder.toBuffer());
let instance1 = new WebAssembly.Instance(module1, {'':{memory:mem_1}});
builder = new WasmModuleBuilder();
builder.addFunction('main', kSig_i_v).addBody([kExprI32Const, 0, kExprI32LoadMem, 0, 0]);
builder.addImportedTable('', 'table');
builder.addFunctionTableInit(0, false, [0], true);
builder.addImportedMemory('', 'memory', 1);
let module2 = new WebAssembly.Module(builder.toBuffer());
let instance2 = new WebAssembly.Instance(module2, {
'': {
table: instance1.exports.table,
memory: mem_2
}
});
assertEquals(instance1.exports.main(0), 1000);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment