| // Copyright 2013 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/arm64/codegen-arm64.h" |
| |
| #if V8_TARGET_ARCH_ARM64 |
| |
| #include "src/arm64/assembler-arm64-inl.h" |
| #include "src/arm64/macro-assembler-arm64-inl.h" |
| #include "src/arm64/simulator-arm64.h" |
| #include "src/codegen.h" |
| #include "src/macro-assembler.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| #define __ ACCESS_MASM(masm) |
| |
| UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) { |
| return nullptr; |
| } |
| |
| |
| // ------------------------------------------------------------------------- |
| // Platform-specific RuntimeCallHelper functions. |
| |
| void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { |
| masm->EnterFrame(StackFrame::INTERNAL); |
| DCHECK(!masm->has_frame()); |
| masm->set_has_frame(true); |
| } |
| |
| |
| void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { |
| masm->LeaveFrame(StackFrame::INTERNAL); |
| DCHECK(masm->has_frame()); |
| masm->set_has_frame(false); |
| } |
| |
| |
| // ------------------------------------------------------------------------- |
| // Code generators |
| |
| CodeAgingHelper::CodeAgingHelper(Isolate* isolate) { |
| USE(isolate); |
| DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength); |
| // The sequence of instructions that is patched out for aging code is the |
| // following boilerplate stack-building prologue that is found both in |
| // FUNCTION and OPTIMIZED_FUNCTION code: |
| PatchingAssembler patcher(isolate, young_sequence_.start(), |
| young_sequence_.length() / kInstructionSize); |
| // The young sequence is the frame setup code for FUNCTION code types. It is |
| // generated by FullCodeGenerator::Generate. |
| MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher); |
| |
| #ifdef DEBUG |
| const int length = kCodeAgeStubEntryOffset / kInstructionSize; |
| DCHECK(old_sequence_.length() >= kCodeAgeStubEntryOffset); |
| PatchingAssembler patcher_old(isolate, old_sequence_.start(), length); |
| MacroAssembler::EmitCodeAgeSequence(&patcher_old, NULL); |
| #endif |
| } |
| |
| |
| #ifdef DEBUG |
| bool CodeAgingHelper::IsOld(byte* candidate) const { |
| return memcmp(candidate, old_sequence_.start(), kCodeAgeStubEntryOffset) == 0; |
| } |
| #endif |
| |
| |
| bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) { |
| return MacroAssembler::IsYoungSequence(isolate, sequence); |
| } |
| |
| Code::Age Code::GetCodeAge(Isolate* isolate, byte* sequence) { |
| if (IsYoungSequence(isolate, sequence)) return kNoAgeCodeAge; |
| |
| byte* target = sequence + kCodeAgeStubEntryOffset; |
| Code* stub = GetCodeFromTargetAddress(Memory::Address_at(target)); |
| return GetAgeOfCodeAgeStub(stub); |
| } |
| |
| void Code::PatchPlatformCodeAge(Isolate* isolate, byte* sequence, |
| Code::Age age) { |
| PatchingAssembler patcher(isolate, sequence, |
| kNoCodeAgeSequenceLength / kInstructionSize); |
| if (age == kNoAgeCodeAge) { |
| MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher); |
| } else { |
| Code* stub = GetCodeAgeStub(isolate, age); |
| MacroAssembler::EmitCodeAgeSequence(&patcher, stub); |
| } |
| } |
| |
| |
| void StringCharLoadGenerator::Generate(MacroAssembler* masm, |
| Register string, |
| Register index, |
| Register result, |
| Label* call_runtime) { |
| DCHECK(string.Is64Bits() && index.Is32Bits() && result.Is64Bits()); |
| Label indirect_string_loaded; |
| __ Bind(&indirect_string_loaded); |
| |
| // Fetch the instance type of the receiver into result register. |
| __ Ldr(result, FieldMemOperand(string, HeapObject::kMapOffset)); |
| __ Ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
| |
| // We need special handling for indirect strings. |
| Label check_sequential; |
| __ TestAndBranchIfAllClear(result, kIsIndirectStringMask, &check_sequential); |
| |
| // Dispatch on the indirect string shape: slice or cons. |
| Label cons_string, thin_string; |
| __ And(result, result, kStringRepresentationMask); |
| __ Cmp(result, kConsStringTag); |
| __ B(eq, &cons_string); |
| __ Cmp(result, kThinStringTag); |
| __ B(eq, &thin_string); |
| |
| // Handle slices. |
| __ Ldr(result.W(), |
| UntagSmiFieldMemOperand(string, SlicedString::kOffsetOffset)); |
| __ Ldr(string, FieldMemOperand(string, SlicedString::kParentOffset)); |
| __ Add(index, index, result.W()); |
| __ B(&indirect_string_loaded); |
| |
| // Handle thin strings. |
| __ Bind(&thin_string); |
| __ Ldr(string, FieldMemOperand(string, ThinString::kActualOffset)); |
| __ B(&indirect_string_loaded); |
| |
| // Handle cons strings. |
| // Check whether the right hand side is the empty string (i.e. if |
| // this is really a flat string in a cons string). If that is not |
| // the case we would rather go to the runtime system now to flatten |
| // the string. |
| __ Bind(&cons_string); |
| __ Ldr(result, FieldMemOperand(string, ConsString::kSecondOffset)); |
| __ JumpIfNotRoot(result, Heap::kempty_stringRootIndex, call_runtime); |
| // Get the first of the two strings and load its instance type. |
| __ Ldr(string, FieldMemOperand(string, ConsString::kFirstOffset)); |
| __ B(&indirect_string_loaded); |
| |
| // Distinguish sequential and external strings. Only these two string |
| // representations can reach here (slices and flat cons strings have been |
| // reduced to the underlying sequential or external string). |
| Label external_string, check_encoding; |
| __ Bind(&check_sequential); |
| STATIC_ASSERT(kSeqStringTag == 0); |
| __ TestAndBranchIfAnySet(result, kStringRepresentationMask, &external_string); |
| |
| // Prepare sequential strings |
| STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize); |
| __ Add(string, string, SeqTwoByteString::kHeaderSize - kHeapObjectTag); |
| __ B(&check_encoding); |
| |
| // Handle external strings. |
| __ Bind(&external_string); |
| if (FLAG_debug_code) { |
| // Assert that we do not have a cons or slice (indirect strings) here. |
| // Sequential strings have already been ruled out. |
| __ Tst(result, kIsIndirectStringMask); |
| __ Assert(eq, kExternalStringExpectedButNotFound); |
| } |
| // Rule out short external strings. |
| STATIC_ASSERT(kShortExternalStringTag != 0); |
| // TestAndBranchIfAnySet can emit Tbnz. Do not use it because call_runtime |
| // can be bound far away in deferred code. |
| __ Tst(result, kShortExternalStringMask); |
| __ B(ne, call_runtime); |
| __ Ldr(string, FieldMemOperand(string, ExternalString::kResourceDataOffset)); |
| |
| Label one_byte, done; |
| __ Bind(&check_encoding); |
| STATIC_ASSERT(kTwoByteStringTag == 0); |
| __ TestAndBranchIfAnySet(result, kStringEncodingMask, &one_byte); |
| // Two-byte string. |
| __ Ldrh(result, MemOperand(string, index, SXTW, 1)); |
| __ B(&done); |
| __ Bind(&one_byte); |
| // One-byte string. |
| __ Ldrb(result, MemOperand(string, index, SXTW)); |
| __ Bind(&done); |
| } |
| |
| #undef __ |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_TARGET_ARCH_ARM64 |