PPC/s390: [builtins] Convert CEntry/GetProperty/StringAdd stubs to builtins

Port d8131cd63a

Original Commit Message:

    Stubs and builtins are very similar. The main differences are that
    stubs can be parameterized and may be generated at runtime, whereas
    builtins are generated at mksnapshot-time and shipped with the snapshot
    (or embedded into the binary).

    My main motivation for these conversions is that we can generate
    faster calls and jumps to (embedded) builtins callees from (embedded)
    builtin callers. Instead of going through the builtins constants table
    indirection, we can simply do a pc-relative call/jump.

    This also unlocks other refactorings, e.g. removal of
    CallRuntimeDelayed.

R=jgruber@chromium.org, joransiu@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=
LOG=N

Change-Id: I193e4275470d492912a7d0f8523c3b8c29f1b146
Reviewed-on: https://chromium-review.googlesource.com/1050732
Commit-Queue: Junliang Yan <jyan@ca.ibm.com>
Reviewed-by: Joran Siu <joransiu@ca.ibm.com>
Cr-Commit-Position: refs/heads/master@{#53081}
This commit is contained in:
Junliang Yan 2018-05-08 17:12:18 -04:00 committed by Commit Bot
parent e084eea628
commit 7ff35bd542
8 changed files with 419 additions and 451 deletions

View File

@ -5,6 +5,7 @@
#if V8_TARGET_ARCH_PPC
#include "src/assembler-inl.h"
#include "src/code-factory.h"
#include "src/code-stubs.h"
#include "src/debug/debug.h"
#include "src/deoptimizer.h"
@ -52,7 +53,7 @@ void AdaptorWithExitFrameType(MacroAssembler* masm,
// ordinary functions).
__ LoadP(cp, FieldMemOperand(r4, JSFunction::kContextOffset));
// CEntryStub expects r3 to contain the number of arguments including the
// CEntry expects r3 to contain the number of arguments including the
// receiver and the extra arguments.
__ addi(r3, r3,
Operand(BuiltinExitFrameConstants::kNumExtraArgsWithReceiver));
@ -67,9 +68,10 @@ void AdaptorWithExitFrameType(MacroAssembler* masm,
// JumpToExternalReference. We have already loaded entry point to r15
// in Generate_adaptor.
__ mr(r4, r15);
CEntryStub stub(masm->isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
exit_frame_type == Builtins::BUILTIN_EXIT);
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
Handle<Code> code =
CodeFactory::CEntry(masm->isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
exit_frame_type == Builtins::BUILTIN_EXIT);
__ Jump(code, RelocInfo::CODE_TARGET);
}
} // namespace
@ -2664,7 +2666,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
// Pass the WASM instance as an explicit argument to WasmCompileLazy.
__ Push(kWasmInstanceRegister);
// Initialize the JavaScript context with 0. CEntryStub will use it to
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ LoadSmiLiteral(cp, Smi::kZero);
__ CallRuntime(Runtime::kWasmCompileLazy);
@ -2681,6 +2683,199 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ Jump(r11);
}
void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
SaveFPRegsMode save_doubles, ArgvMode argv_mode,
bool builtin_exit_frame) {
// Called from JavaScript; parameters are on stack as if calling JS function.
// r3: number of arguments including receiver
// r4: pointer to builtin function
// fp: frame pointer (restored after C call)
// sp: stack pointer (restored as callee's sp after C call)
// cp: current context (C callee-saved)
//
// If argv_mode == kArgvInRegister:
// r5: pointer to the first argument
ProfileEntryHookStub::MaybeCallEntryHook(masm);
__ mr(r15, r4);
if (argv_mode == kArgvInRegister) {
// Move argv into the correct register.
__ mr(r4, r5);
} else {
// Compute the argv pointer.
__ ShiftLeftImm(r4, r3, Operand(kPointerSizeLog2));
__ add(r4, r4, sp);
__ subi(r4, r4, Operand(kPointerSize));
}
// Enter the exit frame that transitions from JavaScript to C++.
FrameScope scope(masm, StackFrame::MANUAL);
// Need at least one extra slot for return address location.
int arg_stack_space = 1;
// Pass buffer for return value on stack if necessary
bool needs_return_buffer =
(result_size == 2 && !ABI_RETURNS_OBJECT_PAIRS_IN_REGS);
if (needs_return_buffer) {
arg_stack_space += result_size;
}
__ EnterExitFrame(
save_doubles, arg_stack_space,
builtin_exit_frame ? StackFrame::BUILTIN_EXIT : StackFrame::EXIT);
// Store a copy of argc in callee-saved registers for later.
__ mr(r14, r3);
// r3, r14: number of arguments including receiver (C callee-saved)
// r4: pointer to the first argument
// r15: pointer to builtin function (C callee-saved)
// Result returned in registers or stack, depending on result size and ABI.
Register isolate_reg = r5;
if (needs_return_buffer) {
// The return value is a non-scalar value.
// Use frame storage reserved by calling function to pass return
// buffer as implicit first argument.
__ mr(r5, r4);
__ mr(r4, r3);
__ addi(r3, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize));
isolate_reg = r6;
}
// Call C built-in.
__ Move(isolate_reg, ExternalReference::isolate_address(masm->isolate()));
Register target = r15;
if (ABI_USES_FUNCTION_DESCRIPTORS) {
// AIX/PPC64BE Linux use a function descriptor.
__ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(r15, kPointerSize));
__ LoadP(ip, MemOperand(r15, 0)); // Instruction address
target = ip;
} else if (ABI_CALL_VIA_IP) {
__ Move(ip, r15);
target = ip;
}
// To let the GC traverse the return address of the exit frames, we need to
// know where the return address is. The CEntryStub is unmovable, so
// we can store the address on the stack to be able to find it again and
// we never have to restore it, because it will not change.
Label start_call;
constexpr int after_call_offset = 5 * Assembler::kInstrSize;
DCHECK_NE(r7, target);
__ LoadPC(r7);
__ bind(&start_call);
__ addi(r7, r7, Operand(after_call_offset));
__ StoreP(r7, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize));
__ Call(target);
DCHECK_EQ(after_call_offset - Assembler::kInstrSize,
__ SizeOfCodeGeneratedSince(&start_call));
// If return value is on the stack, pop it to registers.
if (needs_return_buffer) {
__ LoadP(r4, MemOperand(r3, kPointerSize));
__ LoadP(r3, MemOperand(r3));
}
// Check result for exception sentinel.
Label exception_returned;
__ CompareRoot(r3, Heap::kExceptionRootIndex);
__ beq(&exception_returned);
// Check that there is no pending exception, otherwise we
// should have returned the exception sentinel.
if (FLAG_debug_code) {
Label okay;
ExternalReference pending_exception_address = ExternalReference::Create(
IsolateAddressId::kPendingExceptionAddress, masm->isolate());
__ Move(r6, pending_exception_address);
__ LoadP(r6, MemOperand(r6));
__ CompareRoot(r6, Heap::kTheHoleValueRootIndex);
// Cannot use check here as it attempts to generate call into runtime.
__ beq(&okay);
__ stop("Unexpected pending exception");
__ bind(&okay);
}
// Exit C frame and return.
// r3:r4: result
// sp: stack pointer
// fp: frame pointer
Register argc = argv_mode == kArgvInRegister
// We don't want to pop arguments so set argc to no_reg.
? no_reg
// r14: still holds argc (callee-saved).
: r14;
__ LeaveExitFrame(save_doubles, argc);
__ blr();
// Handling of exception.
__ bind(&exception_returned);
ExternalReference pending_handler_context_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerContextAddress, masm->isolate());
ExternalReference pending_handler_entrypoint_address =
ExternalReference::Create(
IsolateAddressId::kPendingHandlerEntrypointAddress, masm->isolate());
ExternalReference pending_handler_constant_pool_address =
ExternalReference::Create(
IsolateAddressId::kPendingHandlerConstantPoolAddress,
masm->isolate());
ExternalReference pending_handler_fp_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerFPAddress, masm->isolate());
ExternalReference pending_handler_sp_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerSPAddress, masm->isolate());
// Ask the runtime for help to determine the handler. This will set r3 to
// contain the current pending exception, don't clobber it.
ExternalReference find_handler =
ExternalReference::Create(Runtime::kUnwindAndFindExceptionHandler);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ PrepareCallCFunction(3, 0, r3);
__ li(r3, Operand::Zero());
__ li(r4, Operand::Zero());
__ Move(r5, ExternalReference::isolate_address(masm->isolate()));
__ CallCFunction(find_handler, 3);
}
// Retrieve the handler context, SP and FP.
__ Move(cp, pending_handler_context_address);
__ LoadP(cp, MemOperand(cp));
__ Move(sp, pending_handler_sp_address);
__ LoadP(sp, MemOperand(sp));
__ Move(fp, pending_handler_fp_address);
__ LoadP(fp, MemOperand(fp));
// If the handler is a JS frame, restore the context to the frame. Note that
// the context will be set to (cp == 0) for non-JS frames.
Label skip;
__ cmpi(cp, Operand::Zero());
__ beq(&skip);
__ StoreP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ bind(&skip);
// Reset the masking register.
if (FLAG_branch_load_poisoning) {
__ ResetSpeculationPoisonRegister();
}
// Compute the handler entry address and jump to it.
ConstantPoolUnavailableScope constant_pool_unavailable(masm);
__ Move(ip, pending_handler_entrypoint_address);
__ LoadP(ip, MemOperand(ip));
if (FLAG_enable_embedded_constant_pool) {
__ Move(kConstantPoolRegister, pending_handler_constant_pool_address);
__ LoadP(kConstantPoolRegister, MemOperand(kConstantPoolRegister));
}
__ Jump(ip);
}
void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
Label out_of_range, only_low, negate, done, fastpath_done;
Register result_reg = r3;

View File

@ -5,6 +5,7 @@
#if V8_TARGET_ARCH_S390
#include "src/assembler-inl.h"
#include "src/code-factory.h"
#include "src/code-stubs.h"
#include "src/debug/debug.h"
#include "src/deoptimizer.h"
@ -52,7 +53,7 @@ void AdaptorWithExitFrameType(MacroAssembler* masm,
// ordinary functions).
__ LoadP(cp, FieldMemOperand(r3, JSFunction::kContextOffset));
// CEntryStub expects r2 to contain the number of arguments including the
// CEntry expects r2 to contain the number of arguments including the
// receiver and the extra arguments.
__ AddP(r2, r2,
Operand(BuiltinExitFrameConstants::kNumExtraArgsWithReceiver));
@ -67,9 +68,10 @@ void AdaptorWithExitFrameType(MacroAssembler* masm,
// JumpToExternalReference. We have already loaded entry point to r7
// in Generate_adaptor.
__ LoadRR(r3, r7);
CEntryStub stub(masm->isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
exit_frame_type == Builtins::BUILTIN_EXIT);
__ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
Handle<Code> code =
CodeFactory::CEntry(masm->isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
exit_frame_type == Builtins::BUILTIN_EXIT);
__ Jump(code, RelocInfo::CODE_TARGET);
}
} // namespace
@ -2672,7 +2674,7 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
// Pass the WASM instance as an explicit argument to WasmCompileLazy.
__ Push(kWasmInstanceRegister);
// Initialize the JavaScript context with 0. CEntryStub will use it to
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ LoadSmiLiteral(cp, Smi::kZero);
__ CallRuntime(Runtime::kWasmCompileLazy);
@ -2689,6 +2691,186 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ Jump(ip);
}
void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
SaveFPRegsMode save_doubles, ArgvMode argv_mode,
bool builtin_exit_frame) {
// Called from JavaScript; parameters are on stack as if calling JS function.
// r2: number of arguments including receiver
// r3: pointer to builtin function
// fp: frame pointer (restored after C call)
// sp: stack pointer (restored as callee's sp after C call)
// cp: current context (C callee-saved)
//
// If argv_mode == kArgvInRegister:
// r4: pointer to the first argument
ProfileEntryHookStub::MaybeCallEntryHook(masm);
__ LoadRR(r7, r3);
if (argv_mode == kArgvInRegister) {
// Move argv into the correct register.
__ LoadRR(r3, r4);
} else {
// Compute the argv pointer.
__ ShiftLeftP(r3, r2, Operand(kPointerSizeLog2));
__ lay(r3, MemOperand(r3, sp, -kPointerSize));
}
// Enter the exit frame that transitions from JavaScript to C++.
FrameScope scope(masm, StackFrame::MANUAL);
// Need at least one extra slot for return address location.
int arg_stack_space = 1;
// Pass buffer for return value on stack if necessary
bool needs_return_buffer =
result_size == 2 && !ABI_RETURNS_OBJECTPAIR_IN_REGS;
if (needs_return_buffer) {
arg_stack_space += result_size;
}
#if V8_TARGET_ARCH_S390X
// 64-bit linux pass Argument object by reference not value
arg_stack_space += 2;
#endif
__ EnterExitFrame(
save_doubles, arg_stack_space,
builtin_exit_frame ? StackFrame::BUILTIN_EXIT : StackFrame::EXIT);
// Store a copy of argc, argv in callee-saved registers for later.
__ LoadRR(r6, r2);
__ LoadRR(r8, r3);
// r2, r6: number of arguments including receiver (C callee-saved)
// r3, r8: pointer to the first argument
// r7: pointer to builtin function (C callee-saved)
// Result returned in registers or stack, depending on result size and ABI.
Register isolate_reg = r4;
if (needs_return_buffer) {
// The return value is 16-byte non-scalar value.
// Use frame storage reserved by calling function to pass return
// buffer as implicit first argument in R2. Shfit original parameters
// by one register each.
__ LoadRR(r4, r3);
__ LoadRR(r3, r2);
__ la(r2, MemOperand(sp, (kStackFrameExtraParamSlot + 1) * kPointerSize));
isolate_reg = r5;
}
// Call C built-in.
__ Move(isolate_reg, ExternalReference::isolate_address(masm->isolate()));
Register target = r7;
// To let the GC traverse the return address of the exit frames, we need to
// know where the return address is. The CEntryStub is unmovable, so
// we can store the address on the stack to be able to find it again and
// we never have to restore it, because it will not change.
{
Label return_label;
__ larl(r14, &return_label); // Generate the return addr of call later.
__ StoreP(r14, MemOperand(sp, kStackFrameRASlot * kPointerSize));
// zLinux ABI requires caller's frame to have sufficient space for callee
// preserved regsiter save area.
// __ lay(sp, MemOperand(sp, -kCalleeRegisterSaveAreaSize));
__ b(target);
__ bind(&return_label);
// __ la(sp, MemOperand(sp, +kCalleeRegisterSaveAreaSize));
}
// If return value is on the stack, pop it to registers.
if (needs_return_buffer) {
__ LoadP(r3, MemOperand(r2, kPointerSize));
__ LoadP(r2, MemOperand(r2));
}
// Check result for exception sentinel.
Label exception_returned;
__ CompareRoot(r2, Heap::kExceptionRootIndex);
__ beq(&exception_returned, Label::kNear);
// Check that there is no pending exception, otherwise we
// should have returned the exception sentinel.
if (FLAG_debug_code) {
Label okay;
ExternalReference pending_exception_address = ExternalReference::Create(
IsolateAddressId::kPendingExceptionAddress, masm->isolate());
__ Move(r1, pending_exception_address);
__ LoadP(r1, MemOperand(r1));
__ CompareRoot(r1, Heap::kTheHoleValueRootIndex);
// Cannot use check here as it attempts to generate call into runtime.
__ beq(&okay, Label::kNear);
__ stop("Unexpected pending exception");
__ bind(&okay);
}
// Exit C frame and return.
// r2:r3: result
// sp: stack pointer
// fp: frame pointer
Register argc = argv_mode == kArgvInRegister
// We don't want to pop arguments so set argc to no_reg.
? no_reg
// r6: still holds argc (callee-saved).
: r6;
__ LeaveExitFrame(save_doubles, argc);
__ b(r14);
// Handling of exception.
__ bind(&exception_returned);
ExternalReference pending_handler_context_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerContextAddress, masm->isolate());
ExternalReference pending_handler_entrypoint_address =
ExternalReference::Create(
IsolateAddressId::kPendingHandlerEntrypointAddress, masm->isolate());
ExternalReference pending_handler_fp_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerFPAddress, masm->isolate());
ExternalReference pending_handler_sp_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerSPAddress, masm->isolate());
// Ask the runtime for help to determine the handler. This will set r3 to
// contain the current pending exception, don't clobber it.
ExternalReference find_handler =
ExternalReference::Create(Runtime::kUnwindAndFindExceptionHandler);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ PrepareCallCFunction(3, 0, r2);
__ LoadImmP(r2, Operand::Zero());
__ LoadImmP(r3, Operand::Zero());
__ Move(r4, ExternalReference::isolate_address(masm->isolate()));
__ CallCFunction(find_handler, 3);
}
// Retrieve the handler context, SP and FP.
__ Move(cp, pending_handler_context_address);
__ LoadP(cp, MemOperand(cp));
__ Move(sp, pending_handler_sp_address);
__ LoadP(sp, MemOperand(sp));
__ Move(fp, pending_handler_fp_address);
__ LoadP(fp, MemOperand(fp));
// If the handler is a JS frame, restore the context to the frame. Note that
// the context will be set to (cp == 0) for non-JS frames.
Label skip;
__ CmpP(cp, Operand::Zero());
__ beq(&skip, Label::kNear);
__ StoreP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ bind(&skip);
// Reset the masking register.
if (FLAG_branch_load_poisoning) {
__ ResetSpeculationPoisonRegister();
}
// Compute the handler entry address and jump to it.
__ Move(r3, pending_handler_entrypoint_address);
__ LoadP(r3, MemOperand(r3));
__ Jump(r3);
}
void Builtins::Generate_DoubleToI(MacroAssembler* masm) {
Label out_of_range, only_low, negate, done, fastpath_done;
Register result_reg = r2;

View File

@ -36,217 +36,11 @@ void ArrayNArgumentsConstructorStub::Generate(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kNewArray);
}
Movability CEntryStub::NeedsImmovableCode() { return kImmovable; }
void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CEntryStub::GenerateAheadOfTime(isolate);
CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
StoreFastElementStub::GenerateAheadOfTime(isolate);
}
void CodeStub::GenerateFPStubs(Isolate* isolate) {
// Generate if not already in cache.
SaveFPRegsMode mode = kSaveFPRegs;
CEntryStub(isolate, 1, mode).GetCode();
}
void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
CEntryStub stub(isolate, 1, kDontSaveFPRegs);
stub.GetCode();
CEntryStub save_doubles(isolate, 1, kSaveFPRegs);
save_doubles.GetCode();
}
void CEntryStub::Generate(MacroAssembler* masm) {
// Called from JavaScript; parameters are on stack as if calling JS function.
// r3: number of arguments including receiver
// r4: pointer to builtin function
// fp: frame pointer (restored after C call)
// sp: stack pointer (restored as callee's sp after C call)
// cp: current context (C callee-saved)
//
// If argv_in_register():
// r5: pointer to the first argument
ProfileEntryHookStub::MaybeCallEntryHook(masm);
__ mr(r15, r4);
if (argv_in_register()) {
// Move argv into the correct register.
__ mr(r4, r5);
} else {
// Compute the argv pointer.
__ ShiftLeftImm(r4, r3, Operand(kPointerSizeLog2));
__ add(r4, r4, sp);
__ subi(r4, r4, Operand(kPointerSize));
}
// Enter the exit frame that transitions from JavaScript to C++.
FrameScope scope(masm, StackFrame::MANUAL);
// Need at least one extra slot for return address location.
int arg_stack_space = 1;
// Pass buffer for return value on stack if necessary
bool needs_return_buffer =
(result_size() == 2 && !ABI_RETURNS_OBJECT_PAIRS_IN_REGS);
if (needs_return_buffer) {
arg_stack_space += result_size();
}
__ EnterExitFrame(save_doubles(), arg_stack_space, is_builtin_exit()
? StackFrame::BUILTIN_EXIT
: StackFrame::EXIT);
// Store a copy of argc in callee-saved registers for later.
__ mr(r14, r3);
// r3, r14: number of arguments including receiver (C callee-saved)
// r4: pointer to the first argument
// r15: pointer to builtin function (C callee-saved)
// Result returned in registers or stack, depending on result size and ABI.
Register isolate_reg = r5;
if (needs_return_buffer) {
// The return value is a non-scalar value.
// Use frame storage reserved by calling function to pass return
// buffer as implicit first argument.
__ mr(r5, r4);
__ mr(r4, r3);
__ addi(r3, sp, Operand((kStackFrameExtraParamSlot + 1) * kPointerSize));
isolate_reg = r6;
}
// Call C built-in.
__ mov(isolate_reg, Operand(ExternalReference::isolate_address(isolate())));
Register target = r15;
if (ABI_USES_FUNCTION_DESCRIPTORS) {
// AIX/PPC64BE Linux use a function descriptor.
__ LoadP(ToRegister(ABI_TOC_REGISTER), MemOperand(r15, kPointerSize));
__ LoadP(ip, MemOperand(r15, 0)); // Instruction address
target = ip;
} else if (ABI_CALL_VIA_IP) {
__ Move(ip, r15);
target = ip;
}
// To let the GC traverse the return address of the exit frames, we need to
// know where the return address is. The CEntryStub is unmovable, so
// we can store the address on the stack to be able to find it again and
// we never have to restore it, because it will not change.
Label after_call;
__ mov_label_addr(r0, &after_call);
__ StoreP(r0, MemOperand(sp, kStackFrameExtraParamSlot * kPointerSize));
__ Call(target);
__ bind(&after_call);
// If return value is on the stack, pop it to registers.
if (needs_return_buffer) {
__ LoadP(r4, MemOperand(r3, kPointerSize));
__ LoadP(r3, MemOperand(r3));
}
// Check result for exception sentinel.
Label exception_returned;
__ CompareRoot(r3, Heap::kExceptionRootIndex);
__ beq(&exception_returned);
// Check that there is no pending exception, otherwise we
// should have returned the exception sentinel.
if (FLAG_debug_code) {
Label okay;
ExternalReference pending_exception_address = ExternalReference::Create(
IsolateAddressId::kPendingExceptionAddress, isolate());
__ mov(r6, Operand(pending_exception_address));
__ LoadP(r6, MemOperand(r6));
__ CompareRoot(r6, Heap::kTheHoleValueRootIndex);
// Cannot use check here as it attempts to generate call into runtime.
__ beq(&okay);
__ stop("Unexpected pending exception");
__ bind(&okay);
}
// Exit C frame and return.
// r3:r4: result
// sp: stack pointer
// fp: frame pointer
Register argc = argv_in_register()
// We don't want to pop arguments so set argc to no_reg.
? no_reg
// r14: still holds argc (callee-saved).
: r14;
__ LeaveExitFrame(save_doubles(), argc);
__ blr();
// Handling of exception.
__ bind(&exception_returned);
ExternalReference pending_handler_context_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerContextAddress, isolate());
ExternalReference pending_handler_entrypoint_address =
ExternalReference::Create(
IsolateAddressId::kPendingHandlerEntrypointAddress, isolate());
ExternalReference pending_handler_constant_pool_address =
ExternalReference::Create(
IsolateAddressId::kPendingHandlerConstantPoolAddress, isolate());
ExternalReference pending_handler_fp_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerFPAddress, isolate());
ExternalReference pending_handler_sp_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerSPAddress, isolate());
// Ask the runtime for help to determine the handler. This will set r3 to
// contain the current pending exception, don't clobber it.
ExternalReference find_handler =
ExternalReference::Create(Runtime::kUnwindAndFindExceptionHandler);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ PrepareCallCFunction(3, 0, r3);
__ li(r3, Operand::Zero());
__ li(r4, Operand::Zero());
__ mov(r5, Operand(ExternalReference::isolate_address(isolate())));
__ CallCFunction(find_handler, 3);
}
// Retrieve the handler context, SP and FP.
__ mov(cp, Operand(pending_handler_context_address));
__ LoadP(cp, MemOperand(cp));
__ mov(sp, Operand(pending_handler_sp_address));
__ LoadP(sp, MemOperand(sp));
__ mov(fp, Operand(pending_handler_fp_address));
__ LoadP(fp, MemOperand(fp));
// If the handler is a JS frame, restore the context to the frame. Note that
// the context will be set to (cp == 0) for non-JS frames.
Label skip;
__ cmpi(cp, Operand::Zero());
__ beq(&skip);
__ StoreP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ bind(&skip);
// Reset the masking register.
if (FLAG_branch_load_poisoning) {
__ ResetSpeculationPoisonRegister();
}
// Compute the handler entry address and jump to it.
ConstantPoolUnavailableScope constant_pool_unavailable(masm);
__ mov(ip, Operand(pending_handler_entrypoint_address));
__ LoadP(ip, MemOperand(ip));
if (FLAG_enable_embedded_constant_pool) {
__ mov(kConstantPoolRegister,
Operand(pending_handler_constant_pool_address));
__ LoadP(kConstantPoolRegister, MemOperand(kConstantPoolRegister));
}
__ Jump(ip);
}
void JSEntryStub::Generate(MacroAssembler* masm) {
// r3: code entry
// r4: function

View File

@ -253,12 +253,6 @@ void BinaryOpDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void StringAddDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {r4, r3};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void ArgumentAdaptorDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {

View File

@ -12,6 +12,7 @@
#include "src/bootstrapper.h"
#include "src/builtins/constants-table-builder.h"
#include "src/callable.h"
#include "src/code-factory.h"
#include "src/code-stubs.h"
#include "src/debug/debug.h"
#include "src/external-reference-table.h"
@ -1060,7 +1061,7 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
StoreP(kConstantPoolRegister,
MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
}
mov(r8, Operand(CodeObject()));
Move(r8, CodeObject());
StoreP(r8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
// Save the frame pointer and the context in top.
@ -1684,13 +1685,13 @@ void TurboAssembler::CallRuntimeDelayed(Zone* zone, Runtime::FunctionId fid,
// smarter.
mov(r3, Operand(f->nargs));
Move(r4, ExternalReference::Create(f));
CallStubDelayed(new (zone) CEntryStub(nullptr,
#if V8_TARGET_ARCH_PPC64
f->result_size,
Handle<Code> code =
CodeFactory::CEntry(isolate(), f->result_size, save_doubles);
#else
1,
Handle<Code> code = CodeFactory::CEntry(isolate(), 1, save_doubles);
#endif
save_doubles));
Call(code, RelocInfo::CODE_TARGET);
}
void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
@ -1708,14 +1709,13 @@ void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
// smarter.
mov(r3, Operand(num_arguments));
Move(r4, ExternalReference::Create(f));
CEntryStub stub(isolate(),
#if V8_TARGET_ARCH_PPC64
f->result_size,
Handle<Code> code =
CodeFactory::CEntry(isolate(), f->result_size, save_doubles);
#else
1,
Handle<Code> code = CodeFactory::CEntry(isolate(), 1, save_doubles);
#endif
save_doubles);
CallStub(&stub);
Call(code, RelocInfo::CODE_TARGET);
}
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
@ -1731,9 +1731,9 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
bool builtin_exit_frame) {
Move(r4, builtin);
CEntryStub stub(isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
builtin_exit_frame);
Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
Handle<Code> code = CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs,
kArgvOnStack, builtin_exit_frame);
Jump(code, RelocInfo::CODE_TARGET);
}
void MacroAssembler::JumpToInstructionStream(Address entry) {

View File

@ -35,204 +35,11 @@ void ArrayNArgumentsConstructorStub::Generate(MacroAssembler* masm) {
__ TailCallRuntime(Runtime::kNewArray);
}
Movability CEntryStub::NeedsImmovableCode() { return kImmovable; }
void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
CEntryStub::GenerateAheadOfTime(isolate);
CommonArrayConstructorStub::GenerateStubsAheadOfTime(isolate);
StoreFastElementStub::GenerateAheadOfTime(isolate);
}
void CodeStub::GenerateFPStubs(Isolate* isolate) {
SaveFPRegsMode mode = kSaveFPRegs;
CEntryStub(isolate, 1, mode).GetCode();
}
void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
CEntryStub stub(isolate, 1, kDontSaveFPRegs);
stub.GetCode();
CEntryStub save_doubles(isolate, 1, kSaveFPRegs);
save_doubles.GetCode();
}
void CEntryStub::Generate(MacroAssembler* masm) {
// Called from JavaScript; parameters are on stack as if calling JS function.
// r2: number of arguments including receiver
// r3: pointer to builtin function
// fp: frame pointer (restored after C call)
// sp: stack pointer (restored as callee's sp after C call)
// cp: current context (C callee-saved)
//
// If argv_in_register():
// r4: pointer to the first argument
ProfileEntryHookStub::MaybeCallEntryHook(masm);
__ LoadRR(r7, r3);
if (argv_in_register()) {
// Move argv into the correct register.
__ LoadRR(r3, r4);
} else {
// Compute the argv pointer.
__ ShiftLeftP(r3, r2, Operand(kPointerSizeLog2));
__ lay(r3, MemOperand(r3, sp, -kPointerSize));
}
// Enter the exit frame that transitions from JavaScript to C++.
FrameScope scope(masm, StackFrame::MANUAL);
// Need at least one extra slot for return address location.
int arg_stack_space = 1;
// Pass buffer for return value on stack if necessary
bool needs_return_buffer =
result_size() == 2 && !ABI_RETURNS_OBJECTPAIR_IN_REGS;
if (needs_return_buffer) {
arg_stack_space += result_size();
}
#if V8_TARGET_ARCH_S390X
// 64-bit linux pass Argument object by reference not value
arg_stack_space += 2;
#endif
__ EnterExitFrame(save_doubles(), arg_stack_space, is_builtin_exit()
? StackFrame::BUILTIN_EXIT
: StackFrame::EXIT);
// Store a copy of argc, argv in callee-saved registers for later.
__ LoadRR(r6, r2);
__ LoadRR(r8, r3);
// r2, r6: number of arguments including receiver (C callee-saved)
// r3, r8: pointer to the first argument
// r7: pointer to builtin function (C callee-saved)
// Result returned in registers or stack, depending on result size and ABI.
Register isolate_reg = r4;
if (needs_return_buffer) {
// The return value is 16-byte non-scalar value.
// Use frame storage reserved by calling function to pass return
// buffer as implicit first argument in R2. Shfit original parameters
// by one register each.
__ LoadRR(r4, r3);
__ LoadRR(r3, r2);
__ la(r2, MemOperand(sp, (kStackFrameExtraParamSlot + 1) * kPointerSize));
isolate_reg = r5;
}
// Call C built-in.
__ mov(isolate_reg, Operand(ExternalReference::isolate_address(isolate())));
Register target = r7;
// To let the GC traverse the return address of the exit frames, we need to
// know where the return address is. The CEntryStub is unmovable, so
// we can store the address on the stack to be able to find it again and
// we never have to restore it, because it will not change.
{
Label return_label;
__ larl(r14, &return_label); // Generate the return addr of call later.
__ StoreP(r14, MemOperand(sp, kStackFrameRASlot * kPointerSize));
// zLinux ABI requires caller's frame to have sufficient space for callee
// preserved regsiter save area.
// __ lay(sp, MemOperand(sp, -kCalleeRegisterSaveAreaSize));
__ b(target);
__ bind(&return_label);
// __ la(sp, MemOperand(sp, +kCalleeRegisterSaveAreaSize));
}
// If return value is on the stack, pop it to registers.
if (needs_return_buffer) {
__ LoadP(r3, MemOperand(r2, kPointerSize));
__ LoadP(r2, MemOperand(r2));
}
// Check result for exception sentinel.
Label exception_returned;
__ CompareRoot(r2, Heap::kExceptionRootIndex);
__ beq(&exception_returned, Label::kNear);
// Check that there is no pending exception, otherwise we
// should have returned the exception sentinel.
if (FLAG_debug_code) {
Label okay;
ExternalReference pending_exception_address = ExternalReference::Create(
IsolateAddressId::kPendingExceptionAddress, isolate());
__ mov(r1, Operand(pending_exception_address));
__ LoadP(r1, MemOperand(r1));
__ CompareRoot(r1, Heap::kTheHoleValueRootIndex);
// Cannot use check here as it attempts to generate call into runtime.
__ beq(&okay, Label::kNear);
__ stop("Unexpected pending exception");
__ bind(&okay);
}
// Exit C frame and return.
// r2:r3: result
// sp: stack pointer
// fp: frame pointer
Register argc = argv_in_register()
// We don't want to pop arguments so set argc to no_reg.
? no_reg
// r6: still holds argc (callee-saved).
: r6;
__ LeaveExitFrame(save_doubles(), argc);
__ b(r14);
// Handling of exception.
__ bind(&exception_returned);
ExternalReference pending_handler_context_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerContextAddress, isolate());
ExternalReference pending_handler_entrypoint_address =
ExternalReference::Create(
IsolateAddressId::kPendingHandlerEntrypointAddress, isolate());
ExternalReference pending_handler_fp_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerFPAddress, isolate());
ExternalReference pending_handler_sp_address = ExternalReference::Create(
IsolateAddressId::kPendingHandlerSPAddress, isolate());
// Ask the runtime for help to determine the handler. This will set r3 to
// contain the current pending exception, don't clobber it.
ExternalReference find_handler =
ExternalReference::Create(Runtime::kUnwindAndFindExceptionHandler);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ PrepareCallCFunction(3, 0, r2);
__ LoadImmP(r2, Operand::Zero());
__ LoadImmP(r3, Operand::Zero());
__ mov(r4, Operand(ExternalReference::isolate_address(isolate())));
__ CallCFunction(find_handler, 3);
}
// Retrieve the handler context, SP and FP.
__ mov(cp, Operand(pending_handler_context_address));
__ LoadP(cp, MemOperand(cp));
__ mov(sp, Operand(pending_handler_sp_address));
__ LoadP(sp, MemOperand(sp));
__ mov(fp, Operand(pending_handler_fp_address));
__ LoadP(fp, MemOperand(fp));
// If the handler is a JS frame, restore the context to the frame. Note that
// the context will be set to (cp == 0) for non-JS frames.
Label skip;
__ CmpP(cp, Operand::Zero());
__ beq(&skip, Label::kNear);
__ StoreP(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ bind(&skip);
// Reset the masking register.
if (FLAG_branch_load_poisoning) {
__ ResetSpeculationPoisonRegister();
}
// Compute the handler entry address and jump to it.
__ mov(r3, Operand(pending_handler_entrypoint_address));
__ LoadP(r3, MemOperand(r3));
__ Jump(r3);
}
void JSEntryStub::Generate(MacroAssembler* masm) {
// r2: code entry
// r3: function

View File

@ -247,12 +247,6 @@ void BinaryOpDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void StringAddDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {r3, r2};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void ArgumentAdaptorDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {

View File

@ -12,6 +12,7 @@
#include "src/bootstrapper.h"
#include "src/builtins/constants-table-builder.h"
#include "src/callable.h"
#include "src/code-factory.h"
#include "src/code-stubs.h"
#include "src/debug/debug.h"
#include "src/external-reference-table.h"
@ -1084,7 +1085,7 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space,
if (emit_debug_code()) {
StoreP(MemOperand(fp, ExitFrameConstants::kSPOffset), Operand::Zero(), r1);
}
mov(r1, Operand(CodeObject()));
Move(r1, CodeObject());
StoreP(r1, MemOperand(fp, ExitFrameConstants::kCodeOffset));
// Save the frame pointer and the context in top.
@ -1155,14 +1156,14 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles, Register argument_count,
StoreP(MemOperand(ip), Operand(0, RelocInfo::NONE), r0);
// Restore current context from top and clear it in debug mode.
mov(ip, Operand(ExternalReference::Create(IsolateAddressId::kContextAddress,
isolate())));
Move(ip,
ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
LoadP(cp, MemOperand(ip));
#ifdef DEBUG
mov(r1, Operand(Context::kInvalidContext));
mov(ip, Operand(ExternalReference::Create(IsolateAddressId::kContextAddress,
isolate())));
Move(ip,
ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()));
StoreP(r1, MemOperand(ip));
#endif
@ -1584,13 +1585,14 @@ void TurboAssembler::CallRuntimeDelayed(Zone* zone, Runtime::FunctionId fid,
const Runtime::Function* f = Runtime::FunctionForId(fid);
mov(r2, Operand(f->nargs));
Move(r3, ExternalReference::Create(f));
CallStubDelayed(new (zone) CEntryStub(nullptr,
#if V8_TARGET_ARCH_S390X
f->result_size,
Handle<Code> code =
CodeFactory::CEntry(isolate(), f->result_size, save_doubles);
#else
1,
Handle<Code> code = CodeFactory::CEntry(isolate(), 1, save_doubles);
#endif
save_doubles));
Call(code, RelocInfo::CODE_TARGET);
}
void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
@ -1608,14 +1610,14 @@ void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
// smarter.
mov(r2, Operand(num_arguments));
Move(r3, ExternalReference::Create(f));
CEntryStub stub(isolate(),
#if V8_TARGET_ARCH_S390X
f->result_size,
Handle<Code> code =
CodeFactory::CEntry(isolate(), f->result_size, save_doubles);
#else
1,
Handle<Code> code = CodeFactory::CEntry(isolate(), 1, save_doubles);
#endif
save_doubles);
CallStub(&stub);
Call(code, RelocInfo::CODE_TARGET);
}
void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
@ -1630,9 +1632,9 @@ void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) {
void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
bool builtin_exit_frame) {
Move(r3, builtin);
CEntryStub stub(isolate(), 1, kDontSaveFPRegs, kArgvOnStack,
builtin_exit_frame);
Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
Handle<Code> code = CodeFactory::CEntry(isolate(), 1, kDontSaveFPRegs,
kArgvOnStack, builtin_exit_frame);
Jump(code, RelocInfo::CODE_TARGET);
}
void MacroAssembler::JumpToInstructionStream(Address entry) {