[wasm-hints] Fix lazy compilation and validation in interpreter
The interpreter accesses code directly from the code manager. With lazy validation, however, this code is not guaranteed to exist. The interpreter now checks for this and compiles it lazily if needed. It also handles exceptions that may arise from lazy validation. Bug: v8:9003 Change-Id: I37c365f0a4d755ed55630d01c8526f2a3efa9a9e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1594567 Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Commit-Queue: Frederik Gossen <frgossen@google.com> Cr-Commit-Position: refs/heads/master@{#61240}
This commit is contained in:
parent
a0fd791875
commit
ffc75252a5
@ -20,6 +20,7 @@
|
|||||||
#include "src/wasm/function-body-decoder-impl.h"
|
#include "src/wasm/function-body-decoder-impl.h"
|
||||||
#include "src/wasm/function-body-decoder.h"
|
#include "src/wasm/function-body-decoder.h"
|
||||||
#include "src/wasm/memory-tracing.h"
|
#include "src/wasm/memory-tracing.h"
|
||||||
|
#include "src/wasm/module-compiler.h"
|
||||||
#include "src/wasm/wasm-engine.h"
|
#include "src/wasm/wasm-engine.h"
|
||||||
#include "src/wasm/wasm-external-refs.h"
|
#include "src/wasm/wasm-external-refs.h"
|
||||||
#include "src/wasm/wasm-limits.h"
|
#include "src/wasm/wasm-limits.h"
|
||||||
@ -3612,12 +3613,21 @@ class ThreadImpl {
|
|||||||
return {ExternalCallResult::EXTERNAL_RETURNED};
|
return {ExternalCallResult::EXTERNAL_RETURNED};
|
||||||
}
|
}
|
||||||
|
|
||||||
static WasmCode* GetTargetCode(WasmCodeManager* code_manager,
|
static WasmCode* GetTargetCode(Isolate* isolate, Address target) {
|
||||||
Address target) {
|
WasmCodeManager* code_manager = isolate->wasm_engine()->code_manager();
|
||||||
NativeModule* native_module = code_manager->LookupNativeModule(target);
|
NativeModule* native_module = code_manager->LookupNativeModule(target);
|
||||||
if (native_module->is_jump_table_slot(target)) {
|
if (native_module->is_jump_table_slot(target)) {
|
||||||
uint32_t func_index =
|
uint32_t func_index =
|
||||||
native_module->GetFunctionIndexFromJumpTableSlot(target);
|
native_module->GetFunctionIndexFromJumpTableSlot(target);
|
||||||
|
|
||||||
|
if (!native_module->HasCode(func_index)) {
|
||||||
|
bool success = CompileLazy(isolate, native_module, func_index);
|
||||||
|
if (!success) {
|
||||||
|
DCHECK(isolate->has_pending_exception());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return native_module->GetCode(func_index);
|
return native_module->GetCode(func_index);
|
||||||
}
|
}
|
||||||
WasmCode* code = native_module->Lookup(target);
|
WasmCode* code = native_module->Lookup(target);
|
||||||
@ -3631,8 +3641,12 @@ class ThreadImpl {
|
|||||||
|
|
||||||
ImportedFunctionEntry entry(instance_object_, function_index);
|
ImportedFunctionEntry entry(instance_object_, function_index);
|
||||||
Handle<Object> object_ref(entry.object_ref(), isolate_);
|
Handle<Object> object_ref(entry.object_ref(), isolate_);
|
||||||
WasmCode* code =
|
WasmCode* code = GetTargetCode(isolate_, entry.target());
|
||||||
GetTargetCode(isolate_->wasm_engine()->code_manager(), entry.target());
|
|
||||||
|
// In case a function's body is invalid and the function is lazily validated
|
||||||
|
// and compiled we may get an exception.
|
||||||
|
if (code == nullptr) return TryHandleException(isolate_);
|
||||||
|
|
||||||
FunctionSig* sig = module()->functions[function_index].sig;
|
FunctionSig* sig = module()->functions[function_index].sig;
|
||||||
return CallExternalWasmFunction(isolate_, object_ref, code, sig);
|
return CallExternalWasmFunction(isolate_, object_ref, code, sig);
|
||||||
}
|
}
|
||||||
@ -3661,8 +3675,11 @@ class ThreadImpl {
|
|||||||
HandleScope handle_scope(isolate_); // Avoid leaking handles.
|
HandleScope handle_scope(isolate_); // Avoid leaking handles.
|
||||||
FunctionSig* signature = module()->signatures[sig_index];
|
FunctionSig* signature = module()->signatures[sig_index];
|
||||||
Handle<Object> object_ref = handle(entry.object_ref(), isolate_);
|
Handle<Object> object_ref = handle(entry.object_ref(), isolate_);
|
||||||
WasmCode* code =
|
WasmCode* code = GetTargetCode(isolate_, entry.target());
|
||||||
GetTargetCode(isolate_->wasm_engine()->code_manager(), entry.target());
|
|
||||||
|
// In case a function's body is invalid and the function is lazily validated
|
||||||
|
// and compiled we may get an exception.
|
||||||
|
if (code == nullptr) return TryHandleException(isolate_);
|
||||||
|
|
||||||
if (!object_ref->IsWasmInstanceObject() || /* call to an import */
|
if (!object_ref->IsWasmInstanceObject() || /* call to an import */
|
||||||
!instance_object_.is_identical_to(object_ref) /* cross-instance */) {
|
!instance_object_.is_identical_to(object_ref) /* cross-instance */) {
|
||||||
|
113
test/mjsunit/wasm/compilation-hints-interpreter.js
Normal file
113
test/mjsunit/wasm/compilation-hints-interpreter.js
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// Copyright 2019 the V8 project authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be found
|
||||||
|
// in the LICENSE file.
|
||||||
|
|
||||||
|
// Flags: --experimental-wasm-compilation-hints --wasm-lazy-validation
|
||||||
|
|
||||||
|
load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||||
|
|
||||||
|
(function testInterpreterCallsLazyFunctionInOtherInstance() {
|
||||||
|
print(arguments.callee.name);
|
||||||
|
let builder0 = new WasmModuleBuilder();
|
||||||
|
builder0.addFunction("getX", kSig_i_v)
|
||||||
|
.addBody([kExprI32Const, 42])
|
||||||
|
.setCompilationHint(kCompilationHintStrategyLazy,
|
||||||
|
kCompilationHintTierBaseline,
|
||||||
|
kCompilationHintTierBaseline)
|
||||||
|
.exportFunc();
|
||||||
|
let builder1 = new WasmModuleBuilder();
|
||||||
|
builder1.addImport("otherModule", "getX", kSig_i_v);
|
||||||
|
builder1.addFunction("plusX", kSig_i_i)
|
||||||
|
.addBody([kExprCallFunction, 0,
|
||||||
|
kExprGetLocal, 0,
|
||||||
|
kExprI32Add])
|
||||||
|
.setCompilationHint(kCompilationHintStrategyLazy,
|
||||||
|
kCompilationHintTierInterpreter,
|
||||||
|
kCompilationHintTierInterpreter)
|
||||||
|
.exportFunc();
|
||||||
|
let instance0 = builder0.instantiate();
|
||||||
|
let instance1 = builder1.instantiate(
|
||||||
|
{otherModule: {getX: instance0.exports.getX}});
|
||||||
|
assertEquals(46, instance1.exports.plusX(4));
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function testInterpreterCallsLazyBadFunctionInOtherInstance() {
|
||||||
|
print(arguments.callee.name);
|
||||||
|
let builder0 = new WasmModuleBuilder();
|
||||||
|
builder0.addFunction("getX", kSig_i_v)
|
||||||
|
.addBody([kExprI64Const, 42])
|
||||||
|
.setCompilationHint(kCompilationHintStrategyLazy,
|
||||||
|
kCompilationHintTierBaseline,
|
||||||
|
kCompilationHintTierBaseline)
|
||||||
|
.exportFunc();
|
||||||
|
let builder1 = new WasmModuleBuilder();
|
||||||
|
builder1.addImport("otherModule", "getX", kSig_i_v);
|
||||||
|
builder1.addFunction("plusX", kSig_i_i)
|
||||||
|
.addBody([kExprCallFunction, 0,
|
||||||
|
kExprGetLocal, 0,
|
||||||
|
kExprI32Add])
|
||||||
|
.setCompilationHint(kCompilationHintStrategyLazy,
|
||||||
|
kCompilationHintTierInterpreter,
|
||||||
|
kCompilationHintTierInterpreter)
|
||||||
|
.exportFunc();
|
||||||
|
let instance0 = builder0.instantiate();
|
||||||
|
let instance1 = builder1.instantiate(
|
||||||
|
{otherModule: {getX: instance0.exports.getX}});
|
||||||
|
assertThrows(() => instance1.exports.plusX(4),
|
||||||
|
WebAssembly.CompileError,
|
||||||
|
"Compiling function #0:\"getX\" failed: type error in " +
|
||||||
|
"merge[0] (expected i32, got i64) @+57");
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function testInterpreterCallsLazyFunctionThroughIndirection() {
|
||||||
|
print(arguments.callee.name);
|
||||||
|
let builder = new WasmModuleBuilder();
|
||||||
|
let sig_i_ii = builder.addType(kSig_i_ii);
|
||||||
|
let add = builder.addFunction('add', sig_i_ii)
|
||||||
|
.addBody([kExprGetLocal, 0,
|
||||||
|
kExprGetLocal, 1,
|
||||||
|
kExprI32Add])
|
||||||
|
.setCompilationHint(kCompilationHintStrategyLazy,
|
||||||
|
kCompilationHintTierInterpreter,
|
||||||
|
kCompilationHintTierInterpreter);
|
||||||
|
builder.appendToTable([add.index]);
|
||||||
|
builder.addFunction('main', kSig_i_iii)
|
||||||
|
.addBody([// Call indirect #0 with args <#1, #2>.
|
||||||
|
kExprGetLocal, 1,
|
||||||
|
kExprGetLocal, 2,
|
||||||
|
kExprGetLocal, 0,
|
||||||
|
kExprCallIndirect, sig_i_ii, kTableZero])
|
||||||
|
.setCompilationHint(kCompilationHintStrategyLazy,
|
||||||
|
kCompilationHintTierInterpreter,
|
||||||
|
kCompilationHintTierInterpreter)
|
||||||
|
.exportFunc();
|
||||||
|
assertEquals(99, builder.instantiate().exports.main(0, 22, 77));
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function testInterpreterCallsLazyBadFunctionThroughIndirection() {
|
||||||
|
print(arguments.callee.name);
|
||||||
|
let builder = new WasmModuleBuilder();
|
||||||
|
let sig_i_ii = builder.addType(kSig_i_ii);
|
||||||
|
let add = builder.addFunction('add', sig_i_ii)
|
||||||
|
.addBody([kExprGetLocal, 0,
|
||||||
|
kExprGetLocal, 1,
|
||||||
|
kExprI64Add])
|
||||||
|
.setCompilationHint(kCompilationHintStrategyLazy,
|
||||||
|
kCompilationHintTierInterpreter,
|
||||||
|
kCompilationHintTierInterpreter);
|
||||||
|
builder.appendToTable([add.index]);
|
||||||
|
builder.addFunction('main', kSig_i_iii)
|
||||||
|
.addBody([// Call indirect #0 with args <#1, #2>.
|
||||||
|
kExprGetLocal, 1,
|
||||||
|
kExprGetLocal, 2,
|
||||||
|
kExprGetLocal, 0,
|
||||||
|
kExprCallIndirect, sig_i_ii, kTableZero])
|
||||||
|
.setCompilationHint(kCompilationHintStrategyLazy,
|
||||||
|
kCompilationHintTierInterpreter,
|
||||||
|
kCompilationHintTierInterpreter)
|
||||||
|
.exportFunc();
|
||||||
|
assertThrows(() => builder.instantiate().exports.main(0, 22, 77),
|
||||||
|
WebAssembly.CompileError,
|
||||||
|
"Compiling function #0:\"add\" failed: i64.add[1] expected " +
|
||||||
|
"type i64, found get_local of type i32 @+83");
|
||||||
|
})();
|
Loading…
Reference in New Issue
Block a user