11cb0ef41Sopenharmony_ci// Copyright 2012 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#ifndef INCLUDED_FROM_MACRO_ASSEMBLER_H 61cb0ef41Sopenharmony_ci#error This header must be included via macro-assembler.h 71cb0ef41Sopenharmony_ci#endif 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#ifndef V8_CODEGEN_ARM_MACRO_ASSEMBLER_ARM_H_ 101cb0ef41Sopenharmony_ci#define V8_CODEGEN_ARM_MACRO_ASSEMBLER_ARM_H_ 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci#include "src/codegen/arm/assembler-arm.h" 131cb0ef41Sopenharmony_ci#include "src/codegen/bailout-reason.h" 141cb0ef41Sopenharmony_ci#include "src/common/globals.h" 151cb0ef41Sopenharmony_ci#include "src/objects/tagged-index.h" 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_cinamespace v8 { 181cb0ef41Sopenharmony_cinamespace internal { 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci// TODO(victorgomes): Move definition to macro-assembler.h, once all other 211cb0ef41Sopenharmony_ci// platforms are updated. 221cb0ef41Sopenharmony_cienum class StackLimitKind { kInterruptStackLimit, kRealStackLimit }; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci// ---------------------------------------------------------------------------- 251cb0ef41Sopenharmony_ci// Static helper functions 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ci// Generate a MemOperand for loading a field from an object. 281cb0ef41Sopenharmony_ciinline MemOperand FieldMemOperand(Register object, int offset) { 291cb0ef41Sopenharmony_ci return MemOperand(object, offset - kHeapObjectTag); 301cb0ef41Sopenharmony_ci} 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_cienum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved }; 331cb0ef41Sopenharmony_ci 341cb0ef41Sopenharmony_ciRegister GetRegisterThatIsNotOneOf(Register reg1, Register reg2 = no_reg, 351cb0ef41Sopenharmony_ci Register reg3 = no_reg, 361cb0ef41Sopenharmony_ci Register reg4 = no_reg, 371cb0ef41Sopenharmony_ci Register reg5 = no_reg, 381cb0ef41Sopenharmony_ci Register reg6 = no_reg); 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_cienum TargetAddressStorageMode { 411cb0ef41Sopenharmony_ci CAN_INLINE_TARGET_ADDRESS, 421cb0ef41Sopenharmony_ci NEVER_INLINE_TARGET_ADDRESS 431cb0ef41Sopenharmony_ci}; 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE TurboAssembler : public TurboAssemblerBase { 461cb0ef41Sopenharmony_ci public: 471cb0ef41Sopenharmony_ci using TurboAssemblerBase::TurboAssemblerBase; 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci // Activation support. 501cb0ef41Sopenharmony_ci void EnterFrame(StackFrame::Type type, 511cb0ef41Sopenharmony_ci bool load_constant_pool_pointer_reg = false); 521cb0ef41Sopenharmony_ci // Returns the pc offset at which the frame ends. 531cb0ef41Sopenharmony_ci int LeaveFrame(StackFrame::Type type); 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci// Allocate stack space of given size (i.e. decrement {sp} by the value 561cb0ef41Sopenharmony_ci// stored in the given register, or by a constant). If you need to perform a 571cb0ef41Sopenharmony_ci// stack check, do it before calling this function because this function may 581cb0ef41Sopenharmony_ci// write into the newly allocated space. It may also overwrite the given 591cb0ef41Sopenharmony_ci// register's value, in the version that takes a register. 601cb0ef41Sopenharmony_ci#ifdef V8_OS_WIN 611cb0ef41Sopenharmony_ci void AllocateStackSpace(Register bytes_scratch); 621cb0ef41Sopenharmony_ci void AllocateStackSpace(int bytes); 631cb0ef41Sopenharmony_ci#else 641cb0ef41Sopenharmony_ci void AllocateStackSpace(Register bytes) { sub(sp, sp, bytes); } 651cb0ef41Sopenharmony_ci void AllocateStackSpace(int bytes) { 661cb0ef41Sopenharmony_ci DCHECK_GE(bytes, 0); 671cb0ef41Sopenharmony_ci if (bytes == 0) return; 681cb0ef41Sopenharmony_ci sub(sp, sp, Operand(bytes)); 691cb0ef41Sopenharmony_ci } 701cb0ef41Sopenharmony_ci#endif 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci // Push a fixed frame, consisting of lr, fp 731cb0ef41Sopenharmony_ci void PushCommonFrame(Register marker_reg = no_reg); 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci // Generates function and stub prologue code. 761cb0ef41Sopenharmony_ci void StubPrologue(StackFrame::Type type); 771cb0ef41Sopenharmony_ci void Prologue(); 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci enum ArgumentsCountMode { kCountIncludesReceiver, kCountExcludesReceiver }; 801cb0ef41Sopenharmony_ci enum ArgumentsCountType { kCountIsInteger, kCountIsSmi, kCountIsBytes }; 811cb0ef41Sopenharmony_ci void DropArguments(Register count, ArgumentsCountType type, 821cb0ef41Sopenharmony_ci ArgumentsCountMode mode); 831cb0ef41Sopenharmony_ci void DropArgumentsAndPushNewReceiver(Register argc, Register receiver, 841cb0ef41Sopenharmony_ci ArgumentsCountType type, 851cb0ef41Sopenharmony_ci ArgumentsCountMode mode); 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci // Push a standard frame, consisting of lr, fp, context and JS function 881cb0ef41Sopenharmony_ci void PushStandardFrame(Register function_reg); 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci void InitializeRootRegister(); 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci void Push(Register src) { push(src); } 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_ci void Push(Handle<HeapObject> handle); 951cb0ef41Sopenharmony_ci void Push(Smi smi); 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ci // Push two registers. Pushes leftmost register first (to highest address). 981cb0ef41Sopenharmony_ci void Push(Register src1, Register src2, Condition cond = al) { 991cb0ef41Sopenharmony_ci if (src1.code() > src2.code()) { 1001cb0ef41Sopenharmony_ci stm(db_w, sp, {src1, src2}, cond); 1011cb0ef41Sopenharmony_ci } else { 1021cb0ef41Sopenharmony_ci str(src1, MemOperand(sp, 4, NegPreIndex), cond); 1031cb0ef41Sopenharmony_ci str(src2, MemOperand(sp, 4, NegPreIndex), cond); 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_ci // Push three registers. Pushes leftmost register first (to highest address). 1081cb0ef41Sopenharmony_ci void Push(Register src1, Register src2, Register src3, Condition cond = al) { 1091cb0ef41Sopenharmony_ci if (src1.code() > src2.code()) { 1101cb0ef41Sopenharmony_ci if (src2.code() > src3.code()) { 1111cb0ef41Sopenharmony_ci stm(db_w, sp, {src1, src2, src3}, cond); 1121cb0ef41Sopenharmony_ci } else { 1131cb0ef41Sopenharmony_ci stm(db_w, sp, {src1, src2}, cond); 1141cb0ef41Sopenharmony_ci str(src3, MemOperand(sp, 4, NegPreIndex), cond); 1151cb0ef41Sopenharmony_ci } 1161cb0ef41Sopenharmony_ci } else { 1171cb0ef41Sopenharmony_ci str(src1, MemOperand(sp, 4, NegPreIndex), cond); 1181cb0ef41Sopenharmony_ci Push(src2, src3, cond); 1191cb0ef41Sopenharmony_ci } 1201cb0ef41Sopenharmony_ci } 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci // Push four registers. Pushes leftmost register first (to highest address). 1231cb0ef41Sopenharmony_ci void Push(Register src1, Register src2, Register src3, Register src4, 1241cb0ef41Sopenharmony_ci Condition cond = al) { 1251cb0ef41Sopenharmony_ci if (src1.code() > src2.code()) { 1261cb0ef41Sopenharmony_ci if (src2.code() > src3.code()) { 1271cb0ef41Sopenharmony_ci if (src3.code() > src4.code()) { 1281cb0ef41Sopenharmony_ci stm(db_w, sp, {src1, src2, src3, src4}, cond); 1291cb0ef41Sopenharmony_ci } else { 1301cb0ef41Sopenharmony_ci stm(db_w, sp, {src1, src2, src3}, cond); 1311cb0ef41Sopenharmony_ci str(src4, MemOperand(sp, 4, NegPreIndex), cond); 1321cb0ef41Sopenharmony_ci } 1331cb0ef41Sopenharmony_ci } else { 1341cb0ef41Sopenharmony_ci stm(db_w, sp, {src1, src2}, cond); 1351cb0ef41Sopenharmony_ci Push(src3, src4, cond); 1361cb0ef41Sopenharmony_ci } 1371cb0ef41Sopenharmony_ci } else { 1381cb0ef41Sopenharmony_ci str(src1, MemOperand(sp, 4, NegPreIndex), cond); 1391cb0ef41Sopenharmony_ci Push(src2, src3, src4, cond); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci } 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci // Push five registers. Pushes leftmost register first (to highest address). 1441cb0ef41Sopenharmony_ci void Push(Register src1, Register src2, Register src3, Register src4, 1451cb0ef41Sopenharmony_ci Register src5, Condition cond = al) { 1461cb0ef41Sopenharmony_ci if (src1.code() > src2.code()) { 1471cb0ef41Sopenharmony_ci if (src2.code() > src3.code()) { 1481cb0ef41Sopenharmony_ci if (src3.code() > src4.code()) { 1491cb0ef41Sopenharmony_ci if (src4.code() > src5.code()) { 1501cb0ef41Sopenharmony_ci stm(db_w, sp, {src1, src2, src3, src4, src5}, cond); 1511cb0ef41Sopenharmony_ci } else { 1521cb0ef41Sopenharmony_ci stm(db_w, sp, {src1, src2, src3, src4}, cond); 1531cb0ef41Sopenharmony_ci str(src5, MemOperand(sp, 4, NegPreIndex), cond); 1541cb0ef41Sopenharmony_ci } 1551cb0ef41Sopenharmony_ci } else { 1561cb0ef41Sopenharmony_ci stm(db_w, sp, {src1, src2, src3}, cond); 1571cb0ef41Sopenharmony_ci Push(src4, src5, cond); 1581cb0ef41Sopenharmony_ci } 1591cb0ef41Sopenharmony_ci } else { 1601cb0ef41Sopenharmony_ci stm(db_w, sp, {src1, src2}, cond); 1611cb0ef41Sopenharmony_ci Push(src3, src4, src5, cond); 1621cb0ef41Sopenharmony_ci } 1631cb0ef41Sopenharmony_ci } else { 1641cb0ef41Sopenharmony_ci str(src1, MemOperand(sp, 4, NegPreIndex), cond); 1651cb0ef41Sopenharmony_ci Push(src2, src3, src4, src5, cond); 1661cb0ef41Sopenharmony_ci } 1671cb0ef41Sopenharmony_ci } 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci enum class PushArrayOrder { kNormal, kReverse }; 1701cb0ef41Sopenharmony_ci // `array` points to the first element (the lowest address). 1711cb0ef41Sopenharmony_ci // `array` and `size` are not modified. 1721cb0ef41Sopenharmony_ci void PushArray(Register array, Register size, Register scratch, 1731cb0ef41Sopenharmony_ci PushArrayOrder order = PushArrayOrder::kNormal); 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci void Pop(Register dst) { pop(dst); } 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci // Pop two registers. Pops rightmost register first (from lower address). 1781cb0ef41Sopenharmony_ci void Pop(Register src1, Register src2, Condition cond = al) { 1791cb0ef41Sopenharmony_ci DCHECK(src1 != src2); 1801cb0ef41Sopenharmony_ci if (src1.code() > src2.code()) { 1811cb0ef41Sopenharmony_ci ldm(ia_w, sp, {src1, src2}, cond); 1821cb0ef41Sopenharmony_ci } else { 1831cb0ef41Sopenharmony_ci ldr(src2, MemOperand(sp, 4, PostIndex), cond); 1841cb0ef41Sopenharmony_ci ldr(src1, MemOperand(sp, 4, PostIndex), cond); 1851cb0ef41Sopenharmony_ci } 1861cb0ef41Sopenharmony_ci } 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci // Pop three registers. Pops rightmost register first (from lower address). 1891cb0ef41Sopenharmony_ci void Pop(Register src1, Register src2, Register src3, Condition cond = al) { 1901cb0ef41Sopenharmony_ci DCHECK(!AreAliased(src1, src2, src3)); 1911cb0ef41Sopenharmony_ci if (src1.code() > src2.code()) { 1921cb0ef41Sopenharmony_ci if (src2.code() > src3.code()) { 1931cb0ef41Sopenharmony_ci ldm(ia_w, sp, {src1, src2, src3}, cond); 1941cb0ef41Sopenharmony_ci } else { 1951cb0ef41Sopenharmony_ci ldr(src3, MemOperand(sp, 4, PostIndex), cond); 1961cb0ef41Sopenharmony_ci ldm(ia_w, sp, {src1, src2}, cond); 1971cb0ef41Sopenharmony_ci } 1981cb0ef41Sopenharmony_ci } else { 1991cb0ef41Sopenharmony_ci Pop(src2, src3, cond); 2001cb0ef41Sopenharmony_ci ldr(src1, MemOperand(sp, 4, PostIndex), cond); 2011cb0ef41Sopenharmony_ci } 2021cb0ef41Sopenharmony_ci } 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci // Pop four registers. Pops rightmost register first (from lower address). 2051cb0ef41Sopenharmony_ci void Pop(Register src1, Register src2, Register src3, Register src4, 2061cb0ef41Sopenharmony_ci Condition cond = al) { 2071cb0ef41Sopenharmony_ci DCHECK(!AreAliased(src1, src2, src3, src4)); 2081cb0ef41Sopenharmony_ci if (src1.code() > src2.code()) { 2091cb0ef41Sopenharmony_ci if (src2.code() > src3.code()) { 2101cb0ef41Sopenharmony_ci if (src3.code() > src4.code()) { 2111cb0ef41Sopenharmony_ci ldm(ia_w, sp, {src1, src2, src3, src4}, cond); 2121cb0ef41Sopenharmony_ci } else { 2131cb0ef41Sopenharmony_ci ldr(src4, MemOperand(sp, 4, PostIndex), cond); 2141cb0ef41Sopenharmony_ci ldm(ia_w, sp, {src1, src2, src3}, cond); 2151cb0ef41Sopenharmony_ci } 2161cb0ef41Sopenharmony_ci } else { 2171cb0ef41Sopenharmony_ci Pop(src3, src4, cond); 2181cb0ef41Sopenharmony_ci ldm(ia_w, sp, {src1, src2}, cond); 2191cb0ef41Sopenharmony_ci } 2201cb0ef41Sopenharmony_ci } else { 2211cb0ef41Sopenharmony_ci Pop(src2, src3, src4, cond); 2221cb0ef41Sopenharmony_ci ldr(src1, MemOperand(sp, 4, PostIndex), cond); 2231cb0ef41Sopenharmony_ci } 2241cb0ef41Sopenharmony_ci } 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci // Before calling a C-function from generated code, align arguments on stack. 2271cb0ef41Sopenharmony_ci // After aligning the frame, non-register arguments must be stored in 2281cb0ef41Sopenharmony_ci // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments 2291cb0ef41Sopenharmony_ci // are word sized. If double arguments are used, this function assumes that 2301cb0ef41Sopenharmony_ci // all double arguments are stored before core registers; otherwise the 2311cb0ef41Sopenharmony_ci // correct alignment of the double values is not guaranteed. 2321cb0ef41Sopenharmony_ci // Some compilers/platforms require the stack to be aligned when calling 2331cb0ef41Sopenharmony_ci // C++ code. 2341cb0ef41Sopenharmony_ci // Needs a scratch register to do some arithmetic. This register will be 2351cb0ef41Sopenharmony_ci // trashed. 2361cb0ef41Sopenharmony_ci void PrepareCallCFunction(int num_reg_arguments, int num_double_registers = 0, 2371cb0ef41Sopenharmony_ci Register scratch = no_reg); 2381cb0ef41Sopenharmony_ci 2391cb0ef41Sopenharmony_ci // There are two ways of passing double arguments on ARM, depending on 2401cb0ef41Sopenharmony_ci // whether soft or hard floating point ABI is used. These functions 2411cb0ef41Sopenharmony_ci // abstract parameter passing for the three different ways we call 2421cb0ef41Sopenharmony_ci // C functions from generated code. 2431cb0ef41Sopenharmony_ci void MovToFloatParameter(DwVfpRegister src); 2441cb0ef41Sopenharmony_ci void MovToFloatParameters(DwVfpRegister src1, DwVfpRegister src2); 2451cb0ef41Sopenharmony_ci void MovToFloatResult(DwVfpRegister src); 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_ci // Calls a C function and cleans up the space for arguments allocated 2481cb0ef41Sopenharmony_ci // by PrepareCallCFunction. The called function is not allowed to trigger a 2491cb0ef41Sopenharmony_ci // garbage collection, since that might move the code and invalidate the 2501cb0ef41Sopenharmony_ci // return address (unless this is somehow accounted for by the called 2511cb0ef41Sopenharmony_ci // function). 2521cb0ef41Sopenharmony_ci void CallCFunction(ExternalReference function, int num_arguments); 2531cb0ef41Sopenharmony_ci void CallCFunction(Register function, int num_arguments); 2541cb0ef41Sopenharmony_ci void CallCFunction(ExternalReference function, int num_reg_arguments, 2551cb0ef41Sopenharmony_ci int num_double_arguments); 2561cb0ef41Sopenharmony_ci void CallCFunction(Register function, int num_reg_arguments, 2571cb0ef41Sopenharmony_ci int num_double_arguments); 2581cb0ef41Sopenharmony_ci 2591cb0ef41Sopenharmony_ci void MovFromFloatParameter(DwVfpRegister dst); 2601cb0ef41Sopenharmony_ci void MovFromFloatResult(DwVfpRegister dst); 2611cb0ef41Sopenharmony_ci 2621cb0ef41Sopenharmony_ci void Trap(); 2631cb0ef41Sopenharmony_ci void DebugBreak(); 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci // Calls Abort(msg) if the condition cond is not satisfied. 2661cb0ef41Sopenharmony_ci // Use --debug-code to enable. 2671cb0ef41Sopenharmony_ci void Assert(Condition cond, AbortReason reason); 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_ci // Like Assert(), but without condition. 2701cb0ef41Sopenharmony_ci // Use --debug-code to enable. 2711cb0ef41Sopenharmony_ci void AssertUnreachable(AbortReason reason); 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci // Like Assert(), but always enabled. 2741cb0ef41Sopenharmony_ci void Check(Condition cond, AbortReason reason); 2751cb0ef41Sopenharmony_ci 2761cb0ef41Sopenharmony_ci // Print a message to stdout and abort execution. 2771cb0ef41Sopenharmony_ci void Abort(AbortReason msg); 2781cb0ef41Sopenharmony_ci 2791cb0ef41Sopenharmony_ci void LslPair(Register dst_low, Register dst_high, Register src_low, 2801cb0ef41Sopenharmony_ci Register src_high, Register shift); 2811cb0ef41Sopenharmony_ci void LslPair(Register dst_low, Register dst_high, Register src_low, 2821cb0ef41Sopenharmony_ci Register src_high, uint32_t shift); 2831cb0ef41Sopenharmony_ci void LsrPair(Register dst_low, Register dst_high, Register src_low, 2841cb0ef41Sopenharmony_ci Register src_high, Register shift); 2851cb0ef41Sopenharmony_ci void LsrPair(Register dst_low, Register dst_high, Register src_low, 2861cb0ef41Sopenharmony_ci Register src_high, uint32_t shift); 2871cb0ef41Sopenharmony_ci void AsrPair(Register dst_low, Register dst_high, Register src_low, 2881cb0ef41Sopenharmony_ci Register src_high, Register shift); 2891cb0ef41Sopenharmony_ci void AsrPair(Register dst_low, Register dst_high, Register src_low, 2901cb0ef41Sopenharmony_ci Register src_high, uint32_t shift); 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_ci void LoadFromConstantsTable(Register destination, int constant_index) final; 2931cb0ef41Sopenharmony_ci void LoadRootRegisterOffset(Register destination, intptr_t offset) final; 2941cb0ef41Sopenharmony_ci void LoadRootRelative(Register destination, int32_t offset) final; 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci // Jump, Call, and Ret pseudo instructions implementing inter-working. 2971cb0ef41Sopenharmony_ci void Call(Register target, Condition cond = al); 2981cb0ef41Sopenharmony_ci void Call(Address target, RelocInfo::Mode rmode, Condition cond = al, 2991cb0ef41Sopenharmony_ci TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS, 3001cb0ef41Sopenharmony_ci bool check_constant_pool = true); 3011cb0ef41Sopenharmony_ci void Call(Handle<Code> code, RelocInfo::Mode rmode = RelocInfo::CODE_TARGET, 3021cb0ef41Sopenharmony_ci Condition cond = al, 3031cb0ef41Sopenharmony_ci TargetAddressStorageMode mode = CAN_INLINE_TARGET_ADDRESS, 3041cb0ef41Sopenharmony_ci bool check_constant_pool = true); 3051cb0ef41Sopenharmony_ci void Call(Label* target); 3061cb0ef41Sopenharmony_ci 3071cb0ef41Sopenharmony_ci MemOperand EntryFromBuiltinAsOperand(Builtin builtin); 3081cb0ef41Sopenharmony_ci void LoadEntryFromBuiltin(Builtin builtin, Register destination); 3091cb0ef41Sopenharmony_ci // Load the builtin given by the Smi in |builtin| into the same 3101cb0ef41Sopenharmony_ci // register. 3111cb0ef41Sopenharmony_ci void LoadEntryFromBuiltinIndex(Register builtin_index); 3121cb0ef41Sopenharmony_ci void CallBuiltinByIndex(Register builtin_index); 3131cb0ef41Sopenharmony_ci void CallBuiltin(Builtin builtin, Condition cond = al); 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci void LoadCodeObjectEntry(Register destination, Register code_object); 3161cb0ef41Sopenharmony_ci void CallCodeObject(Register code_object); 3171cb0ef41Sopenharmony_ci void JumpCodeObject(Register code_object, 3181cb0ef41Sopenharmony_ci JumpMode jump_mode = JumpMode::kJump); 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci // Generates an instruction sequence s.t. the return address points to the 3211cb0ef41Sopenharmony_ci // instruction following the call. 3221cb0ef41Sopenharmony_ci // The return address on the stack is used by frame iteration. 3231cb0ef41Sopenharmony_ci void StoreReturnAddressAndCall(Register target); 3241cb0ef41Sopenharmony_ci 3251cb0ef41Sopenharmony_ci void CallForDeoptimization(Builtin target, int deopt_id, Label* exit, 3261cb0ef41Sopenharmony_ci DeoptimizeKind kind, Label* ret, 3271cb0ef41Sopenharmony_ci Label* jump_deoptimization_entry_label); 3281cb0ef41Sopenharmony_ci 3291cb0ef41Sopenharmony_ci // Emit code to discard a non-negative number of pointer-sized elements 3301cb0ef41Sopenharmony_ci // from the stack, clobbering only the sp register. 3311cb0ef41Sopenharmony_ci void Drop(int count, Condition cond = al); 3321cb0ef41Sopenharmony_ci void Drop(Register count, Condition cond = al); 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci void Ret(Condition cond = al); 3351cb0ef41Sopenharmony_ci void Ret(int drop, Condition cond = al); 3361cb0ef41Sopenharmony_ci 3371cb0ef41Sopenharmony_ci // Compare single values and move the result to the normal condition flags. 3381cb0ef41Sopenharmony_ci void VFPCompareAndSetFlags(const SwVfpRegister src1, const SwVfpRegister src2, 3391cb0ef41Sopenharmony_ci const Condition cond = al); 3401cb0ef41Sopenharmony_ci void VFPCompareAndSetFlags(const SwVfpRegister src1, const float src2, 3411cb0ef41Sopenharmony_ci const Condition cond = al); 3421cb0ef41Sopenharmony_ci 3431cb0ef41Sopenharmony_ci // Compare double values and move the result to the normal condition flags. 3441cb0ef41Sopenharmony_ci void VFPCompareAndSetFlags(const DwVfpRegister src1, const DwVfpRegister src2, 3451cb0ef41Sopenharmony_ci const Condition cond = al); 3461cb0ef41Sopenharmony_ci void VFPCompareAndSetFlags(const DwVfpRegister src1, const double src2, 3471cb0ef41Sopenharmony_ci const Condition cond = al); 3481cb0ef41Sopenharmony_ci 3491cb0ef41Sopenharmony_ci // If the value is a NaN, canonicalize the value else, do nothing. 3501cb0ef41Sopenharmony_ci void VFPCanonicalizeNaN(const DwVfpRegister dst, const DwVfpRegister src, 3511cb0ef41Sopenharmony_ci const Condition cond = al); 3521cb0ef41Sopenharmony_ci void VFPCanonicalizeNaN(const DwVfpRegister value, 3531cb0ef41Sopenharmony_ci const Condition cond = al) { 3541cb0ef41Sopenharmony_ci VFPCanonicalizeNaN(value, value, cond); 3551cb0ef41Sopenharmony_ci } 3561cb0ef41Sopenharmony_ci 3571cb0ef41Sopenharmony_ci void VmovHigh(Register dst, DwVfpRegister src); 3581cb0ef41Sopenharmony_ci void VmovHigh(DwVfpRegister dst, Register src); 3591cb0ef41Sopenharmony_ci void VmovLow(Register dst, DwVfpRegister src); 3601cb0ef41Sopenharmony_ci void VmovLow(DwVfpRegister dst, Register src); 3611cb0ef41Sopenharmony_ci 3621cb0ef41Sopenharmony_ci void CheckPageFlag(Register object, int mask, Condition cc, 3631cb0ef41Sopenharmony_ci Label* condition_met); 3641cb0ef41Sopenharmony_ci 3651cb0ef41Sopenharmony_ci // Check whether d16-d31 are available on the CPU. The result is given by the 3661cb0ef41Sopenharmony_ci // Z condition flag: Z==0 if d16-d31 available, Z==1 otherwise. 3671cb0ef41Sopenharmony_ci void CheckFor32DRegs(Register scratch); 3681cb0ef41Sopenharmony_ci 3691cb0ef41Sopenharmony_ci void MaybeSaveRegisters(RegList registers); 3701cb0ef41Sopenharmony_ci void MaybeRestoreRegisters(RegList registers); 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_ci void CallEphemeronKeyBarrier(Register object, Operand offset, 3731cb0ef41Sopenharmony_ci SaveFPRegsMode fp_mode); 3741cb0ef41Sopenharmony_ci 3751cb0ef41Sopenharmony_ci void CallRecordWriteStubSaveRegisters( 3761cb0ef41Sopenharmony_ci Register object, Operand offset, 3771cb0ef41Sopenharmony_ci RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode, 3781cb0ef41Sopenharmony_ci StubCallMode mode = StubCallMode::kCallBuiltinPointer); 3791cb0ef41Sopenharmony_ci void CallRecordWriteStub( 3801cb0ef41Sopenharmony_ci Register object, Register slot_address, 3811cb0ef41Sopenharmony_ci RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode, 3821cb0ef41Sopenharmony_ci StubCallMode mode = StubCallMode::kCallBuiltinPointer); 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_ci // For a given |object| and |offset|: 3851cb0ef41Sopenharmony_ci // - Move |object| to |dst_object|. 3861cb0ef41Sopenharmony_ci // - Compute the address of the slot pointed to by |offset| in |object| and 3871cb0ef41Sopenharmony_ci // write it to |dst_slot|. |offset| can be either an immediate or a 3881cb0ef41Sopenharmony_ci // register. 3891cb0ef41Sopenharmony_ci // This method makes sure |object| and |offset| are allowed to overlap with 3901cb0ef41Sopenharmony_ci // the destination registers. 3911cb0ef41Sopenharmony_ci void MoveObjectAndSlot(Register dst_object, Register dst_slot, 3921cb0ef41Sopenharmony_ci Register object, Operand offset); 3931cb0ef41Sopenharmony_ci 3941cb0ef41Sopenharmony_ci // Does a runtime check for 16/32 FP registers. Either way, pushes 32 double 3951cb0ef41Sopenharmony_ci // values to location, saving [d0..(d15|d31)]. 3961cb0ef41Sopenharmony_ci void SaveFPRegs(Register location, Register scratch); 3971cb0ef41Sopenharmony_ci 3981cb0ef41Sopenharmony_ci // Does a runtime check for 16/32 FP registers. Either way, pops 32 double 3991cb0ef41Sopenharmony_ci // values to location, restoring [d0..(d15|d31)]. 4001cb0ef41Sopenharmony_ci void RestoreFPRegs(Register location, Register scratch); 4011cb0ef41Sopenharmony_ci 4021cb0ef41Sopenharmony_ci // As above, but with heap semantics instead of stack semantics, i.e.: the 4031cb0ef41Sopenharmony_ci // location starts at the lowest address and grows towards higher addresses, 4041cb0ef41Sopenharmony_ci // for both saves and restores. 4051cb0ef41Sopenharmony_ci void SaveFPRegsToHeap(Register location, Register scratch); 4061cb0ef41Sopenharmony_ci void RestoreFPRegsFromHeap(Register location, Register scratch); 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci // Calculate how much stack space (in bytes) are required to store caller 4091cb0ef41Sopenharmony_ci // registers excluding those specified in the arguments. 4101cb0ef41Sopenharmony_ci int RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode, 4111cb0ef41Sopenharmony_ci Register exclusion1 = no_reg, 4121cb0ef41Sopenharmony_ci Register exclusion2 = no_reg, 4131cb0ef41Sopenharmony_ci Register exclusion3 = no_reg) const; 4141cb0ef41Sopenharmony_ci 4151cb0ef41Sopenharmony_ci // Push caller saved registers on the stack, and return the number of bytes 4161cb0ef41Sopenharmony_ci // stack pointer is adjusted. 4171cb0ef41Sopenharmony_ci int PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg, 4181cb0ef41Sopenharmony_ci Register exclusion2 = no_reg, 4191cb0ef41Sopenharmony_ci Register exclusion3 = no_reg); 4201cb0ef41Sopenharmony_ci // Restore caller saved registers from the stack, and return the number of 4211cb0ef41Sopenharmony_ci // bytes stack pointer is adjusted. 4221cb0ef41Sopenharmony_ci int PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1 = no_reg, 4231cb0ef41Sopenharmony_ci Register exclusion2 = no_reg, 4241cb0ef41Sopenharmony_ci Register exclusion3 = no_reg); 4251cb0ef41Sopenharmony_ci void Jump(Register target, Condition cond = al); 4261cb0ef41Sopenharmony_ci void Jump(Address target, RelocInfo::Mode rmode, Condition cond = al); 4271cb0ef41Sopenharmony_ci void Jump(Handle<Code> code, RelocInfo::Mode rmode, Condition cond = al); 4281cb0ef41Sopenharmony_ci void Jump(const ExternalReference& reference); 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_ci // Perform a floating-point min or max operation with the 4311cb0ef41Sopenharmony_ci // (IEEE-754-compatible) semantics of ARM64's fmin/fmax. Some cases, typically 4321cb0ef41Sopenharmony_ci // NaNs or +/-0.0, are expected to be rare and are handled in out-of-line 4331cb0ef41Sopenharmony_ci // code. The specific behaviour depends on supported instructions. 4341cb0ef41Sopenharmony_ci // 4351cb0ef41Sopenharmony_ci // These functions assume (and assert) that left!=right. It is permitted 4361cb0ef41Sopenharmony_ci // for the result to alias either input register. 4371cb0ef41Sopenharmony_ci void FloatMax(SwVfpRegister result, SwVfpRegister left, SwVfpRegister right, 4381cb0ef41Sopenharmony_ci Label* out_of_line); 4391cb0ef41Sopenharmony_ci void FloatMin(SwVfpRegister result, SwVfpRegister left, SwVfpRegister right, 4401cb0ef41Sopenharmony_ci Label* out_of_line); 4411cb0ef41Sopenharmony_ci void FloatMax(DwVfpRegister result, DwVfpRegister left, DwVfpRegister right, 4421cb0ef41Sopenharmony_ci Label* out_of_line); 4431cb0ef41Sopenharmony_ci void FloatMin(DwVfpRegister result, DwVfpRegister left, DwVfpRegister right, 4441cb0ef41Sopenharmony_ci Label* out_of_line); 4451cb0ef41Sopenharmony_ci 4461cb0ef41Sopenharmony_ci // Generate out-of-line cases for the macros above. 4471cb0ef41Sopenharmony_ci void FloatMaxOutOfLine(SwVfpRegister result, SwVfpRegister left, 4481cb0ef41Sopenharmony_ci SwVfpRegister right); 4491cb0ef41Sopenharmony_ci void FloatMinOutOfLine(SwVfpRegister result, SwVfpRegister left, 4501cb0ef41Sopenharmony_ci SwVfpRegister right); 4511cb0ef41Sopenharmony_ci void FloatMaxOutOfLine(DwVfpRegister result, DwVfpRegister left, 4521cb0ef41Sopenharmony_ci DwVfpRegister right); 4531cb0ef41Sopenharmony_ci void FloatMinOutOfLine(DwVfpRegister result, DwVfpRegister left, 4541cb0ef41Sopenharmony_ci DwVfpRegister right); 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci void ExtractLane(Register dst, QwNeonRegister src, NeonDataType dt, int lane); 4571cb0ef41Sopenharmony_ci void ExtractLane(Register dst, DwVfpRegister src, NeonDataType dt, int lane); 4581cb0ef41Sopenharmony_ci void ExtractLane(SwVfpRegister dst, QwNeonRegister src, int lane); 4591cb0ef41Sopenharmony_ci void ExtractLane(DwVfpRegister dst, QwNeonRegister src, int lane); 4601cb0ef41Sopenharmony_ci void ReplaceLane(QwNeonRegister dst, QwNeonRegister src, Register src_lane, 4611cb0ef41Sopenharmony_ci NeonDataType dt, int lane); 4621cb0ef41Sopenharmony_ci void ReplaceLane(QwNeonRegister dst, QwNeonRegister src, 4631cb0ef41Sopenharmony_ci SwVfpRegister src_lane, int lane); 4641cb0ef41Sopenharmony_ci void ReplaceLane(QwNeonRegister dst, QwNeonRegister src, 4651cb0ef41Sopenharmony_ci DwVfpRegister src_lane, int lane); 4661cb0ef41Sopenharmony_ci 4671cb0ef41Sopenharmony_ci void LoadLane(NeonSize sz, NeonListOperand dst_list, uint8_t lane, 4681cb0ef41Sopenharmony_ci NeonMemOperand src); 4691cb0ef41Sopenharmony_ci void StoreLane(NeonSize sz, NeonListOperand src_list, uint8_t lane, 4701cb0ef41Sopenharmony_ci NeonMemOperand dst); 4711cb0ef41Sopenharmony_ci 4721cb0ef41Sopenharmony_ci // Register move. May do nothing if the registers are identical. 4731cb0ef41Sopenharmony_ci void Move(Register dst, Smi smi); 4741cb0ef41Sopenharmony_ci void Move(Register dst, Handle<HeapObject> value); 4751cb0ef41Sopenharmony_ci void Move(Register dst, ExternalReference reference); 4761cb0ef41Sopenharmony_ci void Move(Register dst, Register src, Condition cond = al); 4771cb0ef41Sopenharmony_ci void Move(Register dst, const MemOperand& src) { ldr(dst, src); } 4781cb0ef41Sopenharmony_ci void Move(Register dst, const Operand& src, SBit sbit = LeaveCC, 4791cb0ef41Sopenharmony_ci Condition cond = al) { 4801cb0ef41Sopenharmony_ci if (!src.IsRegister() || src.rm() != dst || sbit != LeaveCC) { 4811cb0ef41Sopenharmony_ci mov(dst, src, sbit, cond); 4821cb0ef41Sopenharmony_ci } 4831cb0ef41Sopenharmony_ci } 4841cb0ef41Sopenharmony_ci // Move src0 to dst0 and src1 to dst1, handling possible overlaps. 4851cb0ef41Sopenharmony_ci void MovePair(Register dst0, Register src0, Register dst1, Register src1); 4861cb0ef41Sopenharmony_ci 4871cb0ef41Sopenharmony_ci void Move(SwVfpRegister dst, SwVfpRegister src, Condition cond = al); 4881cb0ef41Sopenharmony_ci void Move(DwVfpRegister dst, DwVfpRegister src, Condition cond = al); 4891cb0ef41Sopenharmony_ci void Move(QwNeonRegister dst, QwNeonRegister src); 4901cb0ef41Sopenharmony_ci 4911cb0ef41Sopenharmony_ci // Simulate s-register moves for imaginary s32 - s63 registers. 4921cb0ef41Sopenharmony_ci void VmovExtended(Register dst, int src_code); 4931cb0ef41Sopenharmony_ci void VmovExtended(int dst_code, Register src); 4941cb0ef41Sopenharmony_ci // Move between s-registers and imaginary s-registers. 4951cb0ef41Sopenharmony_ci void VmovExtended(int dst_code, int src_code); 4961cb0ef41Sopenharmony_ci void VmovExtended(int dst_code, const MemOperand& src); 4971cb0ef41Sopenharmony_ci void VmovExtended(const MemOperand& dst, int src_code); 4981cb0ef41Sopenharmony_ci 4991cb0ef41Sopenharmony_ci // Register swap. Note that the register operands should be distinct. 5001cb0ef41Sopenharmony_ci void Swap(Register srcdst0, Register srcdst1); 5011cb0ef41Sopenharmony_ci void Swap(DwVfpRegister srcdst0, DwVfpRegister srcdst1); 5021cb0ef41Sopenharmony_ci void Swap(QwNeonRegister srcdst0, QwNeonRegister srcdst1); 5031cb0ef41Sopenharmony_ci 5041cb0ef41Sopenharmony_ci // Get the actual activation frame alignment for target environment. 5051cb0ef41Sopenharmony_ci static int ActivationFrameAlignment(); 5061cb0ef41Sopenharmony_ci 5071cb0ef41Sopenharmony_ci void Bfc(Register dst, Register src, int lsb, int width, Condition cond = al); 5081cb0ef41Sopenharmony_ci 5091cb0ef41Sopenharmony_ci void SmiUntag(Register reg, SBit s = LeaveCC) { 5101cb0ef41Sopenharmony_ci mov(reg, Operand::SmiUntag(reg), s); 5111cb0ef41Sopenharmony_ci } 5121cb0ef41Sopenharmony_ci void SmiUntag(Register dst, Register src, SBit s = LeaveCC) { 5131cb0ef41Sopenharmony_ci mov(dst, Operand::SmiUntag(src), s); 5141cb0ef41Sopenharmony_ci } 5151cb0ef41Sopenharmony_ci 5161cb0ef41Sopenharmony_ci void SmiToInt32(Register smi) { SmiUntag(smi); } 5171cb0ef41Sopenharmony_ci 5181cb0ef41Sopenharmony_ci // Load an object from the root table. 5191cb0ef41Sopenharmony_ci void LoadRoot(Register destination, RootIndex index) final { 5201cb0ef41Sopenharmony_ci LoadRoot(destination, index, al); 5211cb0ef41Sopenharmony_ci } 5221cb0ef41Sopenharmony_ci void LoadRoot(Register destination, RootIndex index, Condition cond); 5231cb0ef41Sopenharmony_ci 5241cb0ef41Sopenharmony_ci // Jump if the register contains a smi. 5251cb0ef41Sopenharmony_ci void JumpIfSmi(Register value, Label* smi_label); 5261cb0ef41Sopenharmony_ci 5271cb0ef41Sopenharmony_ci void JumpIfEqual(Register x, int32_t y, Label* dest); 5281cb0ef41Sopenharmony_ci void JumpIfLessThan(Register x, int32_t y, Label* dest); 5291cb0ef41Sopenharmony_ci 5301cb0ef41Sopenharmony_ci void LoadMap(Register destination, Register object); 5311cb0ef41Sopenharmony_ci 5321cb0ef41Sopenharmony_ci // Performs a truncating conversion of a floating point number as used by 5331cb0ef41Sopenharmony_ci // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it 5341cb0ef41Sopenharmony_ci // succeeds, otherwise falls through if result is saturated. On return 5351cb0ef41Sopenharmony_ci // 'result' either holds answer, or is clobbered on fall through. 5361cb0ef41Sopenharmony_ci void TryInlineTruncateDoubleToI(Register result, DwVfpRegister input, 5371cb0ef41Sopenharmony_ci Label* done); 5381cb0ef41Sopenharmony_ci 5391cb0ef41Sopenharmony_ci // Performs a truncating conversion of a floating point number as used by 5401cb0ef41Sopenharmony_ci // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 5411cb0ef41Sopenharmony_ci // Exits with 'result' holding the answer. 5421cb0ef41Sopenharmony_ci void TruncateDoubleToI(Isolate* isolate, Zone* zone, Register result, 5431cb0ef41Sopenharmony_ci DwVfpRegister double_input, StubCallMode stub_mode); 5441cb0ef41Sopenharmony_ci 5451cb0ef41Sopenharmony_ci // EABI variant for double arguments in use. 5461cb0ef41Sopenharmony_ci bool use_eabi_hardfloat() { 5471cb0ef41Sopenharmony_ci#ifdef __arm__ 5481cb0ef41Sopenharmony_ci return base::OS::ArmUsingHardFloat(); 5491cb0ef41Sopenharmony_ci#elif USE_EABI_HARDFLOAT 5501cb0ef41Sopenharmony_ci return true; 5511cb0ef41Sopenharmony_ci#else 5521cb0ef41Sopenharmony_ci return false; 5531cb0ef41Sopenharmony_ci#endif 5541cb0ef41Sopenharmony_ci } 5551cb0ef41Sopenharmony_ci 5561cb0ef41Sopenharmony_ci // Compute the start of the generated instruction stream from the current PC. 5571cb0ef41Sopenharmony_ci // This is an alternative to embedding the {CodeObject} handle as a reference. 5581cb0ef41Sopenharmony_ci void ComputeCodeStartAddress(Register dst); 5591cb0ef41Sopenharmony_ci 5601cb0ef41Sopenharmony_ci // Control-flow integrity: 5611cb0ef41Sopenharmony_ci 5621cb0ef41Sopenharmony_ci // Define a function entrypoint. This doesn't emit any code for this 5631cb0ef41Sopenharmony_ci // architecture, as control-flow integrity is not supported for it. 5641cb0ef41Sopenharmony_ci void CodeEntry() {} 5651cb0ef41Sopenharmony_ci // Define an exception handler. 5661cb0ef41Sopenharmony_ci void ExceptionHandler() {} 5671cb0ef41Sopenharmony_ci // Define an exception handler and bind a label. 5681cb0ef41Sopenharmony_ci void BindExceptionHandler(Label* label) { bind(label); } 5691cb0ef41Sopenharmony_ci 5701cb0ef41Sopenharmony_ci // Wasm SIMD helpers. These instructions don't have direct lowering to native 5711cb0ef41Sopenharmony_ci // instructions. These helpers allow us to define the optimal code sequence, 5721cb0ef41Sopenharmony_ci // and be used in both TurboFan and Liftoff. 5731cb0ef41Sopenharmony_ci void I64x2BitMask(Register dst, QwNeonRegister src); 5741cb0ef41Sopenharmony_ci void I64x2Eq(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 5751cb0ef41Sopenharmony_ci void I64x2Ne(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 5761cb0ef41Sopenharmony_ci void I64x2GtS(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 5771cb0ef41Sopenharmony_ci void I64x2GeS(QwNeonRegister dst, QwNeonRegister src1, QwNeonRegister src2); 5781cb0ef41Sopenharmony_ci void I64x2AllTrue(Register dst, QwNeonRegister src); 5791cb0ef41Sopenharmony_ci void I64x2Abs(QwNeonRegister dst, QwNeonRegister src); 5801cb0ef41Sopenharmony_ci void F64x2ConvertLowI32x4S(QwNeonRegister dst, QwNeonRegister src); 5811cb0ef41Sopenharmony_ci void F64x2ConvertLowI32x4U(QwNeonRegister dst, QwNeonRegister src); 5821cb0ef41Sopenharmony_ci void F64x2PromoteLowF32x4(QwNeonRegister dst, QwNeonRegister src); 5831cb0ef41Sopenharmony_ci 5841cb0ef41Sopenharmony_ci private: 5851cb0ef41Sopenharmony_ci // Compare single values and then load the fpscr flags to a register. 5861cb0ef41Sopenharmony_ci void VFPCompareAndLoadFlags(const SwVfpRegister src1, 5871cb0ef41Sopenharmony_ci const SwVfpRegister src2, 5881cb0ef41Sopenharmony_ci const Register fpscr_flags, 5891cb0ef41Sopenharmony_ci const Condition cond = al); 5901cb0ef41Sopenharmony_ci void VFPCompareAndLoadFlags(const SwVfpRegister src1, const float src2, 5911cb0ef41Sopenharmony_ci const Register fpscr_flags, 5921cb0ef41Sopenharmony_ci const Condition cond = al); 5931cb0ef41Sopenharmony_ci 5941cb0ef41Sopenharmony_ci // Compare double values and then load the fpscr flags to a register. 5951cb0ef41Sopenharmony_ci void VFPCompareAndLoadFlags(const DwVfpRegister src1, 5961cb0ef41Sopenharmony_ci const DwVfpRegister src2, 5971cb0ef41Sopenharmony_ci const Register fpscr_flags, 5981cb0ef41Sopenharmony_ci const Condition cond = al); 5991cb0ef41Sopenharmony_ci void VFPCompareAndLoadFlags(const DwVfpRegister src1, const double src2, 6001cb0ef41Sopenharmony_ci const Register fpscr_flags, 6011cb0ef41Sopenharmony_ci const Condition cond = al); 6021cb0ef41Sopenharmony_ci 6031cb0ef41Sopenharmony_ci void Jump(intptr_t target, RelocInfo::Mode rmode, Condition cond = al); 6041cb0ef41Sopenharmony_ci 6051cb0ef41Sopenharmony_ci // Implementation helpers for FloatMin and FloatMax. 6061cb0ef41Sopenharmony_ci template <typename T> 6071cb0ef41Sopenharmony_ci void FloatMaxHelper(T result, T left, T right, Label* out_of_line); 6081cb0ef41Sopenharmony_ci template <typename T> 6091cb0ef41Sopenharmony_ci void FloatMinHelper(T result, T left, T right, Label* out_of_line); 6101cb0ef41Sopenharmony_ci template <typename T> 6111cb0ef41Sopenharmony_ci void FloatMaxOutOfLineHelper(T result, T left, T right); 6121cb0ef41Sopenharmony_ci template <typename T> 6131cb0ef41Sopenharmony_ci void FloatMinOutOfLineHelper(T result, T left, T right); 6141cb0ef41Sopenharmony_ci 6151cb0ef41Sopenharmony_ci int CalculateStackPassedWords(int num_reg_arguments, 6161cb0ef41Sopenharmony_ci int num_double_arguments); 6171cb0ef41Sopenharmony_ci 6181cb0ef41Sopenharmony_ci void CallCFunctionHelper(Register function, int num_reg_arguments, 6191cb0ef41Sopenharmony_ci int num_double_arguments); 6201cb0ef41Sopenharmony_ci}; 6211cb0ef41Sopenharmony_ci 6221cb0ef41Sopenharmony_ci// MacroAssembler implements a collection of frequently used macros. 6231cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { 6241cb0ef41Sopenharmony_ci public: 6251cb0ef41Sopenharmony_ci using TurboAssembler::TurboAssembler; 6261cb0ef41Sopenharmony_ci 6271cb0ef41Sopenharmony_ci void Mls(Register dst, Register src1, Register src2, Register srcA, 6281cb0ef41Sopenharmony_ci Condition cond = al); 6291cb0ef41Sopenharmony_ci void And(Register dst, Register src1, const Operand& src2, 6301cb0ef41Sopenharmony_ci Condition cond = al); 6311cb0ef41Sopenharmony_ci void Ubfx(Register dst, Register src, int lsb, int width, 6321cb0ef41Sopenharmony_ci Condition cond = al); 6331cb0ef41Sopenharmony_ci void Sbfx(Register dst, Register src, int lsb, int width, 6341cb0ef41Sopenharmony_ci Condition cond = al); 6351cb0ef41Sopenharmony_ci 6361cb0ef41Sopenharmony_ci // --------------------------------------------------------------------------- 6371cb0ef41Sopenharmony_ci // GC Support 6381cb0ef41Sopenharmony_ci 6391cb0ef41Sopenharmony_ci // Notify the garbage collector that we wrote a pointer into an object. 6401cb0ef41Sopenharmony_ci // |object| is the object being stored into, |value| is the object being 6411cb0ef41Sopenharmony_ci // stored. 6421cb0ef41Sopenharmony_ci // The offset is the offset from the start of the object, not the offset from 6431cb0ef41Sopenharmony_ci // the tagged HeapObject pointer. For use with FieldMemOperand(reg, off). 6441cb0ef41Sopenharmony_ci void RecordWriteField( 6451cb0ef41Sopenharmony_ci Register object, int offset, Register value, LinkRegisterStatus lr_status, 6461cb0ef41Sopenharmony_ci SaveFPRegsMode save_fp, 6471cb0ef41Sopenharmony_ci RememberedSetAction remembered_set_action = RememberedSetAction::kEmit, 6481cb0ef41Sopenharmony_ci SmiCheck smi_check = SmiCheck::kInline); 6491cb0ef41Sopenharmony_ci 6501cb0ef41Sopenharmony_ci // For a given |object| notify the garbage collector that the slot at |offset| 6511cb0ef41Sopenharmony_ci // has been written. |value| is the object being stored. 6521cb0ef41Sopenharmony_ci void RecordWrite( 6531cb0ef41Sopenharmony_ci Register object, Operand offset, Register value, 6541cb0ef41Sopenharmony_ci LinkRegisterStatus lr_status, SaveFPRegsMode save_fp, 6551cb0ef41Sopenharmony_ci RememberedSetAction remembered_set_action = RememberedSetAction::kEmit, 6561cb0ef41Sopenharmony_ci SmiCheck smi_check = SmiCheck::kInline); 6571cb0ef41Sopenharmony_ci 6581cb0ef41Sopenharmony_ci // Enter exit frame. 6591cb0ef41Sopenharmony_ci // stack_space - extra stack space, used for alignment before call to C. 6601cb0ef41Sopenharmony_ci void EnterExitFrame(bool save_doubles, int stack_space = 0, 6611cb0ef41Sopenharmony_ci StackFrame::Type frame_type = StackFrame::EXIT); 6621cb0ef41Sopenharmony_ci 6631cb0ef41Sopenharmony_ci // Leave the current exit frame. Expects the return value in r0. 6641cb0ef41Sopenharmony_ci // Expect the number of values, pushed prior to the exit frame, to 6651cb0ef41Sopenharmony_ci // remove in a register (or no_reg, if there is nothing to remove). 6661cb0ef41Sopenharmony_ci void LeaveExitFrame(bool save_doubles, Register argument_count, 6671cb0ef41Sopenharmony_ci bool argument_count_is_length = false); 6681cb0ef41Sopenharmony_ci 6691cb0ef41Sopenharmony_ci // Load the global proxy from the current context. 6701cb0ef41Sopenharmony_ci void LoadGlobalProxy(Register dst); 6711cb0ef41Sopenharmony_ci 6721cb0ef41Sopenharmony_ci void LoadNativeContextSlot(Register dst, int index); 6731cb0ef41Sopenharmony_ci 6741cb0ef41Sopenharmony_ci // --------------------------------------------------------------------------- 6751cb0ef41Sopenharmony_ci // JavaScript invokes 6761cb0ef41Sopenharmony_ci 6771cb0ef41Sopenharmony_ci // Invoke the JavaScript function code by either calling or jumping. 6781cb0ef41Sopenharmony_ci void InvokeFunctionCode(Register function, Register new_target, 6791cb0ef41Sopenharmony_ci Register expected_parameter_count, 6801cb0ef41Sopenharmony_ci Register actual_parameter_count, InvokeType type); 6811cb0ef41Sopenharmony_ci 6821cb0ef41Sopenharmony_ci // On function call, call into the debugger. 6831cb0ef41Sopenharmony_ci void CallDebugOnFunctionCall(Register fun, Register new_target, 6841cb0ef41Sopenharmony_ci Register expected_parameter_count, 6851cb0ef41Sopenharmony_ci Register actual_parameter_count); 6861cb0ef41Sopenharmony_ci 6871cb0ef41Sopenharmony_ci // Invoke the JavaScript function in the given register. Changes the 6881cb0ef41Sopenharmony_ci // current context to the context in the function before invoking. 6891cb0ef41Sopenharmony_ci void InvokeFunctionWithNewTarget(Register function, Register new_target, 6901cb0ef41Sopenharmony_ci Register actual_parameter_count, 6911cb0ef41Sopenharmony_ci InvokeType type); 6921cb0ef41Sopenharmony_ci 6931cb0ef41Sopenharmony_ci void InvokeFunction(Register function, Register expected_parameter_count, 6941cb0ef41Sopenharmony_ci Register actual_parameter_count, InvokeType type); 6951cb0ef41Sopenharmony_ci 6961cb0ef41Sopenharmony_ci // Exception handling 6971cb0ef41Sopenharmony_ci 6981cb0ef41Sopenharmony_ci // Push a new stack handler and link into stack handler chain. 6991cb0ef41Sopenharmony_ci void PushStackHandler(); 7001cb0ef41Sopenharmony_ci 7011cb0ef41Sopenharmony_ci // Unlink the stack handler on top of the stack from the stack handler chain. 7021cb0ef41Sopenharmony_ci // Must preserve the result register. 7031cb0ef41Sopenharmony_ci void PopStackHandler(); 7041cb0ef41Sopenharmony_ci 7051cb0ef41Sopenharmony_ci // --------------------------------------------------------------------------- 7061cb0ef41Sopenharmony_ci // Support functions. 7071cb0ef41Sopenharmony_ci 7081cb0ef41Sopenharmony_ci // Compare object type for heap object. heap_object contains a non-Smi 7091cb0ef41Sopenharmony_ci // whose object type should be compared with the given type. This both 7101cb0ef41Sopenharmony_ci // sets the flags and leaves the object type in the type_reg register. 7111cb0ef41Sopenharmony_ci // It leaves the map in the map register (unless the type_reg and map register 7121cb0ef41Sopenharmony_ci // are the same register). It leaves the heap object in the heap_object 7131cb0ef41Sopenharmony_ci // register unless the heap_object register is the same register as one of the 7141cb0ef41Sopenharmony_ci // other registers. 7151cb0ef41Sopenharmony_ci // Type_reg can be no_reg. In that case a scratch register is used. 7161cb0ef41Sopenharmony_ci void CompareObjectType(Register heap_object, Register map, Register type_reg, 7171cb0ef41Sopenharmony_ci InstanceType type); 7181cb0ef41Sopenharmony_ci 7191cb0ef41Sopenharmony_ci // Compare instance type in a map. map contains a valid map object whose 7201cb0ef41Sopenharmony_ci // object type should be compared with the given type. This both 7211cb0ef41Sopenharmony_ci // sets the flags and leaves the object type in the type_reg register. 7221cb0ef41Sopenharmony_ci void CompareInstanceType(Register map, Register type_reg, InstanceType type); 7231cb0ef41Sopenharmony_ci 7241cb0ef41Sopenharmony_ci // Compare instance type ranges for a map (lower_limit and higher_limit 7251cb0ef41Sopenharmony_ci // inclusive). 7261cb0ef41Sopenharmony_ci // 7271cb0ef41Sopenharmony_ci // Always use unsigned comparisons: ls for a positive result. 7281cb0ef41Sopenharmony_ci void CompareInstanceTypeRange(Register map, Register type_reg, 7291cb0ef41Sopenharmony_ci InstanceType lower_limit, 7301cb0ef41Sopenharmony_ci InstanceType higher_limit); 7311cb0ef41Sopenharmony_ci 7321cb0ef41Sopenharmony_ci // Compare the object in a register to a value from the root list. 7331cb0ef41Sopenharmony_ci // Acquires a scratch register. 7341cb0ef41Sopenharmony_ci void CompareRoot(Register obj, RootIndex index); 7351cb0ef41Sopenharmony_ci void PushRoot(RootIndex index) { 7361cb0ef41Sopenharmony_ci UseScratchRegisterScope temps(this); 7371cb0ef41Sopenharmony_ci Register scratch = temps.Acquire(); 7381cb0ef41Sopenharmony_ci LoadRoot(scratch, index); 7391cb0ef41Sopenharmony_ci Push(scratch); 7401cb0ef41Sopenharmony_ci } 7411cb0ef41Sopenharmony_ci 7421cb0ef41Sopenharmony_ci // Compare the object in a register to a value and jump if they are equal. 7431cb0ef41Sopenharmony_ci void JumpIfRoot(Register with, RootIndex index, Label* if_equal) { 7441cb0ef41Sopenharmony_ci CompareRoot(with, index); 7451cb0ef41Sopenharmony_ci b(eq, if_equal); 7461cb0ef41Sopenharmony_ci } 7471cb0ef41Sopenharmony_ci 7481cb0ef41Sopenharmony_ci // Compare the object in a register to a value and jump if they are not equal. 7491cb0ef41Sopenharmony_ci void JumpIfNotRoot(Register with, RootIndex index, Label* if_not_equal) { 7501cb0ef41Sopenharmony_ci CompareRoot(with, index); 7511cb0ef41Sopenharmony_ci b(ne, if_not_equal); 7521cb0ef41Sopenharmony_ci } 7531cb0ef41Sopenharmony_ci 7541cb0ef41Sopenharmony_ci // Checks if value is in range [lower_limit, higher_limit] using a single 7551cb0ef41Sopenharmony_ci // comparison. Flags C=0 or Z=1 indicate the value is in the range (condition 7561cb0ef41Sopenharmony_ci // ls). 7571cb0ef41Sopenharmony_ci void CompareRange(Register value, unsigned lower_limit, 7581cb0ef41Sopenharmony_ci unsigned higher_limit); 7591cb0ef41Sopenharmony_ci void JumpIfIsInRange(Register value, unsigned lower_limit, 7601cb0ef41Sopenharmony_ci unsigned higher_limit, Label* on_in_range); 7611cb0ef41Sopenharmony_ci 7621cb0ef41Sopenharmony_ci // It assumes that the arguments are located below the stack pointer. 7631cb0ef41Sopenharmony_ci // argc is the number of arguments not including the receiver. 7641cb0ef41Sopenharmony_ci // TODO(victorgomes): Remove this function once we stick with the reversed 7651cb0ef41Sopenharmony_ci // arguments order. 7661cb0ef41Sopenharmony_ci MemOperand ReceiverOperand(Register argc) { 7671cb0ef41Sopenharmony_ci return MemOperand(sp, 0); 7681cb0ef41Sopenharmony_ci } 7691cb0ef41Sopenharmony_ci 7701cb0ef41Sopenharmony_ci // --------------------------------------------------------------------------- 7711cb0ef41Sopenharmony_ci // Runtime calls 7721cb0ef41Sopenharmony_ci 7731cb0ef41Sopenharmony_ci // Call a runtime routine. 7741cb0ef41Sopenharmony_ci void CallRuntime(const Runtime::Function* f, int num_arguments, 7751cb0ef41Sopenharmony_ci SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore); 7761cb0ef41Sopenharmony_ci 7771cb0ef41Sopenharmony_ci // Convenience function: Same as above, but takes the fid instead. 7781cb0ef41Sopenharmony_ci void CallRuntime(Runtime::FunctionId fid, 7791cb0ef41Sopenharmony_ci SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore) { 7801cb0ef41Sopenharmony_ci const Runtime::Function* function = Runtime::FunctionForId(fid); 7811cb0ef41Sopenharmony_ci CallRuntime(function, function->nargs, save_doubles); 7821cb0ef41Sopenharmony_ci } 7831cb0ef41Sopenharmony_ci 7841cb0ef41Sopenharmony_ci // Convenience function: Same as above, but takes the fid instead. 7851cb0ef41Sopenharmony_ci void CallRuntime(Runtime::FunctionId fid, int num_arguments, 7861cb0ef41Sopenharmony_ci SaveFPRegsMode save_doubles = SaveFPRegsMode::kIgnore) { 7871cb0ef41Sopenharmony_ci CallRuntime(Runtime::FunctionForId(fid), num_arguments, save_doubles); 7881cb0ef41Sopenharmony_ci } 7891cb0ef41Sopenharmony_ci 7901cb0ef41Sopenharmony_ci // Convenience function: tail call a runtime routine (jump). 7911cb0ef41Sopenharmony_ci void TailCallRuntime(Runtime::FunctionId fid); 7921cb0ef41Sopenharmony_ci 7931cb0ef41Sopenharmony_ci // Jump to a runtime routine. 7941cb0ef41Sopenharmony_ci void JumpToExternalReference(const ExternalReference& builtin, 7951cb0ef41Sopenharmony_ci bool builtin_exit_frame = false); 7961cb0ef41Sopenharmony_ci 7971cb0ef41Sopenharmony_ci // Generates a trampoline to jump to the off-heap instruction stream. 7981cb0ef41Sopenharmony_ci void JumpToOffHeapInstructionStream(Address entry); 7991cb0ef41Sopenharmony_ci 8001cb0ef41Sopenharmony_ci // --------------------------------------------------------------------------- 8011cb0ef41Sopenharmony_ci // In-place weak references. 8021cb0ef41Sopenharmony_ci void LoadWeakValue(Register out, Register in, Label* target_if_cleared); 8031cb0ef41Sopenharmony_ci 8041cb0ef41Sopenharmony_ci // --------------------------------------------------------------------------- 8051cb0ef41Sopenharmony_ci // StatsCounter support 8061cb0ef41Sopenharmony_ci 8071cb0ef41Sopenharmony_ci void IncrementCounter(StatsCounter* counter, int value, Register scratch1, 8081cb0ef41Sopenharmony_ci Register scratch2) { 8091cb0ef41Sopenharmony_ci if (!FLAG_native_code_counters) return; 8101cb0ef41Sopenharmony_ci EmitIncrementCounter(counter, value, scratch1, scratch2); 8111cb0ef41Sopenharmony_ci } 8121cb0ef41Sopenharmony_ci void EmitIncrementCounter(StatsCounter* counter, int value, Register scratch1, 8131cb0ef41Sopenharmony_ci Register scratch2); 8141cb0ef41Sopenharmony_ci void DecrementCounter(StatsCounter* counter, int value, Register scratch1, 8151cb0ef41Sopenharmony_ci Register scratch2) { 8161cb0ef41Sopenharmony_ci if (!FLAG_native_code_counters) return; 8171cb0ef41Sopenharmony_ci EmitDecrementCounter(counter, value, scratch1, scratch2); 8181cb0ef41Sopenharmony_ci } 8191cb0ef41Sopenharmony_ci void EmitDecrementCounter(StatsCounter* counter, int value, Register scratch1, 8201cb0ef41Sopenharmony_ci Register scratch2); 8211cb0ef41Sopenharmony_ci 8221cb0ef41Sopenharmony_ci // --------------------------------------------------------------------------- 8231cb0ef41Sopenharmony_ci // Stack limit utilities 8241cb0ef41Sopenharmony_ci void LoadStackLimit(Register destination, StackLimitKind kind); 8251cb0ef41Sopenharmony_ci void StackOverflowCheck(Register num_args, Register scratch, 8261cb0ef41Sopenharmony_ci Label* stack_overflow); 8271cb0ef41Sopenharmony_ci 8281cb0ef41Sopenharmony_ci // --------------------------------------------------------------------------- 8291cb0ef41Sopenharmony_ci // Smi utilities 8301cb0ef41Sopenharmony_ci 8311cb0ef41Sopenharmony_ci void SmiTag(Register reg, SBit s = LeaveCC); 8321cb0ef41Sopenharmony_ci void SmiTag(Register dst, Register src, SBit s = LeaveCC); 8331cb0ef41Sopenharmony_ci 8341cb0ef41Sopenharmony_ci // Test if the register contains a smi (Z == 0 (eq) if true). 8351cb0ef41Sopenharmony_ci void SmiTst(Register value); 8361cb0ef41Sopenharmony_ci // Jump if either of the registers contain a non-smi. 8371cb0ef41Sopenharmony_ci void JumpIfNotSmi(Register value, Label* not_smi_label); 8381cb0ef41Sopenharmony_ci 8391cb0ef41Sopenharmony_ci // Abort execution if argument is a smi, enabled via --debug-code. 8401cb0ef41Sopenharmony_ci void AssertNotSmi(Register object); 8411cb0ef41Sopenharmony_ci void AssertSmi(Register object); 8421cb0ef41Sopenharmony_ci 8431cb0ef41Sopenharmony_ci // Abort execution if argument is not a Constructor, enabled via --debug-code. 8441cb0ef41Sopenharmony_ci void AssertConstructor(Register object); 8451cb0ef41Sopenharmony_ci 8461cb0ef41Sopenharmony_ci // Abort execution if argument is not a JSFunction, enabled via --debug-code. 8471cb0ef41Sopenharmony_ci void AssertFunction(Register object); 8481cb0ef41Sopenharmony_ci 8491cb0ef41Sopenharmony_ci // Abort execution if argument is not a callable JSFunction, enabled via 8501cb0ef41Sopenharmony_ci // --debug-code. 8511cb0ef41Sopenharmony_ci void AssertCallableFunction(Register object); 8521cb0ef41Sopenharmony_ci 8531cb0ef41Sopenharmony_ci // Abort execution if argument is not a JSBoundFunction, 8541cb0ef41Sopenharmony_ci // enabled via --debug-code. 8551cb0ef41Sopenharmony_ci void AssertBoundFunction(Register object); 8561cb0ef41Sopenharmony_ci 8571cb0ef41Sopenharmony_ci // Abort execution if argument is not a JSGeneratorObject (or subclass), 8581cb0ef41Sopenharmony_ci // enabled via --debug-code. 8591cb0ef41Sopenharmony_ci void AssertGeneratorObject(Register object); 8601cb0ef41Sopenharmony_ci 8611cb0ef41Sopenharmony_ci // Abort execution if argument is not undefined or an AllocationSite, enabled 8621cb0ef41Sopenharmony_ci // via --debug-code. 8631cb0ef41Sopenharmony_ci void AssertUndefinedOrAllocationSite(Register object, Register scratch); 8641cb0ef41Sopenharmony_ci 8651cb0ef41Sopenharmony_ci template <typename Field> 8661cb0ef41Sopenharmony_ci void DecodeField(Register dst, Register src) { 8671cb0ef41Sopenharmony_ci Ubfx(dst, src, Field::kShift, Field::kSize); 8681cb0ef41Sopenharmony_ci } 8691cb0ef41Sopenharmony_ci 8701cb0ef41Sopenharmony_ci template <typename Field> 8711cb0ef41Sopenharmony_ci void DecodeField(Register reg) { 8721cb0ef41Sopenharmony_ci DecodeField<Field>(reg, reg); 8731cb0ef41Sopenharmony_ci } 8741cb0ef41Sopenharmony_ci 8751cb0ef41Sopenharmony_ci private: 8761cb0ef41Sopenharmony_ci // Helper functions for generating invokes. 8771cb0ef41Sopenharmony_ci void InvokePrologue(Register expected_parameter_count, 8781cb0ef41Sopenharmony_ci Register actual_parameter_count, Label* done, 8791cb0ef41Sopenharmony_ci InvokeType type); 8801cb0ef41Sopenharmony_ci 8811cb0ef41Sopenharmony_ci DISALLOW_IMPLICIT_CONSTRUCTORS(MacroAssembler); 8821cb0ef41Sopenharmony_ci}; 8831cb0ef41Sopenharmony_ci 8841cb0ef41Sopenharmony_ci#define ACCESS_MASM(masm) masm-> 8851cb0ef41Sopenharmony_ci 8861cb0ef41Sopenharmony_ci} // namespace internal 8871cb0ef41Sopenharmony_ci} // namespace v8 8881cb0ef41Sopenharmony_ci 8891cb0ef41Sopenharmony_ci#endif // V8_CODEGEN_ARM_MACRO_ASSEMBLER_ARM_H_ 890