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