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#if V8_TARGET_ARCH_IA32 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <stdint.h> 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ci#include "include/v8-internal.h" 101cb0ef41Sopenharmony_ci#include "src/base/bits.h" 111cb0ef41Sopenharmony_ci#include "src/base/logging.h" 121cb0ef41Sopenharmony_ci#include "src/base/macros.h" 131cb0ef41Sopenharmony_ci#include "src/base/platform/platform.h" 141cb0ef41Sopenharmony_ci#include "src/builtins/builtins.h" 151cb0ef41Sopenharmony_ci#include "src/codegen/assembler.h" 161cb0ef41Sopenharmony_ci#include "src/codegen/bailout-reason.h" 171cb0ef41Sopenharmony_ci#include "src/codegen/code-factory.h" 181cb0ef41Sopenharmony_ci#include "src/codegen/cpu-features.h" 191cb0ef41Sopenharmony_ci#include "src/codegen/external-reference.h" 201cb0ef41Sopenharmony_ci#include "src/codegen/ia32/assembler-ia32.h" 211cb0ef41Sopenharmony_ci#include "src/codegen/ia32/register-ia32.h" 221cb0ef41Sopenharmony_ci#include "src/codegen/interface-descriptors-inl.h" 231cb0ef41Sopenharmony_ci#include "src/codegen/label.h" 241cb0ef41Sopenharmony_ci#include "src/codegen/macro-assembler.h" 251cb0ef41Sopenharmony_ci#include "src/codegen/register.h" 261cb0ef41Sopenharmony_ci#include "src/codegen/reglist.h" 271cb0ef41Sopenharmony_ci#include "src/codegen/reloc-info.h" 281cb0ef41Sopenharmony_ci#include "src/codegen/turbo-assembler.h" 291cb0ef41Sopenharmony_ci#include "src/common/globals.h" 301cb0ef41Sopenharmony_ci#include "src/deoptimizer/deoptimizer.h" 311cb0ef41Sopenharmony_ci#include "src/execution/frame-constants.h" 321cb0ef41Sopenharmony_ci#include "src/execution/frames.h" 331cb0ef41Sopenharmony_ci#include "src/execution/isolate-data.h" 341cb0ef41Sopenharmony_ci#include "src/execution/isolate.h" 351cb0ef41Sopenharmony_ci#include "src/flags/flags.h" 361cb0ef41Sopenharmony_ci#include "src/handles/handles-inl.h" 371cb0ef41Sopenharmony_ci#include "src/handles/handles.h" 381cb0ef41Sopenharmony_ci#include "src/heap/basic-memory-chunk.h" 391cb0ef41Sopenharmony_ci#include "src/heap/factory-inl.h" 401cb0ef41Sopenharmony_ci#include "src/heap/factory.h" 411cb0ef41Sopenharmony_ci#include "src/heap/memory-chunk.h" 421cb0ef41Sopenharmony_ci#include "src/logging/counters.h" 431cb0ef41Sopenharmony_ci#include "src/objects/code.h" 441cb0ef41Sopenharmony_ci#include "src/objects/contexts.h" 451cb0ef41Sopenharmony_ci#include "src/objects/fixed-array.h" 461cb0ef41Sopenharmony_ci#include "src/objects/heap-object.h" 471cb0ef41Sopenharmony_ci#include "src/objects/js-function.h" 481cb0ef41Sopenharmony_ci#include "src/objects/map.h" 491cb0ef41Sopenharmony_ci#include "src/objects/objects.h" 501cb0ef41Sopenharmony_ci#include "src/objects/oddball.h" 511cb0ef41Sopenharmony_ci#include "src/objects/shared-function-info.h" 521cb0ef41Sopenharmony_ci#include "src/objects/slots-inl.h" 531cb0ef41Sopenharmony_ci#include "src/objects/smi.h" 541cb0ef41Sopenharmony_ci#include "src/roots/roots-inl.h" 551cb0ef41Sopenharmony_ci#include "src/roots/roots.h" 561cb0ef41Sopenharmony_ci#include "src/runtime/runtime.h" 571cb0ef41Sopenharmony_ci#include "src/utils/utils.h" 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci// Satisfy cpplint check, but don't include platform-specific header. It is 601cb0ef41Sopenharmony_ci// included recursively via macro-assembler.h. 611cb0ef41Sopenharmony_ci#if 0 621cb0ef41Sopenharmony_ci#include "src/codegen/ia32/macro-assembler-ia32.h" 631cb0ef41Sopenharmony_ci#endif 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_cinamespace v8 { 661cb0ef41Sopenharmony_cinamespace internal { 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ciOperand StackArgumentsAccessor::GetArgumentOperand(int index) const { 691cb0ef41Sopenharmony_ci DCHECK_GE(index, 0); 701cb0ef41Sopenharmony_ci // arg[0] = esp + kPCOnStackSize; 711cb0ef41Sopenharmony_ci // arg[i] = arg[0] + i * kSystemPointerSize; 721cb0ef41Sopenharmony_ci return Operand(esp, kPCOnStackSize + index * kSystemPointerSize); 731cb0ef41Sopenharmony_ci} 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci// ------------------------------------------------------------------------- 761cb0ef41Sopenharmony_ci// MacroAssembler implementation. 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_civoid TurboAssembler::InitializeRootRegister() { 791cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 801cb0ef41Sopenharmony_ci ExternalReference isolate_root = ExternalReference::isolate_root(isolate()); 811cb0ef41Sopenharmony_ci Move(kRootRegister, Immediate(isolate_root)); 821cb0ef41Sopenharmony_ci} 831cb0ef41Sopenharmony_ci 841cb0ef41Sopenharmony_ciOperand TurboAssembler::RootAsOperand(RootIndex index) { 851cb0ef41Sopenharmony_ci DCHECK(root_array_available()); 861cb0ef41Sopenharmony_ci return Operand(kRootRegister, RootRegisterOffsetForRootIndex(index)); 871cb0ef41Sopenharmony_ci} 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_civoid TurboAssembler::LoadRoot(Register destination, RootIndex index) { 901cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 911cb0ef41Sopenharmony_ci if (root_array_available()) { 921cb0ef41Sopenharmony_ci mov(destination, RootAsOperand(index)); 931cb0ef41Sopenharmony_ci return; 941cb0ef41Sopenharmony_ci } 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci if (RootsTable::IsImmortalImmovable(index)) { 971cb0ef41Sopenharmony_ci Handle<Object> object = isolate()->root_handle(index); 981cb0ef41Sopenharmony_ci if (object->IsSmi()) { 991cb0ef41Sopenharmony_ci mov(destination, Immediate(Smi::cast(*object))); 1001cb0ef41Sopenharmony_ci return; 1011cb0ef41Sopenharmony_ci } else { 1021cb0ef41Sopenharmony_ci DCHECK(object->IsHeapObject()); 1031cb0ef41Sopenharmony_ci mov(destination, Handle<HeapObject>::cast(object)); 1041cb0ef41Sopenharmony_ci return; 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci } 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci ExternalReference isolate_root = ExternalReference::isolate_root(isolate()); 1091cb0ef41Sopenharmony_ci lea(destination, 1101cb0ef41Sopenharmony_ci Operand(isolate_root.address(), RelocInfo::EXTERNAL_REFERENCE)); 1111cb0ef41Sopenharmony_ci mov(destination, Operand(destination, RootRegisterOffsetForRootIndex(index))); 1121cb0ef41Sopenharmony_ci} 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_civoid TurboAssembler::CompareRoot(Register with, Register scratch, 1151cb0ef41Sopenharmony_ci RootIndex index) { 1161cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 1171cb0ef41Sopenharmony_ci if (root_array_available()) { 1181cb0ef41Sopenharmony_ci CompareRoot(with, index); 1191cb0ef41Sopenharmony_ci } else { 1201cb0ef41Sopenharmony_ci ExternalReference isolate_root = ExternalReference::isolate_root(isolate()); 1211cb0ef41Sopenharmony_ci lea(scratch, 1221cb0ef41Sopenharmony_ci Operand(isolate_root.address(), RelocInfo::EXTERNAL_REFERENCE)); 1231cb0ef41Sopenharmony_ci cmp(with, Operand(scratch, RootRegisterOffsetForRootIndex(index))); 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci} 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_civoid TurboAssembler::CompareRoot(Register with, RootIndex index) { 1281cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 1291cb0ef41Sopenharmony_ci if (root_array_available()) { 1301cb0ef41Sopenharmony_ci cmp(with, RootAsOperand(index)); 1311cb0ef41Sopenharmony_ci return; 1321cb0ef41Sopenharmony_ci } 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci DCHECK(RootsTable::IsImmortalImmovable(index)); 1351cb0ef41Sopenharmony_ci Handle<Object> object = isolate()->root_handle(index); 1361cb0ef41Sopenharmony_ci if (object->IsHeapObject()) { 1371cb0ef41Sopenharmony_ci cmp(with, Handle<HeapObject>::cast(object)); 1381cb0ef41Sopenharmony_ci } else { 1391cb0ef41Sopenharmony_ci cmp(with, Immediate(Smi::cast(*object))); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci} 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_civoid MacroAssembler::PushRoot(RootIndex index) { 1441cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 1451cb0ef41Sopenharmony_ci if (root_array_available()) { 1461cb0ef41Sopenharmony_ci DCHECK(RootsTable::IsImmortalImmovable(index)); 1471cb0ef41Sopenharmony_ci push(RootAsOperand(index)); 1481cb0ef41Sopenharmony_ci return; 1491cb0ef41Sopenharmony_ci } 1501cb0ef41Sopenharmony_ci 1511cb0ef41Sopenharmony_ci // TODO(v8:6666): Add a scratch register or remove all uses. 1521cb0ef41Sopenharmony_ci DCHECK(RootsTable::IsImmortalImmovable(index)); 1531cb0ef41Sopenharmony_ci Handle<Object> object = isolate()->root_handle(index); 1541cb0ef41Sopenharmony_ci if (object->IsHeapObject()) { 1551cb0ef41Sopenharmony_ci Push(Handle<HeapObject>::cast(object)); 1561cb0ef41Sopenharmony_ci } else { 1571cb0ef41Sopenharmony_ci Push(Smi::cast(*object)); 1581cb0ef41Sopenharmony_ci } 1591cb0ef41Sopenharmony_ci} 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_civoid MacroAssembler::CompareRange(Register value, unsigned lower_limit, 1621cb0ef41Sopenharmony_ci unsigned higher_limit, Register scratch) { 1631cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 1641cb0ef41Sopenharmony_ci DCHECK_LT(lower_limit, higher_limit); 1651cb0ef41Sopenharmony_ci if (lower_limit != 0) { 1661cb0ef41Sopenharmony_ci lea(scratch, Operand(value, 0u - lower_limit)); 1671cb0ef41Sopenharmony_ci cmp(scratch, Immediate(higher_limit - lower_limit)); 1681cb0ef41Sopenharmony_ci } else { 1691cb0ef41Sopenharmony_ci cmp(value, Immediate(higher_limit)); 1701cb0ef41Sopenharmony_ci } 1711cb0ef41Sopenharmony_ci} 1721cb0ef41Sopenharmony_ci 1731cb0ef41Sopenharmony_civoid MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit, 1741cb0ef41Sopenharmony_ci unsigned higher_limit, Register scratch, 1751cb0ef41Sopenharmony_ci Label* on_in_range, 1761cb0ef41Sopenharmony_ci Label::Distance near_jump) { 1771cb0ef41Sopenharmony_ci CompareRange(value, lower_limit, higher_limit, scratch); 1781cb0ef41Sopenharmony_ci j(below_equal, on_in_range, near_jump); 1791cb0ef41Sopenharmony_ci} 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_civoid TurboAssembler::PushArray(Register array, Register size, Register scratch, 1821cb0ef41Sopenharmony_ci PushArrayOrder order) { 1831cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 1841cb0ef41Sopenharmony_ci DCHECK(!AreAliased(array, size, scratch)); 1851cb0ef41Sopenharmony_ci Register counter = scratch; 1861cb0ef41Sopenharmony_ci Label loop, entry; 1871cb0ef41Sopenharmony_ci if (order == PushArrayOrder::kReverse) { 1881cb0ef41Sopenharmony_ci mov(counter, 0); 1891cb0ef41Sopenharmony_ci jmp(&entry); 1901cb0ef41Sopenharmony_ci bind(&loop); 1911cb0ef41Sopenharmony_ci Push(Operand(array, counter, times_system_pointer_size, 0)); 1921cb0ef41Sopenharmony_ci inc(counter); 1931cb0ef41Sopenharmony_ci bind(&entry); 1941cb0ef41Sopenharmony_ci cmp(counter, size); 1951cb0ef41Sopenharmony_ci j(less, &loop, Label::kNear); 1961cb0ef41Sopenharmony_ci } else { 1971cb0ef41Sopenharmony_ci mov(counter, size); 1981cb0ef41Sopenharmony_ci jmp(&entry); 1991cb0ef41Sopenharmony_ci bind(&loop); 2001cb0ef41Sopenharmony_ci Push(Operand(array, counter, times_system_pointer_size, 0)); 2011cb0ef41Sopenharmony_ci bind(&entry); 2021cb0ef41Sopenharmony_ci dec(counter); 2031cb0ef41Sopenharmony_ci j(greater_equal, &loop, Label::kNear); 2041cb0ef41Sopenharmony_ci } 2051cb0ef41Sopenharmony_ci} 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ciOperand TurboAssembler::ExternalReferenceAsOperand(ExternalReference reference, 2081cb0ef41Sopenharmony_ci Register scratch) { 2091cb0ef41Sopenharmony_ci if (root_array_available() && options().enable_root_relative_access) { 2101cb0ef41Sopenharmony_ci intptr_t delta = 2111cb0ef41Sopenharmony_ci RootRegisterOffsetForExternalReference(isolate(), reference); 2121cb0ef41Sopenharmony_ci return Operand(kRootRegister, delta); 2131cb0ef41Sopenharmony_ci } 2141cb0ef41Sopenharmony_ci if (root_array_available() && options().isolate_independent_code) { 2151cb0ef41Sopenharmony_ci if (IsAddressableThroughRootRegister(isolate(), reference)) { 2161cb0ef41Sopenharmony_ci // Some external references can be efficiently loaded as an offset from 2171cb0ef41Sopenharmony_ci // kRootRegister. 2181cb0ef41Sopenharmony_ci intptr_t offset = 2191cb0ef41Sopenharmony_ci RootRegisterOffsetForExternalReference(isolate(), reference); 2201cb0ef41Sopenharmony_ci return Operand(kRootRegister, offset); 2211cb0ef41Sopenharmony_ci } else { 2221cb0ef41Sopenharmony_ci // Otherwise, do a memory load from the external reference table. 2231cb0ef41Sopenharmony_ci mov(scratch, Operand(kRootRegister, 2241cb0ef41Sopenharmony_ci RootRegisterOffsetForExternalReferenceTableEntry( 2251cb0ef41Sopenharmony_ci isolate(), reference))); 2261cb0ef41Sopenharmony_ci return Operand(scratch, 0); 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci } 2291cb0ef41Sopenharmony_ci Move(scratch, Immediate(reference)); 2301cb0ef41Sopenharmony_ci return Operand(scratch, 0); 2311cb0ef41Sopenharmony_ci} 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci// TODO(v8:6666): If possible, refactor into a platform-independent function in 2341cb0ef41Sopenharmony_ci// TurboAssembler. 2351cb0ef41Sopenharmony_ciOperand TurboAssembler::ExternalReferenceAddressAsOperand( 2361cb0ef41Sopenharmony_ci ExternalReference reference) { 2371cb0ef41Sopenharmony_ci DCHECK(root_array_available()); 2381cb0ef41Sopenharmony_ci DCHECK(options().isolate_independent_code); 2391cb0ef41Sopenharmony_ci return Operand( 2401cb0ef41Sopenharmony_ci kRootRegister, 2411cb0ef41Sopenharmony_ci RootRegisterOffsetForExternalReferenceTableEntry(isolate(), reference)); 2421cb0ef41Sopenharmony_ci} 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ci// TODO(v8:6666): If possible, refactor into a platform-independent function in 2451cb0ef41Sopenharmony_ci// TurboAssembler. 2461cb0ef41Sopenharmony_ciOperand TurboAssembler::HeapObjectAsOperand(Handle<HeapObject> object) { 2471cb0ef41Sopenharmony_ci DCHECK(root_array_available()); 2481cb0ef41Sopenharmony_ci 2491cb0ef41Sopenharmony_ci Builtin builtin; 2501cb0ef41Sopenharmony_ci RootIndex root_index; 2511cb0ef41Sopenharmony_ci if (isolate()->roots_table().IsRootHandle(object, &root_index)) { 2521cb0ef41Sopenharmony_ci return RootAsOperand(root_index); 2531cb0ef41Sopenharmony_ci } else if (isolate()->builtins()->IsBuiltinHandle(object, &builtin)) { 2541cb0ef41Sopenharmony_ci return Operand(kRootRegister, RootRegisterOffsetForBuiltin(builtin)); 2551cb0ef41Sopenharmony_ci } else if (object.is_identical_to(code_object_) && 2561cb0ef41Sopenharmony_ci Builtins::IsBuiltinId(maybe_builtin_)) { 2571cb0ef41Sopenharmony_ci return Operand(kRootRegister, RootRegisterOffsetForBuiltin(maybe_builtin_)); 2581cb0ef41Sopenharmony_ci } else { 2591cb0ef41Sopenharmony_ci // Objects in the constants table need an additional indirection, which 2601cb0ef41Sopenharmony_ci // cannot be represented as a single Operand. 2611cb0ef41Sopenharmony_ci UNREACHABLE(); 2621cb0ef41Sopenharmony_ci } 2631cb0ef41Sopenharmony_ci} 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_civoid TurboAssembler::LoadFromConstantsTable(Register destination, 2661cb0ef41Sopenharmony_ci int constant_index) { 2671cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 2681cb0ef41Sopenharmony_ci DCHECK(RootsTable::IsImmortalImmovable(RootIndex::kBuiltinsConstantsTable)); 2691cb0ef41Sopenharmony_ci LoadRoot(destination, RootIndex::kBuiltinsConstantsTable); 2701cb0ef41Sopenharmony_ci mov(destination, 2711cb0ef41Sopenharmony_ci FieldOperand(destination, FixedArray::OffsetOfElementAt(constant_index))); 2721cb0ef41Sopenharmony_ci} 2731cb0ef41Sopenharmony_ci 2741cb0ef41Sopenharmony_civoid TurboAssembler::LoadRootRegisterOffset(Register destination, 2751cb0ef41Sopenharmony_ci intptr_t offset) { 2761cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 2771cb0ef41Sopenharmony_ci DCHECK(is_int32(offset)); 2781cb0ef41Sopenharmony_ci DCHECK(root_array_available()); 2791cb0ef41Sopenharmony_ci if (offset == 0) { 2801cb0ef41Sopenharmony_ci mov(destination, kRootRegister); 2811cb0ef41Sopenharmony_ci } else { 2821cb0ef41Sopenharmony_ci lea(destination, Operand(kRootRegister, static_cast<int32_t>(offset))); 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci} 2851cb0ef41Sopenharmony_ci 2861cb0ef41Sopenharmony_civoid TurboAssembler::LoadRootRelative(Register destination, int32_t offset) { 2871cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 2881cb0ef41Sopenharmony_ci DCHECK(root_array_available()); 2891cb0ef41Sopenharmony_ci mov(destination, Operand(kRootRegister, offset)); 2901cb0ef41Sopenharmony_ci} 2911cb0ef41Sopenharmony_ci 2921cb0ef41Sopenharmony_civoid TurboAssembler::LoadAddress(Register destination, 2931cb0ef41Sopenharmony_ci ExternalReference source) { 2941cb0ef41Sopenharmony_ci // TODO(jgruber): Add support for enable_root_relative_access. 2951cb0ef41Sopenharmony_ci if (root_array_available() && options().isolate_independent_code) { 2961cb0ef41Sopenharmony_ci IndirectLoadExternalReference(destination, source); 2971cb0ef41Sopenharmony_ci return; 2981cb0ef41Sopenharmony_ci } 2991cb0ef41Sopenharmony_ci mov(destination, Immediate(source)); 3001cb0ef41Sopenharmony_ci} 3011cb0ef41Sopenharmony_ci 3021cb0ef41Sopenharmony_cistatic constexpr Register saved_regs[] = {eax, ecx, edx}; 3031cb0ef41Sopenharmony_ci 3041cb0ef41Sopenharmony_cistatic constexpr int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register); 3051cb0ef41Sopenharmony_ci 3061cb0ef41Sopenharmony_ciint TurboAssembler::RequiredStackSizeForCallerSaved(SaveFPRegsMode fp_mode, 3071cb0ef41Sopenharmony_ci Register exclusion1, 3081cb0ef41Sopenharmony_ci Register exclusion2, 3091cb0ef41Sopenharmony_ci Register exclusion3) const { 3101cb0ef41Sopenharmony_ci int bytes = 0; 3111cb0ef41Sopenharmony_ci for (int i = 0; i < kNumberOfSavedRegs; i++) { 3121cb0ef41Sopenharmony_ci Register reg = saved_regs[i]; 3131cb0ef41Sopenharmony_ci if (reg != exclusion1 && reg != exclusion2 && reg != exclusion3) { 3141cb0ef41Sopenharmony_ci bytes += kSystemPointerSize; 3151cb0ef41Sopenharmony_ci } 3161cb0ef41Sopenharmony_ci } 3171cb0ef41Sopenharmony_ci 3181cb0ef41Sopenharmony_ci if (fp_mode == SaveFPRegsMode::kSave) { 3191cb0ef41Sopenharmony_ci // Count all XMM registers except XMM0. 3201cb0ef41Sopenharmony_ci bytes += kStackSavedSavedFPSize * (XMMRegister::kNumRegisters - 1); 3211cb0ef41Sopenharmony_ci } 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ci return bytes; 3241cb0ef41Sopenharmony_ci} 3251cb0ef41Sopenharmony_ci 3261cb0ef41Sopenharmony_ciint TurboAssembler::PushCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1, 3271cb0ef41Sopenharmony_ci Register exclusion2, Register exclusion3) { 3281cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 3291cb0ef41Sopenharmony_ci // We don't allow a GC in a write barrier slow path so there is no need to 3301cb0ef41Sopenharmony_ci // store the registers in any particular way, but we do have to store and 3311cb0ef41Sopenharmony_ci // restore them. 3321cb0ef41Sopenharmony_ci int bytes = 0; 3331cb0ef41Sopenharmony_ci for (int i = 0; i < kNumberOfSavedRegs; i++) { 3341cb0ef41Sopenharmony_ci Register reg = saved_regs[i]; 3351cb0ef41Sopenharmony_ci if (reg != exclusion1 && reg != exclusion2 && reg != exclusion3) { 3361cb0ef41Sopenharmony_ci push(reg); 3371cb0ef41Sopenharmony_ci bytes += kSystemPointerSize; 3381cb0ef41Sopenharmony_ci } 3391cb0ef41Sopenharmony_ci } 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_ci if (fp_mode == SaveFPRegsMode::kSave) { 3421cb0ef41Sopenharmony_ci // Save all XMM registers except XMM0. 3431cb0ef41Sopenharmony_ci const int delta = kStackSavedSavedFPSize * (XMMRegister::kNumRegisters - 1); 3441cb0ef41Sopenharmony_ci AllocateStackSpace(delta); 3451cb0ef41Sopenharmony_ci for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) { 3461cb0ef41Sopenharmony_ci XMMRegister reg = XMMRegister::from_code(i); 3471cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY 3481cb0ef41Sopenharmony_ci Movdqu(Operand(esp, (i - 1) * kStackSavedSavedFPSize), reg); 3491cb0ef41Sopenharmony_ci#else 3501cb0ef41Sopenharmony_ci Movsd(Operand(esp, (i - 1) * kStackSavedSavedFPSize), reg); 3511cb0ef41Sopenharmony_ci#endif // V8_ENABLE_WEBASSEMBLY 3521cb0ef41Sopenharmony_ci } 3531cb0ef41Sopenharmony_ci bytes += delta; 3541cb0ef41Sopenharmony_ci } 3551cb0ef41Sopenharmony_ci 3561cb0ef41Sopenharmony_ci return bytes; 3571cb0ef41Sopenharmony_ci} 3581cb0ef41Sopenharmony_ci 3591cb0ef41Sopenharmony_ciint TurboAssembler::PopCallerSaved(SaveFPRegsMode fp_mode, Register exclusion1, 3601cb0ef41Sopenharmony_ci Register exclusion2, Register exclusion3) { 3611cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 3621cb0ef41Sopenharmony_ci int bytes = 0; 3631cb0ef41Sopenharmony_ci if (fp_mode == SaveFPRegsMode::kSave) { 3641cb0ef41Sopenharmony_ci // Restore all XMM registers except XMM0. 3651cb0ef41Sopenharmony_ci const int delta = kStackSavedSavedFPSize * (XMMRegister::kNumRegisters - 1); 3661cb0ef41Sopenharmony_ci for (int i = XMMRegister::kNumRegisters - 1; i > 0; i--) { 3671cb0ef41Sopenharmony_ci XMMRegister reg = XMMRegister::from_code(i); 3681cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY 3691cb0ef41Sopenharmony_ci Movdqu(reg, Operand(esp, (i - 1) * kStackSavedSavedFPSize)); 3701cb0ef41Sopenharmony_ci#else 3711cb0ef41Sopenharmony_ci Movsd(reg, Operand(esp, (i - 1) * kStackSavedSavedFPSize)); 3721cb0ef41Sopenharmony_ci#endif // V8_ENABLE_WEBASSEMBLY 3731cb0ef41Sopenharmony_ci } 3741cb0ef41Sopenharmony_ci add(esp, Immediate(delta)); 3751cb0ef41Sopenharmony_ci bytes += delta; 3761cb0ef41Sopenharmony_ci } 3771cb0ef41Sopenharmony_ci 3781cb0ef41Sopenharmony_ci for (int i = kNumberOfSavedRegs - 1; i >= 0; i--) { 3791cb0ef41Sopenharmony_ci Register reg = saved_regs[i]; 3801cb0ef41Sopenharmony_ci if (reg != exclusion1 && reg != exclusion2 && reg != exclusion3) { 3811cb0ef41Sopenharmony_ci pop(reg); 3821cb0ef41Sopenharmony_ci bytes += kSystemPointerSize; 3831cb0ef41Sopenharmony_ci } 3841cb0ef41Sopenharmony_ci } 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ci return bytes; 3871cb0ef41Sopenharmony_ci} 3881cb0ef41Sopenharmony_ci 3891cb0ef41Sopenharmony_civoid MacroAssembler::RecordWriteField(Register object, int offset, 3901cb0ef41Sopenharmony_ci Register value, Register slot_address, 3911cb0ef41Sopenharmony_ci SaveFPRegsMode save_fp, 3921cb0ef41Sopenharmony_ci RememberedSetAction remembered_set_action, 3931cb0ef41Sopenharmony_ci SmiCheck smi_check) { 3941cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 3951cb0ef41Sopenharmony_ci // First, check if a write barrier is even needed. The tests below 3961cb0ef41Sopenharmony_ci // catch stores of Smis. 3971cb0ef41Sopenharmony_ci Label done; 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_ci // Skip barrier if writing a smi. 4001cb0ef41Sopenharmony_ci if (smi_check == SmiCheck::kInline) { 4011cb0ef41Sopenharmony_ci JumpIfSmi(value, &done); 4021cb0ef41Sopenharmony_ci } 4031cb0ef41Sopenharmony_ci 4041cb0ef41Sopenharmony_ci // Although the object register is tagged, the offset is relative to the start 4051cb0ef41Sopenharmony_ci // of the object, so so offset must be a multiple of kTaggedSize. 4061cb0ef41Sopenharmony_ci DCHECK(IsAligned(offset, kTaggedSize)); 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci lea(slot_address, FieldOperand(object, offset)); 4091cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 4101cb0ef41Sopenharmony_ci Label ok; 4111cb0ef41Sopenharmony_ci test_b(slot_address, Immediate(kTaggedSize - 1)); 4121cb0ef41Sopenharmony_ci j(zero, &ok, Label::kNear); 4131cb0ef41Sopenharmony_ci int3(); 4141cb0ef41Sopenharmony_ci bind(&ok); 4151cb0ef41Sopenharmony_ci } 4161cb0ef41Sopenharmony_ci 4171cb0ef41Sopenharmony_ci RecordWrite(object, slot_address, value, save_fp, remembered_set_action, 4181cb0ef41Sopenharmony_ci SmiCheck::kOmit); 4191cb0ef41Sopenharmony_ci 4201cb0ef41Sopenharmony_ci bind(&done); 4211cb0ef41Sopenharmony_ci 4221cb0ef41Sopenharmony_ci // Clobber clobbered input registers when running with the debug-code flag 4231cb0ef41Sopenharmony_ci // turned on to provoke errors. 4241cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 4251cb0ef41Sopenharmony_ci mov(value, Immediate(bit_cast<int32_t>(kZapValue))); 4261cb0ef41Sopenharmony_ci mov(slot_address, Immediate(bit_cast<int32_t>(kZapValue))); 4271cb0ef41Sopenharmony_ci } 4281cb0ef41Sopenharmony_ci} 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_civoid TurboAssembler::MaybeSaveRegisters(RegList registers) { 4311cb0ef41Sopenharmony_ci for (Register reg : registers) { 4321cb0ef41Sopenharmony_ci push(reg); 4331cb0ef41Sopenharmony_ci } 4341cb0ef41Sopenharmony_ci} 4351cb0ef41Sopenharmony_ci 4361cb0ef41Sopenharmony_civoid TurboAssembler::MaybeRestoreRegisters(RegList registers) { 4371cb0ef41Sopenharmony_ci for (Register reg : base::Reversed(registers)) { 4381cb0ef41Sopenharmony_ci pop(reg); 4391cb0ef41Sopenharmony_ci } 4401cb0ef41Sopenharmony_ci} 4411cb0ef41Sopenharmony_ci 4421cb0ef41Sopenharmony_civoid TurboAssembler::CallEphemeronKeyBarrier(Register object, 4431cb0ef41Sopenharmony_ci Register slot_address, 4441cb0ef41Sopenharmony_ci SaveFPRegsMode fp_mode) { 4451cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 4461cb0ef41Sopenharmony_ci DCHECK(!AreAliased(object, slot_address)); 4471cb0ef41Sopenharmony_ci RegList registers = 4481cb0ef41Sopenharmony_ci WriteBarrierDescriptor::ComputeSavedRegisters(object, slot_address); 4491cb0ef41Sopenharmony_ci MaybeSaveRegisters(registers); 4501cb0ef41Sopenharmony_ci 4511cb0ef41Sopenharmony_ci Register object_parameter = WriteBarrierDescriptor::ObjectRegister(); 4521cb0ef41Sopenharmony_ci Register slot_address_parameter = 4531cb0ef41Sopenharmony_ci WriteBarrierDescriptor::SlotAddressRegister(); 4541cb0ef41Sopenharmony_ci 4551cb0ef41Sopenharmony_ci push(object); 4561cb0ef41Sopenharmony_ci push(slot_address); 4571cb0ef41Sopenharmony_ci pop(slot_address_parameter); 4581cb0ef41Sopenharmony_ci pop(object_parameter); 4591cb0ef41Sopenharmony_ci 4601cb0ef41Sopenharmony_ci Call(isolate()->builtins()->code_handle( 4611cb0ef41Sopenharmony_ci Builtins::GetEphemeronKeyBarrierStub(fp_mode)), 4621cb0ef41Sopenharmony_ci RelocInfo::CODE_TARGET); 4631cb0ef41Sopenharmony_ci 4641cb0ef41Sopenharmony_ci MaybeRestoreRegisters(registers); 4651cb0ef41Sopenharmony_ci} 4661cb0ef41Sopenharmony_ci 4671cb0ef41Sopenharmony_civoid TurboAssembler::CallRecordWriteStubSaveRegisters( 4681cb0ef41Sopenharmony_ci Register object, Register slot_address, 4691cb0ef41Sopenharmony_ci RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode, 4701cb0ef41Sopenharmony_ci StubCallMode mode) { 4711cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 4721cb0ef41Sopenharmony_ci DCHECK(!AreAliased(object, slot_address)); 4731cb0ef41Sopenharmony_ci RegList registers = 4741cb0ef41Sopenharmony_ci WriteBarrierDescriptor::ComputeSavedRegisters(object, slot_address); 4751cb0ef41Sopenharmony_ci MaybeSaveRegisters(registers); 4761cb0ef41Sopenharmony_ci 4771cb0ef41Sopenharmony_ci Register object_parameter = WriteBarrierDescriptor::ObjectRegister(); 4781cb0ef41Sopenharmony_ci Register slot_address_parameter = 4791cb0ef41Sopenharmony_ci WriteBarrierDescriptor::SlotAddressRegister(); 4801cb0ef41Sopenharmony_ci 4811cb0ef41Sopenharmony_ci push(object); 4821cb0ef41Sopenharmony_ci push(slot_address); 4831cb0ef41Sopenharmony_ci pop(slot_address_parameter); 4841cb0ef41Sopenharmony_ci pop(object_parameter); 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ci CallRecordWriteStub(object_parameter, slot_address_parameter, 4871cb0ef41Sopenharmony_ci remembered_set_action, fp_mode, mode); 4881cb0ef41Sopenharmony_ci 4891cb0ef41Sopenharmony_ci MaybeRestoreRegisters(registers); 4901cb0ef41Sopenharmony_ci} 4911cb0ef41Sopenharmony_ci 4921cb0ef41Sopenharmony_civoid TurboAssembler::CallRecordWriteStub( 4931cb0ef41Sopenharmony_ci Register object, Register slot_address, 4941cb0ef41Sopenharmony_ci RememberedSetAction remembered_set_action, SaveFPRegsMode fp_mode, 4951cb0ef41Sopenharmony_ci StubCallMode mode) { 4961cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 4971cb0ef41Sopenharmony_ci // Use CallRecordWriteStubSaveRegisters if the object and slot registers 4981cb0ef41Sopenharmony_ci // need to be caller saved. 4991cb0ef41Sopenharmony_ci DCHECK_EQ(WriteBarrierDescriptor::ObjectRegister(), object); 5001cb0ef41Sopenharmony_ci DCHECK_EQ(WriteBarrierDescriptor::SlotAddressRegister(), slot_address); 5011cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY 5021cb0ef41Sopenharmony_ci if (mode == StubCallMode::kCallWasmRuntimeStub) { 5031cb0ef41Sopenharmony_ci // Use {wasm_call} for direct Wasm call within a module. 5041cb0ef41Sopenharmony_ci auto wasm_target = 5051cb0ef41Sopenharmony_ci wasm::WasmCode::GetRecordWriteStub(remembered_set_action, fp_mode); 5061cb0ef41Sopenharmony_ci wasm_call(wasm_target, RelocInfo::WASM_STUB_CALL); 5071cb0ef41Sopenharmony_ci#else 5081cb0ef41Sopenharmony_ci if (false) { 5091cb0ef41Sopenharmony_ci#endif 5101cb0ef41Sopenharmony_ci } else { 5111cb0ef41Sopenharmony_ci Builtin builtin = 5121cb0ef41Sopenharmony_ci Builtins::GetRecordWriteStub(remembered_set_action, fp_mode); 5131cb0ef41Sopenharmony_ci if (options().inline_offheap_trampolines) { 5141cb0ef41Sopenharmony_ci CallBuiltin(builtin); 5151cb0ef41Sopenharmony_ci } else { 5161cb0ef41Sopenharmony_ci Handle<Code> code_target = isolate()->builtins()->code_handle(builtin); 5171cb0ef41Sopenharmony_ci Call(code_target, RelocInfo::CODE_TARGET); 5181cb0ef41Sopenharmony_ci } 5191cb0ef41Sopenharmony_ci } 5201cb0ef41Sopenharmony_ci} 5211cb0ef41Sopenharmony_ci 5221cb0ef41Sopenharmony_civoid MacroAssembler::RecordWrite(Register object, Register slot_address, 5231cb0ef41Sopenharmony_ci Register value, SaveFPRegsMode fp_mode, 5241cb0ef41Sopenharmony_ci RememberedSetAction remembered_set_action, 5251cb0ef41Sopenharmony_ci SmiCheck smi_check) { 5261cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 5271cb0ef41Sopenharmony_ci DCHECK(!AreAliased(object, value, slot_address)); 5281cb0ef41Sopenharmony_ci AssertNotSmi(object); 5291cb0ef41Sopenharmony_ci 5301cb0ef41Sopenharmony_ci if ((remembered_set_action == RememberedSetAction::kOmit && 5311cb0ef41Sopenharmony_ci !FLAG_incremental_marking) || 5321cb0ef41Sopenharmony_ci FLAG_disable_write_barriers) { 5331cb0ef41Sopenharmony_ci return; 5341cb0ef41Sopenharmony_ci } 5351cb0ef41Sopenharmony_ci 5361cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 5371cb0ef41Sopenharmony_ci ASM_CODE_COMMENT_STRING(this, "Verify slot_address"); 5381cb0ef41Sopenharmony_ci Label ok; 5391cb0ef41Sopenharmony_ci cmp(value, Operand(slot_address, 0)); 5401cb0ef41Sopenharmony_ci j(equal, &ok, Label::kNear); 5411cb0ef41Sopenharmony_ci int3(); 5421cb0ef41Sopenharmony_ci bind(&ok); 5431cb0ef41Sopenharmony_ci } 5441cb0ef41Sopenharmony_ci 5451cb0ef41Sopenharmony_ci // First, check if a write barrier is even needed. The tests below 5461cb0ef41Sopenharmony_ci // catch stores of Smis and stores into young gen. 5471cb0ef41Sopenharmony_ci Label done; 5481cb0ef41Sopenharmony_ci 5491cb0ef41Sopenharmony_ci if (smi_check == SmiCheck::kInline) { 5501cb0ef41Sopenharmony_ci // Skip barrier if writing a smi. 5511cb0ef41Sopenharmony_ci JumpIfSmi(value, &done, Label::kNear); 5521cb0ef41Sopenharmony_ci } 5531cb0ef41Sopenharmony_ci 5541cb0ef41Sopenharmony_ci CheckPageFlag(value, 5551cb0ef41Sopenharmony_ci value, // Used as scratch. 5561cb0ef41Sopenharmony_ci MemoryChunk::kPointersToHereAreInterestingMask, zero, &done, 5571cb0ef41Sopenharmony_ci Label::kNear); 5581cb0ef41Sopenharmony_ci CheckPageFlag(object, 5591cb0ef41Sopenharmony_ci value, // Used as scratch. 5601cb0ef41Sopenharmony_ci MemoryChunk::kPointersFromHereAreInterestingMask, zero, &done, 5611cb0ef41Sopenharmony_ci Label::kNear); 5621cb0ef41Sopenharmony_ci RecordComment("CheckPageFlag]"); 5631cb0ef41Sopenharmony_ci 5641cb0ef41Sopenharmony_ci CallRecordWriteStub(object, slot_address, remembered_set_action, fp_mode); 5651cb0ef41Sopenharmony_ci 5661cb0ef41Sopenharmony_ci bind(&done); 5671cb0ef41Sopenharmony_ci 5681cb0ef41Sopenharmony_ci // Clobber clobbered registers when running with the debug-code flag 5691cb0ef41Sopenharmony_ci // turned on to provoke errors. 5701cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 5711cb0ef41Sopenharmony_ci ASM_CODE_COMMENT_STRING(this, "Clobber slot_address and value"); 5721cb0ef41Sopenharmony_ci mov(slot_address, Immediate(bit_cast<int32_t>(kZapValue))); 5731cb0ef41Sopenharmony_ci mov(value, Immediate(bit_cast<int32_t>(kZapValue))); 5741cb0ef41Sopenharmony_ci } 5751cb0ef41Sopenharmony_ci} 5761cb0ef41Sopenharmony_ci 5771cb0ef41Sopenharmony_civoid TurboAssembler::Cvtsi2ss(XMMRegister dst, Operand src) { 5781cb0ef41Sopenharmony_ci xorps(dst, dst); 5791cb0ef41Sopenharmony_ci cvtsi2ss(dst, src); 5801cb0ef41Sopenharmony_ci} 5811cb0ef41Sopenharmony_ci 5821cb0ef41Sopenharmony_civoid TurboAssembler::Cvtsi2sd(XMMRegister dst, Operand src) { 5831cb0ef41Sopenharmony_ci xorpd(dst, dst); 5841cb0ef41Sopenharmony_ci cvtsi2sd(dst, src); 5851cb0ef41Sopenharmony_ci} 5861cb0ef41Sopenharmony_ci 5871cb0ef41Sopenharmony_civoid TurboAssembler::Cvtui2ss(XMMRegister dst, Operand src, Register tmp) { 5881cb0ef41Sopenharmony_ci Label done; 5891cb0ef41Sopenharmony_ci Register src_reg = src.is_reg_only() ? src.reg() : tmp; 5901cb0ef41Sopenharmony_ci if (src_reg == tmp) mov(tmp, src); 5911cb0ef41Sopenharmony_ci cvtsi2ss(dst, src_reg); 5921cb0ef41Sopenharmony_ci test(src_reg, src_reg); 5931cb0ef41Sopenharmony_ci j(positive, &done, Label::kNear); 5941cb0ef41Sopenharmony_ci 5951cb0ef41Sopenharmony_ci // Compute {src/2 | (src&1)} (retain the LSB to avoid rounding errors). 5961cb0ef41Sopenharmony_ci if (src_reg != tmp) mov(tmp, src_reg); 5971cb0ef41Sopenharmony_ci shr(tmp, 1); 5981cb0ef41Sopenharmony_ci // The LSB is shifted into CF. If it is set, set the LSB in {tmp}. 5991cb0ef41Sopenharmony_ci Label msb_not_set; 6001cb0ef41Sopenharmony_ci j(not_carry, &msb_not_set, Label::kNear); 6011cb0ef41Sopenharmony_ci or_(tmp, Immediate(1)); 6021cb0ef41Sopenharmony_ci bind(&msb_not_set); 6031cb0ef41Sopenharmony_ci cvtsi2ss(dst, tmp); 6041cb0ef41Sopenharmony_ci addss(dst, dst); 6051cb0ef41Sopenharmony_ci bind(&done); 6061cb0ef41Sopenharmony_ci} 6071cb0ef41Sopenharmony_ci 6081cb0ef41Sopenharmony_civoid TurboAssembler::Cvttss2ui(Register dst, Operand src, XMMRegister tmp) { 6091cb0ef41Sopenharmony_ci Label done; 6101cb0ef41Sopenharmony_ci cvttss2si(dst, src); 6111cb0ef41Sopenharmony_ci test(dst, dst); 6121cb0ef41Sopenharmony_ci j(positive, &done); 6131cb0ef41Sopenharmony_ci Move(tmp, static_cast<float>(INT32_MIN)); 6141cb0ef41Sopenharmony_ci addss(tmp, src); 6151cb0ef41Sopenharmony_ci cvttss2si(dst, tmp); 6161cb0ef41Sopenharmony_ci or_(dst, Immediate(0x80000000)); 6171cb0ef41Sopenharmony_ci bind(&done); 6181cb0ef41Sopenharmony_ci} 6191cb0ef41Sopenharmony_ci 6201cb0ef41Sopenharmony_civoid TurboAssembler::Cvtui2sd(XMMRegister dst, Operand src, Register scratch) { 6211cb0ef41Sopenharmony_ci Label done; 6221cb0ef41Sopenharmony_ci cmp(src, Immediate(0)); 6231cb0ef41Sopenharmony_ci ExternalReference uint32_bias = ExternalReference::address_of_uint32_bias(); 6241cb0ef41Sopenharmony_ci Cvtsi2sd(dst, src); 6251cb0ef41Sopenharmony_ci j(not_sign, &done, Label::kNear); 6261cb0ef41Sopenharmony_ci addsd(dst, ExternalReferenceAsOperand(uint32_bias, scratch)); 6271cb0ef41Sopenharmony_ci bind(&done); 6281cb0ef41Sopenharmony_ci} 6291cb0ef41Sopenharmony_ci 6301cb0ef41Sopenharmony_civoid TurboAssembler::Cvttsd2ui(Register dst, Operand src, XMMRegister tmp) { 6311cb0ef41Sopenharmony_ci Move(tmp, -2147483648.0); 6321cb0ef41Sopenharmony_ci addsd(tmp, src); 6331cb0ef41Sopenharmony_ci cvttsd2si(dst, tmp); 6341cb0ef41Sopenharmony_ci add(dst, Immediate(0x80000000)); 6351cb0ef41Sopenharmony_ci} 6361cb0ef41Sopenharmony_ci 6371cb0ef41Sopenharmony_civoid TurboAssembler::ShlPair(Register high, Register low, uint8_t shift) { 6381cb0ef41Sopenharmony_ci DCHECK_GE(63, shift); 6391cb0ef41Sopenharmony_ci if (shift >= 32) { 6401cb0ef41Sopenharmony_ci mov(high, low); 6411cb0ef41Sopenharmony_ci if (shift != 32) shl(high, shift - 32); 6421cb0ef41Sopenharmony_ci xor_(low, low); 6431cb0ef41Sopenharmony_ci } else { 6441cb0ef41Sopenharmony_ci shld(high, low, shift); 6451cb0ef41Sopenharmony_ci shl(low, shift); 6461cb0ef41Sopenharmony_ci } 6471cb0ef41Sopenharmony_ci} 6481cb0ef41Sopenharmony_ci 6491cb0ef41Sopenharmony_civoid TurboAssembler::ShlPair_cl(Register high, Register low) { 6501cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 6511cb0ef41Sopenharmony_ci shld_cl(high, low); 6521cb0ef41Sopenharmony_ci shl_cl(low); 6531cb0ef41Sopenharmony_ci Label done; 6541cb0ef41Sopenharmony_ci test(ecx, Immediate(0x20)); 6551cb0ef41Sopenharmony_ci j(equal, &done, Label::kNear); 6561cb0ef41Sopenharmony_ci mov(high, low); 6571cb0ef41Sopenharmony_ci xor_(low, low); 6581cb0ef41Sopenharmony_ci bind(&done); 6591cb0ef41Sopenharmony_ci} 6601cb0ef41Sopenharmony_ci 6611cb0ef41Sopenharmony_civoid TurboAssembler::ShrPair(Register high, Register low, uint8_t shift) { 6621cb0ef41Sopenharmony_ci DCHECK_GE(63, shift); 6631cb0ef41Sopenharmony_ci if (shift >= 32) { 6641cb0ef41Sopenharmony_ci mov(low, high); 6651cb0ef41Sopenharmony_ci if (shift != 32) shr(low, shift - 32); 6661cb0ef41Sopenharmony_ci xor_(high, high); 6671cb0ef41Sopenharmony_ci } else { 6681cb0ef41Sopenharmony_ci shrd(low, high, shift); 6691cb0ef41Sopenharmony_ci shr(high, shift); 6701cb0ef41Sopenharmony_ci } 6711cb0ef41Sopenharmony_ci} 6721cb0ef41Sopenharmony_ci 6731cb0ef41Sopenharmony_civoid TurboAssembler::ShrPair_cl(Register high, Register low) { 6741cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 6751cb0ef41Sopenharmony_ci shrd_cl(low, high); 6761cb0ef41Sopenharmony_ci shr_cl(high); 6771cb0ef41Sopenharmony_ci Label done; 6781cb0ef41Sopenharmony_ci test(ecx, Immediate(0x20)); 6791cb0ef41Sopenharmony_ci j(equal, &done, Label::kNear); 6801cb0ef41Sopenharmony_ci mov(low, high); 6811cb0ef41Sopenharmony_ci xor_(high, high); 6821cb0ef41Sopenharmony_ci bind(&done); 6831cb0ef41Sopenharmony_ci} 6841cb0ef41Sopenharmony_ci 6851cb0ef41Sopenharmony_civoid TurboAssembler::SarPair(Register high, Register low, uint8_t shift) { 6861cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 6871cb0ef41Sopenharmony_ci DCHECK_GE(63, shift); 6881cb0ef41Sopenharmony_ci if (shift >= 32) { 6891cb0ef41Sopenharmony_ci mov(low, high); 6901cb0ef41Sopenharmony_ci if (shift != 32) sar(low, shift - 32); 6911cb0ef41Sopenharmony_ci sar(high, 31); 6921cb0ef41Sopenharmony_ci } else { 6931cb0ef41Sopenharmony_ci shrd(low, high, shift); 6941cb0ef41Sopenharmony_ci sar(high, shift); 6951cb0ef41Sopenharmony_ci } 6961cb0ef41Sopenharmony_ci} 6971cb0ef41Sopenharmony_ci 6981cb0ef41Sopenharmony_civoid TurboAssembler::SarPair_cl(Register high, Register low) { 6991cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 7001cb0ef41Sopenharmony_ci shrd_cl(low, high); 7011cb0ef41Sopenharmony_ci sar_cl(high); 7021cb0ef41Sopenharmony_ci Label done; 7031cb0ef41Sopenharmony_ci test(ecx, Immediate(0x20)); 7041cb0ef41Sopenharmony_ci j(equal, &done, Label::kNear); 7051cb0ef41Sopenharmony_ci mov(low, high); 7061cb0ef41Sopenharmony_ci sar(high, 31); 7071cb0ef41Sopenharmony_ci bind(&done); 7081cb0ef41Sopenharmony_ci} 7091cb0ef41Sopenharmony_ci 7101cb0ef41Sopenharmony_civoid TurboAssembler::LoadMap(Register destination, Register object) { 7111cb0ef41Sopenharmony_ci mov(destination, FieldOperand(object, HeapObject::kMapOffset)); 7121cb0ef41Sopenharmony_ci} 7131cb0ef41Sopenharmony_ci 7141cb0ef41Sopenharmony_civoid MacroAssembler::CmpObjectType(Register heap_object, InstanceType type, 7151cb0ef41Sopenharmony_ci Register map) { 7161cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 7171cb0ef41Sopenharmony_ci LoadMap(map, heap_object); 7181cb0ef41Sopenharmony_ci CmpInstanceType(map, type); 7191cb0ef41Sopenharmony_ci} 7201cb0ef41Sopenharmony_ci 7211cb0ef41Sopenharmony_civoid MacroAssembler::CmpInstanceType(Register map, InstanceType type) { 7221cb0ef41Sopenharmony_ci cmpw(FieldOperand(map, Map::kInstanceTypeOffset), Immediate(type)); 7231cb0ef41Sopenharmony_ci} 7241cb0ef41Sopenharmony_ci 7251cb0ef41Sopenharmony_civoid MacroAssembler::CmpInstanceTypeRange(Register map, 7261cb0ef41Sopenharmony_ci Register instance_type_out, 7271cb0ef41Sopenharmony_ci Register scratch, 7281cb0ef41Sopenharmony_ci InstanceType lower_limit, 7291cb0ef41Sopenharmony_ci InstanceType higher_limit) { 7301cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 7311cb0ef41Sopenharmony_ci DCHECK_LT(lower_limit, higher_limit); 7321cb0ef41Sopenharmony_ci movzx_w(instance_type_out, FieldOperand(map, Map::kInstanceTypeOffset)); 7331cb0ef41Sopenharmony_ci CompareRange(instance_type_out, lower_limit, higher_limit, scratch); 7341cb0ef41Sopenharmony_ci} 7351cb0ef41Sopenharmony_ci 7361cb0ef41Sopenharmony_civoid MacroAssembler::AssertSmi(Register object) { 7371cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 7381cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 7391cb0ef41Sopenharmony_ci test(object, Immediate(kSmiTagMask)); 7401cb0ef41Sopenharmony_ci Check(equal, AbortReason::kOperandIsNotASmi); 7411cb0ef41Sopenharmony_ci } 7421cb0ef41Sopenharmony_ci} 7431cb0ef41Sopenharmony_ci 7441cb0ef41Sopenharmony_civoid MacroAssembler::AssertConstructor(Register object) { 7451cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 7461cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 7471cb0ef41Sopenharmony_ci test(object, Immediate(kSmiTagMask)); 7481cb0ef41Sopenharmony_ci Check(not_equal, AbortReason::kOperandIsASmiAndNotAConstructor); 7491cb0ef41Sopenharmony_ci Push(object); 7501cb0ef41Sopenharmony_ci LoadMap(object, object); 7511cb0ef41Sopenharmony_ci test_b(FieldOperand(object, Map::kBitFieldOffset), 7521cb0ef41Sopenharmony_ci Immediate(Map::Bits1::IsConstructorBit::kMask)); 7531cb0ef41Sopenharmony_ci Pop(object); 7541cb0ef41Sopenharmony_ci Check(not_zero, AbortReason::kOperandIsNotAConstructor); 7551cb0ef41Sopenharmony_ci } 7561cb0ef41Sopenharmony_ci} 7571cb0ef41Sopenharmony_ci 7581cb0ef41Sopenharmony_civoid MacroAssembler::AssertFunction(Register object, Register scratch) { 7591cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 7601cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 7611cb0ef41Sopenharmony_ci test(object, Immediate(kSmiTagMask)); 7621cb0ef41Sopenharmony_ci Check(not_equal, AbortReason::kOperandIsASmiAndNotAFunction); 7631cb0ef41Sopenharmony_ci Push(object); 7641cb0ef41Sopenharmony_ci LoadMap(object, object); 7651cb0ef41Sopenharmony_ci CmpInstanceTypeRange(object, scratch, scratch, FIRST_JS_FUNCTION_TYPE, 7661cb0ef41Sopenharmony_ci LAST_JS_FUNCTION_TYPE); 7671cb0ef41Sopenharmony_ci Pop(object); 7681cb0ef41Sopenharmony_ci Check(below_equal, AbortReason::kOperandIsNotAFunction); 7691cb0ef41Sopenharmony_ci } 7701cb0ef41Sopenharmony_ci} 7711cb0ef41Sopenharmony_ci 7721cb0ef41Sopenharmony_civoid MacroAssembler::AssertCallableFunction(Register object, Register scratch) { 7731cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 7741cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 7751cb0ef41Sopenharmony_ci test(object, Immediate(kSmiTagMask)); 7761cb0ef41Sopenharmony_ci Check(not_equal, AbortReason::kOperandIsASmiAndNotAFunction); 7771cb0ef41Sopenharmony_ci Push(object); 7781cb0ef41Sopenharmony_ci LoadMap(object, object); 7791cb0ef41Sopenharmony_ci CmpInstanceTypeRange(object, scratch, scratch, 7801cb0ef41Sopenharmony_ci FIRST_CALLABLE_JS_FUNCTION_TYPE, 7811cb0ef41Sopenharmony_ci LAST_CALLABLE_JS_FUNCTION_TYPE); 7821cb0ef41Sopenharmony_ci Pop(object); 7831cb0ef41Sopenharmony_ci Check(below_equal, AbortReason::kOperandIsNotACallableFunction); 7841cb0ef41Sopenharmony_ci } 7851cb0ef41Sopenharmony_ci} 7861cb0ef41Sopenharmony_ci 7871cb0ef41Sopenharmony_civoid MacroAssembler::AssertBoundFunction(Register object) { 7881cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 7891cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 7901cb0ef41Sopenharmony_ci test(object, Immediate(kSmiTagMask)); 7911cb0ef41Sopenharmony_ci Check(not_equal, AbortReason::kOperandIsASmiAndNotABoundFunction); 7921cb0ef41Sopenharmony_ci Push(object); 7931cb0ef41Sopenharmony_ci CmpObjectType(object, JS_BOUND_FUNCTION_TYPE, object); 7941cb0ef41Sopenharmony_ci Pop(object); 7951cb0ef41Sopenharmony_ci Check(equal, AbortReason::kOperandIsNotABoundFunction); 7961cb0ef41Sopenharmony_ci } 7971cb0ef41Sopenharmony_ci} 7981cb0ef41Sopenharmony_ci 7991cb0ef41Sopenharmony_civoid MacroAssembler::AssertGeneratorObject(Register object) { 8001cb0ef41Sopenharmony_ci if (!FLAG_debug_code) return; 8011cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 8021cb0ef41Sopenharmony_ci 8031cb0ef41Sopenharmony_ci test(object, Immediate(kSmiTagMask)); 8041cb0ef41Sopenharmony_ci Check(not_equal, AbortReason::kOperandIsASmiAndNotAGeneratorObject); 8051cb0ef41Sopenharmony_ci 8061cb0ef41Sopenharmony_ci { 8071cb0ef41Sopenharmony_ci Push(object); 8081cb0ef41Sopenharmony_ci Register map = object; 8091cb0ef41Sopenharmony_ci 8101cb0ef41Sopenharmony_ci LoadMap(map, object); 8111cb0ef41Sopenharmony_ci 8121cb0ef41Sopenharmony_ci Label do_check; 8131cb0ef41Sopenharmony_ci // Check if JSGeneratorObject 8141cb0ef41Sopenharmony_ci CmpInstanceType(map, JS_GENERATOR_OBJECT_TYPE); 8151cb0ef41Sopenharmony_ci j(equal, &do_check, Label::kNear); 8161cb0ef41Sopenharmony_ci 8171cb0ef41Sopenharmony_ci // Check if JSAsyncFunctionObject. 8181cb0ef41Sopenharmony_ci CmpInstanceType(map, JS_ASYNC_FUNCTION_OBJECT_TYPE); 8191cb0ef41Sopenharmony_ci j(equal, &do_check, Label::kNear); 8201cb0ef41Sopenharmony_ci 8211cb0ef41Sopenharmony_ci // Check if JSAsyncGeneratorObject 8221cb0ef41Sopenharmony_ci CmpInstanceType(map, JS_ASYNC_GENERATOR_OBJECT_TYPE); 8231cb0ef41Sopenharmony_ci 8241cb0ef41Sopenharmony_ci bind(&do_check); 8251cb0ef41Sopenharmony_ci Pop(object); 8261cb0ef41Sopenharmony_ci } 8271cb0ef41Sopenharmony_ci 8281cb0ef41Sopenharmony_ci Check(equal, AbortReason::kOperandIsNotAGeneratorObject); 8291cb0ef41Sopenharmony_ci} 8301cb0ef41Sopenharmony_ci 8311cb0ef41Sopenharmony_civoid MacroAssembler::AssertUndefinedOrAllocationSite(Register object, 8321cb0ef41Sopenharmony_ci Register scratch) { 8331cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 8341cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 8351cb0ef41Sopenharmony_ci Label done_checking; 8361cb0ef41Sopenharmony_ci AssertNotSmi(object); 8371cb0ef41Sopenharmony_ci CompareRoot(object, scratch, RootIndex::kUndefinedValue); 8381cb0ef41Sopenharmony_ci j(equal, &done_checking); 8391cb0ef41Sopenharmony_ci LoadRoot(scratch, RootIndex::kAllocationSiteWithWeakNextMap); 8401cb0ef41Sopenharmony_ci cmp(FieldOperand(object, 0), scratch); 8411cb0ef41Sopenharmony_ci Assert(equal, AbortReason::kExpectedUndefinedOrCell); 8421cb0ef41Sopenharmony_ci bind(&done_checking); 8431cb0ef41Sopenharmony_ci } 8441cb0ef41Sopenharmony_ci} 8451cb0ef41Sopenharmony_ci 8461cb0ef41Sopenharmony_civoid MacroAssembler::AssertNotSmi(Register object) { 8471cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 8481cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 8491cb0ef41Sopenharmony_ci test(object, Immediate(kSmiTagMask)); 8501cb0ef41Sopenharmony_ci Check(not_equal, AbortReason::kOperandIsASmi); 8511cb0ef41Sopenharmony_ci } 8521cb0ef41Sopenharmony_ci} 8531cb0ef41Sopenharmony_ci 8541cb0ef41Sopenharmony_civoid TurboAssembler::StubPrologue(StackFrame::Type type) { 8551cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 8561cb0ef41Sopenharmony_ci push(ebp); // Caller's frame pointer. 8571cb0ef41Sopenharmony_ci mov(ebp, esp); 8581cb0ef41Sopenharmony_ci push(Immediate(StackFrame::TypeToMarker(type))); 8591cb0ef41Sopenharmony_ci} 8601cb0ef41Sopenharmony_ci 8611cb0ef41Sopenharmony_civoid TurboAssembler::Prologue() { 8621cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 8631cb0ef41Sopenharmony_ci push(ebp); // Caller's frame pointer. 8641cb0ef41Sopenharmony_ci mov(ebp, esp); 8651cb0ef41Sopenharmony_ci push(kContextRegister); // Callee's context. 8661cb0ef41Sopenharmony_ci push(kJSFunctionRegister); // Callee's JS function. 8671cb0ef41Sopenharmony_ci push(kJavaScriptCallArgCountRegister); // Actual argument count. 8681cb0ef41Sopenharmony_ci} 8691cb0ef41Sopenharmony_ci 8701cb0ef41Sopenharmony_civoid TurboAssembler::DropArguments(Register count, ArgumentsCountType type, 8711cb0ef41Sopenharmony_ci ArgumentsCountMode mode) { 8721cb0ef41Sopenharmony_ci int receiver_bytes = 8731cb0ef41Sopenharmony_ci (mode == kCountExcludesReceiver) ? kSystemPointerSize : 0; 8741cb0ef41Sopenharmony_ci switch (type) { 8751cb0ef41Sopenharmony_ci case kCountIsInteger: { 8761cb0ef41Sopenharmony_ci lea(esp, Operand(esp, count, times_system_pointer_size, receiver_bytes)); 8771cb0ef41Sopenharmony_ci break; 8781cb0ef41Sopenharmony_ci } 8791cb0ef41Sopenharmony_ci case kCountIsSmi: { 8801cb0ef41Sopenharmony_ci STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 8811cb0ef41Sopenharmony_ci // SMIs are stored shifted left by 1 byte with the tag being 0. 8821cb0ef41Sopenharmony_ci // This is equivalent to multiplying by 2. To convert SMIs to bytes we 8831cb0ef41Sopenharmony_ci // can therefore just multiply the stored value by half the system pointer 8841cb0ef41Sopenharmony_ci // size. 8851cb0ef41Sopenharmony_ci lea(esp, 8861cb0ef41Sopenharmony_ci Operand(esp, count, times_half_system_pointer_size, receiver_bytes)); 8871cb0ef41Sopenharmony_ci break; 8881cb0ef41Sopenharmony_ci } 8891cb0ef41Sopenharmony_ci case kCountIsBytes: { 8901cb0ef41Sopenharmony_ci if (receiver_bytes == 0) { 8911cb0ef41Sopenharmony_ci add(esp, count); 8921cb0ef41Sopenharmony_ci } else { 8931cb0ef41Sopenharmony_ci lea(esp, Operand(esp, count, times_1, receiver_bytes)); 8941cb0ef41Sopenharmony_ci } 8951cb0ef41Sopenharmony_ci break; 8961cb0ef41Sopenharmony_ci } 8971cb0ef41Sopenharmony_ci } 8981cb0ef41Sopenharmony_ci} 8991cb0ef41Sopenharmony_ci 9001cb0ef41Sopenharmony_civoid TurboAssembler::DropArguments(Register count, Register scratch, 9011cb0ef41Sopenharmony_ci ArgumentsCountType type, 9021cb0ef41Sopenharmony_ci ArgumentsCountMode mode) { 9031cb0ef41Sopenharmony_ci DCHECK(!AreAliased(count, scratch)); 9041cb0ef41Sopenharmony_ci PopReturnAddressTo(scratch); 9051cb0ef41Sopenharmony_ci DropArguments(count, type, mode); 9061cb0ef41Sopenharmony_ci PushReturnAddressFrom(scratch); 9071cb0ef41Sopenharmony_ci} 9081cb0ef41Sopenharmony_ci 9091cb0ef41Sopenharmony_civoid TurboAssembler::DropArgumentsAndPushNewReceiver(Register argc, 9101cb0ef41Sopenharmony_ci Register receiver, 9111cb0ef41Sopenharmony_ci Register scratch, 9121cb0ef41Sopenharmony_ci ArgumentsCountType type, 9131cb0ef41Sopenharmony_ci ArgumentsCountMode mode) { 9141cb0ef41Sopenharmony_ci DCHECK(!AreAliased(argc, receiver, scratch)); 9151cb0ef41Sopenharmony_ci PopReturnAddressTo(scratch); 9161cb0ef41Sopenharmony_ci DropArguments(argc, type, mode); 9171cb0ef41Sopenharmony_ci Push(receiver); 9181cb0ef41Sopenharmony_ci PushReturnAddressFrom(scratch); 9191cb0ef41Sopenharmony_ci} 9201cb0ef41Sopenharmony_ci 9211cb0ef41Sopenharmony_civoid TurboAssembler::DropArgumentsAndPushNewReceiver(Register argc, 9221cb0ef41Sopenharmony_ci Operand receiver, 9231cb0ef41Sopenharmony_ci Register scratch, 9241cb0ef41Sopenharmony_ci ArgumentsCountType type, 9251cb0ef41Sopenharmony_ci ArgumentsCountMode mode) { 9261cb0ef41Sopenharmony_ci DCHECK(!AreAliased(argc, scratch)); 9271cb0ef41Sopenharmony_ci DCHECK(!receiver.is_reg(scratch)); 9281cb0ef41Sopenharmony_ci PopReturnAddressTo(scratch); 9291cb0ef41Sopenharmony_ci DropArguments(argc, type, mode); 9301cb0ef41Sopenharmony_ci Push(receiver); 9311cb0ef41Sopenharmony_ci PushReturnAddressFrom(scratch); 9321cb0ef41Sopenharmony_ci} 9331cb0ef41Sopenharmony_ci 9341cb0ef41Sopenharmony_civoid TurboAssembler::EnterFrame(StackFrame::Type type) { 9351cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 9361cb0ef41Sopenharmony_ci push(ebp); 9371cb0ef41Sopenharmony_ci mov(ebp, esp); 9381cb0ef41Sopenharmony_ci if (!StackFrame::IsJavaScript(type)) { 9391cb0ef41Sopenharmony_ci Push(Immediate(StackFrame::TypeToMarker(type))); 9401cb0ef41Sopenharmony_ci } 9411cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY 9421cb0ef41Sopenharmony_ci if (type == StackFrame::WASM) Push(kWasmInstanceRegister); 9431cb0ef41Sopenharmony_ci#endif // V8_ENABLE_WEBASSEMBLY 9441cb0ef41Sopenharmony_ci} 9451cb0ef41Sopenharmony_ci 9461cb0ef41Sopenharmony_civoid TurboAssembler::LeaveFrame(StackFrame::Type type) { 9471cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 9481cb0ef41Sopenharmony_ci if (FLAG_debug_code && !StackFrame::IsJavaScript(type)) { 9491cb0ef41Sopenharmony_ci cmp(Operand(ebp, CommonFrameConstants::kContextOrFrameTypeOffset), 9501cb0ef41Sopenharmony_ci Immediate(StackFrame::TypeToMarker(type))); 9511cb0ef41Sopenharmony_ci Check(equal, AbortReason::kStackFrameTypesMustMatch); 9521cb0ef41Sopenharmony_ci } 9531cb0ef41Sopenharmony_ci leave(); 9541cb0ef41Sopenharmony_ci} 9551cb0ef41Sopenharmony_ci 9561cb0ef41Sopenharmony_ci#ifdef V8_OS_WIN 9571cb0ef41Sopenharmony_civoid TurboAssembler::AllocateStackSpace(Register bytes_scratch) { 9581cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 9591cb0ef41Sopenharmony_ci // In windows, we cannot increment the stack size by more than one page 9601cb0ef41Sopenharmony_ci // (minimum page size is 4KB) without accessing at least one byte on the 9611cb0ef41Sopenharmony_ci // page. Check this: 9621cb0ef41Sopenharmony_ci // https://msdn.microsoft.com/en-us/library/aa227153(v=vs.60).aspx. 9631cb0ef41Sopenharmony_ci Label check_offset; 9641cb0ef41Sopenharmony_ci Label touch_next_page; 9651cb0ef41Sopenharmony_ci jmp(&check_offset); 9661cb0ef41Sopenharmony_ci bind(&touch_next_page); 9671cb0ef41Sopenharmony_ci sub(esp, Immediate(kStackPageSize)); 9681cb0ef41Sopenharmony_ci // Just to touch the page, before we increment further. 9691cb0ef41Sopenharmony_ci mov(Operand(esp, 0), Immediate(0)); 9701cb0ef41Sopenharmony_ci sub(bytes_scratch, Immediate(kStackPageSize)); 9711cb0ef41Sopenharmony_ci 9721cb0ef41Sopenharmony_ci bind(&check_offset); 9731cb0ef41Sopenharmony_ci cmp(bytes_scratch, kStackPageSize); 9741cb0ef41Sopenharmony_ci j(greater_equal, &touch_next_page); 9751cb0ef41Sopenharmony_ci 9761cb0ef41Sopenharmony_ci sub(esp, bytes_scratch); 9771cb0ef41Sopenharmony_ci} 9781cb0ef41Sopenharmony_ci 9791cb0ef41Sopenharmony_civoid TurboAssembler::AllocateStackSpace(int bytes) { 9801cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 9811cb0ef41Sopenharmony_ci DCHECK_GE(bytes, 0); 9821cb0ef41Sopenharmony_ci while (bytes >= kStackPageSize) { 9831cb0ef41Sopenharmony_ci sub(esp, Immediate(kStackPageSize)); 9841cb0ef41Sopenharmony_ci mov(Operand(esp, 0), Immediate(0)); 9851cb0ef41Sopenharmony_ci bytes -= kStackPageSize; 9861cb0ef41Sopenharmony_ci } 9871cb0ef41Sopenharmony_ci if (bytes == 0) return; 9881cb0ef41Sopenharmony_ci sub(esp, Immediate(bytes)); 9891cb0ef41Sopenharmony_ci} 9901cb0ef41Sopenharmony_ci#endif 9911cb0ef41Sopenharmony_ci 9921cb0ef41Sopenharmony_civoid MacroAssembler::EnterExitFramePrologue(StackFrame::Type frame_type, 9931cb0ef41Sopenharmony_ci Register scratch) { 9941cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 9951cb0ef41Sopenharmony_ci DCHECK(frame_type == StackFrame::EXIT || 9961cb0ef41Sopenharmony_ci frame_type == StackFrame::BUILTIN_EXIT); 9971cb0ef41Sopenharmony_ci 9981cb0ef41Sopenharmony_ci // Set up the frame structure on the stack. 9991cb0ef41Sopenharmony_ci DCHECK_EQ(+2 * kSystemPointerSize, ExitFrameConstants::kCallerSPDisplacement); 10001cb0ef41Sopenharmony_ci DCHECK_EQ(+1 * kSystemPointerSize, ExitFrameConstants::kCallerPCOffset); 10011cb0ef41Sopenharmony_ci DCHECK_EQ(0 * kSystemPointerSize, ExitFrameConstants::kCallerFPOffset); 10021cb0ef41Sopenharmony_ci push(ebp); 10031cb0ef41Sopenharmony_ci mov(ebp, esp); 10041cb0ef41Sopenharmony_ci 10051cb0ef41Sopenharmony_ci // Reserve room for entry stack pointer. 10061cb0ef41Sopenharmony_ci push(Immediate(StackFrame::TypeToMarker(frame_type))); 10071cb0ef41Sopenharmony_ci DCHECK_EQ(-2 * kSystemPointerSize, ExitFrameConstants::kSPOffset); 10081cb0ef41Sopenharmony_ci push(Immediate(0)); // Saved entry sp, patched before call. 10091cb0ef41Sopenharmony_ci 10101cb0ef41Sopenharmony_ci STATIC_ASSERT(edx == kRuntimeCallFunctionRegister); 10111cb0ef41Sopenharmony_ci STATIC_ASSERT(esi == kContextRegister); 10121cb0ef41Sopenharmony_ci 10131cb0ef41Sopenharmony_ci // Save the frame pointer and the context in top. 10141cb0ef41Sopenharmony_ci ExternalReference c_entry_fp_address = 10151cb0ef41Sopenharmony_ci ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, isolate()); 10161cb0ef41Sopenharmony_ci ExternalReference context_address = 10171cb0ef41Sopenharmony_ci ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()); 10181cb0ef41Sopenharmony_ci ExternalReference c_function_address = 10191cb0ef41Sopenharmony_ci ExternalReference::Create(IsolateAddressId::kCFunctionAddress, isolate()); 10201cb0ef41Sopenharmony_ci 10211cb0ef41Sopenharmony_ci DCHECK(!AreAliased(scratch, ebp, esi, edx)); 10221cb0ef41Sopenharmony_ci mov(ExternalReferenceAsOperand(c_entry_fp_address, scratch), ebp); 10231cb0ef41Sopenharmony_ci mov(ExternalReferenceAsOperand(context_address, scratch), esi); 10241cb0ef41Sopenharmony_ci mov(ExternalReferenceAsOperand(c_function_address, scratch), edx); 10251cb0ef41Sopenharmony_ci} 10261cb0ef41Sopenharmony_ci 10271cb0ef41Sopenharmony_civoid MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) { 10281cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 10291cb0ef41Sopenharmony_ci // Optionally save all XMM registers. 10301cb0ef41Sopenharmony_ci if (save_doubles) { 10311cb0ef41Sopenharmony_ci int space = 10321cb0ef41Sopenharmony_ci XMMRegister::kNumRegisters * kDoubleSize + argc * kSystemPointerSize; 10331cb0ef41Sopenharmony_ci AllocateStackSpace(space); 10341cb0ef41Sopenharmony_ci const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp; 10351cb0ef41Sopenharmony_ci for (int i = 0; i < XMMRegister::kNumRegisters; i++) { 10361cb0ef41Sopenharmony_ci XMMRegister reg = XMMRegister::from_code(i); 10371cb0ef41Sopenharmony_ci movsd(Operand(ebp, offset - ((i + 1) * kDoubleSize)), reg); 10381cb0ef41Sopenharmony_ci } 10391cb0ef41Sopenharmony_ci } else { 10401cb0ef41Sopenharmony_ci AllocateStackSpace(argc * kSystemPointerSize); 10411cb0ef41Sopenharmony_ci } 10421cb0ef41Sopenharmony_ci 10431cb0ef41Sopenharmony_ci // Get the required frame alignment for the OS. 10441cb0ef41Sopenharmony_ci const int kFrameAlignment = base::OS::ActivationFrameAlignment(); 10451cb0ef41Sopenharmony_ci if (kFrameAlignment > 0) { 10461cb0ef41Sopenharmony_ci DCHECK(base::bits::IsPowerOfTwo(kFrameAlignment)); 10471cb0ef41Sopenharmony_ci and_(esp, -kFrameAlignment); 10481cb0ef41Sopenharmony_ci } 10491cb0ef41Sopenharmony_ci 10501cb0ef41Sopenharmony_ci // Patch the saved entry sp. 10511cb0ef41Sopenharmony_ci mov(Operand(ebp, ExitFrameConstants::kSPOffset), esp); 10521cb0ef41Sopenharmony_ci} 10531cb0ef41Sopenharmony_ci 10541cb0ef41Sopenharmony_civoid MacroAssembler::EnterExitFrame(int argc, bool save_doubles, 10551cb0ef41Sopenharmony_ci StackFrame::Type frame_type) { 10561cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 10571cb0ef41Sopenharmony_ci EnterExitFramePrologue(frame_type, edi); 10581cb0ef41Sopenharmony_ci 10591cb0ef41Sopenharmony_ci // Set up argc and argv in callee-saved registers. 10601cb0ef41Sopenharmony_ci int offset = StandardFrameConstants::kCallerSPOffset - kSystemPointerSize; 10611cb0ef41Sopenharmony_ci mov(edi, eax); 10621cb0ef41Sopenharmony_ci lea(esi, Operand(ebp, eax, times_system_pointer_size, offset)); 10631cb0ef41Sopenharmony_ci 10641cb0ef41Sopenharmony_ci // Reserve space for argc, argv and isolate. 10651cb0ef41Sopenharmony_ci EnterExitFrameEpilogue(argc, save_doubles); 10661cb0ef41Sopenharmony_ci} 10671cb0ef41Sopenharmony_ci 10681cb0ef41Sopenharmony_civoid MacroAssembler::EnterApiExitFrame(int argc, Register scratch) { 10691cb0ef41Sopenharmony_ci EnterExitFramePrologue(StackFrame::EXIT, scratch); 10701cb0ef41Sopenharmony_ci EnterExitFrameEpilogue(argc, false); 10711cb0ef41Sopenharmony_ci} 10721cb0ef41Sopenharmony_ci 10731cb0ef41Sopenharmony_civoid MacroAssembler::LeaveExitFrame(bool save_doubles, bool pop_arguments) { 10741cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 10751cb0ef41Sopenharmony_ci // Optionally restore all XMM registers. 10761cb0ef41Sopenharmony_ci if (save_doubles) { 10771cb0ef41Sopenharmony_ci const int offset = -ExitFrameConstants::kFixedFrameSizeFromFp; 10781cb0ef41Sopenharmony_ci for (int i = 0; i < XMMRegister::kNumRegisters; i++) { 10791cb0ef41Sopenharmony_ci XMMRegister reg = XMMRegister::from_code(i); 10801cb0ef41Sopenharmony_ci movsd(reg, Operand(ebp, offset - ((i + 1) * kDoubleSize))); 10811cb0ef41Sopenharmony_ci } 10821cb0ef41Sopenharmony_ci } 10831cb0ef41Sopenharmony_ci 10841cb0ef41Sopenharmony_ci if (pop_arguments) { 10851cb0ef41Sopenharmony_ci // Get the return address from the stack and restore the frame pointer. 10861cb0ef41Sopenharmony_ci mov(ecx, Operand(ebp, 1 * kSystemPointerSize)); 10871cb0ef41Sopenharmony_ci mov(ebp, Operand(ebp, 0 * kSystemPointerSize)); 10881cb0ef41Sopenharmony_ci 10891cb0ef41Sopenharmony_ci // Pop the arguments and the receiver from the caller stack. 10901cb0ef41Sopenharmony_ci lea(esp, Operand(esi, 1 * kSystemPointerSize)); 10911cb0ef41Sopenharmony_ci 10921cb0ef41Sopenharmony_ci // Push the return address to get ready to return. 10931cb0ef41Sopenharmony_ci push(ecx); 10941cb0ef41Sopenharmony_ci } else { 10951cb0ef41Sopenharmony_ci // Otherwise just leave the exit frame. 10961cb0ef41Sopenharmony_ci leave(); 10971cb0ef41Sopenharmony_ci } 10981cb0ef41Sopenharmony_ci 10991cb0ef41Sopenharmony_ci LeaveExitFrameEpilogue(); 11001cb0ef41Sopenharmony_ci} 11011cb0ef41Sopenharmony_ci 11021cb0ef41Sopenharmony_civoid MacroAssembler::LeaveExitFrameEpilogue() { 11031cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 11041cb0ef41Sopenharmony_ci // Clear the top frame. 11051cb0ef41Sopenharmony_ci ExternalReference c_entry_fp_address = 11061cb0ef41Sopenharmony_ci ExternalReference::Create(IsolateAddressId::kCEntryFPAddress, isolate()); 11071cb0ef41Sopenharmony_ci mov(ExternalReferenceAsOperand(c_entry_fp_address, esi), Immediate(0)); 11081cb0ef41Sopenharmony_ci 11091cb0ef41Sopenharmony_ci // Restore current context from top and clear it in debug mode. 11101cb0ef41Sopenharmony_ci ExternalReference context_address = 11111cb0ef41Sopenharmony_ci ExternalReference::Create(IsolateAddressId::kContextAddress, isolate()); 11121cb0ef41Sopenharmony_ci mov(esi, ExternalReferenceAsOperand(context_address, esi)); 11131cb0ef41Sopenharmony_ci#ifdef DEBUG 11141cb0ef41Sopenharmony_ci push(eax); 11151cb0ef41Sopenharmony_ci mov(ExternalReferenceAsOperand(context_address, eax), 11161cb0ef41Sopenharmony_ci Immediate(Context::kInvalidContext)); 11171cb0ef41Sopenharmony_ci pop(eax); 11181cb0ef41Sopenharmony_ci#endif 11191cb0ef41Sopenharmony_ci} 11201cb0ef41Sopenharmony_ci 11211cb0ef41Sopenharmony_civoid MacroAssembler::LeaveApiExitFrame() { 11221cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 11231cb0ef41Sopenharmony_ci mov(esp, ebp); 11241cb0ef41Sopenharmony_ci pop(ebp); 11251cb0ef41Sopenharmony_ci 11261cb0ef41Sopenharmony_ci LeaveExitFrameEpilogue(); 11271cb0ef41Sopenharmony_ci} 11281cb0ef41Sopenharmony_ci 11291cb0ef41Sopenharmony_civoid MacroAssembler::PushStackHandler(Register scratch) { 11301cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 11311cb0ef41Sopenharmony_ci // Adjust this code if not the case. 11321cb0ef41Sopenharmony_ci STATIC_ASSERT(StackHandlerConstants::kSize == 2 * kSystemPointerSize); 11331cb0ef41Sopenharmony_ci STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); 11341cb0ef41Sopenharmony_ci 11351cb0ef41Sopenharmony_ci push(Immediate(0)); // Padding. 11361cb0ef41Sopenharmony_ci 11371cb0ef41Sopenharmony_ci // Link the current handler as the next handler. 11381cb0ef41Sopenharmony_ci ExternalReference handler_address = 11391cb0ef41Sopenharmony_ci ExternalReference::Create(IsolateAddressId::kHandlerAddress, isolate()); 11401cb0ef41Sopenharmony_ci push(ExternalReferenceAsOperand(handler_address, scratch)); 11411cb0ef41Sopenharmony_ci 11421cb0ef41Sopenharmony_ci // Set this new handler as the current one. 11431cb0ef41Sopenharmony_ci mov(ExternalReferenceAsOperand(handler_address, scratch), esp); 11441cb0ef41Sopenharmony_ci} 11451cb0ef41Sopenharmony_ci 11461cb0ef41Sopenharmony_civoid MacroAssembler::PopStackHandler(Register scratch) { 11471cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 11481cb0ef41Sopenharmony_ci STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); 11491cb0ef41Sopenharmony_ci ExternalReference handler_address = 11501cb0ef41Sopenharmony_ci ExternalReference::Create(IsolateAddressId::kHandlerAddress, isolate()); 11511cb0ef41Sopenharmony_ci pop(ExternalReferenceAsOperand(handler_address, scratch)); 11521cb0ef41Sopenharmony_ci add(esp, Immediate(StackHandlerConstants::kSize - kSystemPointerSize)); 11531cb0ef41Sopenharmony_ci} 11541cb0ef41Sopenharmony_ci 11551cb0ef41Sopenharmony_civoid MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments, 11561cb0ef41Sopenharmony_ci SaveFPRegsMode save_doubles) { 11571cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 11581cb0ef41Sopenharmony_ci // If the expected number of arguments of the runtime function is 11591cb0ef41Sopenharmony_ci // constant, we check that the actual number of arguments match the 11601cb0ef41Sopenharmony_ci // expectation. 11611cb0ef41Sopenharmony_ci CHECK(f->nargs < 0 || f->nargs == num_arguments); 11621cb0ef41Sopenharmony_ci 11631cb0ef41Sopenharmony_ci // TODO(1236192): Most runtime routines don't need the number of 11641cb0ef41Sopenharmony_ci // arguments passed in because it is constant. At some point we 11651cb0ef41Sopenharmony_ci // should remove this need and make the runtime routine entry code 11661cb0ef41Sopenharmony_ci // smarter. 11671cb0ef41Sopenharmony_ci Move(kRuntimeCallArgCountRegister, Immediate(num_arguments)); 11681cb0ef41Sopenharmony_ci Move(kRuntimeCallFunctionRegister, Immediate(ExternalReference::Create(f))); 11691cb0ef41Sopenharmony_ci Handle<Code> code = 11701cb0ef41Sopenharmony_ci CodeFactory::CEntry(isolate(), f->result_size, save_doubles); 11711cb0ef41Sopenharmony_ci Call(code, RelocInfo::CODE_TARGET); 11721cb0ef41Sopenharmony_ci} 11731cb0ef41Sopenharmony_ci 11741cb0ef41Sopenharmony_civoid MacroAssembler::TailCallRuntime(Runtime::FunctionId fid) { 11751cb0ef41Sopenharmony_ci // ----------- S t a t e ------------- 11761cb0ef41Sopenharmony_ci // -- esp[0] : return address 11771cb0ef41Sopenharmony_ci // -- esp[8] : argument num_arguments - 1 11781cb0ef41Sopenharmony_ci // ... 11791cb0ef41Sopenharmony_ci // -- esp[8 * num_arguments] : argument 0 (receiver) 11801cb0ef41Sopenharmony_ci // 11811cb0ef41Sopenharmony_ci // For runtime functions with variable arguments: 11821cb0ef41Sopenharmony_ci // -- eax : number of arguments 11831cb0ef41Sopenharmony_ci // ----------------------------------- 11841cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 11851cb0ef41Sopenharmony_ci const Runtime::Function* function = Runtime::FunctionForId(fid); 11861cb0ef41Sopenharmony_ci DCHECK_EQ(1, function->result_size); 11871cb0ef41Sopenharmony_ci if (function->nargs >= 0) { 11881cb0ef41Sopenharmony_ci // TODO(1236192): Most runtime routines don't need the number of 11891cb0ef41Sopenharmony_ci // arguments passed in because it is constant. At some point we 11901cb0ef41Sopenharmony_ci // should remove this need and make the runtime routine entry code 11911cb0ef41Sopenharmony_ci // smarter. 11921cb0ef41Sopenharmony_ci Move(kRuntimeCallArgCountRegister, Immediate(function->nargs)); 11931cb0ef41Sopenharmony_ci } 11941cb0ef41Sopenharmony_ci JumpToExternalReference(ExternalReference::Create(fid)); 11951cb0ef41Sopenharmony_ci} 11961cb0ef41Sopenharmony_ci 11971cb0ef41Sopenharmony_civoid MacroAssembler::JumpToExternalReference(const ExternalReference& ext, 11981cb0ef41Sopenharmony_ci bool builtin_exit_frame) { 11991cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 12001cb0ef41Sopenharmony_ci // Set the entry point and jump to the C entry runtime stub. 12011cb0ef41Sopenharmony_ci Move(kRuntimeCallFunctionRegister, Immediate(ext)); 12021cb0ef41Sopenharmony_ci Handle<Code> code = CodeFactory::CEntry(isolate(), 1, SaveFPRegsMode::kIgnore, 12031cb0ef41Sopenharmony_ci ArgvMode::kStack, builtin_exit_frame); 12041cb0ef41Sopenharmony_ci Jump(code, RelocInfo::CODE_TARGET); 12051cb0ef41Sopenharmony_ci} 12061cb0ef41Sopenharmony_ci 12071cb0ef41Sopenharmony_civoid MacroAssembler::JumpToOffHeapInstructionStream(Address entry) { 12081cb0ef41Sopenharmony_ci jmp(entry, RelocInfo::OFF_HEAP_TARGET); 12091cb0ef41Sopenharmony_ci} 12101cb0ef41Sopenharmony_ci 12111cb0ef41Sopenharmony_civoid MacroAssembler::CompareStackLimit(Register with, StackLimitKind kind) { 12121cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 12131cb0ef41Sopenharmony_ci DCHECK(root_array_available()); 12141cb0ef41Sopenharmony_ci Isolate* isolate = this->isolate(); 12151cb0ef41Sopenharmony_ci // Address through the root register. No load is needed. 12161cb0ef41Sopenharmony_ci ExternalReference limit = 12171cb0ef41Sopenharmony_ci kind == StackLimitKind::kRealStackLimit 12181cb0ef41Sopenharmony_ci ? ExternalReference::address_of_real_jslimit(isolate) 12191cb0ef41Sopenharmony_ci : ExternalReference::address_of_jslimit(isolate); 12201cb0ef41Sopenharmony_ci DCHECK(TurboAssembler::IsAddressableThroughRootRegister(isolate, limit)); 12211cb0ef41Sopenharmony_ci 12221cb0ef41Sopenharmony_ci intptr_t offset = 12231cb0ef41Sopenharmony_ci TurboAssembler::RootRegisterOffsetForExternalReference(isolate, limit); 12241cb0ef41Sopenharmony_ci cmp(with, Operand(kRootRegister, offset)); 12251cb0ef41Sopenharmony_ci} 12261cb0ef41Sopenharmony_ci 12271cb0ef41Sopenharmony_civoid MacroAssembler::StackOverflowCheck(Register num_args, Register scratch, 12281cb0ef41Sopenharmony_ci Label* stack_overflow, 12291cb0ef41Sopenharmony_ci bool include_receiver) { 12301cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 12311cb0ef41Sopenharmony_ci DCHECK_NE(num_args, scratch); 12321cb0ef41Sopenharmony_ci // Check the stack for overflow. We are not trying to catch 12331cb0ef41Sopenharmony_ci // interruptions (e.g. debug break and preemption) here, so the "real stack 12341cb0ef41Sopenharmony_ci // limit" is checked. 12351cb0ef41Sopenharmony_ci ExternalReference real_stack_limit = 12361cb0ef41Sopenharmony_ci ExternalReference::address_of_real_jslimit(isolate()); 12371cb0ef41Sopenharmony_ci // Compute the space that is left as a negative number in scratch. If 12381cb0ef41Sopenharmony_ci // we already overflowed, this will be a positive number. 12391cb0ef41Sopenharmony_ci mov(scratch, ExternalReferenceAsOperand(real_stack_limit, scratch)); 12401cb0ef41Sopenharmony_ci sub(scratch, esp); 12411cb0ef41Sopenharmony_ci // TODO(victorgomes): Remove {include_receiver} and always require one extra 12421cb0ef41Sopenharmony_ci // word of the stack space. 12431cb0ef41Sopenharmony_ci lea(scratch, Operand(scratch, num_args, times_system_pointer_size, 0)); 12441cb0ef41Sopenharmony_ci if (include_receiver) { 12451cb0ef41Sopenharmony_ci add(scratch, Immediate(kSystemPointerSize)); 12461cb0ef41Sopenharmony_ci } 12471cb0ef41Sopenharmony_ci // See if we overflowed, i.e. scratch is positive. 12481cb0ef41Sopenharmony_ci cmp(scratch, Immediate(0)); 12491cb0ef41Sopenharmony_ci // TODO(victorgomes): Save some bytes in the builtins that use stack checks 12501cb0ef41Sopenharmony_ci // by jumping to a builtin that throws the exception. 12511cb0ef41Sopenharmony_ci j(greater, stack_overflow); // Signed comparison. 12521cb0ef41Sopenharmony_ci} 12531cb0ef41Sopenharmony_ci 12541cb0ef41Sopenharmony_civoid MacroAssembler::InvokePrologue(Register expected_parameter_count, 12551cb0ef41Sopenharmony_ci Register actual_parameter_count, 12561cb0ef41Sopenharmony_ci Label* done, InvokeType type) { 12571cb0ef41Sopenharmony_ci if (expected_parameter_count == actual_parameter_count) return; 12581cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 12591cb0ef41Sopenharmony_ci DCHECK_EQ(actual_parameter_count, eax); 12601cb0ef41Sopenharmony_ci DCHECK_EQ(expected_parameter_count, ecx); 12611cb0ef41Sopenharmony_ci Label regular_invoke; 12621cb0ef41Sopenharmony_ci 12631cb0ef41Sopenharmony_ci // If the expected parameter count is equal to the adaptor sentinel, no need 12641cb0ef41Sopenharmony_ci // to push undefined value as arguments. 12651cb0ef41Sopenharmony_ci if (kDontAdaptArgumentsSentinel != 0) { 12661cb0ef41Sopenharmony_ci cmp(expected_parameter_count, Immediate(kDontAdaptArgumentsSentinel)); 12671cb0ef41Sopenharmony_ci j(equal, ®ular_invoke, Label::kFar); 12681cb0ef41Sopenharmony_ci } 12691cb0ef41Sopenharmony_ci 12701cb0ef41Sopenharmony_ci // If overapplication or if the actual argument count is equal to the 12711cb0ef41Sopenharmony_ci // formal parameter count, no need to push extra undefined values. 12721cb0ef41Sopenharmony_ci sub(expected_parameter_count, actual_parameter_count); 12731cb0ef41Sopenharmony_ci j(less_equal, ®ular_invoke, Label::kFar); 12741cb0ef41Sopenharmony_ci 12751cb0ef41Sopenharmony_ci // We need to preserve edx, edi, esi and ebx. 12761cb0ef41Sopenharmony_ci movd(xmm0, edx); 12771cb0ef41Sopenharmony_ci movd(xmm1, edi); 12781cb0ef41Sopenharmony_ci movd(xmm2, esi); 12791cb0ef41Sopenharmony_ci movd(xmm3, ebx); 12801cb0ef41Sopenharmony_ci 12811cb0ef41Sopenharmony_ci Label stack_overflow; 12821cb0ef41Sopenharmony_ci StackOverflowCheck(expected_parameter_count, edx, &stack_overflow); 12831cb0ef41Sopenharmony_ci 12841cb0ef41Sopenharmony_ci Register scratch = esi; 12851cb0ef41Sopenharmony_ci 12861cb0ef41Sopenharmony_ci // Underapplication. Move the arguments already in the stack, including the 12871cb0ef41Sopenharmony_ci // receiver and the return address. 12881cb0ef41Sopenharmony_ci { 12891cb0ef41Sopenharmony_ci Label copy, check; 12901cb0ef41Sopenharmony_ci Register src = edx, dest = esp, num = edi, current = ebx; 12911cb0ef41Sopenharmony_ci mov(src, esp); 12921cb0ef41Sopenharmony_ci lea(scratch, 12931cb0ef41Sopenharmony_ci Operand(expected_parameter_count, times_system_pointer_size, 0)); 12941cb0ef41Sopenharmony_ci AllocateStackSpace(scratch); 12951cb0ef41Sopenharmony_ci // Extra words are the receiver (if not already included in argc) and the 12961cb0ef41Sopenharmony_ci // return address (if a jump). 12971cb0ef41Sopenharmony_ci int extra_words = type == InvokeType::kCall ? 0 : 1; 12981cb0ef41Sopenharmony_ci lea(num, Operand(eax, extra_words)); // Number of words to copy. 12991cb0ef41Sopenharmony_ci Move(current, 0); 13001cb0ef41Sopenharmony_ci // Fall-through to the loop body because there are non-zero words to copy. 13011cb0ef41Sopenharmony_ci bind(©); 13021cb0ef41Sopenharmony_ci mov(scratch, Operand(src, current, times_system_pointer_size, 0)); 13031cb0ef41Sopenharmony_ci mov(Operand(dest, current, times_system_pointer_size, 0), scratch); 13041cb0ef41Sopenharmony_ci inc(current); 13051cb0ef41Sopenharmony_ci bind(&check); 13061cb0ef41Sopenharmony_ci cmp(current, num); 13071cb0ef41Sopenharmony_ci j(less, ©); 13081cb0ef41Sopenharmony_ci lea(edx, Operand(esp, num, times_system_pointer_size, 0)); 13091cb0ef41Sopenharmony_ci } 13101cb0ef41Sopenharmony_ci 13111cb0ef41Sopenharmony_ci // Fill remaining expected arguments with undefined values. 13121cb0ef41Sopenharmony_ci movd(ebx, xmm3); // Restore root. 13131cb0ef41Sopenharmony_ci LoadRoot(scratch, RootIndex::kUndefinedValue); 13141cb0ef41Sopenharmony_ci { 13151cb0ef41Sopenharmony_ci Label loop; 13161cb0ef41Sopenharmony_ci bind(&loop); 13171cb0ef41Sopenharmony_ci dec(expected_parameter_count); 13181cb0ef41Sopenharmony_ci mov(Operand(edx, expected_parameter_count, times_system_pointer_size, 0), 13191cb0ef41Sopenharmony_ci scratch); 13201cb0ef41Sopenharmony_ci j(greater, &loop, Label::kNear); 13211cb0ef41Sopenharmony_ci } 13221cb0ef41Sopenharmony_ci 13231cb0ef41Sopenharmony_ci // Restore remaining registers. 13241cb0ef41Sopenharmony_ci movd(esi, xmm2); 13251cb0ef41Sopenharmony_ci movd(edi, xmm1); 13261cb0ef41Sopenharmony_ci movd(edx, xmm0); 13271cb0ef41Sopenharmony_ci 13281cb0ef41Sopenharmony_ci jmp(®ular_invoke); 13291cb0ef41Sopenharmony_ci 13301cb0ef41Sopenharmony_ci bind(&stack_overflow); 13311cb0ef41Sopenharmony_ci { 13321cb0ef41Sopenharmony_ci FrameScope frame( 13331cb0ef41Sopenharmony_ci this, has_frame() ? StackFrame::NO_FRAME_TYPE : StackFrame::INTERNAL); 13341cb0ef41Sopenharmony_ci CallRuntime(Runtime::kThrowStackOverflow); 13351cb0ef41Sopenharmony_ci int3(); // This should be unreachable. 13361cb0ef41Sopenharmony_ci } 13371cb0ef41Sopenharmony_ci 13381cb0ef41Sopenharmony_ci bind(®ular_invoke); 13391cb0ef41Sopenharmony_ci} 13401cb0ef41Sopenharmony_ci 13411cb0ef41Sopenharmony_civoid MacroAssembler::CallDebugOnFunctionCall(Register fun, Register new_target, 13421cb0ef41Sopenharmony_ci Register expected_parameter_count, 13431cb0ef41Sopenharmony_ci Register actual_parameter_count) { 13441cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 13451cb0ef41Sopenharmony_ci FrameScope frame( 13461cb0ef41Sopenharmony_ci this, has_frame() ? StackFrame::NO_FRAME_TYPE : StackFrame::INTERNAL); 13471cb0ef41Sopenharmony_ci SmiTag(expected_parameter_count); 13481cb0ef41Sopenharmony_ci Push(expected_parameter_count); 13491cb0ef41Sopenharmony_ci 13501cb0ef41Sopenharmony_ci SmiTag(actual_parameter_count); 13511cb0ef41Sopenharmony_ci Push(actual_parameter_count); 13521cb0ef41Sopenharmony_ci SmiUntag(actual_parameter_count); 13531cb0ef41Sopenharmony_ci 13541cb0ef41Sopenharmony_ci if (new_target.is_valid()) { 13551cb0ef41Sopenharmony_ci Push(new_target); 13561cb0ef41Sopenharmony_ci } 13571cb0ef41Sopenharmony_ci Push(fun); 13581cb0ef41Sopenharmony_ci Push(fun); 13591cb0ef41Sopenharmony_ci // Arguments are located 2 words below the base pointer. 13601cb0ef41Sopenharmony_ci Operand receiver_op = Operand(ebp, kSystemPointerSize * 2); 13611cb0ef41Sopenharmony_ci Push(receiver_op); 13621cb0ef41Sopenharmony_ci CallRuntime(Runtime::kDebugOnFunctionCall); 13631cb0ef41Sopenharmony_ci Pop(fun); 13641cb0ef41Sopenharmony_ci if (new_target.is_valid()) { 13651cb0ef41Sopenharmony_ci Pop(new_target); 13661cb0ef41Sopenharmony_ci } 13671cb0ef41Sopenharmony_ci Pop(actual_parameter_count); 13681cb0ef41Sopenharmony_ci SmiUntag(actual_parameter_count); 13691cb0ef41Sopenharmony_ci 13701cb0ef41Sopenharmony_ci Pop(expected_parameter_count); 13711cb0ef41Sopenharmony_ci SmiUntag(expected_parameter_count); 13721cb0ef41Sopenharmony_ci} 13731cb0ef41Sopenharmony_ci 13741cb0ef41Sopenharmony_civoid MacroAssembler::InvokeFunctionCode(Register function, Register new_target, 13751cb0ef41Sopenharmony_ci Register expected_parameter_count, 13761cb0ef41Sopenharmony_ci Register actual_parameter_count, 13771cb0ef41Sopenharmony_ci InvokeType type) { 13781cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 13791cb0ef41Sopenharmony_ci // You can't call a function without a valid frame. 13801cb0ef41Sopenharmony_ci DCHECK_IMPLIES(type == InvokeType::kCall, has_frame()); 13811cb0ef41Sopenharmony_ci DCHECK_EQ(function, edi); 13821cb0ef41Sopenharmony_ci DCHECK_IMPLIES(new_target.is_valid(), new_target == edx); 13831cb0ef41Sopenharmony_ci DCHECK(expected_parameter_count == ecx || expected_parameter_count == eax); 13841cb0ef41Sopenharmony_ci DCHECK_EQ(actual_parameter_count, eax); 13851cb0ef41Sopenharmony_ci 13861cb0ef41Sopenharmony_ci // On function call, call into the debugger if necessary. 13871cb0ef41Sopenharmony_ci Label debug_hook, continue_after_hook; 13881cb0ef41Sopenharmony_ci { 13891cb0ef41Sopenharmony_ci ExternalReference debug_hook_active = 13901cb0ef41Sopenharmony_ci ExternalReference::debug_hook_on_function_call_address(isolate()); 13911cb0ef41Sopenharmony_ci push(eax); 13921cb0ef41Sopenharmony_ci cmpb(ExternalReferenceAsOperand(debug_hook_active, eax), Immediate(0)); 13931cb0ef41Sopenharmony_ci pop(eax); 13941cb0ef41Sopenharmony_ci j(not_equal, &debug_hook); 13951cb0ef41Sopenharmony_ci } 13961cb0ef41Sopenharmony_ci bind(&continue_after_hook); 13971cb0ef41Sopenharmony_ci 13981cb0ef41Sopenharmony_ci // Clear the new.target register if not given. 13991cb0ef41Sopenharmony_ci if (!new_target.is_valid()) { 14001cb0ef41Sopenharmony_ci Move(edx, isolate()->factory()->undefined_value()); 14011cb0ef41Sopenharmony_ci } 14021cb0ef41Sopenharmony_ci 14031cb0ef41Sopenharmony_ci Label done; 14041cb0ef41Sopenharmony_ci InvokePrologue(expected_parameter_count, actual_parameter_count, &done, type); 14051cb0ef41Sopenharmony_ci // We call indirectly through the code field in the function to 14061cb0ef41Sopenharmony_ci // allow recompilation to take effect without changing any of the 14071cb0ef41Sopenharmony_ci // call sites. 14081cb0ef41Sopenharmony_ci static_assert(kJavaScriptCallCodeStartRegister == ecx, "ABI mismatch"); 14091cb0ef41Sopenharmony_ci mov(ecx, FieldOperand(function, JSFunction::kCodeOffset)); 14101cb0ef41Sopenharmony_ci switch (type) { 14111cb0ef41Sopenharmony_ci case InvokeType::kCall: 14121cb0ef41Sopenharmony_ci CallCodeObject(ecx); 14131cb0ef41Sopenharmony_ci break; 14141cb0ef41Sopenharmony_ci case InvokeType::kJump: 14151cb0ef41Sopenharmony_ci JumpCodeObject(ecx); 14161cb0ef41Sopenharmony_ci break; 14171cb0ef41Sopenharmony_ci } 14181cb0ef41Sopenharmony_ci jmp(&done, Label::kNear); 14191cb0ef41Sopenharmony_ci 14201cb0ef41Sopenharmony_ci // Deferred debug hook. 14211cb0ef41Sopenharmony_ci bind(&debug_hook); 14221cb0ef41Sopenharmony_ci CallDebugOnFunctionCall(function, new_target, expected_parameter_count, 14231cb0ef41Sopenharmony_ci actual_parameter_count); 14241cb0ef41Sopenharmony_ci jmp(&continue_after_hook); 14251cb0ef41Sopenharmony_ci 14261cb0ef41Sopenharmony_ci bind(&done); 14271cb0ef41Sopenharmony_ci} 14281cb0ef41Sopenharmony_ci 14291cb0ef41Sopenharmony_civoid MacroAssembler::InvokeFunction(Register fun, Register new_target, 14301cb0ef41Sopenharmony_ci Register actual_parameter_count, 14311cb0ef41Sopenharmony_ci InvokeType type) { 14321cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 14331cb0ef41Sopenharmony_ci // You can't call a function without a valid frame. 14341cb0ef41Sopenharmony_ci DCHECK(type == InvokeType::kJump || has_frame()); 14351cb0ef41Sopenharmony_ci 14361cb0ef41Sopenharmony_ci DCHECK(fun == edi); 14371cb0ef41Sopenharmony_ci mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 14381cb0ef41Sopenharmony_ci mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 14391cb0ef41Sopenharmony_ci movzx_w(ecx, 14401cb0ef41Sopenharmony_ci FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset)); 14411cb0ef41Sopenharmony_ci 14421cb0ef41Sopenharmony_ci InvokeFunctionCode(edi, new_target, ecx, actual_parameter_count, type); 14431cb0ef41Sopenharmony_ci} 14441cb0ef41Sopenharmony_ci 14451cb0ef41Sopenharmony_civoid MacroAssembler::LoadGlobalProxy(Register dst) { 14461cb0ef41Sopenharmony_ci LoadNativeContextSlot(dst, Context::GLOBAL_PROXY_INDEX); 14471cb0ef41Sopenharmony_ci} 14481cb0ef41Sopenharmony_ci 14491cb0ef41Sopenharmony_civoid MacroAssembler::LoadNativeContextSlot(Register destination, int index) { 14501cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 14511cb0ef41Sopenharmony_ci // Load the native context from the current context. 14521cb0ef41Sopenharmony_ci LoadMap(destination, esi); 14531cb0ef41Sopenharmony_ci mov(destination, 14541cb0ef41Sopenharmony_ci FieldOperand(destination, 14551cb0ef41Sopenharmony_ci Map::kConstructorOrBackPointerOrNativeContextOffset)); 14561cb0ef41Sopenharmony_ci // Load the function from the native context. 14571cb0ef41Sopenharmony_ci mov(destination, Operand(destination, Context::SlotOffset(index))); 14581cb0ef41Sopenharmony_ci} 14591cb0ef41Sopenharmony_ci 14601cb0ef41Sopenharmony_civoid TurboAssembler::Ret() { ret(0); } 14611cb0ef41Sopenharmony_ci 14621cb0ef41Sopenharmony_civoid TurboAssembler::Ret(int bytes_dropped, Register scratch) { 14631cb0ef41Sopenharmony_ci if (is_uint16(bytes_dropped)) { 14641cb0ef41Sopenharmony_ci ret(bytes_dropped); 14651cb0ef41Sopenharmony_ci } else { 14661cb0ef41Sopenharmony_ci pop(scratch); 14671cb0ef41Sopenharmony_ci add(esp, Immediate(bytes_dropped)); 14681cb0ef41Sopenharmony_ci push(scratch); 14691cb0ef41Sopenharmony_ci ret(0); 14701cb0ef41Sopenharmony_ci } 14711cb0ef41Sopenharmony_ci} 14721cb0ef41Sopenharmony_ci 14731cb0ef41Sopenharmony_civoid TurboAssembler::Push(Immediate value) { 14741cb0ef41Sopenharmony_ci if (root_array_available() && options().isolate_independent_code) { 14751cb0ef41Sopenharmony_ci if (value.is_embedded_object()) { 14761cb0ef41Sopenharmony_ci Push(HeapObjectAsOperand(value.embedded_object())); 14771cb0ef41Sopenharmony_ci return; 14781cb0ef41Sopenharmony_ci } else if (value.is_external_reference()) { 14791cb0ef41Sopenharmony_ci Push(ExternalReferenceAddressAsOperand(value.external_reference())); 14801cb0ef41Sopenharmony_ci return; 14811cb0ef41Sopenharmony_ci } 14821cb0ef41Sopenharmony_ci } 14831cb0ef41Sopenharmony_ci push(value); 14841cb0ef41Sopenharmony_ci} 14851cb0ef41Sopenharmony_ci 14861cb0ef41Sopenharmony_civoid MacroAssembler::Drop(int stack_elements) { 14871cb0ef41Sopenharmony_ci if (stack_elements > 0) { 14881cb0ef41Sopenharmony_ci add(esp, Immediate(stack_elements * kSystemPointerSize)); 14891cb0ef41Sopenharmony_ci } 14901cb0ef41Sopenharmony_ci} 14911cb0ef41Sopenharmony_ci 14921cb0ef41Sopenharmony_civoid TurboAssembler::Move(Register dst, Register src) { 14931cb0ef41Sopenharmony_ci if (dst != src) { 14941cb0ef41Sopenharmony_ci mov(dst, src); 14951cb0ef41Sopenharmony_ci } 14961cb0ef41Sopenharmony_ci} 14971cb0ef41Sopenharmony_ci 14981cb0ef41Sopenharmony_civoid TurboAssembler::Move(Register dst, const Immediate& src) { 14991cb0ef41Sopenharmony_ci if (!src.is_heap_object_request() && src.is_zero()) { 15001cb0ef41Sopenharmony_ci xor_(dst, dst); // Shorter than mov of 32-bit immediate 0. 15011cb0ef41Sopenharmony_ci } else if (src.is_external_reference()) { 15021cb0ef41Sopenharmony_ci LoadAddress(dst, src.external_reference()); 15031cb0ef41Sopenharmony_ci } else { 15041cb0ef41Sopenharmony_ci mov(dst, src); 15051cb0ef41Sopenharmony_ci } 15061cb0ef41Sopenharmony_ci} 15071cb0ef41Sopenharmony_ci 15081cb0ef41Sopenharmony_civoid TurboAssembler::Move(Operand dst, const Immediate& src) { 15091cb0ef41Sopenharmony_ci // Since there's no scratch register available, take a detour through the 15101cb0ef41Sopenharmony_ci // stack. 15111cb0ef41Sopenharmony_ci if (root_array_available() && options().isolate_independent_code) { 15121cb0ef41Sopenharmony_ci if (src.is_embedded_object() || src.is_external_reference() || 15131cb0ef41Sopenharmony_ci src.is_heap_object_request()) { 15141cb0ef41Sopenharmony_ci Push(src); 15151cb0ef41Sopenharmony_ci pop(dst); 15161cb0ef41Sopenharmony_ci return; 15171cb0ef41Sopenharmony_ci } 15181cb0ef41Sopenharmony_ci } 15191cb0ef41Sopenharmony_ci 15201cb0ef41Sopenharmony_ci if (src.is_embedded_object()) { 15211cb0ef41Sopenharmony_ci mov(dst, src.embedded_object()); 15221cb0ef41Sopenharmony_ci } else { 15231cb0ef41Sopenharmony_ci mov(dst, src); 15241cb0ef41Sopenharmony_ci } 15251cb0ef41Sopenharmony_ci} 15261cb0ef41Sopenharmony_ci 15271cb0ef41Sopenharmony_civoid TurboAssembler::Move(Register dst, Operand src) { mov(dst, src); } 15281cb0ef41Sopenharmony_ci 15291cb0ef41Sopenharmony_civoid TurboAssembler::Move(Register dst, Handle<HeapObject> src) { 15301cb0ef41Sopenharmony_ci if (root_array_available() && options().isolate_independent_code) { 15311cb0ef41Sopenharmony_ci IndirectLoadConstant(dst, src); 15321cb0ef41Sopenharmony_ci return; 15331cb0ef41Sopenharmony_ci } 15341cb0ef41Sopenharmony_ci mov(dst, src); 15351cb0ef41Sopenharmony_ci} 15361cb0ef41Sopenharmony_ci 15371cb0ef41Sopenharmony_civoid TurboAssembler::Move(XMMRegister dst, uint32_t src) { 15381cb0ef41Sopenharmony_ci if (src == 0) { 15391cb0ef41Sopenharmony_ci pxor(dst, dst); 15401cb0ef41Sopenharmony_ci } else { 15411cb0ef41Sopenharmony_ci unsigned cnt = base::bits::CountPopulation(src); 15421cb0ef41Sopenharmony_ci unsigned nlz = base::bits::CountLeadingZeros32(src); 15431cb0ef41Sopenharmony_ci unsigned ntz = base::bits::CountTrailingZeros32(src); 15441cb0ef41Sopenharmony_ci if (nlz + cnt + ntz == 32) { 15451cb0ef41Sopenharmony_ci pcmpeqd(dst, dst); 15461cb0ef41Sopenharmony_ci if (ntz == 0) { 15471cb0ef41Sopenharmony_ci psrld(dst, 32 - cnt); 15481cb0ef41Sopenharmony_ci } else { 15491cb0ef41Sopenharmony_ci pslld(dst, 32 - cnt); 15501cb0ef41Sopenharmony_ci if (nlz != 0) psrld(dst, nlz); 15511cb0ef41Sopenharmony_ci } 15521cb0ef41Sopenharmony_ci } else { 15531cb0ef41Sopenharmony_ci push(eax); 15541cb0ef41Sopenharmony_ci mov(eax, Immediate(src)); 15551cb0ef41Sopenharmony_ci movd(dst, Operand(eax)); 15561cb0ef41Sopenharmony_ci pop(eax); 15571cb0ef41Sopenharmony_ci } 15581cb0ef41Sopenharmony_ci } 15591cb0ef41Sopenharmony_ci} 15601cb0ef41Sopenharmony_ci 15611cb0ef41Sopenharmony_civoid TurboAssembler::Move(XMMRegister dst, uint64_t src) { 15621cb0ef41Sopenharmony_ci if (src == 0) { 15631cb0ef41Sopenharmony_ci pxor(dst, dst); 15641cb0ef41Sopenharmony_ci } else { 15651cb0ef41Sopenharmony_ci uint32_t lower = static_cast<uint32_t>(src); 15661cb0ef41Sopenharmony_ci uint32_t upper = static_cast<uint32_t>(src >> 32); 15671cb0ef41Sopenharmony_ci unsigned cnt = base::bits::CountPopulation(src); 15681cb0ef41Sopenharmony_ci unsigned nlz = base::bits::CountLeadingZeros64(src); 15691cb0ef41Sopenharmony_ci unsigned ntz = base::bits::CountTrailingZeros64(src); 15701cb0ef41Sopenharmony_ci if (nlz + cnt + ntz == 64) { 15711cb0ef41Sopenharmony_ci pcmpeqd(dst, dst); 15721cb0ef41Sopenharmony_ci if (ntz == 0) { 15731cb0ef41Sopenharmony_ci psrlq(dst, 64 - cnt); 15741cb0ef41Sopenharmony_ci } else { 15751cb0ef41Sopenharmony_ci psllq(dst, 64 - cnt); 15761cb0ef41Sopenharmony_ci if (nlz != 0) psrlq(dst, nlz); 15771cb0ef41Sopenharmony_ci } 15781cb0ef41Sopenharmony_ci } else if (lower == 0) { 15791cb0ef41Sopenharmony_ci Move(dst, upper); 15801cb0ef41Sopenharmony_ci psllq(dst, 32); 15811cb0ef41Sopenharmony_ci } else if (CpuFeatures::IsSupported(SSE4_1)) { 15821cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, SSE4_1); 15831cb0ef41Sopenharmony_ci push(eax); 15841cb0ef41Sopenharmony_ci Move(eax, Immediate(lower)); 15851cb0ef41Sopenharmony_ci movd(dst, Operand(eax)); 15861cb0ef41Sopenharmony_ci if (upper != lower) { 15871cb0ef41Sopenharmony_ci Move(eax, Immediate(upper)); 15881cb0ef41Sopenharmony_ci } 15891cb0ef41Sopenharmony_ci pinsrd(dst, Operand(eax), 1); 15901cb0ef41Sopenharmony_ci pop(eax); 15911cb0ef41Sopenharmony_ci } else { 15921cb0ef41Sopenharmony_ci push(Immediate(upper)); 15931cb0ef41Sopenharmony_ci push(Immediate(lower)); 15941cb0ef41Sopenharmony_ci movsd(dst, Operand(esp, 0)); 15951cb0ef41Sopenharmony_ci add(esp, Immediate(kDoubleSize)); 15961cb0ef41Sopenharmony_ci } 15971cb0ef41Sopenharmony_ci } 15981cb0ef41Sopenharmony_ci} 15991cb0ef41Sopenharmony_ci 16001cb0ef41Sopenharmony_civoid TurboAssembler::PextrdPreSse41(Register dst, XMMRegister src, 16011cb0ef41Sopenharmony_ci uint8_t imm8) { 16021cb0ef41Sopenharmony_ci if (imm8 == 0) { 16031cb0ef41Sopenharmony_ci Movd(dst, src); 16041cb0ef41Sopenharmony_ci return; 16051cb0ef41Sopenharmony_ci } 16061cb0ef41Sopenharmony_ci // Without AVX or SSE, we can only have 64-bit values in xmm registers. 16071cb0ef41Sopenharmony_ci // We don't have an xmm scratch register, so move the data via the stack. This 16081cb0ef41Sopenharmony_ci // path is rarely required, so it's acceptable to be slow. 16091cb0ef41Sopenharmony_ci DCHECK_LT(imm8, 2); 16101cb0ef41Sopenharmony_ci AllocateStackSpace(kDoubleSize); 16111cb0ef41Sopenharmony_ci movsd(Operand(esp, 0), src); 16121cb0ef41Sopenharmony_ci mov(dst, Operand(esp, imm8 * kUInt32Size)); 16131cb0ef41Sopenharmony_ci add(esp, Immediate(kDoubleSize)); 16141cb0ef41Sopenharmony_ci} 16151cb0ef41Sopenharmony_ci 16161cb0ef41Sopenharmony_civoid TurboAssembler::PinsrdPreSse41(XMMRegister dst, Operand src, uint8_t imm8, 16171cb0ef41Sopenharmony_ci uint32_t* load_pc_offset) { 16181cb0ef41Sopenharmony_ci // Without AVX or SSE, we can only have 64-bit values in xmm registers. 16191cb0ef41Sopenharmony_ci // We don't have an xmm scratch register, so move the data via the stack. This 16201cb0ef41Sopenharmony_ci // path is rarely required, so it's acceptable to be slow. 16211cb0ef41Sopenharmony_ci DCHECK_LT(imm8, 2); 16221cb0ef41Sopenharmony_ci AllocateStackSpace(kDoubleSize); 16231cb0ef41Sopenharmony_ci // Write original content of {dst} to the stack. 16241cb0ef41Sopenharmony_ci movsd(Operand(esp, 0), dst); 16251cb0ef41Sopenharmony_ci // Overwrite the portion specified in {imm8}. 16261cb0ef41Sopenharmony_ci if (src.is_reg_only()) { 16271cb0ef41Sopenharmony_ci mov(Operand(esp, imm8 * kUInt32Size), src.reg()); 16281cb0ef41Sopenharmony_ci } else { 16291cb0ef41Sopenharmony_ci movss(dst, src); 16301cb0ef41Sopenharmony_ci movss(Operand(esp, imm8 * kUInt32Size), dst); 16311cb0ef41Sopenharmony_ci } 16321cb0ef41Sopenharmony_ci // Load back the full value into {dst}. 16331cb0ef41Sopenharmony_ci movsd(dst, Operand(esp, 0)); 16341cb0ef41Sopenharmony_ci add(esp, Immediate(kDoubleSize)); 16351cb0ef41Sopenharmony_ci} 16361cb0ef41Sopenharmony_ci 16371cb0ef41Sopenharmony_civoid TurboAssembler::Lzcnt(Register dst, Operand src) { 16381cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(LZCNT)) { 16391cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, LZCNT); 16401cb0ef41Sopenharmony_ci lzcnt(dst, src); 16411cb0ef41Sopenharmony_ci return; 16421cb0ef41Sopenharmony_ci } 16431cb0ef41Sopenharmony_ci Label not_zero_src; 16441cb0ef41Sopenharmony_ci bsr(dst, src); 16451cb0ef41Sopenharmony_ci j(not_zero, ¬_zero_src, Label::kNear); 16461cb0ef41Sopenharmony_ci mov(dst, 63); // 63^31 == 32 16471cb0ef41Sopenharmony_ci bind(¬_zero_src); 16481cb0ef41Sopenharmony_ci xor_(dst, Immediate(31)); // for x in [0..31], 31^x == 31-x. 16491cb0ef41Sopenharmony_ci} 16501cb0ef41Sopenharmony_ci 16511cb0ef41Sopenharmony_civoid TurboAssembler::Tzcnt(Register dst, Operand src) { 16521cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(BMI1)) { 16531cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, BMI1); 16541cb0ef41Sopenharmony_ci tzcnt(dst, src); 16551cb0ef41Sopenharmony_ci return; 16561cb0ef41Sopenharmony_ci } 16571cb0ef41Sopenharmony_ci Label not_zero_src; 16581cb0ef41Sopenharmony_ci bsf(dst, src); 16591cb0ef41Sopenharmony_ci j(not_zero, ¬_zero_src, Label::kNear); 16601cb0ef41Sopenharmony_ci mov(dst, 32); // The result of tzcnt is 32 if src = 0. 16611cb0ef41Sopenharmony_ci bind(¬_zero_src); 16621cb0ef41Sopenharmony_ci} 16631cb0ef41Sopenharmony_ci 16641cb0ef41Sopenharmony_civoid TurboAssembler::Popcnt(Register dst, Operand src) { 16651cb0ef41Sopenharmony_ci if (CpuFeatures::IsSupported(POPCNT)) { 16661cb0ef41Sopenharmony_ci CpuFeatureScope scope(this, POPCNT); 16671cb0ef41Sopenharmony_ci popcnt(dst, src); 16681cb0ef41Sopenharmony_ci return; 16691cb0ef41Sopenharmony_ci } 16701cb0ef41Sopenharmony_ci FATAL("no POPCNT support"); 16711cb0ef41Sopenharmony_ci} 16721cb0ef41Sopenharmony_ci 16731cb0ef41Sopenharmony_civoid MacroAssembler::LoadWeakValue(Register in_out, Label* target_if_cleared) { 16741cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 16751cb0ef41Sopenharmony_ci cmp(in_out, Immediate(kClearedWeakHeapObjectLower32)); 16761cb0ef41Sopenharmony_ci j(equal, target_if_cleared); 16771cb0ef41Sopenharmony_ci 16781cb0ef41Sopenharmony_ci and_(in_out, Immediate(~kWeakHeapObjectMask)); 16791cb0ef41Sopenharmony_ci} 16801cb0ef41Sopenharmony_ci 16811cb0ef41Sopenharmony_civoid MacroAssembler::EmitIncrementCounter(StatsCounter* counter, int value, 16821cb0ef41Sopenharmony_ci Register scratch) { 16831cb0ef41Sopenharmony_ci DCHECK_GT(value, 0); 16841cb0ef41Sopenharmony_ci if (FLAG_native_code_counters && counter->Enabled()) { 16851cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 16861cb0ef41Sopenharmony_ci Operand operand = 16871cb0ef41Sopenharmony_ci ExternalReferenceAsOperand(ExternalReference::Create(counter), scratch); 16881cb0ef41Sopenharmony_ci if (value == 1) { 16891cb0ef41Sopenharmony_ci inc(operand); 16901cb0ef41Sopenharmony_ci } else { 16911cb0ef41Sopenharmony_ci add(operand, Immediate(value)); 16921cb0ef41Sopenharmony_ci } 16931cb0ef41Sopenharmony_ci } 16941cb0ef41Sopenharmony_ci} 16951cb0ef41Sopenharmony_ci 16961cb0ef41Sopenharmony_civoid MacroAssembler::EmitDecrementCounter(StatsCounter* counter, int value, 16971cb0ef41Sopenharmony_ci Register scratch) { 16981cb0ef41Sopenharmony_ci DCHECK_GT(value, 0); 16991cb0ef41Sopenharmony_ci if (FLAG_native_code_counters && counter->Enabled()) { 17001cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 17011cb0ef41Sopenharmony_ci Operand operand = 17021cb0ef41Sopenharmony_ci ExternalReferenceAsOperand(ExternalReference::Create(counter), scratch); 17031cb0ef41Sopenharmony_ci if (value == 1) { 17041cb0ef41Sopenharmony_ci dec(operand); 17051cb0ef41Sopenharmony_ci } else { 17061cb0ef41Sopenharmony_ci sub(operand, Immediate(value)); 17071cb0ef41Sopenharmony_ci } 17081cb0ef41Sopenharmony_ci } 17091cb0ef41Sopenharmony_ci} 17101cb0ef41Sopenharmony_ci 17111cb0ef41Sopenharmony_civoid TurboAssembler::Assert(Condition cc, AbortReason reason) { 17121cb0ef41Sopenharmony_ci if (FLAG_debug_code) Check(cc, reason); 17131cb0ef41Sopenharmony_ci} 17141cb0ef41Sopenharmony_ci 17151cb0ef41Sopenharmony_civoid TurboAssembler::AssertUnreachable(AbortReason reason) { 17161cb0ef41Sopenharmony_ci if (FLAG_debug_code) Abort(reason); 17171cb0ef41Sopenharmony_ci} 17181cb0ef41Sopenharmony_ci 17191cb0ef41Sopenharmony_civoid TurboAssembler::Check(Condition cc, AbortReason reason) { 17201cb0ef41Sopenharmony_ci Label L; 17211cb0ef41Sopenharmony_ci j(cc, &L); 17221cb0ef41Sopenharmony_ci Abort(reason); 17231cb0ef41Sopenharmony_ci // will not return here 17241cb0ef41Sopenharmony_ci bind(&L); 17251cb0ef41Sopenharmony_ci} 17261cb0ef41Sopenharmony_ci 17271cb0ef41Sopenharmony_civoid TurboAssembler::CheckStackAlignment() { 17281cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 17291cb0ef41Sopenharmony_ci int frame_alignment = base::OS::ActivationFrameAlignment(); 17301cb0ef41Sopenharmony_ci int frame_alignment_mask = frame_alignment - 1; 17311cb0ef41Sopenharmony_ci if (frame_alignment > kSystemPointerSize) { 17321cb0ef41Sopenharmony_ci DCHECK(base::bits::IsPowerOfTwo(frame_alignment)); 17331cb0ef41Sopenharmony_ci Label alignment_as_expected; 17341cb0ef41Sopenharmony_ci test(esp, Immediate(frame_alignment_mask)); 17351cb0ef41Sopenharmony_ci j(zero, &alignment_as_expected); 17361cb0ef41Sopenharmony_ci // Abort if stack is not aligned. 17371cb0ef41Sopenharmony_ci int3(); 17381cb0ef41Sopenharmony_ci bind(&alignment_as_expected); 17391cb0ef41Sopenharmony_ci } 17401cb0ef41Sopenharmony_ci} 17411cb0ef41Sopenharmony_ci 17421cb0ef41Sopenharmony_civoid TurboAssembler::Abort(AbortReason reason) { 17431cb0ef41Sopenharmony_ci if (FLAG_code_comments) { 17441cb0ef41Sopenharmony_ci const char* msg = GetAbortReason(reason); 17451cb0ef41Sopenharmony_ci RecordComment("Abort message: "); 17461cb0ef41Sopenharmony_ci RecordComment(msg); 17471cb0ef41Sopenharmony_ci } 17481cb0ef41Sopenharmony_ci 17491cb0ef41Sopenharmony_ci // Avoid emitting call to builtin if requested. 17501cb0ef41Sopenharmony_ci if (trap_on_abort()) { 17511cb0ef41Sopenharmony_ci int3(); 17521cb0ef41Sopenharmony_ci return; 17531cb0ef41Sopenharmony_ci } 17541cb0ef41Sopenharmony_ci 17551cb0ef41Sopenharmony_ci if (should_abort_hard()) { 17561cb0ef41Sopenharmony_ci // We don't care if we constructed a frame. Just pretend we did. 17571cb0ef41Sopenharmony_ci FrameScope assume_frame(this, StackFrame::NO_FRAME_TYPE); 17581cb0ef41Sopenharmony_ci PrepareCallCFunction(1, eax); 17591cb0ef41Sopenharmony_ci mov(Operand(esp, 0), Immediate(static_cast<int>(reason))); 17601cb0ef41Sopenharmony_ci CallCFunction(ExternalReference::abort_with_reason(), 1); 17611cb0ef41Sopenharmony_ci return; 17621cb0ef41Sopenharmony_ci } 17631cb0ef41Sopenharmony_ci 17641cb0ef41Sopenharmony_ci Move(edx, Smi::FromInt(static_cast<int>(reason))); 17651cb0ef41Sopenharmony_ci 17661cb0ef41Sopenharmony_ci // Disable stub call restrictions to always allow calls to abort. 17671cb0ef41Sopenharmony_ci if (!has_frame()) { 17681cb0ef41Sopenharmony_ci // We don't actually want to generate a pile of code for this, so just 17691cb0ef41Sopenharmony_ci // claim there is a stack frame, without generating one. 17701cb0ef41Sopenharmony_ci FrameScope scope(this, StackFrame::NO_FRAME_TYPE); 17711cb0ef41Sopenharmony_ci Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET); 17721cb0ef41Sopenharmony_ci } else { 17731cb0ef41Sopenharmony_ci Call(BUILTIN_CODE(isolate(), Abort), RelocInfo::CODE_TARGET); 17741cb0ef41Sopenharmony_ci } 17751cb0ef41Sopenharmony_ci // will not return here 17761cb0ef41Sopenharmony_ci int3(); 17771cb0ef41Sopenharmony_ci} 17781cb0ef41Sopenharmony_ci 17791cb0ef41Sopenharmony_civoid TurboAssembler::PrepareCallCFunction(int num_arguments, Register scratch) { 17801cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 17811cb0ef41Sopenharmony_ci int frame_alignment = base::OS::ActivationFrameAlignment(); 17821cb0ef41Sopenharmony_ci if (frame_alignment != 0) { 17831cb0ef41Sopenharmony_ci // Make stack end at alignment and make room for num_arguments words 17841cb0ef41Sopenharmony_ci // and the original value of esp. 17851cb0ef41Sopenharmony_ci mov(scratch, esp); 17861cb0ef41Sopenharmony_ci AllocateStackSpace((num_arguments + 1) * kSystemPointerSize); 17871cb0ef41Sopenharmony_ci DCHECK(base::bits::IsPowerOfTwo(frame_alignment)); 17881cb0ef41Sopenharmony_ci and_(esp, -frame_alignment); 17891cb0ef41Sopenharmony_ci mov(Operand(esp, num_arguments * kSystemPointerSize), scratch); 17901cb0ef41Sopenharmony_ci } else { 17911cb0ef41Sopenharmony_ci AllocateStackSpace(num_arguments * kSystemPointerSize); 17921cb0ef41Sopenharmony_ci } 17931cb0ef41Sopenharmony_ci} 17941cb0ef41Sopenharmony_ci 17951cb0ef41Sopenharmony_civoid TurboAssembler::CallCFunction(ExternalReference function, 17961cb0ef41Sopenharmony_ci int num_arguments) { 17971cb0ef41Sopenharmony_ci // Trashing eax is ok as it will be the return value. 17981cb0ef41Sopenharmony_ci Move(eax, Immediate(function)); 17991cb0ef41Sopenharmony_ci CallCFunction(eax, num_arguments); 18001cb0ef41Sopenharmony_ci} 18011cb0ef41Sopenharmony_ci 18021cb0ef41Sopenharmony_civoid TurboAssembler::CallCFunction(Register function, int num_arguments) { 18031cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 18041cb0ef41Sopenharmony_ci DCHECK_LE(num_arguments, kMaxCParameters); 18051cb0ef41Sopenharmony_ci DCHECK(has_frame()); 18061cb0ef41Sopenharmony_ci // Check stack alignment. 18071cb0ef41Sopenharmony_ci if (FLAG_debug_code) { 18081cb0ef41Sopenharmony_ci CheckStackAlignment(); 18091cb0ef41Sopenharmony_ci } 18101cb0ef41Sopenharmony_ci 18111cb0ef41Sopenharmony_ci // Save the frame pointer and PC so that the stack layout remains iterable, 18121cb0ef41Sopenharmony_ci // even without an ExitFrame which normally exists between JS and C frames. 18131cb0ef41Sopenharmony_ci // Find two caller-saved scratch registers. 18141cb0ef41Sopenharmony_ci Register pc_scratch = eax; 18151cb0ef41Sopenharmony_ci Register scratch = ecx; 18161cb0ef41Sopenharmony_ci if (function == eax) pc_scratch = edx; 18171cb0ef41Sopenharmony_ci if (function == ecx) scratch = edx; 18181cb0ef41Sopenharmony_ci PushPC(); 18191cb0ef41Sopenharmony_ci pop(pc_scratch); 18201cb0ef41Sopenharmony_ci 18211cb0ef41Sopenharmony_ci // See x64 code for reasoning about how to address the isolate data fields. 18221cb0ef41Sopenharmony_ci DCHECK_IMPLIES(!root_array_available(), isolate() != nullptr); 18231cb0ef41Sopenharmony_ci mov(root_array_available() 18241cb0ef41Sopenharmony_ci ? Operand(kRootRegister, IsolateData::fast_c_call_caller_pc_offset()) 18251cb0ef41Sopenharmony_ci : ExternalReferenceAsOperand( 18261cb0ef41Sopenharmony_ci ExternalReference::fast_c_call_caller_pc_address(isolate()), 18271cb0ef41Sopenharmony_ci scratch), 18281cb0ef41Sopenharmony_ci pc_scratch); 18291cb0ef41Sopenharmony_ci mov(root_array_available() 18301cb0ef41Sopenharmony_ci ? Operand(kRootRegister, IsolateData::fast_c_call_caller_fp_offset()) 18311cb0ef41Sopenharmony_ci : ExternalReferenceAsOperand( 18321cb0ef41Sopenharmony_ci ExternalReference::fast_c_call_caller_fp_address(isolate()), 18331cb0ef41Sopenharmony_ci scratch), 18341cb0ef41Sopenharmony_ci ebp); 18351cb0ef41Sopenharmony_ci 18361cb0ef41Sopenharmony_ci call(function); 18371cb0ef41Sopenharmony_ci 18381cb0ef41Sopenharmony_ci // We don't unset the PC; the FP is the source of truth. 18391cb0ef41Sopenharmony_ci mov(root_array_available() 18401cb0ef41Sopenharmony_ci ? Operand(kRootRegister, IsolateData::fast_c_call_caller_fp_offset()) 18411cb0ef41Sopenharmony_ci : ExternalReferenceAsOperand( 18421cb0ef41Sopenharmony_ci ExternalReference::fast_c_call_caller_fp_address(isolate()), 18431cb0ef41Sopenharmony_ci scratch), 18441cb0ef41Sopenharmony_ci Immediate(0)); 18451cb0ef41Sopenharmony_ci 18461cb0ef41Sopenharmony_ci if (base::OS::ActivationFrameAlignment() != 0) { 18471cb0ef41Sopenharmony_ci mov(esp, Operand(esp, num_arguments * kSystemPointerSize)); 18481cb0ef41Sopenharmony_ci } else { 18491cb0ef41Sopenharmony_ci add(esp, Immediate(num_arguments * kSystemPointerSize)); 18501cb0ef41Sopenharmony_ci } 18511cb0ef41Sopenharmony_ci} 18521cb0ef41Sopenharmony_ci 18531cb0ef41Sopenharmony_civoid TurboAssembler::PushPC() { 18541cb0ef41Sopenharmony_ci // Push the current PC onto the stack as "return address" via calling 18551cb0ef41Sopenharmony_ci // the next instruction. 18561cb0ef41Sopenharmony_ci Label get_pc; 18571cb0ef41Sopenharmony_ci call(&get_pc); 18581cb0ef41Sopenharmony_ci bind(&get_pc); 18591cb0ef41Sopenharmony_ci} 18601cb0ef41Sopenharmony_ci 18611cb0ef41Sopenharmony_civoid TurboAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) { 18621cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 18631cb0ef41Sopenharmony_ci DCHECK_IMPLIES(options().isolate_independent_code, 18641cb0ef41Sopenharmony_ci Builtins::IsIsolateIndependentBuiltin(*code_object)); 18651cb0ef41Sopenharmony_ci if (options().inline_offheap_trampolines) { 18661cb0ef41Sopenharmony_ci Builtin builtin = Builtin::kNoBuiltinId; 18671cb0ef41Sopenharmony_ci if (isolate()->builtins()->IsBuiltinHandle(code_object, &builtin)) { 18681cb0ef41Sopenharmony_ci // Inline the trampoline. 18691cb0ef41Sopenharmony_ci CallBuiltin(builtin); 18701cb0ef41Sopenharmony_ci return; 18711cb0ef41Sopenharmony_ci } 18721cb0ef41Sopenharmony_ci } 18731cb0ef41Sopenharmony_ci DCHECK(RelocInfo::IsCodeTarget(rmode)); 18741cb0ef41Sopenharmony_ci call(code_object, rmode); 18751cb0ef41Sopenharmony_ci} 18761cb0ef41Sopenharmony_ci 18771cb0ef41Sopenharmony_civoid TurboAssembler::LoadEntryFromBuiltinIndex(Register builtin_index) { 18781cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 18791cb0ef41Sopenharmony_ci STATIC_ASSERT(kSystemPointerSize == 4); 18801cb0ef41Sopenharmony_ci STATIC_ASSERT(kSmiShiftSize == 0); 18811cb0ef41Sopenharmony_ci STATIC_ASSERT(kSmiTagSize == 1); 18821cb0ef41Sopenharmony_ci STATIC_ASSERT(kSmiTag == 0); 18831cb0ef41Sopenharmony_ci 18841cb0ef41Sopenharmony_ci // The builtin_index register contains the builtin index as a Smi. 18851cb0ef41Sopenharmony_ci // Untagging is folded into the indexing operand below (we use 18861cb0ef41Sopenharmony_ci // times_half_system_pointer_size instead of times_system_pointer_size since 18871cb0ef41Sopenharmony_ci // smis are already shifted by one). 18881cb0ef41Sopenharmony_ci mov(builtin_index, 18891cb0ef41Sopenharmony_ci Operand(kRootRegister, builtin_index, times_half_system_pointer_size, 18901cb0ef41Sopenharmony_ci IsolateData::builtin_entry_table_offset())); 18911cb0ef41Sopenharmony_ci} 18921cb0ef41Sopenharmony_ci 18931cb0ef41Sopenharmony_civoid TurboAssembler::CallBuiltinByIndex(Register builtin_index) { 18941cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 18951cb0ef41Sopenharmony_ci LoadEntryFromBuiltinIndex(builtin_index); 18961cb0ef41Sopenharmony_ci call(builtin_index); 18971cb0ef41Sopenharmony_ci} 18981cb0ef41Sopenharmony_ci 18991cb0ef41Sopenharmony_civoid TurboAssembler::CallBuiltin(Builtin builtin) { 19001cb0ef41Sopenharmony_ci ASM_CODE_COMMENT_STRING(this, CommentForOffHeapTrampoline("call", builtin)); 19011cb0ef41Sopenharmony_ci DCHECK(Builtins::IsBuiltinId(builtin)); 19021cb0ef41Sopenharmony_ci call(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET); 19031cb0ef41Sopenharmony_ci} 19041cb0ef41Sopenharmony_ci 19051cb0ef41Sopenharmony_ciOperand TurboAssembler::EntryFromBuiltinAsOperand(Builtin builtin) { 19061cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 19071cb0ef41Sopenharmony_ci return Operand(kRootRegister, IsolateData::BuiltinEntrySlotOffset(builtin)); 19081cb0ef41Sopenharmony_ci} 19091cb0ef41Sopenharmony_ci 19101cb0ef41Sopenharmony_civoid TurboAssembler::LoadCodeObjectEntry(Register destination, 19111cb0ef41Sopenharmony_ci Register code_object) { 19121cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 19131cb0ef41Sopenharmony_ci // Code objects are called differently depending on whether we are generating 19141cb0ef41Sopenharmony_ci // builtin code (which will later be embedded into the binary) or compiling 19151cb0ef41Sopenharmony_ci // user JS code at runtime. 19161cb0ef41Sopenharmony_ci // * Builtin code runs in --jitless mode and thus must not call into on-heap 19171cb0ef41Sopenharmony_ci // Code targets. Instead, we dispatch through the builtins entry table. 19181cb0ef41Sopenharmony_ci // * Codegen at runtime does not have this restriction and we can use the 19191cb0ef41Sopenharmony_ci // shorter, branchless instruction sequence. The assumption here is that 19201cb0ef41Sopenharmony_ci // targets are usually generated code and not builtin Code objects. 19211cb0ef41Sopenharmony_ci 19221cb0ef41Sopenharmony_ci if (options().isolate_independent_code) { 19231cb0ef41Sopenharmony_ci DCHECK(root_array_available()); 19241cb0ef41Sopenharmony_ci Label if_code_is_off_heap, out; 19251cb0ef41Sopenharmony_ci 19261cb0ef41Sopenharmony_ci // Check whether the Code object is an off-heap trampoline. If so, call its 19271cb0ef41Sopenharmony_ci // (off-heap) entry point directly without going through the (on-heap) 19281cb0ef41Sopenharmony_ci // trampoline. Otherwise, just call the Code object as always. 19291cb0ef41Sopenharmony_ci test(FieldOperand(code_object, Code::kFlagsOffset), 19301cb0ef41Sopenharmony_ci Immediate(Code::IsOffHeapTrampoline::kMask)); 19311cb0ef41Sopenharmony_ci j(not_equal, &if_code_is_off_heap); 19321cb0ef41Sopenharmony_ci 19331cb0ef41Sopenharmony_ci // Not an off-heap trampoline, the entry point is at 19341cb0ef41Sopenharmony_ci // Code::raw_instruction_start(). 19351cb0ef41Sopenharmony_ci Move(destination, code_object); 19361cb0ef41Sopenharmony_ci add(destination, Immediate(Code::kHeaderSize - kHeapObjectTag)); 19371cb0ef41Sopenharmony_ci jmp(&out); 19381cb0ef41Sopenharmony_ci 19391cb0ef41Sopenharmony_ci // An off-heap trampoline, the entry point is loaded from the builtin entry 19401cb0ef41Sopenharmony_ci // table. 19411cb0ef41Sopenharmony_ci bind(&if_code_is_off_heap); 19421cb0ef41Sopenharmony_ci mov(destination, FieldOperand(code_object, Code::kBuiltinIndexOffset)); 19431cb0ef41Sopenharmony_ci mov(destination, 19441cb0ef41Sopenharmony_ci Operand(kRootRegister, destination, times_system_pointer_size, 19451cb0ef41Sopenharmony_ci IsolateData::builtin_entry_table_offset())); 19461cb0ef41Sopenharmony_ci 19471cb0ef41Sopenharmony_ci bind(&out); 19481cb0ef41Sopenharmony_ci } else { 19491cb0ef41Sopenharmony_ci Move(destination, code_object); 19501cb0ef41Sopenharmony_ci add(destination, Immediate(Code::kHeaderSize - kHeapObjectTag)); 19511cb0ef41Sopenharmony_ci } 19521cb0ef41Sopenharmony_ci} 19531cb0ef41Sopenharmony_ci 19541cb0ef41Sopenharmony_civoid TurboAssembler::CallCodeObject(Register code_object) { 19551cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 19561cb0ef41Sopenharmony_ci LoadCodeObjectEntry(code_object, code_object); 19571cb0ef41Sopenharmony_ci call(code_object); 19581cb0ef41Sopenharmony_ci} 19591cb0ef41Sopenharmony_ci 19601cb0ef41Sopenharmony_civoid TurboAssembler::JumpCodeObject(Register code_object, JumpMode jump_mode) { 19611cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 19621cb0ef41Sopenharmony_ci LoadCodeObjectEntry(code_object, code_object); 19631cb0ef41Sopenharmony_ci switch (jump_mode) { 19641cb0ef41Sopenharmony_ci case JumpMode::kJump: 19651cb0ef41Sopenharmony_ci jmp(code_object); 19661cb0ef41Sopenharmony_ci return; 19671cb0ef41Sopenharmony_ci case JumpMode::kPushAndReturn: 19681cb0ef41Sopenharmony_ci push(code_object); 19691cb0ef41Sopenharmony_ci ret(0); 19701cb0ef41Sopenharmony_ci return; 19711cb0ef41Sopenharmony_ci } 19721cb0ef41Sopenharmony_ci} 19731cb0ef41Sopenharmony_ci 19741cb0ef41Sopenharmony_civoid TurboAssembler::Jump(const ExternalReference& reference) { 19751cb0ef41Sopenharmony_ci DCHECK(root_array_available()); 19761cb0ef41Sopenharmony_ci jmp(Operand(kRootRegister, RootRegisterOffsetForExternalReferenceTableEntry( 19771cb0ef41Sopenharmony_ci isolate(), reference))); 19781cb0ef41Sopenharmony_ci} 19791cb0ef41Sopenharmony_ci 19801cb0ef41Sopenharmony_civoid TurboAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) { 19811cb0ef41Sopenharmony_ci DCHECK_IMPLIES(options().isolate_independent_code, 19821cb0ef41Sopenharmony_ci Builtins::IsIsolateIndependentBuiltin(*code_object)); 19831cb0ef41Sopenharmony_ci if (options().inline_offheap_trampolines) { 19841cb0ef41Sopenharmony_ci Builtin builtin = Builtin::kNoBuiltinId; 19851cb0ef41Sopenharmony_ci if (isolate()->builtins()->IsBuiltinHandle(code_object, &builtin)) { 19861cb0ef41Sopenharmony_ci // Inline the trampoline. 19871cb0ef41Sopenharmony_ci RecordCommentForOffHeapTrampoline(builtin); 19881cb0ef41Sopenharmony_ci jmp(BuiltinEntry(builtin), RelocInfo::OFF_HEAP_TARGET); 19891cb0ef41Sopenharmony_ci return; 19901cb0ef41Sopenharmony_ci } 19911cb0ef41Sopenharmony_ci } 19921cb0ef41Sopenharmony_ci DCHECK(RelocInfo::IsCodeTarget(rmode)); 19931cb0ef41Sopenharmony_ci jmp(code_object, rmode); 19941cb0ef41Sopenharmony_ci} 19951cb0ef41Sopenharmony_ci 19961cb0ef41Sopenharmony_civoid TurboAssembler::CheckPageFlag(Register object, Register scratch, int mask, 19971cb0ef41Sopenharmony_ci Condition cc, Label* condition_met, 19981cb0ef41Sopenharmony_ci Label::Distance condition_met_distance) { 19991cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 20001cb0ef41Sopenharmony_ci DCHECK(cc == zero || cc == not_zero); 20011cb0ef41Sopenharmony_ci if (scratch == object) { 20021cb0ef41Sopenharmony_ci and_(scratch, Immediate(~kPageAlignmentMask)); 20031cb0ef41Sopenharmony_ci } else { 20041cb0ef41Sopenharmony_ci mov(scratch, Immediate(~kPageAlignmentMask)); 20051cb0ef41Sopenharmony_ci and_(scratch, object); 20061cb0ef41Sopenharmony_ci } 20071cb0ef41Sopenharmony_ci if (mask < (1 << kBitsPerByte)) { 20081cb0ef41Sopenharmony_ci test_b(Operand(scratch, BasicMemoryChunk::kFlagsOffset), Immediate(mask)); 20091cb0ef41Sopenharmony_ci } else { 20101cb0ef41Sopenharmony_ci test(Operand(scratch, BasicMemoryChunk::kFlagsOffset), Immediate(mask)); 20111cb0ef41Sopenharmony_ci } 20121cb0ef41Sopenharmony_ci j(cc, condition_met, condition_met_distance); 20131cb0ef41Sopenharmony_ci} 20141cb0ef41Sopenharmony_ci 20151cb0ef41Sopenharmony_civoid TurboAssembler::ComputeCodeStartAddress(Register dst) { 20161cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 20171cb0ef41Sopenharmony_ci // In order to get the address of the current instruction, we first need 20181cb0ef41Sopenharmony_ci // to use a call and then use a pop, thus pushing the return address to 20191cb0ef41Sopenharmony_ci // the stack and then popping it into the register. 20201cb0ef41Sopenharmony_ci Label current; 20211cb0ef41Sopenharmony_ci call(¤t); 20221cb0ef41Sopenharmony_ci int pc = pc_offset(); 20231cb0ef41Sopenharmony_ci bind(¤t); 20241cb0ef41Sopenharmony_ci pop(dst); 20251cb0ef41Sopenharmony_ci if (pc != 0) { 20261cb0ef41Sopenharmony_ci sub(dst, Immediate(pc)); 20271cb0ef41Sopenharmony_ci } 20281cb0ef41Sopenharmony_ci} 20291cb0ef41Sopenharmony_ci 20301cb0ef41Sopenharmony_civoid TurboAssembler::CallForDeoptimization(Builtin target, int, Label* exit, 20311cb0ef41Sopenharmony_ci DeoptimizeKind kind, Label* ret, 20321cb0ef41Sopenharmony_ci Label*) { 20331cb0ef41Sopenharmony_ci ASM_CODE_COMMENT(this); 20341cb0ef41Sopenharmony_ci CallBuiltin(target); 20351cb0ef41Sopenharmony_ci DCHECK_EQ(SizeOfCodeGeneratedSince(exit), 20361cb0ef41Sopenharmony_ci (kind == DeoptimizeKind::kLazy) ? Deoptimizer::kLazyDeoptExitSize 20371cb0ef41Sopenharmony_ci : Deoptimizer::kEagerDeoptExitSize); 20381cb0ef41Sopenharmony_ci} 20391cb0ef41Sopenharmony_ci 20401cb0ef41Sopenharmony_civoid TurboAssembler::Trap() { int3(); } 20411cb0ef41Sopenharmony_civoid TurboAssembler::DebugBreak() { int3(); } 20421cb0ef41Sopenharmony_ci 20431cb0ef41Sopenharmony_ci} // namespace internal 20441cb0ef41Sopenharmony_ci} // namespace v8 20451cb0ef41Sopenharmony_ci 20461cb0ef41Sopenharmony_ci#endif // V8_TARGET_ARCH_IA32 2047