[wasm] Preserve interpreter entry even on tier-up.
This makes sure that a tier-up from Ignition to TurboFan (or any other code publishing) preserves redirections to the Interpreter. Currently an interpreted function never switches back to compiled. R=titzer@chromium.org TEST=mjsunit/wasm/interpreter-mixed BUG=v8:7921,v8:8018 Change-Id: Ifca479953509708c998c11cc00b481c232678e00 Reviewed-on: https://chromium-review.googlesource.com/1179661 Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Ben Titzer <titzer@chromium.org> Cr-Commit-Position: refs/heads/master@{#55195}
This commit is contained in:
parent
606fcce2ac
commit
2b89727539
@ -1020,7 +1020,7 @@ RUNTIME_FUNCTION(Runtime_RedirectToWasmInterpreter) {
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_WasmTraceMemory) {
|
||||
HandleScope hs(isolate);
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
CONVERT_ARG_CHECKED(Smi, info_addr, 0);
|
||||
|
||||
@ -1048,8 +1048,21 @@ RUNTIME_FUNCTION(Runtime_WasmTraceMemory) {
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_WasmTierUpFunction) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(2, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(WasmInstanceObject, instance, 0);
|
||||
CONVERT_SMI_ARG_CHECKED(function_index, 1);
|
||||
if (!isolate->wasm_engine()->CompileFunction(
|
||||
isolate, instance->module_object()->native_module(), function_index,
|
||||
wasm::WasmEngine::kOptimizedTier)) {
|
||||
return ReadOnlyRoots(isolate).exception();
|
||||
}
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_IsLiftoffFunction) {
|
||||
HandleScope shs(isolate);
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
|
||||
CHECK(WasmExportedFunction::IsWasmExportedFunction(*function));
|
||||
|
@ -522,6 +522,7 @@ namespace internal {
|
||||
F(InNewSpace, 1, 1) \
|
||||
F(IsAsmWasmCode, 1, 1) \
|
||||
F(IsConcurrentRecompilationSupported, 0, 1) \
|
||||
F(WasmTierUpFunction, 2, 1) \
|
||||
F(IsLiftoffFunction, 1, 1) \
|
||||
F(IsWasmCode, 1, 1) \
|
||||
F(IsWasmTrapHandlerEnabled, 0, 1) \
|
||||
|
@ -408,7 +408,9 @@ WasmCode* NativeModule::AddCodeCopy(Handle<Code> code, WasmCode::Kind kind,
|
||||
WasmCode* NativeModule::AddInterpreterEntry(Handle<Code> code, uint32_t index) {
|
||||
WasmCode* ret = AddAnonymousCode(code, WasmCode::kInterpreterEntry);
|
||||
ret->index_ = Just(index);
|
||||
base::LockGuard<base::Mutex> lock(&allocation_mutex_);
|
||||
PatchJumpTable(index, ret->instruction_start(), WasmCode::kFlushICache);
|
||||
set_code(index, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -572,9 +574,13 @@ WasmCode* NativeModule::AddDeserializedCode(
|
||||
}
|
||||
|
||||
void NativeModule::PublishCode(WasmCode* code) {
|
||||
// TODO(clemensh): Remove the need for locking here. Probably requires
|
||||
// word-aligning the jump table slots.
|
||||
base::LockGuard<base::Mutex> lock(&allocation_mutex_);
|
||||
// Skip publishing code if there is an active redirection to the interpreter
|
||||
// for the given function index, in order to preserve the redirection.
|
||||
if (has_code(code->index()) &&
|
||||
this->code(code->index())->kind() == WasmCode::kInterpreterEntry) {
|
||||
return;
|
||||
}
|
||||
if (!code->protected_instructions_.is_empty()) {
|
||||
code->RegisterTrapHandlerData();
|
||||
}
|
||||
|
@ -302,8 +302,6 @@ class V8_EXPORT_PRIVATE NativeModule final {
|
||||
return jump_table_->contains(address);
|
||||
}
|
||||
|
||||
uint32_t GetFunctionIndexFromJumpTableSlot(Address slot_address) const;
|
||||
|
||||
// Transition this module from code relying on trap handlers (i.e. without
|
||||
// explicit memory bounds checks) to code that does not require trap handlers
|
||||
// (i.e. code with explicit bounds checks).
|
||||
@ -316,6 +314,10 @@ class V8_EXPORT_PRIVATE NativeModule final {
|
||||
// slot within {jump_table_}).
|
||||
Address GetCallTargetForFunction(uint32_t func_index) const;
|
||||
|
||||
// Reverse lookup from a given call target (i.e. a jump table slot as the
|
||||
// above {GetCallTargetForFunction} returns) to a function index.
|
||||
uint32_t GetFunctionIndexFromJumpTableSlot(Address slot_address) const;
|
||||
|
||||
bool SetExecutable(bool executable);
|
||||
|
||||
// For cctests, where we build both WasmModule and the runtime objects
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "src/compilation-statistics.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/objects/js-promise.h"
|
||||
#include "src/wasm/function-compiler.h"
|
||||
#include "src/wasm/module-compiler.h"
|
||||
#include "src/wasm/module-decoder.h"
|
||||
#include "src/wasm/streaming-decoder.h"
|
||||
@ -167,6 +168,20 @@ std::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation(
|
||||
return job->CreateStreamingDecoder();
|
||||
}
|
||||
|
||||
bool WasmEngine::CompileFunction(Isolate* isolate, NativeModule* native_module,
|
||||
uint32_t function_index,
|
||||
CompilationTier tier) {
|
||||
ErrorThrower thrower(isolate, "Manually requested tier up");
|
||||
WasmCompilationUnit::CompilationMode mode =
|
||||
(tier == kBaselineTier) ? WasmCompilationUnit::CompilationMode::kLiftoff
|
||||
: WasmCompilationUnit::CompilationMode::kTurbofan;
|
||||
WasmCode* ret = WasmCompilationUnit::CompileWasmFunction(
|
||||
native_module, &thrower, isolate,
|
||||
GetModuleEnv(native_module->compilation_state()),
|
||||
&native_module->module()->functions[function_index], mode);
|
||||
return ret != nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<NativeModule> WasmEngine::ExportNativeModule(
|
||||
Handle<WasmModuleObject> module_object) {
|
||||
return module_object->managed_native_module()->get();
|
||||
|
@ -91,6 +91,13 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
||||
Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context,
|
||||
std::shared_ptr<CompilationResultResolver> resolver);
|
||||
|
||||
// Compiles the function with the given index at a specific compilation tier
|
||||
// and returns true on success, false (and pending exception) otherwise. This
|
||||
// is mostly used for testing to force a function into a specific tier.
|
||||
enum CompilationTier { kBaselineTier, kOptimizedTier };
|
||||
bool CompileFunction(Isolate* isolate, NativeModule* native_module,
|
||||
uint32_t function_index, CompilationTier tier);
|
||||
|
||||
// Exports the sharable parts of the given module object so that they can be
|
||||
// transferred to a different Context/Isolate using the same engine.
|
||||
std::shared_ptr<NativeModule> ExportNativeModule(
|
||||
|
@ -2318,6 +2318,7 @@ class ThreadImpl {
|
||||
uint32_t entry_index = Pop().to<uint32_t>();
|
||||
// Assume only one table for now.
|
||||
DCHECK_LE(module()->tables.size(), 1u);
|
||||
CommitPc(pc); // TODO(wasm): Be more disciplined about committing PC.
|
||||
ExternalCallResult result =
|
||||
CallIndirectFunction(0, entry_index, imm.sig_index);
|
||||
switch (result.type) {
|
||||
|
@ -193,3 +193,27 @@ function redirectToInterpreter(
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
(function testInterpreterPreservedOnTierUp() {
|
||||
print(arguments.callee.name);
|
||||
var builder = new WasmModuleBuilder();
|
||||
var fun_body = [kExprI32Const, 23];
|
||||
var fun = builder.addFunction('fun', kSig_i_v).addBody(fun_body).exportFunc();
|
||||
var instance = builder.instantiate();
|
||||
var exp = instance.exports;
|
||||
|
||||
// Initially the interpreter is not being called.
|
||||
var initial_interpreted = %WasmNumInterpretedCalls(instance);
|
||||
assertEquals(23, exp.fun());
|
||||
assertEquals(initial_interpreted + 0, %WasmNumInterpretedCalls(instance));
|
||||
|
||||
// Redirection will cause the interpreter to be called.
|
||||
%RedirectToWasmInterpreter(instance, fun.index);
|
||||
assertEquals(23, exp.fun());
|
||||
assertEquals(initial_interpreted + 1, %WasmNumInterpretedCalls(instance));
|
||||
|
||||
// Requesting a tier-up still ensure the interpreter is being called.
|
||||
%WasmTierUpFunction(instance, fun.index);
|
||||
assertEquals(23, exp.fun());
|
||||
assertEquals(initial_interpreted + 2, %WasmNumInterpretedCalls(instance));
|
||||
})();
|
||||
|
@ -310,7 +310,7 @@ function checkStack(stack, expected_lines) {
|
||||
if (!(e instanceof TypeError)) throw e;
|
||||
checkStack(stripPath(e.stack), [
|
||||
'TypeError: ' + kTrapMsgs[kTrapTypeError], // -
|
||||
' at indirect (wasm-function[2]:1)', // -
|
||||
' at indirect (wasm-function[2]:3)', // -
|
||||
' at main (wasm-function[3]:3)', // -
|
||||
/^ at testIllegalImports \(interpreter.js:\d+:22\)$/, // -
|
||||
/^ at interpreter.js:\d+:3$/
|
||||
|
Loading…
Reference in New Issue
Block a user