Commit 30d6b245 authored by Milad Fa's avatar Milad Fa Committed by V8 LUCI CQ

PPC/s390: [ext-code-space] Add InterpreterEntryTrampolineForProfiling builtin

Port 1067c6ac

Original Commit Message:

    ... - a code range size agnostic version of InterpreterEntryTrampoline
    builtin. The new builtin is fully compatible with the default version
    and used as a template for creating interpreter entry trampoline
    Code objects when --interpreted-frames-native-stack is enabled.

    This CL introduces a new assembler option "position_independent_code"
    which affects the way builtin calls are generated.
    This mode is enabled only for InterpreterEntryTrampolineForProfiling.

    Motivation:

    * InterpreterEntryTrampoline uses RelocInfo::CODE_TARGET for calling
      other builtins which requires the code range to be small enough to
      allow PC-relative jumps/calls between Code objects. This is the
      reason why --interpreted-frames-native-stack was not supported on
      arm and might not work on arm64 because the code range is bigger
      than the max PC-relative distance for call/jump instructions.
      The new builtin calls other builtins via builtins entry table which
      makes the code fully relocatable and usable for any code range size.

    * RelocInfo::CODE_TARGET requires a target code to be materialized
      as a Code object which contradicts the Code-less builtins goal.

    * The --interpreted-frames-native-stack is rarely used in the wild but
      we have to pay the price of deserializing InterpreterEntryTrampoline
      builtin as a Code object which consumes address space in the code
      range and thus limits the number of V8 isolates that can be created
      because of code range exhaustion. Now the pointer compression cage
      becomes the limiting factor instead of the code range.

    * We can remove complicated logic of Factory::CopyCode() and respective
      support on GC side.

R=ishell@chromium.org, joransiu@ca.ibm.com, junyan@redhat.com, midawson@redhat.com
BUG=
LOG=N

Change-Id: I2ed5edbffc5c33717f4becf8370369f7a4d000fb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3816765Reviewed-by: 's avatarJunliang Yan <junyan@redhat.com>
Commit-Queue: Milad Farazmand <mfarazma@redhat.com>
Cr-Commit-Position: refs/heads/main@{#82317}
parent 9e2b4aee
......@@ -169,11 +169,9 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
if (root_array_available_ && options().isolate_independent_code) {
Label skip;
Register scratch = ip;
int offset = IsolateData::BuiltinEntrySlotOffset(code->builtin_id());
LoadU64(scratch, MemOperand(kRootRegister, offset), r0);
LoadU64(ip, EntryFromBuiltinAsOperand(code->builtin_id()), r0);
if (cond != al) b(NegateCondition(cond), &skip, cr);
Jump(scratch);
Jump(ip);
bind(&skip);
return;
} else if (options().inline_offheap_trampolines && target_is_builtin) {
......@@ -253,10 +251,10 @@ void TurboAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
bool target_is_builtin =
isolate()->builtins()->IsBuiltinHandle(code, &builtin);
if (root_array_available_ && options().isolate_independent_code) {
if ((target_is_builtin && options().builtin_calls_as_table_load) ||
(root_array_available_ && options().isolate_independent_code)) {
Label skip;
int offset = IsolateData::BuiltinEntrySlotOffset(code->builtin_id());
LoadU64(ip, MemOperand(kRootRegister, offset));
LoadU64(ip, EntryFromBuiltinAsOperand(builtin));
if (cond != al) b(NegateCondition(cond), &skip);
Call(ip);
bind(&skip);
......@@ -273,10 +271,13 @@ void TurboAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
void TurboAssembler::CallBuiltin(Builtin builtin, Condition cond) {
ASM_CODE_COMMENT_STRING(this, CommentForOffHeapTrampoline("call", builtin));
DCHECK(Builtins::IsBuiltinId(builtin));
// Use ip directly instead of using UseScratchRegisterScope, as we do not
// preserve scratch registers across calls.
mov(ip, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
if (options().builtin_calls_as_table_load) {
LoadEntryFromBuiltin(builtin, ip);
} else {
mov(ip, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
}
Label skip;
if (cond != al) b(NegateCondition(cond), &skip);
Call(ip);
......@@ -286,7 +287,11 @@ void TurboAssembler::CallBuiltin(Builtin builtin, Condition cond) {
void TurboAssembler::TailCallBuiltin(Builtin builtin) {
ASM_CODE_COMMENT_STRING(this,
CommentForOffHeapTrampoline("tail call", builtin));
mov(ip, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
if (options().builtin_calls_as_table_load) {
LoadEntryFromBuiltin(builtin, ip);
} else {
mov(ip, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
}
Jump(ip);
}
......@@ -772,12 +777,12 @@ void TurboAssembler::CallRecordWriteStub(Register object, Register slot_address,
#endif
} else {
auto builtin_index = Builtins::GetRecordWriteStub(fp_mode);
if (options().inline_offheap_trampolines) {
if (options().inline_offheap_trampolines ||
options().builtin_calls_as_table_load) {
RecordCommentForOffHeapTrampoline(builtin_index);
// Use ip directly instead of using UseScratchRegisterScope, as we do
// not preserve scratch registers across calls.
mov(ip, Operand(BuiltinEntry(builtin_index), RelocInfo::OFF_HEAP_TARGET));
Call(ip);
CallBuiltin(builtin_index, al);
} else {
Handle<Code> code_target =
isolate()->builtins()->code_handle(builtin_index);
......@@ -2096,14 +2101,20 @@ void TurboAssembler::Abort(AbortReason reason) {
LoadSmiLiteral(r4, Smi::FromInt(static_cast<int>(reason)));
// Disable stub call restrictions to always allow calls to abort.
if (!has_frame_) {
{
// We don't actually want to generate a pile of code for this, so just
// claim there is a stack frame, without generating one.
FrameScope scope(this, StackFrame::NO_FRAME_TYPE);
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
} else {
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
if (root_array_available()) {
// Generate an indirect call via builtins entry table here in order to
// ensure that the interpreter_entry_return_pc_offset is the same for
// InterpreterEntryTrampoline and InterpreterEntryTrampolineForProfiling
// when FLAG_debug_code is enabled.
LoadEntryFromBuiltin(Builtin::kAbort, ip);
Call(ip);
} else {
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
}
}
// will not return here
}
......
......@@ -394,13 +394,17 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
bool target_is_builtin =
isolate()->builtins()->IsBuiltinHandle(code, &builtin);
if (options().inline_offheap_trampolines && target_is_builtin) {
if ((options().inline_offheap_trampolines ||
options().builtin_calls_as_table_load) &&
target_is_builtin) {
// Inline the trampoline.
RecordCommentForOffHeapTrampoline(builtin);
mov(ip, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
b(cond, ip);
return;
}
DCHECK(RelocInfo::IsCodeTarget(rmode));
DCHECK(!options().builtin_calls_as_table_load);
jump(code, RelocInfo::RELATIVE_CODE_TARGET, cond);
}
......@@ -452,28 +456,38 @@ void TurboAssembler::Call(Handle<Code> code, RelocInfo::Mode rmode,
bool target_is_builtin =
isolate()->builtins()->IsBuiltinHandle(code, &builtin);
if (target_is_builtin && options().inline_offheap_trampolines) {
if (target_is_builtin && (options().inline_offheap_trampolines ||
options().builtin_calls_as_table_load)) {
// Inline the trampoline.
CallBuiltin(builtin);
return;
}
DCHECK(code->IsExecutable());
DCHECK(RelocInfo::IsCodeTarget(rmode));
DCHECK(!options().builtin_calls_as_table_load);
call(code, rmode);
}
void TurboAssembler::CallBuiltin(Builtin builtin) {
ASM_CODE_COMMENT_STRING(this, CommentForOffHeapTrampoline("call", builtin));
DCHECK(Builtins::IsBuiltinId(builtin));
// Use ip directly instead of using UseScratchRegisterScope, as we do not
// preserve scratch registers across calls.
mov(ip, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
if (options().builtin_calls_as_table_load) {
LoadEntryFromBuiltin(builtin, ip);
} else {
mov(ip, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
}
Call(ip);
}
void TurboAssembler::TailCallBuiltin(Builtin builtin) {
ASM_CODE_COMMENT_STRING(this,
CommentForOffHeapTrampoline("tail call", builtin));
mov(ip, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
if (options().builtin_calls_as_table_load) {
LoadEntryFromBuiltin(builtin, ip);
} else {
mov(ip, Operand(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET));
}
b(ip);
}
......@@ -1008,10 +1022,10 @@ void TurboAssembler::CallRecordWriteStub(Register object, Register slot_address,
#endif
} else {
auto builtin_index = Builtins::GetRecordWriteStub(fp_mode);
if (options().inline_offheap_trampolines) {
if (options().inline_offheap_trampolines ||
options().builtin_calls_as_table_load) {
RecordCommentForOffHeapTrampoline(builtin_index);
mov(ip, Operand(BuiltinEntry(builtin_index), RelocInfo::OFF_HEAP_TARGET));
Call(ip);
CallBuiltin(builtin_index);
} else {
Handle<Code> code_target =
isolate()->builtins()->code_handle(builtin_index);
......@@ -2094,14 +2108,20 @@ void TurboAssembler::Abort(AbortReason reason) {
LoadSmiLiteral(r3, Smi::FromInt(static_cast<int>(reason)));
// Disable stub call restrictions to always allow calls to abort.
if (!has_frame_) {
{
// We don't actually want to generate a pile of code for this, so just
// claim there is a stack frame, without generating one.
FrameScope scope(this, StackFrame::NO_FRAME_TYPE);
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
} else {
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
if (root_array_available()) {
// Generate an indirect call via builtins entry table here in order to
// ensure that the interpreter_entry_return_pc_offset is the same for
// InterpreterEntryTrampoline and InterpreterEntryTrampolineForProfiling
// when FLAG_debug_code is enabled.
LoadEntryFromBuiltin(Builtin::kAbort, ip);
Call(ip);
} else {
Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET);
}
}
// will not return here
}
......
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