1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/arm64/codegen-arm64.h"
6
7 #if V8_TARGET_ARCH_ARM64
8
9 #include "src/arm64/simulator-arm64.h"
10 #include "src/codegen.h"
11 #include "src/macro-assembler.h"
12
13 namespace v8 {
14 namespace internal {
15
16 #define __ ACCESS_MASM(masm)
17
CreateSqrtFunction(Isolate * isolate)18 UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
19 return nullptr;
20 }
21
22
23 // -------------------------------------------------------------------------
24 // Platform-specific RuntimeCallHelper functions.
25
BeforeCall(MacroAssembler * masm) const26 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
27 masm->EnterFrame(StackFrame::INTERNAL);
28 DCHECK(!masm->has_frame());
29 masm->set_has_frame(true);
30 }
31
32
AfterCall(MacroAssembler * masm) const33 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
34 masm->LeaveFrame(StackFrame::INTERNAL);
35 DCHECK(masm->has_frame());
36 masm->set_has_frame(false);
37 }
38
39
40 // -------------------------------------------------------------------------
41 // Code generators
42
CodeAgingHelper(Isolate * isolate)43 CodeAgingHelper::CodeAgingHelper(Isolate* isolate) {
44 USE(isolate);
45 DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength);
46 // The sequence of instructions that is patched out for aging code is the
47 // following boilerplate stack-building prologue that is found both in
48 // FUNCTION and OPTIMIZED_FUNCTION code:
49 PatchingAssembler patcher(isolate, young_sequence_.start(),
50 young_sequence_.length() / kInstructionSize);
51 // The young sequence is the frame setup code for FUNCTION code types. It is
52 // generated by FullCodeGenerator::Generate.
53 MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher);
54
55 #ifdef DEBUG
56 const int length = kCodeAgeStubEntryOffset / kInstructionSize;
57 DCHECK(old_sequence_.length() >= kCodeAgeStubEntryOffset);
58 PatchingAssembler patcher_old(isolate, old_sequence_.start(), length);
59 MacroAssembler::EmitCodeAgeSequence(&patcher_old, NULL);
60 #endif
61 }
62
63
64 #ifdef DEBUG
IsOld(byte * candidate) const65 bool CodeAgingHelper::IsOld(byte* candidate) const {
66 return memcmp(candidate, old_sequence_.start(), kCodeAgeStubEntryOffset) == 0;
67 }
68 #endif
69
70
IsYoungSequence(Isolate * isolate,byte * sequence)71 bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
72 return MacroAssembler::IsYoungSequence(isolate, sequence);
73 }
74
GetCodeAge(Isolate * isolate,byte * sequence)75 Code::Age Code::GetCodeAge(Isolate* isolate, byte* sequence) {
76 if (IsYoungSequence(isolate, sequence)) return kNoAgeCodeAge;
77
78 byte* target = sequence + kCodeAgeStubEntryOffset;
79 Code* stub = GetCodeFromTargetAddress(Memory::Address_at(target));
80 return GetAgeOfCodeAgeStub(stub);
81 }
82
PatchPlatformCodeAge(Isolate * isolate,byte * sequence,Code::Age age)83 void Code::PatchPlatformCodeAge(Isolate* isolate, byte* sequence,
84 Code::Age age) {
85 PatchingAssembler patcher(isolate, sequence,
86 kNoCodeAgeSequenceLength / kInstructionSize);
87 if (age == kNoAgeCodeAge) {
88 MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher);
89 } else {
90 Code* stub = GetCodeAgeStub(isolate, age);
91 MacroAssembler::EmitCodeAgeSequence(&patcher, stub);
92 }
93 }
94
95
Generate(MacroAssembler * masm,Register string,Register index,Register result,Label * call_runtime)96 void StringCharLoadGenerator::Generate(MacroAssembler* masm,
97 Register string,
98 Register index,
99 Register result,
100 Label* call_runtime) {
101 DCHECK(string.Is64Bits() && index.Is32Bits() && result.Is64Bits());
102 Label indirect_string_loaded;
103 __ Bind(&indirect_string_loaded);
104
105 // Fetch the instance type of the receiver into result register.
106 __ Ldr(result, FieldMemOperand(string, HeapObject::kMapOffset));
107 __ Ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
108
109 // We need special handling for indirect strings.
110 Label check_sequential;
111 __ TestAndBranchIfAllClear(result, kIsIndirectStringMask, &check_sequential);
112
113 // Dispatch on the indirect string shape: slice or cons.
114 Label cons_string, thin_string;
115 __ And(result, result, kStringRepresentationMask);
116 __ Cmp(result, kConsStringTag);
117 __ B(eq, &cons_string);
118 __ Cmp(result, kThinStringTag);
119 __ B(eq, &thin_string);
120
121 // Handle slices.
122 __ Ldr(result.W(),
123 UntagSmiFieldMemOperand(string, SlicedString::kOffsetOffset));
124 __ Ldr(string, FieldMemOperand(string, SlicedString::kParentOffset));
125 __ Add(index, index, result.W());
126 __ B(&indirect_string_loaded);
127
128 // Handle thin strings.
129 __ Bind(&thin_string);
130 __ Ldr(string, FieldMemOperand(string, ThinString::kActualOffset));
131 __ B(&indirect_string_loaded);
132
133 // Handle cons strings.
134 // Check whether the right hand side is the empty string (i.e. if
135 // this is really a flat string in a cons string). If that is not
136 // the case we would rather go to the runtime system now to flatten
137 // the string.
138 __ Bind(&cons_string);
139 __ Ldr(result, FieldMemOperand(string, ConsString::kSecondOffset));
140 __ JumpIfNotRoot(result, Heap::kempty_stringRootIndex, call_runtime);
141 // Get the first of the two strings and load its instance type.
142 __ Ldr(string, FieldMemOperand(string, ConsString::kFirstOffset));
143 __ B(&indirect_string_loaded);
144
145 // Distinguish sequential and external strings. Only these two string
146 // representations can reach here (slices and flat cons strings have been
147 // reduced to the underlying sequential or external string).
148 Label external_string, check_encoding;
149 __ Bind(&check_sequential);
150 STATIC_ASSERT(kSeqStringTag == 0);
151 __ TestAndBranchIfAnySet(result, kStringRepresentationMask, &external_string);
152
153 // Prepare sequential strings
154 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
155 __ Add(string, string, SeqTwoByteString::kHeaderSize - kHeapObjectTag);
156 __ B(&check_encoding);
157
158 // Handle external strings.
159 __ Bind(&external_string);
160 if (FLAG_debug_code) {
161 // Assert that we do not have a cons or slice (indirect strings) here.
162 // Sequential strings have already been ruled out.
163 __ Tst(result, kIsIndirectStringMask);
164 __ Assert(eq, kExternalStringExpectedButNotFound);
165 }
166 // Rule out short external strings.
167 STATIC_ASSERT(kShortExternalStringTag != 0);
168 // TestAndBranchIfAnySet can emit Tbnz. Do not use it because call_runtime
169 // can be bound far away in deferred code.
170 __ Tst(result, kShortExternalStringMask);
171 __ B(ne, call_runtime);
172 __ Ldr(string, FieldMemOperand(string, ExternalString::kResourceDataOffset));
173
174 Label one_byte, done;
175 __ Bind(&check_encoding);
176 STATIC_ASSERT(kTwoByteStringTag == 0);
177 __ TestAndBranchIfAnySet(result, kStringEncodingMask, &one_byte);
178 // Two-byte string.
179 __ Ldrh(result, MemOperand(string, index, SXTW, 1));
180 __ B(&done);
181 __ Bind(&one_byte);
182 // One-byte string.
183 __ Ldrb(result, MemOperand(string, index, SXTW));
184 __ Bind(&done);
185 }
186
187 #undef __
188
189 } // namespace internal
190 } // namespace v8
191
192 #endif // V8_TARGET_ARCH_ARM64
193