1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2013 the V8 project authors. All rights reserved. 2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file. 4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/v8.h" 6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#if V8_TARGET_ARCH_ARM64 8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/arm64/simulator-arm64.h" 10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/codegen.h" 11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/macro-assembler.h" 12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace v8 { 14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace internal { 15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#define __ ACCESS_MASM(masm) 17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#if defined(USE_SIMULATOR) 19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochbyte* fast_exp_arm64_machine_code = NULL; 20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochdouble fast_exp_simulator(double x) { 21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Simulator * simulator = Simulator::current(Isolate::Current()); 22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Simulator::CallArgument args[] = { 23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Simulator::CallArgument(x), 24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Simulator::CallArgument::End() 25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch }; 26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return simulator->CallDouble(fast_exp_arm64_machine_code, args); 27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif 29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochUnaryMathFunction CreateExpFunction() { 32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (!FLAG_fast_math) return &std::exp; 33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Use the Math.exp implemetation in MathExpGenerator::EmitMathExp() to create 35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // an AAPCS64-compliant exp() function. This will be faster than the C 36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // library's exp() function, but probably less accurate. 37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch size_t actual_size; 38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch byte* buffer = 39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true)); 40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (buffer == NULL) return &std::exp; 41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ExternalReference::InitializeMathExpData(); 43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); 44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch masm.SetStackPointer(csp); 45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The argument will be in d0 on entry. 47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DoubleRegister input = d0; 48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Use other caller-saved registers for all other values. 49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DoubleRegister result = d1; 50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DoubleRegister double_temp1 = d2; 51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DoubleRegister double_temp2 = d3; 52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register temp1 = x10; 53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register temp2 = x11; 54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register temp3 = x12; 55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch MathExpGenerator::EmitMathExp(&masm, input, result, 57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch double_temp1, double_temp2, 58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch temp1, temp2, temp3); 59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Move the result to the return register. 60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch masm.Fmov(d0, result); 61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch masm.Ret(); 62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CodeDesc desc; 64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch masm.GetCode(&desc); 65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!RelocInfo::RequiresRelocation(desc)); 66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CpuFeatures::FlushICache(buffer, actual_size); 68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch base::OS::ProtectCode(buffer, actual_size); 69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#if !defined(USE_SIMULATOR) 71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return FUNCTION_CAST<UnaryMathFunction>(buffer); 72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#else 73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch fast_exp_arm64_machine_code = buffer; 74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return &fast_exp_simulator; 75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif 76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochUnaryMathFunction CreateSqrtFunction() { 80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return &std::sqrt; 81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// ------------------------------------------------------------------------- 85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Platform-specific RuntimeCallHelper functions. 86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { 88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch masm->EnterFrame(StackFrame::INTERNAL); 89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!masm->has_frame()); 90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch masm->set_has_frame(true); 91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { 95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch masm->LeaveFrame(StackFrame::INTERNAL); 96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(masm->has_frame()); 97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch masm->set_has_frame(false); 98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// ------------------------------------------------------------------------- 102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Code generators 103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid ElementsTransitionGenerator::GenerateMapChangeElementsTransition( 105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch MacroAssembler* masm, 106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register receiver, 107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register key, 108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register value, 109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register target_map, 110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch AllocationSiteMode mode, 111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label* allocation_memento_found) { 112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ASM_LOCATION( 113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "ElementsTransitionGenerator::GenerateMapChangeElementsTransition"); 114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!AreAliased(receiver, key, value, target_map)); 115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (mode == TRACK_ALLOCATION_SITE) { 117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(allocation_memento_found != NULL); 118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11, 119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch allocation_memento_found); 120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Set transitioned map. 123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); 124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ RecordWriteField(receiver, 125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch HeapObject::kMapOffset, 126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch target_map, 127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch x10, 128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch kLRHasNotBeenSaved, 129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch kDontSaveFPRegs, 130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch EMIT_REMEMBERED_SET, 131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch OMIT_SMI_CHECK); 132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid ElementsTransitionGenerator::GenerateSmiToDouble( 136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch MacroAssembler* masm, 137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register receiver, 138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register key, 139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register value, 140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register target_map, 141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch AllocationSiteMode mode, 142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label* fail) { 143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ASM_LOCATION("ElementsTransitionGenerator::GenerateSmiToDouble"); 144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label gc_required, only_change_map; 145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register elements = x4; 146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register length = x5; 147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register array_size = x6; 148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register array = x7; 149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register scratch = x6; 151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Verify input registers don't conflict with locals. 153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!AreAliased(receiver, key, value, target_map, 154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch elements, length, array_size, array)); 155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (mode == TRACK_ALLOCATION_SITE) { 157b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11, fail); 158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Check for empty arrays, which only require a map transition and no changes 161b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // to the backing store. 162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); 163b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ JumpIfRoot(elements, Heap::kEmptyFixedArrayRootIndex, &only_change_map); 164b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Push(lr); 166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldrsw(length, UntagSmiFieldMemOperand(elements, 167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FixedArray::kLengthOffset)); 168b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Allocate new FixedDoubleArray. 170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Lsl(array_size, length, kDoubleSizeLog2); 171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(array_size, array_size, FixedDoubleArray::kHeaderSize); 172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Allocate(array_size, array, x10, x11, &gc_required, DOUBLE_ALIGNMENT); 173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Register array is non-tagged heap object. 174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Set the destination FixedDoubleArray's length and map. 176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register map_root = array_size; 177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ LoadRoot(map_root, Heap::kFixedDoubleArrayMapRootIndex); 178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ SmiTag(x11, length); 179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(x11, MemOperand(array, FixedDoubleArray::kLengthOffset)); 180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(map_root, MemOperand(array, HeapObject::kMapOffset)); 181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); 183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch, 184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch kLRHasBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, 185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch OMIT_SMI_CHECK); 186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Replace receiver's backing store with newly created FixedDoubleArray. 188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(x10, array, kHeapObjectTag); 189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(x10, FieldMemOperand(receiver, JSObject::kElementsOffset)); 190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ RecordWriteField(receiver, JSObject::kElementsOffset, x10, 191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch scratch, kLRHasBeenSaved, kDontSaveFPRegs, 192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); 193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Prepare for conversion loop. 195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register src_elements = x10; 196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register dst_elements = x11; 197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register dst_end = x12; 198b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(src_elements, elements, FixedArray::kHeaderSize - kHeapObjectTag); 199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(dst_elements, array, FixedDoubleArray::kHeaderSize); 200b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(dst_end, dst_elements, Operand(length, LSL, kDoubleSizeLog2)); 201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FPRegister nan_d = d1; 203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fmov(nan_d, rawbits_to_double(kHoleNanInt64)); 204b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label entry, done; 206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(&entry); 207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&only_change_map); 209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); 210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch, 211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, 212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch OMIT_SMI_CHECK); 213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(&done); 214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Call into runtime if GC is required. 216b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&gc_required); 217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Pop(lr); 218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(fail); 219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Iterate over the array, copying and coverting smis to doubles. If an 221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // element is non-smi, write a hole to the destination. 222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch { 223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label loop; 224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&loop); 225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(x13, MemOperand(src_elements, kPointerSize, PostIndex)); 226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ SmiUntagToDouble(d0, x13, kSpeculativeUntag); 227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Tst(x13, kSmiTagMask); 228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fcsel(d0, d0, nan_d, eq); 229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(d0, MemOperand(dst_elements, kDoubleSize, PostIndex)); 230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&entry); 232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Cmp(dst_elements, dst_end); 233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(lt, &loop); 234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Pop(lr); 237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&done); 238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid ElementsTransitionGenerator::GenerateDoubleToObject( 242b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch MacroAssembler* masm, 243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register receiver, 244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register key, 245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register value, 246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register target_map, 247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch AllocationSiteMode mode, 248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label* fail) { 249b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ASM_LOCATION("ElementsTransitionGenerator::GenerateDoubleToObject"); 250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register elements = x4; 251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register array_size = x6; 252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register array = x7; 253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register length = x5; 254b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Verify input registers don't conflict with locals. 256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!AreAliased(receiver, key, value, target_map, 257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch elements, array_size, array, length)); 258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (mode == TRACK_ALLOCATION_SITE) { 260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11, fail); 261b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Check for empty arrays, which only require a map transition and no changes 264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // to the backing store. 265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label only_change_map; 266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); 268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ JumpIfRoot(elements, Heap::kEmptyFixedArrayRootIndex, &only_change_map); 269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 270b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Push(lr); 271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // TODO(all): These registers may not need to be pushed. Examine 272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // RecordWriteStub and check whether it's needed. 273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Push(target_map, receiver, key, value); 274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldrsw(length, UntagSmiFieldMemOperand(elements, 275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FixedArray::kLengthOffset)); 276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Allocate new FixedArray. 277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label gc_required; 278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Mov(array_size, FixedDoubleArray::kHeaderSize); 279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(array_size, array_size, Operand(length, LSL, kPointerSizeLog2)); 280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Allocate(array_size, array, x10, x11, &gc_required, NO_ALLOCATION_FLAGS); 281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Set destination FixedDoubleArray's length and map. 283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register map_root = array_size; 284b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ LoadRoot(map_root, Heap::kFixedArrayMapRootIndex); 285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ SmiTag(x11, length); 286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(x11, MemOperand(array, FixedDoubleArray::kLengthOffset)); 287b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(map_root, MemOperand(array, HeapObject::kMapOffset)); 288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Prepare for conversion loop. 290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register src_elements = x10; 291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register dst_elements = x11; 292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register dst_end = x12; 293b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(src_elements, elements, 294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FixedDoubleArray::kHeaderSize - kHeapObjectTag); 295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(dst_elements, array, FixedArray::kHeaderSize); 296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(array, array, kHeapObjectTag); 297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(dst_end, dst_elements, Operand(length, LSL, kPointerSizeLog2)); 298b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register the_hole = x14; 300b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register heap_num_map = x15; 301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ LoadRoot(the_hole, Heap::kTheHoleValueRootIndex); 302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ LoadRoot(heap_num_map, Heap::kHeapNumberMapRootIndex); 303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label entry; 305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(&entry); 306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Call into runtime if GC is required. 308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&gc_required); 309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Pop(value, key, receiver, target_map); 310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Pop(lr); 311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(fail); 312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch { 314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label loop, convert_hole; 315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&loop); 316b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(x13, MemOperand(src_elements, kPointerSize, PostIndex)); 317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Cmp(x13, kHoleNanInt64); 318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(eq, &convert_hole); 319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Non-hole double, copy value into a heap number. 321b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register heap_num = length; 322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register scratch = array_size; 323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register scratch2 = elements; 324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ AllocateHeapNumber(heap_num, &gc_required, scratch, scratch2, 325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch x13, heap_num_map); 326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Mov(x13, dst_elements); 327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(heap_num, MemOperand(dst_elements, kPointerSize, PostIndex)); 328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ RecordWrite(array, x13, heap_num, kLRHasBeenSaved, kDontSaveFPRegs, 329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); 330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(&entry); 332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Replace the-hole NaN with the-hole pointer. 334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&convert_hole); 335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(the_hole, MemOperand(dst_elements, kPointerSize, PostIndex)); 336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 337b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&entry); 338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Cmp(dst_elements, dst_end); 339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(lt, &loop); 340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Pop(value, key, receiver, target_map); 343b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Replace receiver's backing store with newly created and filled FixedArray. 344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(array, FieldMemOperand(receiver, JSObject::kElementsOffset)); 345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ RecordWriteField(receiver, JSObject::kElementsOffset, array, x13, 346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch kLRHasBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET, 347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch OMIT_SMI_CHECK); 348b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Pop(lr); 349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&only_change_map); 351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); 352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, x13, 353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET, 354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch OMIT_SMI_CHECK); 355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochCodeAgingHelper::CodeAgingHelper() { 359b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength); 360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The sequence of instructions that is patched out for aging code is the 361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // following boilerplate stack-building prologue that is found both in 362b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // FUNCTION and OPTIMIZED_FUNCTION code: 363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch PatchingAssembler patcher(young_sequence_.start(), 364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch young_sequence_.length() / kInstructionSize); 365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The young sequence is the frame setup code for FUNCTION code types. It is 366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // generated by FullCodeGenerator::Generate. 367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher); 368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 369b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#ifdef DEBUG 370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch const int length = kCodeAgeStubEntryOffset / kInstructionSize; 371b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(old_sequence_.length() >= kCodeAgeStubEntryOffset); 372b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch PatchingAssembler patcher_old(old_sequence_.start(), length); 373b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch MacroAssembler::EmitCodeAgeSequence(&patcher_old, NULL); 374b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif 375b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 376b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 377b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 378b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#ifdef DEBUG 379b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochbool CodeAgingHelper::IsOld(byte* candidate) const { 380b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return memcmp(candidate, old_sequence_.start(), kCodeAgeStubEntryOffset) == 0; 381b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif 383b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochbool Code::IsYoungSequence(Isolate* isolate, byte* sequence) { 386b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return MacroAssembler::IsYoungSequence(isolate, sequence); 387b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 388b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 389b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 390b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age, 391b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch MarkingParity* parity) { 392b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (IsYoungSequence(isolate, sequence)) { 393b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *age = kNoAgeCodeAge; 394b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *parity = NO_MARKING_PARITY; 395b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 396b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch byte* target = sequence + kCodeAgeStubEntryOffset; 397b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Code* stub = GetCodeFromTargetAddress(Memory::Address_at(target)); 398b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch GetCodeAgeAndParity(stub, age, parity); 399b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 400b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 401b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 402b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 403b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Code::PatchPlatformCodeAge(Isolate* isolate, 404b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch byte* sequence, 405b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Code::Age age, 406b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch MarkingParity parity) { 407b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch PatchingAssembler patcher(sequence, 408b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch kNoCodeAgeSequenceLength / kInstructionSize); 409b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (age == kNoAgeCodeAge) { 410b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher); 411b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 412b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Code * stub = GetCodeAgeStub(isolate, age, parity); 413b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch MacroAssembler::EmitCodeAgeSequence(&patcher, stub); 414b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 415b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 416b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 417b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 418b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid StringCharLoadGenerator::Generate(MacroAssembler* masm, 419b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register string, 420b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register index, 421b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register result, 422b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label* call_runtime) { 423b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(string.Is64Bits() && index.Is32Bits() && result.Is64Bits()); 424b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Fetch the instance type of the receiver into result register. 425b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); 426b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); 427b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 428b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // We need special handling for indirect strings. 429b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label check_sequential; 430b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ TestAndBranchIfAllClear(result, kIsIndirectStringMask, &check_sequential); 431b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 432b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Dispatch on the indirect string shape: slice or cons. 433b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label cons_string; 434b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ TestAndBranchIfAllClear(result, kSlicedNotConsMask, &cons_string); 435b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 436b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Handle slices. 437b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label indirect_string_loaded; 438b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(result.W(), 439b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch UntagSmiFieldMemOperand(string, SlicedString::kOffsetOffset)); 440b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(string, FieldMemOperand(string, SlicedString::kParentOffset)); 441b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(index, index, result.W()); 442b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(&indirect_string_loaded); 443b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 444b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Handle cons strings. 445b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Check whether the right hand side is the empty string (i.e. if 446b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // this is really a flat string in a cons string). If that is not 447b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // the case we would rather go to the runtime system now to flatten 448b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // the string. 449b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&cons_string); 450b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(result, FieldMemOperand(string, ConsString::kSecondOffset)); 451b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ JumpIfNotRoot(result, Heap::kempty_stringRootIndex, call_runtime); 452b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Get the first of the two strings and load its instance type. 453b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(string, FieldMemOperand(string, ConsString::kFirstOffset)); 454b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 455b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&indirect_string_loaded); 456b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); 457b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); 458b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 459b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Distinguish sequential and external strings. Only these two string 460b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // representations can reach here (slices and flat cons strings have been 461b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // reduced to the underlying sequential or external string). 462b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label external_string, check_encoding; 463b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&check_sequential); 464b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch STATIC_ASSERT(kSeqStringTag == 0); 465b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ TestAndBranchIfAnySet(result, kStringRepresentationMask, &external_string); 466b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 467b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Prepare sequential strings 468b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); 469b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(string, string, SeqTwoByteString::kHeaderSize - kHeapObjectTag); 470b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(&check_encoding); 471b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 472b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Handle external strings. 473b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&external_string); 474b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (FLAG_debug_code) { 475b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Assert that we do not have a cons or slice (indirect strings) here. 476b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Sequential strings have already been ruled out. 477b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Tst(result, kIsIndirectStringMask); 478b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Assert(eq, kExternalStringExpectedButNotFound); 479b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 480b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Rule out short external strings. 481b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch STATIC_ASSERT(kShortExternalStringTag != 0); 482b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // TestAndBranchIfAnySet can emit Tbnz. Do not use it because call_runtime 483b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // can be bound far away in deferred code. 484b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Tst(result, kShortExternalStringMask); 485b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(ne, call_runtime); 486b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(string, FieldMemOperand(string, ExternalString::kResourceDataOffset)); 487b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 488b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label one_byte, done; 489b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&check_encoding); 490b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch STATIC_ASSERT(kTwoByteStringTag == 0); 491b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ TestAndBranchIfAnySet(result, kStringEncodingMask, &one_byte); 492b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Two-byte string. 493b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldrh(result, MemOperand(string, index, SXTW, 1)); 494b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(&done); 495b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&one_byte); 496b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // One-byte string. 497b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldrb(result, MemOperand(string, index, SXTW)); 498b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&done); 499b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 500b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 501b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 502b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic MemOperand ExpConstant(Register base, int index) { 503b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return MemOperand(base, index * kDoubleSize); 504b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 505b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 506b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 507b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid MathExpGenerator::EmitMathExp(MacroAssembler* masm, 508b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DoubleRegister input, 509b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DoubleRegister result, 510b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DoubleRegister double_temp1, 511b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DoubleRegister double_temp2, 512b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register temp1, 513b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register temp2, 514b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register temp3) { 515b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // TODO(jbramley): There are several instances where fnmsub could be used 516b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // instead of fmul and fsub. Doing this changes the result, but since this is 517b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // an estimation anyway, does it matter? 518b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 519b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!AreAliased(input, result, 520b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch double_temp1, double_temp2, 521b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch temp1, temp2, temp3)); 522b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(ExternalReference::math_exp_constants(0).address() != NULL); 523b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!masm->serializer_enabled()); // External references not serializable. 524b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 525b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label done; 526b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DoubleRegister double_temp3 = result; 527b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Register constants = temp3; 528b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 529b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The algorithm used relies on some magic constants which are initialized in 530b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // ExternalReference::InitializeMathExpData(). 531b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 532b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Load the address of the start of the array. 533b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Mov(constants, ExternalReference::math_exp_constants(0)); 534b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 535b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // We have to do a four-way split here: 536b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // - If input <= about -708.4, the output always rounds to zero. 537b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // - If input >= about 709.8, the output always rounds to +infinity. 538b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // - If the input is NaN, the output is NaN. 539b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // - Otherwise, the result needs to be calculated. 540b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label result_is_finite_non_zero; 541b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Assert that we can load offset 0 (the small input threshold) and offset 1 542b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // (the large input threshold) with a single ldp. 543b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(kDRegSize == (ExpConstant(constants, 1).offset() - 544b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ExpConstant(constants, 0).offset())); 545b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldp(double_temp1, double_temp2, ExpConstant(constants, 0)); 546b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 547b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fcmp(input, double_temp1); 548b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fccmp(input, double_temp2, NoFlag, hi); 549b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // At this point, the condition flags can be in one of five states: 550b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // NZCV 551b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // 1000 -708.4 < input < 709.8 result = exp(input) 552b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // 0110 input == 709.8 result = +infinity 553b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // 0010 input > 709.8 result = +infinity 554b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // 0011 input is NaN result = input 555b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // 0000 input <= -708.4 result = +0.0 556b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 557b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Continue the common case first. 'mi' tests N == 1. 558b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(&result_is_finite_non_zero, mi); 559b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 560b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // TODO(jbramley): Consider adding a +infinity register for ARM64. 561b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(double_temp2, ExpConstant(constants, 2)); // Synthesize +infinity. 562b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 563b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Select between +0.0 and +infinity. 'lo' tests C == 0. 564b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fcsel(result, fp_zero, double_temp2, lo); 565b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Select between {+0.0 or +infinity} and input. 'vc' tests V == 0. 566b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fcsel(result, result, input, vc); 567b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ B(&done); 568b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 569b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The rest is magic, as described in InitializeMathExpData(). 570b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&result_is_finite_non_zero); 571b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 572b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Assert that we can load offset 3 and offset 4 with a single ldp. 573b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(kDRegSize == (ExpConstant(constants, 4).offset() - 574b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ExpConstant(constants, 3).offset())); 575b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldp(double_temp1, double_temp3, ExpConstant(constants, 3)); 576b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fmadd(double_temp1, double_temp1, input, double_temp3); 577b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fmov(temp2.W(), double_temp1.S()); 578b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fsub(double_temp1, double_temp1, double_temp3); 579b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 580b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Assert that we can load offset 5 and offset 6 with a single ldp. 581b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(kDRegSize == (ExpConstant(constants, 6).offset() - 582b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ExpConstant(constants, 5).offset())); 583b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldp(double_temp2, double_temp3, ExpConstant(constants, 5)); 584b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // TODO(jbramley): Consider using Fnmsub here. 585b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fmul(double_temp1, double_temp1, double_temp2); 586b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fsub(double_temp1, double_temp1, input); 587b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 588b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fmul(double_temp2, double_temp1, double_temp1); 589b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fsub(double_temp3, double_temp3, double_temp1); 590b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fmul(double_temp3, double_temp3, double_temp2); 591b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 592b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Mov(temp1.W(), Operand(temp2.W(), LSR, 11)); 593b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 594b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldr(double_temp2, ExpConstant(constants, 7)); 595b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // TODO(jbramley): Consider using Fnmsub here. 596b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fmul(double_temp3, double_temp3, double_temp2); 597b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fsub(double_temp3, double_temp3, double_temp1); 598b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 599b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // The 8th constant is 1.0, so use an immediate move rather than a load. 600b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // We can't generate a runtime assertion here as we would need to call Abort 601b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // in the runtime and we don't have an Isolate when we generate this code. 602b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fmov(double_temp2, 1.0); 603b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fadd(double_temp3, double_temp3, double_temp2); 604b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 605b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ And(temp2, temp2, 0x7ff); 606b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(temp1, temp1, 0x3ff); 607b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 608b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Do the final table lookup. 609b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Mov(temp3, ExternalReference::math_exp_log_table()); 610b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 611b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Add(temp3, temp3, Operand(temp2, LSL, kDRegSizeLog2)); 612b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Ldp(temp2.W(), temp3.W(), MemOperand(temp3)); 613b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Orr(temp1.W(), temp3.W(), Operand(temp1.W(), LSL, 20)); 614b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bfi(temp2, temp1, 32, 32); 615b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fmov(double_temp1, temp2); 616b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 617b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Fmul(result, double_temp3, double_temp1); 618b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 619b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Bind(&done); 620b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 621b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 622b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#undef __ 623b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 624b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} } // namespace v8::internal 625b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 626b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif // V8_TARGET_ARCH_ARM64 627