Commit 6e5671e1 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[nojit] Embed InterpreterEntryTrampoline

This marks the InterpreterEntryTrampoline as isolate-independent. With
this change, all builtins are now embedded.

Slight changes were needed to how we deopt into the trampoline. We now
store the entry address within the Interpreter class instead of
embedding the builtin code target.

Bug: v8:7777
Change-Id: If781bf6f06cb2efbab1369ece757f04c343a1b38
Reviewed-on: https://chromium-review.googlesource.com/c/1337734Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57563}
parent ca38b84b
......@@ -924,9 +924,9 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// handler at the current bytecode offset.
Label do_dispatch;
__ bind(&do_dispatch);
__ mov(kInterpreterDispatchTableRegister,
Operand(ExternalReference::interpreter_dispatch_table_address(
masm->isolate())));
__ Move(
kInterpreterDispatchTableRegister,
ExternalReference::interpreter_dispatch_table_address(masm->isolate()));
__ ldrb(r4, MemOperand(kInterpreterBytecodeArrayRegister,
kInterpreterBytecodeOffsetRegister));
__ ldr(
......@@ -1088,8 +1088,10 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
masm->isolate()->heap()->interpreter_entry_return_pc_offset());
DCHECK_NE(interpreter_entry_return_pc_offset, Smi::kZero);
// If the SFI function_data is an InterpreterData, get the trampoline stored
// in it, otherwise get the trampoline from the builtins list.
// If the SFI function_data is an InterpreterData, the function will have a
// custom copy of the interpreter entry trampoline for profiling. If so,
// get the custom trampoline, otherwise grab the entry address of the global
// trampoline.
__ ldr(r2, MemOperand(fp, StandardFrameConstants::kFunctionOffset));
__ ldr(r2, FieldMemOperand(r2, JSFunction::kSharedFunctionInfoOffset));
__ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kFunctionDataOffset));
......@@ -1100,14 +1102,17 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
__ ldr(r2,
FieldMemOperand(r2, InterpreterData::kInterpreterTrampolineOffset));
__ add(r2, r2, Operand(Code::kHeaderSize - kHeapObjectTag));
__ b(&trampoline_loaded);
__ bind(&builtin_trampoline);
__ Move(r2, BUILTIN_CODE(masm->isolate(), InterpreterEntryTrampoline));
__ Move(r2, ExternalReference::
address_of_interpreter_entry_trampoline_instruction_start(
masm->isolate()));
__ ldr(r2, MemOperand(r2));
__ bind(&trampoline_loaded);
__ add(lr, r2, Operand(interpreter_entry_return_pc_offset->value() +
Code::kHeaderSize - kHeapObjectTag));
__ add(lr, r2, Operand(interpreter_entry_return_pc_offset->value()));
// Initialize the dispatch table register.
__ Move(
......
......@@ -1226,8 +1226,10 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
masm->isolate()->heap()->interpreter_entry_return_pc_offset());
DCHECK_NE(interpreter_entry_return_pc_offset, Smi::kZero);
// If the SFI function_data is an InterpreterData, get the trampoline stored
// in it, otherwise get the trampoline from the builtins list.
// If the SFI function_data is an InterpreterData, the function will have a
// custom copy of the interpreter entry trampoline for profiling. If so,
// get the custom trampoline, otherwise grab the entry address of the global
// trampoline.
__ Ldr(x1, MemOperand(fp, StandardFrameConstants::kFunctionOffset));
__ Ldr(x1, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
__ Ldr(x1, FieldMemOperand(x1, SharedFunctionInfo::kFunctionDataOffset));
......@@ -1238,14 +1240,17 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
__ Ldr(x1,
FieldMemOperand(x1, InterpreterData::kInterpreterTrampolineOffset));
__ Add(x1, x1, Operand(Code::kHeaderSize - kHeapObjectTag));
__ B(&trampoline_loaded);
__ Bind(&builtin_trampoline);
__ LoadObject(x1, BUILTIN_CODE(masm->isolate(), InterpreterEntryTrampoline));
__ Mov(x1, ExternalReference::
address_of_interpreter_entry_trampoline_instruction_start(
masm->isolate()));
__ Ldr(x1, MemOperand(x1));
__ Bind(&trampoline_loaded);
__ Add(lr, x1, Operand(interpreter_entry_return_pc_offset->value() +
Code::kHeaderSize - kHeapObjectTag));
__ Add(lr, x1, Operand(interpreter_entry_return_pc_offset->value()));
// Initialize the dispatch table register.
__ Mov(
......
......@@ -220,23 +220,6 @@ bool Builtins::IsIsolateIndependentBuiltin(const Code code) {
}
}
// static
bool Builtins::IsIsolateIndependent(int index) {
DCHECK(IsBuiltinId(index));
switch (index) {
// TODO(jgruber): InterpreterEnterBytecode calculates a pointer into the
// middle of InterpreterEntryTrampoline (see
// interpreter_entry_return_pc_offset). When the builtin is embedded, the
// pointer would need to be calculated at an offset from the embedded
// instruction stream (instead of the trampoline code object).
case kInterpreterEntryTrampoline:
return false;
default:
return true;
}
UNREACHABLE();
}
// static
bool Builtins::IsWasmRuntimeStub(int index) {
DCHECK(IsBuiltinId(index));
......
......@@ -123,9 +123,9 @@ class Builtins {
kNumberOfWideBytecodeHandlers ==
builtin_count);
// Helper methods used for testing isolate-independent builtins.
// TODO(jgruber,v8:6666): Remove once all builtins have been migrated.
static bool IsIsolateIndependent(int index);
// True, iff the given builtin contains no isolate-specific code and can be
// embedded into the binary.
static bool IsIsolateIndependent(int index) { return true; }
// Wasm runtime stubs are treated specially by wasm. To guarantee reachability
// through near jumps, their code is completely copied into a fresh off-heap
......
......@@ -1189,8 +1189,10 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
static constexpr Register scratch = ecx;
// If the SFI function_data is an InterpreterData, get the trampoline stored
// in it, otherwise get the trampoline from the builtins list.
// If the SFI function_data is an InterpreterData, the function will have a
// custom copy of the interpreter entry trampoline for profiling. If so,
// get the custom trampoline, otherwise grab the entry address of the global
// trampoline.
__ mov(scratch, Operand(ebp, StandardFrameConstants::kFunctionOffset));
__ mov(scratch, FieldOperand(scratch, JSFunction::kSharedFunctionInfoOffset));
__ mov(scratch,
......@@ -1201,15 +1203,20 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
__ mov(scratch,
FieldOperand(scratch, InterpreterData::kInterpreterTrampolineOffset));
__ add(scratch, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(&trampoline_loaded, Label::kNear);
__ bind(&builtin_trampoline);
__ Move(scratch, BUILTIN_CODE(masm->isolate(), InterpreterEntryTrampoline));
__ mov(scratch,
__ ExternalReferenceAsOperand(
ExternalReference::
address_of_interpreter_entry_trampoline_instruction_start(
masm->isolate()),
scratch));
__ bind(&trampoline_loaded);
__ Pop(eax);
__ add(scratch, Immediate(interpreter_entry_return_pc_offset->value() +
Code::kHeaderSize - kHeapObjectTag));
__ add(scratch, Immediate(interpreter_entry_return_pc_offset->value()));
__ push(scratch);
// Initialize the dispatch table register.
......
......@@ -1072,8 +1072,10 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
masm->isolate()->heap()->interpreter_entry_return_pc_offset());
DCHECK_NE(interpreter_entry_return_pc_offset, Smi::zero());
// If the SFI function_data is an InterpreterData, get the trampoline stored
// in it, otherwise get the trampoline from the builtins list.
// If the SFI function_data is an InterpreterData, the function will have a
// custom copy of the interpreter entry trampoline for profiling. If so,
// get the custom trampoline, otherwise grab the entry address of the global
// trampoline.
__ lw(t0, MemOperand(fp, StandardFrameConstants::kFunctionOffset));
__ lw(t0, FieldMemOperand(t0, JSFunction::kSharedFunctionInfoOffset));
__ lw(t0, FieldMemOperand(t0, SharedFunctionInfo::kFunctionDataOffset));
......@@ -1083,14 +1085,17 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
Operand(INTERPRETER_DATA_TYPE));
__ lw(t0, FieldMemOperand(t0, InterpreterData::kInterpreterTrampolineOffset));
__ Addu(t0, t0, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Branch(&trampoline_loaded);
__ bind(&builtin_trampoline);
__ li(t0, BUILTIN_CODE(masm->isolate(), InterpreterEntryTrampoline));
__ li(t0, ExternalReference::
address_of_interpreter_entry_trampoline_instruction_start(
masm->isolate()));
__ lw(t0, MemOperand(t0));
__ bind(&trampoline_loaded);
__ Addu(ra, t0, Operand(interpreter_entry_return_pc_offset->value() +
Code::kHeaderSize - kHeapObjectTag));
__ Addu(ra, t0, Operand(interpreter_entry_return_pc_offset->value()));
// Initialize the dispatch table register.
__ li(kInterpreterDispatchTableRegister,
......
......@@ -1071,8 +1071,10 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
masm->isolate()->heap()->interpreter_entry_return_pc_offset());
DCHECK_NE(interpreter_entry_return_pc_offset, Smi::zero());
// If the SFI function_data is an InterpreterData, get the trampoline stored
// in it, otherwise get the trampoline from the builtins list.
// If the SFI function_data is an InterpreterData, the function will have a
// custom copy of the interpreter entry trampoline for profiling. If so,
// get the custom trampoline, otherwise grab the entry address of the global
// trampoline.
__ Ld(t0, MemOperand(fp, StandardFrameConstants::kFunctionOffset));
__ Ld(t0, FieldMemOperand(t0, JSFunction::kSharedFunctionInfoOffset));
__ Ld(t0, FieldMemOperand(t0, SharedFunctionInfo::kFunctionDataOffset));
......@@ -1082,14 +1084,17 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
Operand(INTERPRETER_DATA_TYPE));
__ Ld(t0, FieldMemOperand(t0, InterpreterData::kInterpreterTrampolineOffset));
__ Daddu(t0, t0, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Branch(&trampoline_loaded);
__ bind(&builtin_trampoline);
__ li(t0, BUILTIN_CODE(masm->isolate(), InterpreterEntryTrampoline));
__ li(t0, ExternalReference::
address_of_interpreter_entry_trampoline_instruction_start(
masm->isolate()));
__ Ld(t0, MemOperand(t0));
__ bind(&trampoline_loaded);
__ Daddu(ra, t0, Operand(interpreter_entry_return_pc_offset->value() +
Code::kHeaderSize - kHeapObjectTag));
__ Daddu(ra, t0, Operand(interpreter_entry_return_pc_offset->value()));
// Initialize the dispatch table register.
__ li(kInterpreterDispatchTableRegister,
......
......@@ -1119,8 +1119,10 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
masm->isolate()->heap()->interpreter_entry_return_pc_offset());
DCHECK_NE(interpreter_entry_return_pc_offset, Smi::zero());
// If the SFI function_data is an InterpreterData, get the trampoline stored
// in it, otherwise get the trampoline from the builtins list.
// If the SFI function_data is an InterpreterData, the function will have a
// custom copy of the interpreter entry trampoline for profiling. If so,
// get the custom trampoline, otherwise grab the entry address of the global
// trampoline.
__ LoadP(r5, MemOperand(fp, StandardFrameConstants::kFunctionOffset));
__ LoadP(r5, FieldMemOperand(r5, JSFunction::kSharedFunctionInfoOffset));
__ LoadP(r5, FieldMemOperand(r5, SharedFunctionInfo::kFunctionDataOffset));
......@@ -1131,14 +1133,17 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
__ LoadP(r5,
FieldMemOperand(r5, InterpreterData::kInterpreterTrampolineOffset));
__ addi(r5, r5, Operand(Code::kHeaderSize - kHeapObjectTag));
__ b(&trampoline_loaded);
__ bind(&builtin_trampoline);
__ Move(r5, BUILTIN_CODE(masm->isolate(), InterpreterEntryTrampoline));
__ Move(r5, ExternalReference::
address_of_interpreter_entry_trampoline_instruction_start(
masm->isolate()));
__ LoadP(r5, MemOperand(r5));
__ bind(&trampoline_loaded);
__ addi(r0, r5, Operand(interpreter_entry_return_pc_offset->value() +
Code::kHeaderSize - kHeapObjectTag));
__ addi(r0, r5, Operand(interpreter_entry_return_pc_offset->value()));
__ mtlr(r0);
// Initialize the dispatch table register.
......
......@@ -1124,8 +1124,10 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
masm->isolate()->heap()->interpreter_entry_return_pc_offset());
DCHECK_NE(interpreter_entry_return_pc_offset, Smi::zero());
// If the SFI function_data is an InterpreterData, get the trampoline stored
// in it, otherwise get the trampoline from the builtins list.
// If the SFI function_data is an InterpreterData, the function will have a
// custom copy of the interpreter entry trampoline for profiling. If so,
// get the custom trampoline, otherwise grab the entry address of the global
// trampoline.
__ LoadP(r4, MemOperand(fp, StandardFrameConstants::kFunctionOffset));
__ LoadP(r4, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
__ LoadP(r4, FieldMemOperand(r4, SharedFunctionInfo::kFunctionDataOffset));
......@@ -1136,14 +1138,17 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
__ LoadP(r4,
FieldMemOperand(r4, InterpreterData::kInterpreterTrampolineOffset));
__ AddP(r4, r4, Operand(Code::kHeaderSize - kHeapObjectTag));
__ b(&trampoline_loaded);
__ bind(&builtin_trampoline);
__ Move(r4, BUILTIN_CODE(masm->isolate(), InterpreterEntryTrampoline));
__ Move(r4, ExternalReference::
address_of_interpreter_entry_trampoline_instruction_start(
masm->isolate()));
__ LoadP(r4, MemOperand(r4));
__ bind(&trampoline_loaded);
__ AddP(r14, r4, Operand(interpreter_entry_return_pc_offset->value() +
Code::kHeaderSize - kHeapObjectTag));
__ AddP(r14, r4, Operand(interpreter_entry_return_pc_offset->value()));
// Initialize the dispatch table register.
__ Move(
......
......@@ -1146,8 +1146,10 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
masm->isolate()->heap()->interpreter_entry_return_pc_offset());
DCHECK_NE(interpreter_entry_return_pc_offset, Smi::kZero);
// If the SFI function_data is an InterpreterData, get the trampoline stored
// in it, otherwise get the trampoline from the builtins list.
// If the SFI function_data is an InterpreterData, the function will have a
// custom copy of the interpreter entry trampoline for profiling. If so,
// get the custom trampoline, otherwise grab the entry address of the global
// trampoline.
__ movp(rbx, Operand(rbp, StandardFrameConstants::kFunctionOffset));
__ movp(rbx, FieldOperand(rbx, JSFunction::kSharedFunctionInfoOffset));
__ movp(rbx, FieldOperand(rbx, SharedFunctionInfo::kFunctionDataOffset));
......@@ -1156,14 +1158,19 @@ static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) {
__ movp(rbx,
FieldOperand(rbx, InterpreterData::kInterpreterTrampolineOffset));
__ addp(rbx, Immediate(Code::kHeaderSize - kHeapObjectTag));
__ jmp(&trampoline_loaded, Label::kNear);
__ bind(&builtin_trampoline);
__ Move(rbx, BUILTIN_CODE(masm->isolate(), InterpreterEntryTrampoline));
__ movp(rbx,
__ ExternalReferenceAsOperand(
ExternalReference::
address_of_interpreter_entry_trampoline_instruction_start(
masm->isolate()),
kScratchRegister));
__ bind(&trampoline_loaded);
__ addp(rbx, Immediate(interpreter_entry_return_pc_offset->value() +
Code::kHeaderSize - kHeapObjectTag));
__ addp(rbx, Immediate(interpreter_entry_return_pc_offset->value()));
__ Push(rbx);
// Initialize dispatch table register.
......
......@@ -146,6 +146,14 @@ ExternalReference ExternalReference::interpreter_dispatch_counters(
isolate->interpreter()->bytecode_dispatch_counters_table());
}
ExternalReference
ExternalReference::address_of_interpreter_entry_trampoline_instruction_start(
Isolate* isolate) {
return ExternalReference(
isolate->interpreter()
->address_of_interpreter_entry_trampoline_instruction_start());
}
ExternalReference ExternalReference::bytecode_size_table_address() {
return ExternalReference(
interpreter::Bytecodes::bytecode_size_table_address());
......
......@@ -27,6 +27,8 @@ class StatsCounter;
V(builtins_address, "builtins") \
V(handle_scope_implementer_address, \
"Isolate::handle_scope_implementer_address") \
V(address_of_interpreter_entry_trampoline_instruction_start, \
"Address of the InterpreterEntryTrampoline instruction start") \
V(interpreter_dispatch_counters, "Interpreter::dispatch_counters") \
V(interpreter_dispatch_table_address, "Interpreter::dispatch_table_address") \
V(date_cache_stamp, "date_cache_stamp") \
......
......@@ -50,7 +50,9 @@ class InterpreterCompilationJob final : public UnoptimizedCompilationJob {
DISALLOW_COPY_AND_ASSIGN(InterpreterCompilationJob);
};
Interpreter::Interpreter(Isolate* isolate) : isolate_(isolate) {
Interpreter::Interpreter(Isolate* isolate)
: isolate_(isolate),
interpreter_entry_trampoline_instruction_start_(kNullAddress) {
memset(dispatch_table_, 0, sizeof(dispatch_table_));
if (FLAG_trace_ignition_dispatches) {
......@@ -251,8 +253,17 @@ void Interpreter::ForEachBytecode(
}
}
void Interpreter::InitializeDispatchTable() {
void Interpreter::Initialize() {
Builtins* builtins = isolate_->builtins();
// Set the interpreter entry trampoline entry point now that builtins are
// initialized.
Handle<Code> code = BUILTIN_CODE(isolate_, InterpreterEntryTrampoline);
DCHECK(builtins->is_initialized());
DCHECK(code->is_off_heap_trampoline() || Heap::IsImmovable(*code));
interpreter_entry_trampoline_instruction_start_ = code->InstructionStart();
// Initialize the dispatch table.
Code illegal = builtins->builtin(Builtins::kIllegalHandler);
int builtin_id = Builtins::kFirstBytecodeHandler;
ForEachBytecode([=, &builtin_id](Bytecode bytecode,
......
......@@ -66,7 +66,7 @@ class Interpreter {
void ForEachBytecode(const std::function<void(Bytecode, OperandScale)>& f);
void InitializeDispatchTable();
void Initialize();
bool IsDispatchTableInitialized() const;
......@@ -78,6 +78,11 @@ class Interpreter {
return reinterpret_cast<Address>(bytecode_dispatch_counters_table_.get());
}
Address address_of_interpreter_entry_trampoline_instruction_start() const {
return reinterpret_cast<Address>(
&interpreter_entry_trampoline_instruction_start_);
}
private:
friend class SetupInterpreter;
friend class v8::internal::SetupIsolateDelegate;
......@@ -95,6 +100,7 @@ class Interpreter {
Isolate* isolate_;
Address dispatch_table_[kDispatchTableSize];
std::unique_ptr<uintptr_t[]> bytecode_dispatch_counters_table_;
Address interpreter_entry_trampoline_instruction_start_;
DISALLOW_COPY_AND_ASSIGN(Interpreter);
};
......
......@@ -3328,7 +3328,7 @@ bool Isolate::Init(StartupDeserializer* des) {
if (!create_heap_objects) des->DeserializeInto(this);
load_stub_cache_->Initialize();
store_stub_cache_->Initialize();
interpreter_->InitializeDispatchTable();
interpreter_->Initialize();
heap_.NotifyDeserializationComplete();
}
delete setup_delegate_;
......
......@@ -5001,8 +5001,7 @@ TEST(InterpreterWithNativeStack) {
CHECK(code->IsCode());
CHECK(code->is_interpreter_trampoline_builtin());
CHECK_NE(code->InstructionStart(),
interpreter_entry_trampoline->InstructionStart());
CHECK_NE(code->address(), interpreter_entry_trampoline->address());
}
TEST(InterpreterGetBytecodeHandler) {
......
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