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 18 UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) { 19 return nullptr; 20 } 21 22 23 // ------------------------------------------------------------------------- 24 // Platform-specific RuntimeCallHelper functions. 25 26 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 33 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 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 65 bool CodeAgingHelper::IsOld(byte* candidate) const { 66 return memcmp(candidate, old_sequence_.start(), kCodeAgeStubEntryOffset) == 0; 67 } 68 #endif 69 70 71 bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) { 72 return MacroAssembler::IsYoungSequence(isolate, sequence); 73 } 74 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 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 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