/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/codegen/ppc/macro-assembler-ppc.h
1 911 строк
80 KB
Michaël Zasso
deps: update V8 to 14.6.202.33
24 апр 2026, 19:01
Не верифицирован
24 апр 2026, 19:01
f1e0b83
Код
Авторство
О чём код?
// Copyright 2014 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. #ifndef V8_CODEGEN_PPC_MACRO_ASSEMBLER_PPC_H_ #define V8_CODEGEN_PPC_MACRO_ASSEMBLER_PPC_H_ #ifndef INCLUDED_FROM_MACRO_ASSEMBLER_H #error This header must be included via macro-assembler.h #endif #include "src/base/numbers/double.h" #include "src/base/platform/platform.h" #include "src/codegen/bailout-reason.h" #include "src/codegen/ppc/assembler-ppc.h" #include "src/common/globals.h" #include "src/execution/frame-constants.h" #include "src/execution/isolate-data.h" #include "src/objects/contexts.h" namespace v8 { namespace internal { enum class StackLimitKind { kInterruptStackLimit, kRealStackLimit }; // ---------------------------------------------------------------------------- // Static helper functions // Generate a MemOperand for loading a field from an object. inline MemOperand FieldMemOperand(Register object, int offset) { return MemOperand(object, offset - kHeapObjectTag); } enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved }; Register GetRegisterThatIsNotOneOf(Register reg1, Register reg2 = no_reg, Register reg3 = no_reg, Register reg4 = no_reg, Register reg5 = no_reg, Register reg6 = no_reg); // These exist to provide portability between 32 and 64bit #define ClearLeftImm clrldi #define ClearRightImm clrrdi class V8_EXPORT_PRIVATE MacroAssembler : public MacroAssemblerBase { public: using MacroAssemblerBase::MacroAssemblerBase; void CallBuiltin(Builtin builtin, Condition cond = al); void TailCallBuiltin(Builtin builtin, Condition cond = al, CRegister cr = cr0); void Popcnt32(Register dst, Register src); void Popcnt64(Register dst, Register src); // Converts the integer (untagged smi) in |src| to a double, storing // the result to |dst| void ConvertIntToDouble(Register src, DoubleRegister dst); // Converts the unsigned integer (untagged smi) in |src| to // a double, storing the result to |dst| void ConvertUnsignedIntToDouble(Register src, DoubleRegister dst); // Converts the integer (untagged smi) in |src| to // a float, storing the result in |dst| void ConvertIntToFloat(Register src, DoubleRegister dst); // Converts the unsigned integer (untagged smi) in |src| to // a float, storing the result in |dst| void ConvertUnsignedIntToFloat(Register src, DoubleRegister dst); void ConvertInt64ToFloat(Register src, DoubleRegister double_dst); void ConvertInt64ToDouble(Register src, DoubleRegister double_dst); void ConvertUnsignedInt64ToFloat(Register src, DoubleRegister double_dst); void ConvertUnsignedInt64ToDouble(Register src, DoubleRegister double_dst); // Converts the double_input to an integer. Note that, upon return, // the contents of double_dst will also hold the fixed point representation. void ConvertDoubleToInt64(const DoubleRegister double_input, const Register dst, const DoubleRegister double_dst, FPRoundingMode rounding_mode = kRoundToZero); // Converts the double_input to an unsigned integer. Note that, upon return, // the contents of double_dst will also hold the fixed point representation. void ConvertDoubleToUnsignedInt64( const DoubleRegister double_input, const Register dst, const DoubleRegister double_dst, FPRoundingMode rounding_mode = kRoundToZero); // Activation support. void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg = false); // Returns the pc offset at which the frame ends. int LeaveFrame(StackFrame::Type type, int stack_adjustment = 0); void AllocateStackSpace(int bytes) { DCHECK_GE(bytes, 0); if (bytes == 0) return; AddS64(sp, sp, Operand(-bytes), r0); } void AllocateStackSpace(Register bytes) { sub(sp, sp, bytes); } // Push a fixed frame, consisting of lr, fp, constant pool. void PushCommonFrame(Register marker_reg = no_reg); // Generates function and stub prologue code. void StubPrologue(StackFrame::Type type); void Prologue(); void DropArguments(Register count); void DropArgumentsAndPushNewReceiver(Register argc, Register receiver); // Push a standard frame, consisting of lr, fp, constant pool, // context and JS function void PushStandardFrame(Register function_reg); // Restore caller's frame pointer and return address prior to being // overwritten by tail call stack preparation. void RestoreFrameStateForTailCall(); // Get the actual activation frame alignment for target environment. static int ActivationFrameAlignment(); void InitializeRootRegister() { ExternalReference isolate_root = ExternalReference::isolate_root(isolate()); mov(kRootRegister, Operand(isolate_root)); #ifdef V8_COMPRESS_POINTERS LoadRootRelative(kPtrComprCageBaseRegister, IsolateData::cage_base_offset()); #endif } void LoadDoubleLiteral(DoubleRegister result, base::Double value, Register scratch); // load a literal signed int value <value> to GPR <dst> void LoadIntLiteral(Register dst, int value); // load an SMI value <value> to GPR <dst> void LoadSmiLiteral(Register dst, Tagged<Smi> smi); // dst points to address of mflr void LoadPC(Register dst); void ComputeCodeStartAddress(Register dst); void CmpS64(Register src1, const Operand& src2, Register scratch, CRegister cr = cr0); void CmpS64(Register src1, Register src2, CRegister cr = cr0); void CmpU64(Register src1, const Operand& src2, Register scratch, CRegister cr = cr0); void CmpU64(Register src1, Register src2, CRegister cr = cr0); void CmpS32(Register src1, const Operand& src2, Register scratch, CRegister cr = cr0); void CmpS32(Register src1, Register src2, CRegister cr = cr0); void CmpU32(Register src1, const Operand& src2, Register scratch, CRegister cr = cr0); void CmpU32(Register src1, Register src2, CRegister cr = cr0); void CompareTagged(Register src1, Register src2, CRegister cr = cr0) { if (COMPRESS_POINTERS_BOOL) { CmpS32(src1, src2, cr); } else { CmpS64(src1, src2, cr); } } void Cmp(Register dst, int32_t src) { CmpS32(dst, Operand(src), r0); } void CmpTagged(const Register& src1, const Register& src2) { CompareTagged(src1, src2); } void MinF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs, DoubleRegister scratch = kScratchDoubleReg); void MaxF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs, DoubleRegister scratch = kScratchDoubleReg); // Set new rounding mode RN to FPSCR void SetRoundingMode(FPRoundingMode RN); // reset rounding mode to default (kRoundToNearest) void ResetRoundingMode(); void AddS64(Register dst, Register src, const Operand& value, Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC); void AddS64(Register dst, Register src, Register value, OEBit s = LeaveOE, RCBit r = LeaveRC); void AddS64(Register dst, Register src, int32_t imm, Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC) { AddS64(dst, src, Operand(imm), scratch, s, r); } void SubS64(Register dst, Register src, const Operand& value, Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC); void SubS64(Register dst, Register src, int32_t imm, Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC) { SubS64(dst, src, Operand(imm), scratch, s, r); } void SubS64(Register dst, Register src, Register value, OEBit s = LeaveOE, RCBit r = LeaveRC); void AddS32(Register dst, Register src, const Operand& value, Register scratch = r0, RCBit r = LeaveRC); void AddS32(Register dst, Register src, Register value, RCBit r = LeaveRC); void SubS32(Register dst, Register src, const Operand& value, Register scratch = r0, RCBit r = LeaveRC); void SubS32(Register dst, Register src, Register value, RCBit r = LeaveRC); void MulS64(Register dst, Register src, const Operand& value, Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC); void MulS64(Register dst, Register src, Register value, OEBit s = LeaveOE, RCBit r = LeaveRC); void MulS32(Register dst, Register src, const Operand& value, Register scratch = r0, OEBit s = LeaveOE, RCBit r = LeaveRC); void MulS32(Register dst, Register src, Register value, OEBit s = LeaveOE, RCBit r = LeaveRC); void DivS64(Register dst, Register src, Register value, OEBit s = LeaveOE, RCBit r = LeaveRC); void DivU64(Register dst, Register src, Register value, OEBit s = LeaveOE, RCBit r = LeaveRC); void DivS32(Register dst, Register src, Register value, OEBit s = LeaveOE, RCBit r = LeaveRC); void DivU32(Register dst, Register src, Register value, OEBit s = LeaveOE, RCBit r = LeaveRC); void ModS64(Register dst, Register src, Register value); void ModU64(Register dst, Register src, Register value); void ModS32(Register dst, Register src, Register value); void ModU32(Register dst, Register src, Register value); void AndU64(Register dst, Register src, const Operand& value, Register scratch = r0, RCBit r = SetRC); void AndU64(Register dst, Register src, Register value, RCBit r = SetRC); void OrU64(Register dst, Register src, const Operand& value, Register scratch = r0, RCBit r = SetRC); void OrU64(Register dst, Register src, Register value, RCBit r = LeaveRC); void XorU64(Register dst, Register src, const Operand& value, Register scratch = r0, RCBit r = SetRC); void XorU64(Register dst, Register src, Register value, RCBit r = LeaveRC); void AndU32(Register dst, Register src, const Operand& value, Register scratch = r0, RCBit r = SetRC); void AndU32(Register dst, Register src, Register value, RCBit r = SetRC); void OrU32(Register dst, Register src, const Operand& value, Register scratch = r0, RCBit r = SetRC); void OrU32(Register dst, Register src, Register value, RCBit r = LeaveRC); void XorU32(Register dst, Register src, const Operand& value, Register scratch = r0, RCBit r = SetRC); void XorU32(Register dst, Register src, Register value, RCBit r = LeaveRC); void ShiftLeftU64(Register dst, Register src, const Operand& value, RCBit r = LeaveRC); void ShiftRightU64(Register dst, Register src, const Operand& value, RCBit r = LeaveRC); void ShiftRightS64(Register dst, Register src, const Operand& value, RCBit r = LeaveRC); void ShiftLeftU32(Register dst, Register src, const Operand& value, RCBit r = LeaveRC); void ShiftRightU32(Register dst, Register src, const Operand& value, RCBit r = LeaveRC); void ShiftRightS32(Register dst, Register src, const Operand& value, RCBit r = LeaveRC); void ShiftLeftU64(Register dst, Register src, Register value, RCBit r = LeaveRC); void ShiftRightU64(Register dst, Register src, Register value, RCBit r = LeaveRC); void ShiftRightS64(Register dst, Register src, Register value, RCBit r = LeaveRC); void ShiftLeftU32(Register dst, Register src, Register value, RCBit r = LeaveRC); void ShiftRightU32(Register dst, Register src, Register value, RCBit r = LeaveRC); void ShiftRightS32(Register dst, Register src, Register value, RCBit r = LeaveRC); void CountLeadingZerosU32(Register dst, Register src, RCBit r = LeaveRC); void CountLeadingZerosU64(Register dst, Register src, RCBit r = LeaveRC); void CountTrailingZerosU32(Register dst, Register src, RCBit r = LeaveRC); void CountTrailingZerosU64(Register dst, Register src, RCBit r = LeaveRC); void ClearByteU64(Register dst, int byte_idx); void ReverseBitsU64(Register dst, Register src, Register scratch1, Register scratch2); void ReverseBitsU32(Register dst, Register src, Register scratch1, Register scratch2); void ReverseBitsInSingleByteU64(Register dst, Register src, Register scratch1, Register scratch2, int byte_idx); void AddF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs, RCBit r = LeaveRC); void SubF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs, RCBit r = LeaveRC); void MulF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs, RCBit r = LeaveRC); void DivF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs, RCBit r = LeaveRC); void AddF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs, RCBit r = LeaveRC); void SubF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs, RCBit r = LeaveRC); void MulF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs, RCBit r = LeaveRC); void DivF32(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs, RCBit r = LeaveRC); void CopySignF64(DoubleRegister dst, DoubleRegister lhs, DoubleRegister rhs, RCBit r = LeaveRC); template <class _type> void SignedExtend(Register dst, Register value) { switch (sizeof(_type)) { case 1: extsb(dst, value); break; case 2: extsh(dst, value); break; case 4: extsw(dst, value); break; case 8: if (dst != value) mr(dst, value); break; default: UNREACHABLE(); } } template <class _type> void ZeroExtend(Register dst, Register value) { switch (sizeof(_type)) { case 1: ZeroExtByte(dst, value); break; case 2: ZeroExtHalfWord(dst, value); break; case 4: ZeroExtWord32(dst, value); break; case 8: if (dst != value) mr(dst, value); break; default: UNREACHABLE(); } } template <class _type> void ExtendValue(Register dst, Register value) { if (std::is_signed_v<_type>) { SignedExtend<_type>(dst, value); } else { ZeroExtend<_type>(dst, value); } } template <class _type> void LoadReserve(Register output, MemOperand dst) { switch (sizeof(_type)) { case 1: lbarx(output, dst); break; case 2: lharx(output, dst); break; case 4: lwarx(output, dst); break; case 8: ldarx(output, dst); break; default: UNREACHABLE(); } if (std::is_signed_v<_type>) { SignedExtend<_type>(output, output); } } template <class _type> void StoreConditional(Register value, MemOperand dst) { switch (sizeof(_type)) { case 1: stbcx(value, dst); break; case 2: sthcx(value, dst); break; case 4: stwcx(value, dst); break; case 8: stdcx(value, dst); break; default: UNREACHABLE(); } } template <class _type> void AtomicCompareExchange(MemOperand dst, Register old_value, Register new_value, Register output, Register scratch) { Label loop; Label exit; if (sizeof(_type) != 8) { ExtendValue<_type>(scratch, old_value); old_value = scratch; } lwsync(); bind(&loop); LoadReserve<_type>(output, dst); cmp(output, old_value, cr0); bne(&exit, cr0); StoreConditional<_type>(new_value, dst); bne(&loop, cr0); bind(&exit); sync(); } template <class _type> void AtomicExchange(MemOperand dst, Register new_value, Register output) { Label exchange; lwsync(); bind(&exchange); LoadReserve<_type>(output, dst); StoreConditional<_type>(new_value, dst); bne(&exchange, cr0); sync(); } template <class _type, class bin_op> void AtomicOps(MemOperand dst, Register value, Register output, Register result, bin_op op) { Label binop; lwsync(); bind(&binop); switch (sizeof(_type)) { case 1: lbarx(output, dst); break; case 2: lharx(output, dst); break; case 4: lwarx(output, dst); break; case 8: ldarx(output, dst); break; default: UNREACHABLE(); } op(result, output, value); switch (sizeof(_type)) { case 1: stbcx(result, dst); break; case 2: sthcx(result, dst); break; case 4: stwcx(result, dst); break; case 8: stdcx(result, dst); break; default: UNREACHABLE(); } bne(&binop, cr0); sync(); } void Push(Register src) { push(src); } // Push a handle. void Push(Handle<HeapObject> handle); void Push(Tagged<Smi> smi); void Push(Tagged<TaggedIndex> index); // Push two registers. Pushes leftmost register first (to highest address). void Push(Register src1, Register src2) { StoreU64WithUpdate(src2, MemOperand(sp, -2 * kSystemPointerSize)); StoreU64(src1, MemOperand(sp, kSystemPointerSize)); } // Push three registers. Pushes leftmost register first (to highest address). void Push(Register src1, Register src2, Register src3) { StoreU64WithUpdate(src3, MemOperand(sp, -3 * kSystemPointerSize)); StoreU64(src2, MemOperand(sp, kSystemPointerSize)); StoreU64(src1, MemOperand(sp, 2 * kSystemPointerSize)); } // Push four registers. Pushes leftmost register first (to highest address). void Push(Register src1, Register src2, Register src3, Register src4) { StoreU64WithUpdate(src4, MemOperand(sp, -4 * kSystemPointerSize)); StoreU64(src3, MemOperand(sp, kSystemPointerSize)); StoreU64(src2, MemOperand(sp, 2 * kSystemPointerSize)); StoreU64(src1, MemOperand(sp, 3 * kSystemPointerSize)); } // Push five registers. Pushes leftmost register first (to highest address). void Push(Register src1, Register src2, Register src3, Register src4, Register src5) { StoreU64WithUpdate(src5, MemOperand(sp, -5 * kSystemPointerSize)); StoreU64(src4, MemOperand(sp, kSystemPointerSize)); StoreU64(src3, MemOperand(sp, 2 * kSystemPointerSize)); StoreU64(src2, MemOperand(sp, 3 * kSystemPointerSize)); StoreU64(src1, MemOperand(sp, 4 * kSystemPointerSize)); } enum PushArrayOrder { kNormal, kReverse }; void PushArray(Register array, Register size, Register scratch, Register scratch2, PushArrayOrder order = kNormal); void Pop(Register dst) { pop(dst); } // Pop two registers. Pops rightmost register first (from lower address). void Pop(Register src1, Register src2) { LoadU64(src2, MemOperand(sp, 0)); LoadU64(src1, MemOperand(sp, kSystemPointerSize)); addi(sp, sp, Operand(2 * kSystemPointerSize)); } // Pop three registers. Pops rightmost register first (from lower address). void Pop(Register src1, Register src2, Register src3) { LoadU64(src3, MemOperand(sp, 0)); LoadU64(src2, MemOperand(sp, kSystemPointerSize)); LoadU64(src1, MemOperand(sp, 2 * kSystemPointerSize)); addi(sp, sp, Operand(3 * kSystemPointerSize)); } // Pop four registers. Pops rightmost register first (from lower address). void Pop(Register src1, Register src2, Register src3, Register src4) { LoadU64(src4, MemOperand(sp, 0)); LoadU64(src3, MemOperand(sp, kSystemPointerSize)); LoadU64(src2, MemOperand(sp, 2 * kSystemPointerSize)); LoadU64(src1, MemOperand(sp, 3 * kSystemPointerSize)); addi(sp, sp, Operand(4 * kSystemPointerSize)); } // Pop five registers. Pops rightmost register first (from lower address). void Pop(Register src1, Register src2, Register src3, Register src4, Register src5) { LoadU64(src5, MemOperand(sp, 0)); LoadU64(src4, MemOperand(sp, kSystemPointerSize)); LoadU64(src3, MemOperand(sp, 2 * kSystemPointerSize)); LoadU64(src2, MemOperand(sp, 3 * kSystemPointerSize)); LoadU64(src1, MemOperand(sp, 4 * kSystemPointerSize)); addi(sp, sp, Operand(5 * kSystemPointerSize)); } void MaybeSaveRegisters(RegList registers); void MaybeRestoreRegisters(RegList registers); void CallEphemeronKeyBarrier(Register object, Register slot_address, SaveFPRegsMode fp_mode); void CallRecordWriteStubSaveRegisters( Register object, Register slot_address, SaveFPRegsMode fp_mode, StubCallMode mode = StubCallMode::kCallBuiltinPointer); void CallRecordWriteStub( Register object, Register slot_address, SaveFPRegsMode fp_mode, StubCallMode mode = StubCallMode::kCallBuiltinPointer); void CallVerifySkippedWriteBarrierStubSaveRegisters(Register object, Register value, SaveFPRegsMode fp_mode); void CallVerifySkippedWriteBarrierStub(Register object, Register value); void MultiPush(RegList regs, Register location = sp); void MultiPop(RegList regs, Register location = sp); void MultiPushDoubles(DoubleRegList dregs, Register location = sp); void MultiPopDoubles(DoubleRegList dregs, Register location = sp); void MultiPushV128(Simd128RegList dregs, Register scratch, Register location = sp); void MultiPopV128(Simd128RegList dregs, Register scratch, Register location = sp); void MultiPushF64AndV128(DoubleRegList dregs, Simd128RegList simd_regs, Register scratch1, Register scratch2, Register location = sp); void MultiPopF64AndV128(DoubleRegList dregs, Simd128RegList simd_regs, Register scratch1, Register scratch2, Register location = sp); void PushAll(RegList registers); void PopAll(RegList registers); void PushAll(DoubleRegList registers, int stack_slot_size = kDoubleSize); void PopAll(DoubleRegList registers, int stack_slot_size = kDoubleSize); // Calculate how much stack space (in bytes) are required to store caller // registers excluding those specified in the arguments. int RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg, Register exclusion2 = no_reg, Register exclusion3 = no_reg) const; // Push caller saved registers on the stack, and return the number of bytes // stack pointer is adjusted. int PushCallerSaved(SaveFPRegsMode fp_mode, Register scratch1, Register scratch2, Register exclusion1 = no_reg, Register exclusion2 = no_reg, Register exclusion3 = no_reg); // Restore caller saved registers from the stack, and return the number of // bytes stack pointer is adjusted. int PopCallerSaved(SaveFPRegsMode fp_mode, Register scratch1, Register scratch2, Register exclusion1 = no_reg, Register exclusion2 = no_reg, Register exclusion3 = no_reg); // Load an object from the root table. void LoadRoot(Register destination, RootIndex index) final { LoadRoot(destination, index, al); } void LoadRoot(Register destination, RootIndex index, Condition cond); void LoadTaggedRoot(Register destination, RootIndex index); void SwapP(Register src, Register dst, Register scratch); void SwapP(Register src, MemOperand dst, Register scratch); void SwapP(MemOperand src, MemOperand dst, Register scratch_0, Register scratch_1); void SwapFloat32(DoubleRegister src, DoubleRegister dst, DoubleRegister scratch); void SwapFloat32(DoubleRegister src, MemOperand dst, DoubleRegister scratch); void SwapFloat32(MemOperand src, MemOperand dst, DoubleRegister scratch_0, DoubleRegister scratch_1); void SwapDouble(DoubleRegister src, DoubleRegister dst, DoubleRegister scratch); void SwapDouble(DoubleRegister src, MemOperand dst, DoubleRegister scratch); void SwapDouble(MemOperand src, MemOperand dst, DoubleRegister scratch_0, DoubleRegister scratch_1); void SwapSimd128(Simd128Register src, Simd128Register dst, Simd128Register scratch); void SwapSimd128(Simd128Register src, MemOperand dst, Simd128Register scratch1, Register scratch2); void SwapSimd128(MemOperand src, MemOperand dst, Simd128Register scratch1, Simd128Register scratch2, Register scratch3); void ByteReverseU16(Register dst, Register val, Register scratch); void ByteReverseU32(Register dst, Register val, Register scratch); void ByteReverseU64(Register dst, Register val, Register = r0); // Before calling a C-function from generated code, align arguments on stack. // After aligning the frame, non-register arguments must be stored in // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments // are word sized. If double arguments are used, this function assumes that // all double arguments are stored before core registers; otherwise the // correct alignment of the double values is not guaranteed. // Some compilers/platforms require the stack to be aligned when calling // C++ code. // Needs a scratch register to do some arithmetic. This register will be // trashed. void PrepareCallCFunction(int num_reg_arguments, int num_double_registers, Register scratch); void PrepareCallCFunction(int num_reg_arguments, Register scratch); // There are two ways of passing double arguments on ARM, depending on // whether soft or hard floating point ABI is used. These functions // abstract parameter passing for the three different ways we call // C functions from generated code. void MovToFloatParameter(DoubleRegister src); void MovToFloatParameters(DoubleRegister src1, DoubleRegister src2); void MovToFloatResult(DoubleRegister src); // Calls a C function and cleans up the space for arguments allocated // by PrepareCallCFunction. The called function is not allowed to trigger a // garbage collection, since that might move the code and invalidate the // return address (unless this is somehow accounted for by the called // function). int CallCFunction( ExternalReference function, int num_arguments, SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes, bool has_function_descriptor = true); int CallCFunction( Register function, int num_arguments, SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes, bool has_function_descriptor = true); int CallCFunction( ExternalReference function, int num_reg_arguments, int num_double_arguments, SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes, bool has_function_descriptor = true); int CallCFunction( Register function, int num_reg_arguments, int num_double_arguments, SetIsolateDataSlots set_isolate_data_slots = SetIsolateDataSlots::kYes, bool has_function_descriptor = true); void MovFromFloatParameter(DoubleRegister dst); void MovFromFloatResult(DoubleRegister dst); void Trap(); void DebugBreak(); // Calls Abort(msg) if the condition cond is not satisfied. // Use --debug_code to enable. void Assert(Condition cond, AbortReason reason, CRegister cr = cr0) NOOP_UNLESS_DEBUG_CODE; // Like Assert(), but always enabled. void Check(Condition cond, AbortReason reason, CRegister cr = cr0); // Print a message to stdout and abort execution. void Abort(AbortReason reason); void LoadFromConstantsTable(Register destination, int constant_index) final; void LoadRootRegisterOffset(Register destination, intptr_t offset) final; void LoadRootRelative(Register destination, int32_t offset) final; void StoreRootRelative(int32_t offset, Register value) final; MemOperand AsMemOperand(IsolateFieldId id) { DCHECK(root_array_available()); return MemOperand(kRootRegister, IsolateData::GetOffset(id)); } // Operand pointing to an external reference. // May emit code to set up the scratch register. The operand is // only guaranteed to be correct as long as the scratch register // isn't changed. // If the operand is used more than once, use a scratch register // that is guaranteed not to be clobbered. MemOperand ExternalReferenceAsOperand(ExternalReference reference, Register scratch); MemOperand ExternalReferenceAsOperand(IsolateFieldId id) { return ExternalReferenceAsOperand(ExternalReference::Create(id), no_reg); } // Jump, Call, and Ret pseudo instructions implementing inter-working. void Jump(Register target); void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al, CRegister cr = cr0); void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al, CRegister cr = cr0); void Jump(const ExternalReference& reference); void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al, CRegister cr = cr0); void Call(Register target); void Call(Address target, RelocInfo::Mode rmode, Condition cond = al); void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, Condition cond = al); void Call(Label* target); void GetLabelAddress(Register dst, Label* target); // Load the builtin given by the Smi in |builtin_index| into |target|. void LoadEntryFromBuiltinIndex(Register builtin_index, Register target); void LoadEntryFromBuiltin(Builtin builtin, Register destination); MemOperand EntryFromBuiltinAsOperand(Builtin builtin); void LoadEntrypointFromJSDispatchTable(Register destination, Register dispatch_handle, Register scratch); // Load the code entry point from the Code object. void LoadCodeInstructionStart(Register destination, Register code_object, CodeEntrypointTag tag = kInvalidEntrypointTag); void CallCodeObject(Register code_object); void JumpCodeObject(Register code_object, JumpMode jump_mode = JumpMode::kJump); void CallBuiltinByIndex(Register builtin_index, Register target); void AssertNotDeoptimized(Register scratch); void CallForDeoptimization(Builtin target, int deopt_id, Label* exit, DeoptimizeKind kind, Label* ret, Label* jump_deoptimization_entry_label); // Emit code to discard a non-negative number of pointer-sized elements // from the stack, clobbering only the sp register. void Drop(int count); void Drop(Register count, Register scratch = r0); void Ret() { blr(); } void Ret(Condition cond, CRegister cr = cr0) { bclr(cond, cr); } void Ret(int drop) { Drop(drop); blr(); } // If the value is a NaN, canonicalize the value else, do nothing. void CanonicalizeNaN(const DoubleRegister dst, const DoubleRegister src); void CanonicalizeNaN(const DoubleRegister value) { CanonicalizeNaN(value, value); } void CheckPageFlag(Register object, Register scratch, int mask, Condition cc, Label* condition_met); void PreCheckSkippedWriteBarrier(Register object, Register value, Register scratch, Label* ok); // Move values between integer and floating point registers. void MovIntToDouble(DoubleRegister dst, Register src, Register scratch); void MovUnsignedIntToDouble(DoubleRegister dst, Register src, Register scratch); void MovInt64ToDouble(DoubleRegister dst, Register src); void MovInt64ComponentsToDouble(DoubleRegister dst, Register src_hi, Register src_lo, Register scratch); void InsertDoubleLow(DoubleRegister dst, Register src, Register scratch); void InsertDoubleHigh(DoubleRegister dst, Register src, Register scratch); void MovDoubleLowToInt(Register dst, DoubleRegister src); void MovDoubleHighToInt(Register dst, DoubleRegister src); void MovDoubleToInt64( Register dst, DoubleRegister src); void MovIntToFloat(DoubleRegister dst, Register src, Register scratch); void MovFloatToInt(Register dst, DoubleRegister src, DoubleRegister scratch); // Register move. May do nothing if the registers are identical. void Move(Register dst, Tagged<Smi> smi) { LoadSmiLiteral(dst, smi); } void Move(Register dst, Handle<HeapObject> value, RelocInfo::Mode rmode = RelocInfo::FULL_EMBEDDED_OBJECT); void Move(Register dst, ExternalReference reference); void LoadIsolateField(Register dst, IsolateFieldId id); void Move(Register dst, Register src, Condition cond = al); void Move(DoubleRegister dst, DoubleRegister src); void Move(Register dst, const MemOperand& src) { // TODO(johnyan): Use scratch register scope instead of r0. LoadU64(dst, src, r0); } // Loads a field containing smi value and untags it. void SmiUntagField(Register dst, const MemOperand& src, RCBit rc = LeaveRC, Register scratch = r0); void SmiUntag(Register dst, const MemOperand& src, RCBit rc = LeaveRC, Register scratch = no_reg); void SmiUntag(Register reg, RCBit rc = LeaveRC) { SmiUntag(reg, reg, rc); } void SmiUntag(Register dst, Register src, RCBit rc = LeaveRC) { if (COMPRESS_POINTERS_BOOL) { srawi(dst, src, kSmiShift, rc); } else { ShiftRightS64(dst, src, Operand(kSmiShift), rc); } } void SmiToInt32(Register smi) { if (v8_flags.enable_slow_asserts) { AssertSmi(smi); } DCHECK(SmiValuesAre32Bits() || SmiValuesAre31Bits()); SmiUntag(smi); } void SmiToInt32(Register dst, Register src) { DCHECK(SmiValuesAre32Bits() || SmiValuesAre31Bits()); mr(dst, src); SmiUntag(dst); } // Shift left by kSmiShift void SmiTag(Register reg, RCBit rc = LeaveRC) { SmiTag(reg, reg, rc); } void SmiTag(Register dst, Register src, RCBit rc = LeaveRC) { ShiftLeftU64(dst, src, Operand(kSmiShift), rc); } // Abort execution if argument is a smi, enabled via --debug-code. void AssertNotSmi(Register object) NOOP_UNLESS_DEBUG_CODE; void AssertSmi(Register object) NOOP_UNLESS_DEBUG_CODE; // Abort execution if argument is not a Map, enabled via // --debug-code. void AssertMap(Register object) NOOP_UNLESS_DEBUG_CODE; // Like Assert(), but without condition. // Use --debug-code to enable. void AssertUnreachable(AbortReason reason) NOOP_UNLESS_DEBUG_CODE; void AssertZeroExtended(Register reg) NOOP_UNLESS_DEBUG_CODE; void ZeroExtByte(Register dst, Register src); void ZeroExtHalfWord(Register dst, Register src); void ZeroExtWord32(Register dst, Register src); // --------------------------------------------------------------------------- // Bit testing/extraction // // Bit numbering is such that the least significant bit is bit 0 // (for consistency between 32/64-bit). // Extract consecutive bits (defined by rangeStart - rangeEnd) from src // and, if !test, shift them into the least significant bits of dst. inline void ExtractBitRange(Register dst, Register src, int rangeStart, int rangeEnd, RCBit rc = LeaveRC, bool test = false) { DCHECK(rangeStart >= rangeEnd && rangeStart < kBitsPerSystemPointer); int rotate = (rangeEnd == 0) ? 0 : kBitsPerSystemPointer - rangeEnd; int width = rangeStart - rangeEnd + 1; if (rc == SetRC && rangeStart < 16 && (rangeEnd == 0 || test)) { // Prefer faster andi when applicable. andi(dst, src, Operand(((1 << width) - 1) << rangeEnd)); } else { rldicl(dst, src, rotate, kBitsPerSystemPointer - width, rc); } } inline void ExtractBit(Register dst, Register src, uint32_t bitNumber, RCBit rc = LeaveRC, bool test = false) { ExtractBitRange(dst, src, bitNumber, bitNumber, rc, test); } // Extract consecutive bits (defined by mask) from src and place them // into the least significant bits of dst. inline void ExtractBitMask(Register dst, Register src, uintptr_t mask, RCBit rc = LeaveRC, bool test = false) { int start = kBitsPerSystemPointer - 1; int end; uintptr_t bit = (1L << start); while (bit && (mask & bit) == 0) { start--; bit >>= 1; } end = start; bit >>= 1; while (bit && (mask & bit)) { end--; bit >>= 1; } // 1-bits in mask must be contiguous DCHECK(bit == 0 || (mask & ((bit << 1) - 1)) == 0); ExtractBitRange(dst, src, start, end, rc, test); } // Test single bit in value. inline void TestBit(Register value, int bitNumber, Register scratch = r0) { ExtractBitRange(scratch, value, bitNumber, bitNumber, SetRC, true); } // Test consecutive bit range in value. Range is defined by mask. inline void TestBitMask(Register value, uintptr_t mask, Register scratch = r0) { ExtractBitMask(scratch, value, mask, SetRC, true); } // Test consecutive bit range in value. Range is defined by // rangeStart - rangeEnd. inline void TestBitRange(Register value, int rangeStart, int rangeEnd, Register scratch = r0) { ExtractBitRange(scratch, value, rangeStart, rangeEnd, SetRC, true); } inline void TestIfSmi(Register value, Register scratch) { TestBitRange(value, kSmiTagSize - 1, 0, scratch); } // Jump the register contains a smi. inline void JumpIfSmi(Register value, Label* smi_label) { TestIfSmi(value, r0); beq(smi_label, cr0); // branch if SMI } Condition CheckSmi(Register src) { TestIfSmi(src, r0); return eq; } void JumpIfEqual(Register x, int32_t y, Label* dest); void JumpIfLessThan(Register x, int32_t y, Label* dest); void JumpIfUnsignedLessThan(Register x, int32_t y, Label* dest); // Caution: if {reg} is a 32-bit negative int, it should be sign-extended to // 64-bit before calling this function. void Switch(Register scrach, Register reg, int case_base_value, Label** labels, int num_labels); void JumpIfCodeIsMarkedForDeoptimization(Register code, Register scratch, Label* if_marked_for_deoptimization); void JumpIfCodeIsTurbofanned(Register code, Register scratch, Label* if_turbofanned); void LoadMap(Register destination, Register object); void LoadCompressedMap(Register dst, Register object, Register scratch); void LoadCompressedMap(Register dst, Register object); void LoadFeedbackVector(Register dst, Register closure, Register scratch, Label* fbv_undef); void LoadInterpreterDataBytecodeArray(Register destination, Register interpreter_data); void LoadInterpreterDataInterpreterTrampoline(Register destination, Register interpreter_data); inline void TestIfInt32(Register value, Register scratch, CRegister cr = cr0) { // High bits must be identical to fit into an 32-bit integer extsw(scratch, value); CmpS64(scratch, value, cr); } // Overflow handling functions. // Usage: call the appropriate arithmetic function and then call one of the // flow control functions with the corresponding label. void MoveToCrFromXer(CRegister cr) { mcrxrx(cr); } // Compute dst = left + right, setting condition codes. dst may be same as // either left or right (or a unique register). left and right must not be // the same register. void AddAndCheckForOverflow(Register dst, Register left, Register right, Register overflow_dst, Register scratch = r0); void AddAndCheckForOverflow(Register dst, Register left, intptr_t right, Register overflow_dst, Register scratch = r0); // Compute dst = left - right, setting condition codes. dst may be same as // either left or right (or a unique register). left and right must not be // the same register. void SubAndCheckForOverflow(Register dst, Register left, Register right, Register overflow_dst, Register scratch = r0); // Performs a truncating conversion of a floating point number as used by // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it // succeeds, otherwise falls through if result is saturated. On return // 'result' either holds answer, or is clobbered on fall through. void TryInlineTruncateDoubleToI(Register result, DoubleRegister input, Label* done, DoubleRegister double_scratch); void TruncateDoubleToI(Isolate* isolate, Zone* zone, Register result, DoubleRegister double_input, StubCallMode stub_mode, DoubleRegister double_scratch); void LoadConstantPoolPointerRegister(); // Loads the constant pool pointer (kConstantPoolRegister). void LoadConstantPoolPointerRegisterFromCodeTargetAddress( Register code_target_address, Register scratch1, Register scratch2); void AbortConstantPoolBuilding() { #ifdef DEBUG // Avoid DCHECK(!is_linked()) failure in ~Label() bind(ConstantPoolPosition()); #endif } // Convenience functions to call/jmp to the code of a JSFunction object. void CallJSFunction(Register function_object, uint16_t argument_count); void JumpJSFunction(Register function_object, Register scratch, JumpMode jump_mode = JumpMode::kJump); void CallJSDispatchEntry(JSDispatchHandle dispatch_handle, uint16_t argument_count); #ifdef V8_ENABLE_WEBASSEMBLY void ResolveWasmCodePointer(Register target); void CallWasmCodePointer(Register target, CallJumpMode call_jump_mode = CallJumpMode::kCall); void LoadWasmCodePointer(Register dst, MemOperand src); #endif // Generates an instruction sequence s.t. the return address points to the // instruction following the call. // The return address on the stack is used by frame iteration. void StoreReturnAddressAndCall(Register target); // Enforce platform specific stack alignment. void EnforceStackAlignment(); // Control-flow integrity: // Define a function entrypoint. This doesn't emit any code for this // architecture, as control-flow integrity is not supported for it. void CodeEntry() {} // Define an exception handler. void ExceptionHandler() {} // Define an exception handler and bind a label. void BindExceptionHandler(Label* label) { bind(label); } // --------------------------------------------------------------------------- // Pointer compression Support void SmiToPtrArrayOffset(Register dst, Register src) { #if defined(V8_COMPRESS_POINTERS) || defined(V8_31BIT_SMIS_ON_64BIT_ARCH) static_assert(kSmiTag == 0 && kSmiShift < kSystemPointerSizeLog2); ShiftLeftU64(dst, src, Operand(kSystemPointerSizeLog2 - kSmiShift)); #else static_assert(kSmiTag == 0 && kSmiShift > kSystemPointerSizeLog2); ShiftRightS64(dst, src, Operand(kSmiShift - kSystemPointerSizeLog2)); #endif } // Loads a field containing any tagged value and decompresses it if necessary. void LoadTaggedField(const Register& destination, const MemOperand& field_operand, const Register& scratch = r0); void LoadTaggedSignedField(Register destination, MemOperand field_operand, Register scratch = r0); void LoadTaggedFieldWithoutDecompressing(const Register& destination, const MemOperand& field_operand, const Register& scratch = r0); // Compresses and stores tagged value to given on-heap location. void StoreTaggedField(const Register& value, const MemOperand& dst_field_operand, const Register& scratch = r0); void Zero(const MemOperand& dest); void Zero(const MemOperand& dest1, const MemOperand& dest2); void DecompressTaggedSigned(Register destination, MemOperand field_operand); void DecompressTaggedSigned(Register destination, Register src); void DecompressTagged(Register destination, MemOperand field_operand); void DecompressTagged(Register destination, Register source); void DecompressTagged(const Register& destination, Tagged_t immediate); void LoadF64(DoubleRegister dst, const MemOperand& mem, Register scratch = no_reg); void LoadF32(DoubleRegister dst, const MemOperand& mem, Register scratch = no_reg); void StoreF32(DoubleRegister src, const MemOperand& mem, Register scratch = no_reg); void StoreF64(DoubleRegister src, const MemOperand& mem, Register scratch = no_reg); void LoadF32WithUpdate(DoubleRegister dst, const MemOperand& mem, Register scratch = no_reg); void LoadF64WithUpdate(DoubleRegister dst, const MemOperand& mem, Register scratch = no_reg); void StoreF32WithUpdate(DoubleRegister src, const MemOperand& mem, Register scratch = no_reg); void StoreF64WithUpdate(DoubleRegister src, const MemOperand& mem, Register scratch = no_reg); void LoadU64(Register dst, const MemOperand& mem, Register scratch = no_reg); void LoadU32(Register dst, const MemOperand& mem, Register scratch = no_reg); void LoadS32(Register dst, const MemOperand& mem, Register scratch = no_reg); void LoadS32(Register dst, Register src) { extsw(dst, src); } void LoadU16(Register dst, const MemOperand& mem, Register scratch = no_reg); void LoadS16(Register dst, const MemOperand& mem, Register scratch = no_reg); void LoadU8(Register dst, const MemOperand& mem, Register scratch = no_reg); void LoadS8(Register dst, const MemOperand& mem, Register scratch = no_reg); void StoreU64(Register src, const MemOperand& mem, Register scratch = no_reg); void StoreU32(Register src, const MemOperand& mem, Register scratch); void StoreU16(Register src, const MemOperand& mem, Register scratch); void StoreU8(Register src, const MemOperand& mem, Register scratch); void LoadU64WithUpdate(Register dst, const MemOperand& mem, Register scratch = no_reg); void StoreU64WithUpdate(Register src, const MemOperand& mem, Register scratch = no_reg); void LoadU64LE(Register dst, const MemOperand& mem, Register scratch); void LoadU32LE(Register dst, const MemOperand& mem, Register scratch); void LoadU16LE(Register dst, const MemOperand& mem, Register scratch); void StoreU64LE(Register src, const MemOperand& mem, Register scratch); void StoreU32LE(Register src, const MemOperand& mem, Register scratch); void StoreU16LE(Register src, const MemOperand& mem, Register scratch); void LoadS32LE(Register dst, const MemOperand& mem, Register scratch); void LoadS16LE(Register dst, const MemOperand& mem, Register scratch); void LoadF64LE(DoubleRegister dst, const MemOperand& mem, Register scratch, Register scratch2); void LoadF32LE(DoubleRegister dst, const MemOperand& mem, Register scratch, Register scratch2); void StoreF32LE(DoubleRegister src, const MemOperand& mem, Register scratch, Register scratch2); void StoreF64LE(DoubleRegister src, const MemOperand& mem, Register scratch, Register scratch2); // Simd Support. #define SIMD_BINOP_LIST(V) \ V(F64x2Add) \ V(F64x2Sub) \ V(F64x2Mul) \ V(F64x2Div) \ V(F64x2Eq) \ V(F64x2Lt) \ V(F64x2Le) \ V(F32x4Add) \ V(F32x4Sub) \ V(F32x4Mul) \ V(F32x4Div) \ V(F32x4Min) \ V(F32x4Max) \ V(F32x4Eq) \ V(F32x4Lt) \ V(F32x4Le) \ V(I64x2Add) \ V(I64x2Sub) \ V(I64x2Eq) \ V(I64x2GtS) \ V(I32x4MinS) \ V(I32x4MinU) \ V(I32x4MaxS) \ V(I32x4MaxU) \ V(I32x4Add) \ V(I32x4Sub) \ V(I32x4Mul) \ V(I32x4Eq) \ V(I32x4GtS) \ V(I32x4GtU) \ V(I32x4DotI16x8S) \ V(I16x8Add) \ V(I16x8Sub) \ V(I16x8Mul) \ V(I16x8MinS) \ V(I16x8MinU) \ V(I16x8MaxS) \ V(I16x8MaxU) \ V(I16x8Eq) \ V(I16x8GtS) \ V(I16x8GtU) \ V(I16x8AddSatS) \ V(I16x8SubSatS) \ V(I16x8AddSatU) \ V(I16x8SubSatU) \ V(I16x8SConvertI32x4) \ V(I16x8UConvertI32x4) \ V(I16x8RoundingAverageU) \ V(I16x8Q15MulRSatS) \ V(I8x16Add) \ V(I8x16Sub) \ V(I8x16MinS) \ V(I8x16MinU) \ V(I8x16MaxS) \ V(I8x16MaxU) \ V(I8x16Eq) \ V(I8x16GtS) \ V(I8x16GtU) \ V(I8x16AddSatS) \ V(I8x16SubSatS) \ V(I8x16AddSatU) \ V(I8x16SubSatU) \ V(I8x16SConvertI16x8) \ V(I8x16UConvertI16x8) \ V(I8x16RoundingAverageU) \ V(S128And) \ V(S128Or) \ V(S128Xor) \ V(S128AndNot) #define PROTOTYPE_SIMD_BINOP(name) \ void name(Simd128Register dst, Simd128Register src1, Simd128Register src2); SIMD_BINOP_LIST(PROTOTYPE_SIMD_BINOP) #undef PROTOTYPE_SIMD_BINOP #undef SIMD_BINOP_LIST #define SIMD_BINOP_WITH_SCRATCH_LIST(V) \ V(F64x2Ne) \ V(F64x2Pmin) \ V(F64x2Pmax) \ V(F32x4Ne) \ V(F32x4Pmin) \ V(F32x4Pmax) \ V(I64x2Ne) \ V(I64x2GeS) \ V(I64x2ExtMulLowI32x4S) \ V(I64x2ExtMulHighI32x4S) \ V(I64x2ExtMulLowI32x4U) \ V(I64x2ExtMulHighI32x4U) \ V(I32x4Ne) \ V(I32x4GeS) \ V(I32x4GeU) \ V(I32x4ExtMulLowI16x8S) \ V(I32x4ExtMulHighI16x8S) \ V(I32x4ExtMulLowI16x8U) \ V(I32x4ExtMulHighI16x8U) \ V(I16x8Ne) \ V(I16x8GeS) \ V(I16x8GeU) \ V(I16x8ExtMulLowI8x16S) \ V(I16x8ExtMulHighI8x16S) \ V(I16x8ExtMulLowI8x16U) \ V(I16x8ExtMulHighI8x16U) \ V(I16x8DotI8x16S) \ V(I8x16Ne) \ V(I8x16GeS) \ V(I8x16GeU) \ V(I8x16Swizzle) #define PROTOTYPE_SIMD_BINOP_WITH_SCRATCH(name) \ void name(Simd128Register dst, Simd128Register src1, Simd128Register src2, \ Simd128Register scratch); SIMD_BINOP_WITH_SCRATCH_LIST(PROTOTYPE_SIMD_BINOP_WITH_SCRATCH) #undef PROTOTYPE_SIMD_BINOP_WITH_SCRATCH #undef SIMD_BINOP_WITH_SCRATCH_LIST #define SIMD_SHIFT_LIST(V) \ V(I64x2Shl) \ V(I64x2ShrS) \ V(I64x2ShrU) \ V(I32x4Shl) \ V(I32x4ShrS) \ V(I32x4ShrU) \ V(I16x8Shl) \ V(I16x8ShrS) \ V(I16x8ShrU) \ V(I8x16Shl) \ V(I8x16ShrS) \ V(I8x16ShrU) #define PROTOTYPE_SIMD_SHIFT(name) \ void name(Simd128Register dst, Simd128Register src1, Register src2, \ Simd128Register scratch); \ void name(Simd128Register dst, Simd128Register src1, const Operand& src2, \ Register scratch1, Simd128Register scratch2); SIMD_SHIFT_LIST(PROTOTYPE_SIMD_SHIFT) #undef PROTOTYPE_SIMD_SHIFT #undef SIMD_SHIFT_LIST #define SIMD_BITMASK_LIST(V) \ V(I64x2BitMask) \ V(I32x4BitMask) \ V(I16x8BitMask) #define PROTOTYPE_SIMD_BITMASK(name) \ void name(Register dst, Simd128Register src, Register scratch1, \ Simd128Register scratch2); SIMD_BITMASK_LIST(PROTOTYPE_SIMD_BITMASK) #undef PROTOTYPE_SIMD_BITMASK #undef SIMD_BITMASK_LIST #define SIMD_UNOP_LIST(V) \ V(F64x2Abs) \ V(F64x2Neg) \ V(F64x2Sqrt) \ V(F64x2Ceil) \ V(F64x2Floor) \ V(F64x2Trunc) \ V(F64x2PromoteLowF32x4) \ V(F32x4Abs) \ V(F32x4Neg) \ V(F32x4Sqrt) \ V(F32x4Ceil) \ V(F32x4Floor) \ V(F32x4Trunc) \ V(F32x4SConvertI32x4) \ V(F32x4UConvertI32x4) \ V(I64x2Neg) \ V(F64x2ConvertLowI32x4S) \ V(I64x2SConvertI32x4Low) \ V(I64x2SConvertI32x4High) \ V(I32x4Neg) \ V(I32x4SConvertI16x8Low) \ V(I32x4SConvertI16x8High) \ V(I32x4UConvertF32x4) \ V(I16x8SConvertI8x16Low) \ V(I16x8SConvertI8x16High) \ V(I8x16Popcnt) \ V(S128Not) #define PROTOTYPE_SIMD_UNOP(name) \ void name(Simd128Register dst, Simd128Register src); SIMD_UNOP_LIST(PROTOTYPE_SIMD_UNOP) #undef PROTOTYPE_SIMD_UNOP #undef SIMD_UNOP_LIST #define SIMD_UNOP_WITH_SCRATCH_LIST(V) \ V(F32x4DemoteF64x2Zero) \ V(I64x2Abs) \ V(I32x4Abs) \ V(I32x4SConvertF32x4) \ V(I32x4TruncSatF64x2SZero) \ V(I32x4TruncSatF64x2UZero) \ V(I16x8Abs) \ V(I16x8Neg) \ V(I8x16Abs) \ V(I8x16Neg) #define PROTOTYPE_SIMD_UNOP_WITH_SCRATCH(name) \ void name(Simd128Register dst, Simd128Register src, Simd128Register scratch); SIMD_UNOP_WITH_SCRATCH_LIST(PROTOTYPE_SIMD_UNOP_WITH_SCRATCH) #undef PROTOTYPE_SIMD_UNOP_WITH_SCRATCH #undef SIMD_UNOP_WITH_SCRATCH_LIST #define SIMD_ALL_TRUE_LIST(V) \ V(I64x2AllTrue) \ V(I32x4AllTrue) \ V(I16x8AllTrue) \ V(I8x16AllTrue) #define PROTOTYPE_SIMD_ALL_TRUE(name) \ void name(Register dst, Simd128Register src, Register scratch1, \ Register scratch2, Simd128Register scratch3); SIMD_ALL_TRUE_LIST(PROTOTYPE_SIMD_ALL_TRUE) #undef PROTOTYPE_SIMD_ALL_TRUE #undef SIMD_ALL_TRUE_LIST #define SIMD_QFM_LIST(V) \ V(F64x2Qfma) \ V(F64x2Qfms) \ V(F32x4Qfma) \ V(F32x4Qfms) #define PROTOTYPE_SIMD_QFM(name) \ void name(Simd128Register dst, Simd128Register src1, Simd128Register src2, \ Simd128Register src3, Simd128Register scratch); SIMD_QFM_LIST(PROTOTYPE_SIMD_QFM) #undef PROTOTYPE_SIMD_QFM #undef SIMD_QFM_LIST #define SIMD_EXT_ADD_PAIRWISE_LIST(V) \ V(I32x4ExtAddPairwiseI16x8S) \ V(I32x4ExtAddPairwiseI16x8U) \ V(I16x8ExtAddPairwiseI8x16S) \ V(I16x8ExtAddPairwiseI8x16U) #define PROTOTYPE_SIMD_EXT_ADD_PAIRWISE(name) \ void name(Simd128Register dst, Simd128Register src, \ Simd128Register scratch1, Simd128Register scratch2); SIMD_EXT_ADD_PAIRWISE_LIST(PROTOTYPE_SIMD_EXT_ADD_PAIRWISE) #undef PROTOTYPE_SIMD_EXT_ADD_PAIRWISE #undef SIMD_EXT_ADD_PAIRWISE_LIST void LoadSimd128(Simd128Register dst, const MemOperand& mem, Register scratch); void StoreSimd128(Simd128Register src, const MemOperand& mem, Register scratch); void LoadSimd128LE(Simd128Register dst, const MemOperand& mem, Register scratch); void StoreSimd128LE(Simd128Register src, const MemOperand& mem, Register scratch1, Simd128Register scratch2); void LoadSimd128Uint64(Simd128Register reg, const MemOperand& mem, Register scratch); void LoadSimd128Uint32(Simd128Register reg, const MemOperand& mem, Register scratch); void LoadSimd128Uint16(Simd128Register reg, const MemOperand& mem, Register scratch); void LoadSimd128Uint8(Simd128Register reg, const MemOperand& mem, Register scratch); void StoreSimd128Uint64(Simd128Register reg, const MemOperand& mem, Register scratch); void StoreSimd128Uint32(Simd128Register reg, const MemOperand& mem, Register scratch); void StoreSimd128Uint16(Simd128Register reg, const MemOperand& mem, Register scratch); void StoreSimd128Uint8(Simd128Register reg, const MemOperand& mem, Register scratch); void LoadLane64LE(Simd128Register dst, const MemOperand& mem, int lane, Register scratch1, Simd128Register scratch2); void LoadLane32LE(Simd128Register dst, const MemOperand& mem, int lane, Register scratch1, Simd128Register scratch2); void LoadLane16LE(Simd128Register dst, const MemOperand& mem, int lane, Register scratch1, Simd128Register scratch2); void LoadLane8LE(Simd128Register dst, const MemOperand& mem, int lane, Register scratch1, Simd128Register scratch2); void StoreLane64LE(Simd128Register src, const MemOperand& mem, int lane, Register scratch1, Simd128Register scratch2); void StoreLane32LE(Simd128Register src, const MemOperand& mem, int lane, Register scratch1, Simd128Register scratch2); void StoreLane16LE(Simd128Register src, const MemOperand& mem, int lane, Register scratch1, Simd128Register scratch2); void StoreLane8LE(Simd128Register src, const MemOperand& mem, int lane, Register scratch1, Simd128Register scratch2); void LoadAndSplat64x2LE(Simd128Register dst, const MemOperand& mem, Register scratch); void LoadAndSplat32x4LE(Simd128Register dst, const MemOperand& mem, Register scratch); void LoadAndSplat16x8LE(Simd128Register dst, const MemOperand& me, Register scratch); void LoadAndSplat8x16LE(Simd128Register dst, const MemOperand& mem, Register scratch); void LoadAndExtend32x2SLE(Simd128Register dst, const MemOperand& mem, Register scratch); void LoadAndExtend32x2ULE(Simd128Register dst, const MemOperand& mem, Register scratch1, Simd128Register scratch2); void LoadAndExtend16x4SLE(Simd128Register dst, const MemOperand& mem, Register scratch); void LoadAndExtend16x4ULE(Simd128Register dst, const MemOperand& mem, Register scratch1, Simd128Register scratch2); void LoadAndExtend8x8SLE(Simd128Register dst, const MemOperand& mem, Register scratch); void LoadAndExtend8x8ULE(Simd128Register dst, const MemOperand& mem, Register scratch1, Simd128Register scratch2); void LoadV64ZeroLE(Simd128Register dst, const MemOperand& mem, Register scratch1, Simd128Register scratch2); void LoadV32ZeroLE(Simd128Register dst, const MemOperand& mem, Register scratch1, Simd128Register scratch2); void F64x2Splat(Simd128Register dst, DoubleRegister src, Register scratch); void F32x4Splat(Simd128Register dst, DoubleRegister src, DoubleRegister scratch1, Register scratch2); void I64x2Splat(Simd128Register dst, Register src); void I32x4Splat(Simd128Register dst, Register src); void I16x8Splat(Simd128Register dst, Register src); void I8x16Splat(Simd128Register dst, Register src); void F64x2ExtractLane(DoubleRegister dst, Simd128Register src, uint8_t imm_lane_idx, Simd128Register scratch1, Register scratch2); void F32x4ExtractLane(DoubleRegister dst, Simd128Register src, uint8_t imm_lane_idx, Simd128Register scratch1, Register scratch2, Register scratch3); void I64x2ExtractLane(Register dst, Simd128Register src, uint8_t imm_lane_idx, Simd128Register scratch); void I32x4ExtractLane(Register dst, Simd128Register src, uint8_t imm_lane_idx, Simd128Register scratch); void I16x8ExtractLaneU(Register dst, Simd128Register src, uint8_t imm_lane_idx, Simd128Register scratch); void I16x8ExtractLaneS(Register dst, Simd128Register src, uint8_t imm_lane_idx, Simd128Register scratch); void I8x16ExtractLaneU(Register dst, Simd128Register src, uint8_t imm_lane_idx, Simd128Register scratch); void I8x16ExtractLaneS(Register dst, Simd128Register src, uint8_t imm_lane_idx, Simd128Register scratch); void F64x2ReplaceLane(Simd128Register dst, Simd128Register src1, DoubleRegister src2, uint8_t imm_lane_idx, Register scratch1, Simd128Register scratch2); void F32x4ReplaceLane(Simd128Register dst, Simd128Register src1, DoubleRegister src2, uint8_t imm_lane_idx, Register scratch1, DoubleRegister scratch2, Simd128Register scratch3); void I64x2ReplaceLane(Simd128Register dst, Simd128Register src1, Register src2, uint8_t imm_lane_idx, Simd128Register scratch); void I32x4ReplaceLane(Simd128Register dst, Simd128Register src1, Register src2, uint8_t imm_lane_idx, Simd128Register scratch); void I16x8ReplaceLane(Simd128Register dst, Simd128Register src1, Register src2, uint8_t imm_lane_idx, Simd128Register scratch); void I8x16ReplaceLane(Simd128Register dst, Simd128Register src1, Register src2, uint8_t imm_lane_idx, Simd128Register scratch); void I64x2Mul(Simd128Register dst, Simd128Register src1, Simd128Register src2, Register scratch1, Register scrahc2, Register scratch3, Simd128Register scratch4); void F64x2Min(Simd128Register dst, Simd128Register src1, Simd128Register src2, Simd128Register scratch1, Simd128Register scratch2); void F64x2Max(Simd128Register dst, Simd128Register src1, Simd128Register src2, Simd128Register scratch1, Simd128Register scratch2); void F64x2ConvertLowI32x4U(Simd128Register dst, Simd128Register src, Register scratch1, Simd128Register scratch2); void I64x2UConvertI32x4Low(Simd128Register dst, Simd128Register src, Register scratch1, Simd128Register scratch2); void I64x2UConvertI32x4High(Simd128Register dst, Simd128Register src, Register scratch1, Simd128Register scratch2); void I32x4UConvertI16x8Low(Simd128Register dst, Simd128Register src, Register scratch1, Simd128Register scratch2); void I32x4UConvertI16x8High(Simd128Register dst, Simd128Register src, Register scratch1, Simd128Register scratch2); void I16x8UConvertI8x16Low(Simd128Register dst, Simd128Register src, Register scratch1, Simd128Register scratch2); void I16x8UConvertI8x16High(Simd128Register dst, Simd128Register src, Register scratch1, Simd128Register scratch2); void I8x16BitMask(Register dst, Simd128Register src, Register scratch1, Register scratch2, Simd128Register scratch3); void I8x16Shuffle(Simd128Register dst, Simd128Register src1, Simd128Register src2, uint64_t high, uint64_t low, Register scratch1, Register scratch2, Simd128Register scratch3); void I32x4DotI8x16AddS(Simd128Register dst, Simd128Register src1, Simd128Register src2, Simd128Register src3); void V128AnyTrue(Register dst, Simd128Register src, Register scratch1, Register scratch2, Simd128Register scratch3); void S128Const(Simd128Register dst, uint64_t high, uint64_t low, Register scratch1, Register scratch2); void S128Select(Simd128Register dst, Simd128Register src1, Simd128Register src2, Simd128Register mask); // It assumes that the arguments are located below the stack pointer. void LoadReceiver(Register dest) { LoadU64(dest, MemOperand(sp, 0)); } void StoreReceiver(Register rec) { StoreU64(rec, MemOperand(sp, 0)); } // --------------------------------------------------------------------------- // GC Support void MaybeJumpIfReadOnlyOrSmallSmi(Register, Label*) {} // Notify the garbage collector that we wrote a pointer into an object. // |object| is the object being stored into, |value| is the object being // stored. value and scratch registers are clobbered by the operation. // The offset is the offset from the start of the object, not the offset from // the tagged HeapObject pointer. For use with FieldMemOperand(reg, off). void RecordWriteField(Register object, int offset, Register value, Register slot_address, LinkRegisterStatus lr_status, SaveFPRegsMode save_fp, SmiCheck smi_check = SmiCheck::kInline); // For a given |object| notify the garbage collector that the slot |address| // has been written. |value| is the object being stored. The value and // address registers are clobbered by the operation. void RecordWrite(Register object, Register slot_address, Register value, LinkRegisterStatus lr_status, SaveFPRegsMode save_fp, SmiCheck smi_check = SmiCheck::kInline); // Enter exit frame. // stack_space - extra stack space, used for parameters before call to C. void EnterExitFrame(Register scratch, int stack_space, StackFrame::Type frame_type); // Leave the current exit frame. void LeaveExitFrame(Register scratch); // Load the global proxy from the current context. void LoadGlobalProxy(Register dst) { LoadNativeContextSlot(dst, Context::GLOBAL_PROXY_INDEX); } void LoadNativeContextSlot(Register dst, int index); // Falls through and sets scratch_and_result to 0 on failure, jumps to // on_result on success. void TryLoadOptimizedOsrCode(Register scratch_and_result, CodeKind min_opt_level, Register feedback_vector, FeedbackSlot slot, Label* on_result, Label::Distance distance); // ---------------------------------------------------------------- // new PPC macro-assembler interfaces that are slightly higher level // than assembler-ppc and may generate variable length sequences // load a literal double value <value> to FPR <result> void AddSmiLiteral(Register dst, Register src, Tagged<Smi> smi, Register scratch); void SubSmiLiteral(Register dst, Register src, Tagged<Smi> smi, Register scratch); void CmpSmiLiteral(Register src1, Tagged<Smi> smi, Register scratch, CRegister cr = cr0); void CmplSmiLiteral(Register src1, Tagged<Smi> smi, Register scratch, CRegister cr = cr0); void AndSmiLiteral(Register dst, Register src, Tagged<Smi> smi, Register scratch, RCBit rc = LeaveRC); // --------------------------------------------------------------------------- // JavaScript invokes // Removes current frame and its arguments from the stack preserving // the arguments and a return address pushed to the stack for the next call. // Both |callee_args_count| and |caller_args_countg| do not include // receiver. |callee_args_count| is not modified. |caller_args_count| // is trashed. // Invoke the JavaScript function code by either calling or jumping. void InvokeFunctionCode(Register function, Register new_target, Register expected_parameter_count, Register actual_parameter_count, InvokeType type); // On function call, call into the debugger if necessary. void CheckDebugHook(Register fun, Register new_target, Register expected_parameter_count, Register actual_parameter_count); // Invoke the JavaScript function in the given register. Changes the // current context to the context in the function before invoking. void InvokeFunctionWithNewTarget(Register function, Register new_target, Register actual_parameter_count, InvokeType type); void InvokeFunction(Register function, Register expected_parameter_count, Register actual_parameter_count, InvokeType type); // Exception handling // Push a new stack handler and link into stack handler chain. void PushStackHandler(); // Unlink the stack handler on top of the stack from the stack handler chain. // Must preserve the result register. void PopStackHandler(); // --------------------------------------------------------------------------- // Support functions. // Compare instance type in a map. map contains a valid map object whose // object type should be compared with the given type. This both // sets the flags and leaves the object type in the type_reg register. template <bool use_unsigned_cmp = false> void CompareInstanceType(Register map, Register type_reg, InstanceType type) { static_assert(Map::kInstanceTypeOffset < 4096); static_assert(LAST_TYPE <= 0xFFFF); if (use_unsigned_cmp) { LoadU16(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); CmpU64(type_reg, Operand(type), r0); } else { LoadS16(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset)); CmpS64(type_reg, Operand(type), r0); } } // Compare object type for heap object. heap_object contains a non-Smi // whose object type should be compared with the given type. This both // sets the flags and leaves the object type in the type_reg register. // It leaves the map in the map register (unless the type_reg and map register // are the same register). It leaves the heap object in the heap_object // register unless the heap_object register is the same register as one of the // other registers. // Type_reg can be no_reg. In that case ip is used. template <bool use_unsigned_cmp = false> void CompareObjectType(Register heap_object, Register map, Register type_reg, InstanceType type) { const Register temp = type_reg == no_reg ? r0 : type_reg; LoadMap(map, heap_object); CompareInstanceType<use_unsigned_cmp>(map, temp, type); } // Variant of the above, which compares against a type range rather than a // single type (lower_limit and higher_limit are inclusive). // // Always use unsigned comparisons: ls for a positive result. void CompareObjectTypeRange(Register heap_object, Register map, Register type_reg, Register scratch, InstanceType lower_limit, InstanceType higher_limit); // Variant of the above, which only guarantees to set the correct eq/ne flag. // Neither map, nor type_reg might be set to any particular value. void IsObjectType(Register heap_object, Register scratch1, Register scratch2, InstanceType type); // Compare instance type ranges for a map (lower_limit and higher_limit // inclusive). // // Always use unsigned comparisons: ls for a positive result. void CompareInstanceTypeRange(Register map, Register type_reg, Register scratch, InstanceType lower_limit, InstanceType higher_limit); // Compare the object in a register to a value from the root list. // Uses the ip register as scratch. void CompareRoot(Register obj, RootIndex index); void CompareTaggedRoot(const Register& with, RootIndex index); void PushRoot(RootIndex index) { LoadRoot(r0, index); Push(r0); } // Compare the object in a register to a value and jump if they are equal. void JumpIfRoot(Register with, RootIndex index, Label* if_equal) { CompareRoot(with, index); beq(if_equal); } // Compare the object in a register to a value and jump if they are not equal. void JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal) { CompareRoot(with, index); bne(if_not_equal); } // Checks if value is in range [lower_limit, higher_limit] using a single // comparison. void CompareRange(Register value, Register scratch, unsigned lower_limit, unsigned higher_limit); void JumpIfIsInRange(Register value, Register scratch, unsigned lower_limit, unsigned higher_limit, Label* on_in_range); // Tiering support. void AssertFeedbackCell(Register object, Register scratch) NOOP_UNLESS_DEBUG_CODE; void AssertFeedbackVector(Register object, Register scratch) NOOP_UNLESS_DEBUG_CODE; // TODO(olivf): Rename to GenerateTailCallToUpdatedFunction. void GenerateTailCallToReturnedCode(Runtime::FunctionId function_id); // --------------------------------------------------------------------------- // Runtime calls static int CallSizeNotPredictableCodeSize(Address target, RelocInfo::Mode rmode, Condition cond = al); void CallJSEntry(Register target); // Call a runtime routine. void CallRuntime(const Runtime::Function* f, int num_arguments); // Convenience function: Same as above, but takes the fid instead. void CallRuntime(Runtime::FunctionId fid) { const Runtime::Function* function = Runtime::FunctionForId(fid); CallRuntime(function, function->nargs); } // Convenience function: Same as above, but takes the fid instead. void CallRuntime(Runtime::FunctionId fid, int num_arguments) { CallRuntime(Runtime::FunctionForId(fid), num_arguments); } // Convenience function: tail call a runtime routine (jump). void TailCallRuntime(Runtime::FunctionId fid); // Jump to a runtime routine. void JumpToExternalReference(const ExternalReference& builtin, bool builtin_exit_frame = false); // --------------------------------------------------------------------------- // In-place weak references. void LoadWeakValue(Register out, Register in, Label* target_if_cleared); // --------------------------------------------------------------------------- // StatsCounter support void IncrementCounter(StatsCounter* counter, int value, Register scratch1, Register scratch2) { if (!v8_flags.native_code_counters) return; EmitIncrementCounter(counter, value, scratch1, scratch2); } void EmitIncrementCounter(StatsCounter* counter, int value, Register scratch1, Register scratch2); void DecrementCounter(StatsCounter* counter, int value, Register scratch1, Register scratch2) { if (!v8_flags.native_code_counters) return; EmitDecrementCounter(counter, value, scratch1, scratch2); } void EmitDecrementCounter(StatsCounter* counter, int value, Register scratch1, Register scratch2); // --------------------------------------------------------------------------- // Stack limit utilities void StackOverflowCheck(Register num_args, Register scratch, Label* stack_overflow); void LoadStackLimit(Register destination, StackLimitKind kind, Register scratch); // --------------------------------------------------------------------------- // Smi utilities // Jump if either of the registers contain a non-smi. inline void JumpIfNotSmi(Register value, Label* not_smi_label) { TestIfSmi(value, r0); bne(not_smi_label, cr0); } #if !defined(V8_COMPRESS_POINTERS) && !defined(V8_31BIT_SMIS_ON_64BIT_ARCH) // Ensure it is permissible to read/write int value directly from // upper half of the smi. static_assert(kSmiTag == 0); static_assert(kSmiTagSize + kSmiShiftSize == 32); #endif #if V8_TARGET_ARCH_PPC64 && V8_TARGET_LITTLE_ENDIAN #define SmiWordOffset(offset) (offset + kSystemPointerSize / 2) #else #define SmiWordOffset(offset) offset #endif // Abort execution if argument is not a Constructor, enabled via --debug-code. void AssertConstructor(Register object) NOOP_UNLESS_DEBUG_CODE; // Abort execution if argument is not a JSFunction, enabled via --debug-code. void AssertFunction(Register object) NOOP_UNLESS_DEBUG_CODE; // Abort execution if argument is not a callable JSFunction, enabled via // --debug-code. void AssertCallableFunction(Register object) NOOP_UNLESS_DEBUG_CODE; // Abort execution if argument is not a JSBoundFunction, // enabled via --debug-code. void AssertBoundFunction(Register object) NOOP_UNLESS_DEBUG_CODE; // Abort execution if argument is not a JSGeneratorObject (or subclass), // enabled via --debug-code. void AssertGeneratorObject(Register object) NOOP_UNLESS_DEBUG_CODE; // Abort execution if argument is not undefined or an AllocationSite, enabled // via --debug-code. void AssertUndefinedOrAllocationSite(Register object, Register scratch) NOOP_UNLESS_DEBUG_CODE; void AssertJSAny(Register object, Register map_tmp, Register tmp, AbortReason abort_reason) NOOP_UNLESS_DEBUG_CODE; // --------------------------------------------------------------------------- // Patching helpers. template <typename Field> void DecodeField(Register dst, Register src, RCBit rc = LeaveRC) { ExtractBitRange(dst, src, Field::kShift + Field::kSize - 1, Field::kShift, rc); } template <typename Field> void DecodeField(Register reg, RCBit rc = LeaveRC) { DecodeField<Field>(reg, reg, rc); } void TestCodeIsMarkedForDeoptimization(Register code, Register scratch1, Register scratch2); Operand ClearedValue() const; private: static const int kSmiShift = kSmiTagSize + kSmiShiftSize; int CalculateStackPassedWords(int num_reg_arguments, int num_double_arguments); // Helper functions for generating invokes. void InvokePrologue(Register expected_parameter_count, Register actual_parameter_count, InvokeType type); DISALLOW_IMPLICIT_CONSTRUCTORS(MacroAssembler); }; struct MoveCycleState { // Whether a move in the cycle needs a double scratch register. bool pending_double_scratch_register_use = false; }; // Provides access to exit frame parameters (GC-ed). inline MemOperand ExitFrameStackSlotOperand(int offset) { // The slot at [sp] is reserved in all ExitFrames for storing the return // address before doing the actual call, it's necessary for frame iteration // (see StoreReturnAddressAndCall for details). static constexpr int kSPOffset = 1 * kSystemPointerSize; return MemOperand(sp, (kStackFrameExtraParamSlot * kSystemPointerSize) + offset + kSPOffset); } // Provides access to exit frame stack space (not GC-ed). inline MemOperand ExitFrameCallerStackSlotOperand(int index) { return MemOperand( fp, (BuiltinExitFrameConstants::kFixedSlotCountAboveFp + index) * kSystemPointerSize); } // Calls an API function. Allocates HandleScope, extracts returned value // from handle and propagates exceptions. Clobbers C argument registers // and C caller-saved registers. Restores context. On return removes // (*argc_operand + slots_to_drop_on_return) * kSystemPointerSize // (GCed, includes the call JS arguments space and the additional space // allocated for the fast call). void CallApiFunctionAndReturn(MacroAssembler* masm, bool with_profiling, Register function_address, ExternalReference thunk_ref, Register thunk_arg, int slots_to_drop_on_return, MemOperand* argc_operand, MemOperand return_value_operand, bool handle_interceptor_result); #define ACCESS_MASM(masm) masm-> } // namespace internal } // namespace v8 #endif // V8_CODEGEN_PPC_MACRO_ASSEMBLER_PPC_H_