1 // Copyright 2012 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/x64/codegen-x64.h" 6 7 #if V8_TARGET_ARCH_X64 8 9 #include "src/codegen.h" 10 #include "src/macro-assembler.h" 11 #include "src/x64/assembler-x64-inl.h" 12 13 namespace v8 { 14 namespace internal { 15 16 // ------------------------------------------------------------------------- 17 // Platform-specific RuntimeCallHelper functions. 18 19 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { 20 masm->EnterFrame(StackFrame::INTERNAL); 21 DCHECK(!masm->has_frame()); 22 masm->set_has_frame(true); 23 } 24 25 26 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { 27 masm->LeaveFrame(StackFrame::INTERNAL); 28 DCHECK(masm->has_frame()); 29 masm->set_has_frame(false); 30 } 31 32 33 #define __ masm. 34 35 36 UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) { 37 size_t actual_size; 38 // Allocate buffer in executable space. 39 byte* buffer = 40 static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true)); 41 if (buffer == nullptr) return nullptr; 42 43 MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size), 44 CodeObjectRequired::kNo); 45 // xmm0: raw double input. 46 // Move double input into registers. 47 __ Sqrtsd(xmm0, xmm0); 48 __ Ret(); 49 50 CodeDesc desc; 51 masm.GetCode(&desc); 52 DCHECK(!RelocInfo::RequiresRelocation(desc)); 53 54 Assembler::FlushICache(isolate, buffer, actual_size); 55 base::OS::ProtectCode(buffer, actual_size); 56 return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer); 57 } 58 59 #undef __ 60 61 // ------------------------------------------------------------------------- 62 // Code generators 63 64 #define __ ACCESS_MASM(masm) 65 66 void StringCharLoadGenerator::Generate(MacroAssembler* masm, 67 Register string, 68 Register index, 69 Register result, 70 Label* call_runtime) { 71 Label indirect_string_loaded; 72 __ bind(&indirect_string_loaded); 73 74 // Fetch the instance type of the receiver into result register. 75 __ movp(result, FieldOperand(string, HeapObject::kMapOffset)); 76 __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); 77 78 // We need special handling for indirect strings. 79 Label check_sequential; 80 __ testb(result, Immediate(kIsIndirectStringMask)); 81 __ j(zero, &check_sequential, Label::kNear); 82 83 // Dispatch on the indirect string shape: slice or cons. 84 Label cons_string, thin_string; 85 __ andl(result, Immediate(kStringRepresentationMask)); 86 __ cmpl(result, Immediate(kConsStringTag)); 87 __ j(equal, &cons_string, Label::kNear); 88 __ cmpl(result, Immediate(kThinStringTag)); 89 __ j(equal, &thin_string, Label::kNear); 90 91 // Handle slices. 92 __ SmiToInteger32(result, FieldOperand(string, SlicedString::kOffsetOffset)); 93 __ addp(index, result); 94 __ movp(string, FieldOperand(string, SlicedString::kParentOffset)); 95 __ jmp(&indirect_string_loaded); 96 97 // Handle thin strings. 98 __ bind(&thin_string); 99 __ movp(string, FieldOperand(string, ThinString::kActualOffset)); 100 __ jmp(&indirect_string_loaded); 101 102 // Handle cons strings. 103 // Check whether the right hand side is the empty string (i.e. if 104 // this is really a flat string in a cons string). If that is not 105 // the case we would rather go to the runtime system now to flatten 106 // the string. 107 __ bind(&cons_string); 108 __ CompareRoot(FieldOperand(string, ConsString::kSecondOffset), 109 Heap::kempty_stringRootIndex); 110 __ j(not_equal, call_runtime); 111 __ movp(string, FieldOperand(string, ConsString::kFirstOffset)); 112 __ jmp(&indirect_string_loaded); 113 114 // Distinguish sequential and external strings. Only these two string 115 // representations can reach here (slices and flat cons strings have been 116 // reduced to the underlying sequential or external string). 117 Label seq_string; 118 __ bind(&check_sequential); 119 STATIC_ASSERT(kSeqStringTag == 0); 120 __ testb(result, Immediate(kStringRepresentationMask)); 121 __ j(zero, &seq_string, Label::kNear); 122 123 // Handle external strings. 124 Label one_byte_external, done; 125 if (FLAG_debug_code) { 126 // Assert that we do not have a cons or slice (indirect strings) here. 127 // Sequential strings have already been ruled out. 128 __ testb(result, Immediate(kIsIndirectStringMask)); 129 __ Assert(zero, kExternalStringExpectedButNotFound); 130 } 131 // Rule out short external strings. 132 STATIC_ASSERT(kShortExternalStringTag != 0); 133 __ testb(result, Immediate(kShortExternalStringTag)); 134 __ j(not_zero, call_runtime); 135 // Check encoding. 136 STATIC_ASSERT(kTwoByteStringTag == 0); 137 __ testb(result, Immediate(kStringEncodingMask)); 138 __ movp(result, FieldOperand(string, ExternalString::kResourceDataOffset)); 139 __ j(not_equal, &one_byte_external, Label::kNear); 140 // Two-byte string. 141 __ movzxwl(result, Operand(result, index, times_2, 0)); 142 __ jmp(&done, Label::kNear); 143 __ bind(&one_byte_external); 144 // One-byte string. 145 __ movzxbl(result, Operand(result, index, times_1, 0)); 146 __ jmp(&done, Label::kNear); 147 148 // Dispatch on the encoding: one-byte or two-byte. 149 Label one_byte; 150 __ bind(&seq_string); 151 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); 152 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 153 __ testb(result, Immediate(kStringEncodingMask)); 154 __ j(not_zero, &one_byte, Label::kNear); 155 156 // Two-byte string. 157 // Load the two-byte character code into the result register. 158 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); 159 __ movzxwl(result, FieldOperand(string, 160 index, 161 times_2, 162 SeqTwoByteString::kHeaderSize)); 163 __ jmp(&done, Label::kNear); 164 165 // One-byte string. 166 // Load the byte into the result register. 167 __ bind(&one_byte); 168 __ movzxbl(result, FieldOperand(string, 169 index, 170 times_1, 171 SeqOneByteString::kHeaderSize)); 172 __ bind(&done); 173 } 174 175 #undef __ 176 177 178 CodeAgingHelper::CodeAgingHelper(Isolate* isolate) { 179 USE(isolate); 180 DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength); 181 // The sequence of instructions that is patched out for aging code is the 182 // following boilerplate stack-building prologue that is found both in 183 // FUNCTION and OPTIMIZED_FUNCTION code: 184 CodePatcher patcher(isolate, young_sequence_.start(), 185 young_sequence_.length()); 186 patcher.masm()->pushq(rbp); 187 patcher.masm()->movp(rbp, rsp); 188 patcher.masm()->Push(rsi); 189 patcher.masm()->Push(rdi); 190 } 191 192 193 #ifdef DEBUG 194 bool CodeAgingHelper::IsOld(byte* candidate) const { 195 return *candidate == kCallOpcode; 196 } 197 #endif 198 199 200 bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) { 201 bool result = isolate->code_aging_helper()->IsYoung(sequence); 202 DCHECK(result || isolate->code_aging_helper()->IsOld(sequence)); 203 return result; 204 } 205 206 Code::Age Code::GetCodeAge(Isolate* isolate, byte* sequence) { 207 if (IsYoungSequence(isolate, sequence)) return kNoAgeCodeAge; 208 209 sequence++; // Skip the kCallOpcode byte 210 Address target_address = sequence + *reinterpret_cast<int*>(sequence) + 211 Assembler::kCallTargetAddressOffset; 212 Code* stub = GetCodeFromTargetAddress(target_address); 213 return GetAgeOfCodeAgeStub(stub); 214 } 215 216 void Code::PatchPlatformCodeAge(Isolate* isolate, byte* sequence, 217 Code::Age age) { 218 uint32_t young_length = isolate->code_aging_helper()->young_sequence_length(); 219 if (age == kNoAgeCodeAge) { 220 isolate->code_aging_helper()->CopyYoungSequenceTo(sequence); 221 Assembler::FlushICache(isolate, sequence, young_length); 222 } else { 223 Code* stub = GetCodeAgeStub(isolate, age); 224 CodePatcher patcher(isolate, sequence, young_length); 225 patcher.masm()->call(stub->instruction_start()); 226 patcher.masm()->Nop( 227 kNoCodeAgeSequenceLength - Assembler::kShortCallInstructionLength); 228 } 229 } 230 231 232 Operand StackArgumentsAccessor::GetArgumentOperand(int index) { 233 DCHECK(index >= 0); 234 int receiver = (receiver_mode_ == ARGUMENTS_CONTAIN_RECEIVER) ? 1 : 0; 235 int displacement_to_last_argument = base_reg_.is(rsp) ? 236 kPCOnStackSize : kFPOnStackSize + kPCOnStackSize; 237 displacement_to_last_argument += extra_displacement_to_last_argument_; 238 if (argument_count_reg_.is(no_reg)) { 239 // argument[0] is at base_reg_ + displacement_to_last_argument + 240 // (argument_count_immediate_ + receiver - 1) * kPointerSize. 241 DCHECK(argument_count_immediate_ + receiver > 0); 242 return Operand(base_reg_, displacement_to_last_argument + 243 (argument_count_immediate_ + receiver - 1 - index) * kPointerSize); 244 } else { 245 // argument[0] is at base_reg_ + displacement_to_last_argument + 246 // argument_count_reg_ * times_pointer_size + (receiver - 1) * kPointerSize. 247 return Operand(base_reg_, argument_count_reg_, times_pointer_size, 248 displacement_to_last_argument + (receiver - 1 - index) * kPointerSize); 249 } 250 } 251 252 253 } // namespace internal 254 } // namespace v8 255 256 #endif // V8_TARGET_ARCH_X64 257