Commit 28705dfb authored by Frederik Gossen's avatar Frederik Gossen Committed by Commit Bot

[wasm-hints] Lazy Validation Flag

Add lazy validation for lazily compiled functions. The code is validated
only on first use. This applies to functions that are lazily compiled by
compilation hint as well as to entirely lazy modules.

Bug: v8:9003
Change-Id: If6a640db4bf4b846ac5e3805c138b8ac0a493cf9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1569427
Commit-Queue: Frederik Gossen <frgossen@google.com>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60921}
parent 47a69050
...@@ -670,12 +670,12 @@ DEFINE_BOOL(wasm_trap_handler, true, ...@@ -670,12 +670,12 @@ DEFINE_BOOL(wasm_trap_handler, true,
"use signal handlers to catch out of bounds memory access in wasm" "use signal handlers to catch out of bounds memory access in wasm"
" (currently Linux x86_64 only)") " (currently Linux x86_64 only)")
DEFINE_BOOL(wasm_fuzzer_gen_test, false, DEFINE_BOOL(wasm_fuzzer_gen_test, false,
"Generate a test case when running a wasm fuzzer") "generate a test case when running a wasm fuzzer")
DEFINE_IMPLICATION(wasm_fuzzer_gen_test, single_threaded) DEFINE_IMPLICATION(wasm_fuzzer_gen_test, single_threaded)
DEFINE_BOOL(print_wasm_code, false, "Print WebAssembly code") DEFINE_BOOL(print_wasm_code, false, "Print WebAssembly code")
DEFINE_BOOL(print_wasm_stub_code, false, "Print WebAssembly stub code") DEFINE_BOOL(print_wasm_stub_code, false, "Print WebAssembly stub code")
DEFINE_BOOL(wasm_interpret_all, false, DEFINE_BOOL(wasm_interpret_all, false,
"Execute all wasm code in the wasm interpreter") "execute all wasm code in the wasm interpreter")
DEFINE_BOOL(asm_wasm_lazy_compilation, false, DEFINE_BOOL(asm_wasm_lazy_compilation, false,
"enable lazy compilation for asm-wasm modules") "enable lazy compilation for asm-wasm modules")
DEFINE_IMPLICATION(validate_asm, asm_wasm_lazy_compilation) DEFINE_IMPLICATION(validate_asm, asm_wasm_lazy_compilation)
...@@ -684,7 +684,9 @@ DEFINE_BOOL(wasm_lazy_compilation, false, ...@@ -684,7 +684,9 @@ DEFINE_BOOL(wasm_lazy_compilation, false,
DEFINE_DEBUG_BOOL(trace_wasm_lazy_compilation, false, DEFINE_DEBUG_BOOL(trace_wasm_lazy_compilation, false,
"trace lazy compilation of wasm functions") "trace lazy compilation of wasm functions")
DEFINE_BOOL(wasm_grow_shared_memory, false, DEFINE_BOOL(wasm_grow_shared_memory, false,
"Allow growing shared WebAssembly memory objects") "allow growing shared WebAssembly memory objects")
DEFINE_BOOL(wasm_lazy_validation, false,
"enable lazy validation for lazily compiled wasm functions")
// wasm-interpret-all resets {asm-,}wasm-lazy-compilation. // wasm-interpret-all resets {asm-,}wasm-lazy-compilation.
DEFINE_NEG_IMPLICATION(wasm_interpret_all, asm_wasm_lazy_compilation) DEFINE_NEG_IMPLICATION(wasm_interpret_all, asm_wasm_lazy_compilation)
DEFINE_NEG_IMPLICATION(wasm_interpret_all, wasm_lazy_compilation) DEFINE_NEG_IMPLICATION(wasm_interpret_all, wasm_lazy_compilation)
......
...@@ -1698,6 +1698,16 @@ Object Isolate::UnwindAndFindHandler() { ...@@ -1698,6 +1698,16 @@ Object Isolate::UnwindAndFindHandler() {
wasm_code->constant_pool(), return_sp, frame->fp()); wasm_code->constant_pool(), return_sp, frame->fp());
} }
case StackFrame::WASM_COMPILE_LAZY: {
// Can only fail directly on invocation. This happens if an invalid
// function was validated lazily.
DCHECK_IMPLIES(trap_handler::IsTrapHandlerEnabled(),
trap_handler::IsThreadInWasm());
DCHECK(FLAG_wasm_lazy_validation);
trap_handler::ClearThreadInWasm();
break;
}
case StackFrame::OPTIMIZED: { case StackFrame::OPTIMIZED: {
// For optimized frames we perform a lookup in the handler table. // For optimized frames we perform a lookup in the handler table.
if (!catchable_by_js) break; if (!catchable_by_js) break;
......
...@@ -310,7 +310,8 @@ RUNTIME_FUNCTION(Runtime_WasmCompileLazy) { ...@@ -310,7 +310,8 @@ RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0); CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
CONVERT_SMI_ARG_CHECKED(func_index, 1); CONVERT_SMI_ARG_CHECKED(func_index, 1);
ClearThreadInWasmScope wasm_flag; // This runtime function is always called from wasm code.
ClearThreadInWasmScope flag_scope;
#ifdef DEBUG #ifdef DEBUG
StackFrameIterator it(isolate, isolate->thread_local_top()); StackFrameIterator it(isolate, isolate->thread_local_top());
...@@ -322,10 +323,17 @@ RUNTIME_FUNCTION(Runtime_WasmCompileLazy) { ...@@ -322,10 +323,17 @@ RUNTIME_FUNCTION(Runtime_WasmCompileLazy) {
DCHECK_EQ(*instance, WasmCompileLazyFrame::cast(it.frame())->wasm_instance()); DCHECK_EQ(*instance, WasmCompileLazyFrame::cast(it.frame())->wasm_instance());
#endif #endif
DCHECK(isolate->context().is_null());
isolate->set_context(instance->native_context());
auto* native_module = instance->module_object()->native_module(); auto* native_module = instance->module_object()->native_module();
wasm::CompileLazy(isolate, native_module, func_index); bool success = wasm::CompileLazy(isolate, native_module, func_index);
if (!success) {
DCHECK(isolate->has_pending_exception());
return ReadOnlyRoots(isolate).exception();
}
Address entrypoint = native_module->GetCallTargetForFunction(func_index); Address entrypoint = native_module->GetCallTargetForFunction(func_index);
return Object(entrypoint); return Object(entrypoint);
} }
......
This diff is collapsed.
...@@ -50,8 +50,10 @@ V8_EXPORT_PRIVATE Handle<Script> CreateWasmScript( ...@@ -50,8 +50,10 @@ V8_EXPORT_PRIVATE Handle<Script> CreateWasmScript(
Isolate* isolate, const ModuleWireBytes& wire_bytes, Isolate* isolate, const ModuleWireBytes& wire_bytes,
const std::string& source_map_url); const std::string& source_map_url);
// Triggered by the WasmCompileLazy builtin. // Triggered by the WasmCompileLazy builtin. The return value indicates whether
void CompileLazy(Isolate*, NativeModule*, uint32_t func_index); // compilation was successful. Lazy compilation can fail only if validation is
// also lazy.
bool CompileLazy(Isolate*, NativeModule*, uint32_t func_index);
// Encapsulates all the state and steps of an asynchronous compilation. // Encapsulates all the state and steps of an asynchronous compilation.
// An asynchronous compile job consists of a number of tasks that are executed // An asynchronous compile job consists of a number of tasks that are executed
......
// 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 testInstantiateLazyValidation() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addFunction('id', kSig_i_i)
.addBody([kExprGetLocal, 0,
kExprI64Const, 1,
kExprI32Mul])
.setCompilationHint(kCompilationHintStrategyLazy,
kCompilationHintTierBaseline,
kCompilationHintTierBaseline)
.exportFunc();
let expected_error_msg = "Compiling function #0:\"id\" failed: i32.mul[1] " +
"expected type i32, found i64.const of type i64 " +
"@+56";
let assertCompileErrorOnInvocation = function(instance) {
assertThrows(() => instance.exports.id(3),
WebAssembly.CompileError,
expected_error_msg)
};
// Synchronous case.
let instance = builder.instantiate();
assertCompileErrorOnInvocation(instance);
// Asynchronous case.
let bytes = builder.toBuffer();
assertPromiseResult(WebAssembly.instantiate(bytes)
.then(p => assertCompileErrorOnInvocation(p.instance)));
})();
// 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-test-streaming --wasm-lazy-validation
load('test/mjsunit/wasm/wasm-module-builder.js');
(function testInstantiateStreamingLazyValidation() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addFunction('id', kSig_i_i)
.addBody([kExprGetLocal, 0,
kExprI64Const, 1,
kExprI32Mul])
.setCompilationHint(kCompilationHintStrategyLazy,
kCompilationHintTierDefault,
kCompilationHintTierDefault)
.exportFunc();
let expected_error_msg = "Compiling function #0:\"id\" failed: i32.mul[1] " +
"expected type i32, found i64.const of type i64 " +
"@+56";
let assertCompileErrorOnInvocation = function(instance) {
assertThrows(() => instance.exports.id(3),
WebAssembly.CompileError,
expected_error_msg)
};
let bytes = builder.toBuffer();
assertPromiseResult(WebAssembly.instantiateStreaming(Promise.resolve(bytes))
.then(({module, instance}) => assertCompileErrorOnInvocation(instance)));
})();
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