1 | // Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "platform/globals.h" |
6 | |
7 | #if defined(TARGET_ARCH_ARM64) |
8 | |
9 | #include "vm/compiler/assembler/assembler.h" |
10 | #include "vm/compiler/runtime_api.h" |
11 | #include "vm/constants.h" |
12 | #include "vm/object.h" |
13 | #include "vm/stack_frame.h" |
14 | #include "vm/symbols.h" |
15 | |
16 | #define __ assembler-> |
17 | |
18 | namespace dart { |
19 | |
20 | void GenerateInvokeTTSStub(compiler::Assembler* assembler) { |
21 | __ EnterDartFrame(0); |
22 | |
23 | intptr_t sum = 0; |
24 | for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) { |
25 | if (((1 << i) & kDartAvailableCpuRegs) == 0) continue; |
26 | if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue; |
27 | if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue; |
28 | __ LoadImmediate(static_cast<Register>(i), 0x10 + 2 * i); |
29 | sum += 0x10 + 2 * i; |
30 | } |
31 | |
32 | // Load the arguments into the right TTS calling convention registers. |
33 | __ ldr(TypeTestABI::kInstanceReg, |
34 | compiler::Address( |
35 | FP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize)); |
36 | __ ldr(TypeTestABI::kInstantiatorTypeArgumentsReg, |
37 | compiler::Address( |
38 | FP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize)); |
39 | __ ldr(TypeTestABI::kFunctionTypeArgumentsReg, |
40 | compiler::Address( |
41 | FP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize)); |
42 | __ ldr(TypeTestABI::kDstTypeReg, |
43 | compiler::Address( |
44 | FP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize)); |
45 | |
46 | const intptr_t sub_type_cache_index = __ object_pool_builder().AddObject( |
47 | Object::null_object(), compiler::ObjectPoolBuilderEntry::kPatchable); |
48 | const intptr_t sub_type_cache_offset = |
49 | ObjectPool::element_offset(sub_type_cache_index); |
50 | const intptr_t dst_name_index = __ object_pool_builder().AddObject( |
51 | Symbols::OptimizedOut(), compiler::ObjectPoolBuilderEntry::kPatchable); |
52 | ASSERT((sub_type_cache_index + 1) == dst_name_index); |
53 | ASSERT(__ constant_pool_allowed()); |
54 | |
55 | // Call the TTS. |
56 | __ ldr(R9, compiler::FieldAddress( |
57 | TypeTestABI::kDstTypeReg, |
58 | AbstractType::type_test_stub_entry_point_offset())); |
59 | __ LoadWordFromPoolOffset(TypeTestABI::kSubtypeTestCacheReg, |
60 | sub_type_cache_offset); |
61 | __ blr(R9); |
62 | |
63 | // We have the guarantee that TTS preserve all registers except for one |
64 | // scratch register atm (if the TTS handles the type test successfully). |
65 | // |
66 | // Let the test know whether TTS abi registers were preserved. |
67 | compiler::Label abi_regs_modified, store_abi_regs_modified_bool; |
68 | __ CompareWithMemoryValue( |
69 | TypeTestABI::kInstanceReg, |
70 | compiler::Address( |
71 | FP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize)); |
72 | __ BranchIf(NOT_EQUAL, &abi_regs_modified); |
73 | __ CompareWithMemoryValue( |
74 | TypeTestABI::kInstantiatorTypeArgumentsReg, |
75 | compiler::Address( |
76 | FP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize)); |
77 | __ BranchIf(NOT_EQUAL, &abi_regs_modified); |
78 | __ CompareWithMemoryValue( |
79 | TypeTestABI::kFunctionTypeArgumentsReg, |
80 | compiler::Address( |
81 | FP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize)); |
82 | __ BranchIf(NOT_EQUAL, &abi_regs_modified); |
83 | __ CompareWithMemoryValue( |
84 | TypeTestABI::kDstTypeReg, |
85 | compiler::Address( |
86 | FP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize)); |
87 | __ BranchIf(NOT_EQUAL, &abi_regs_modified); |
88 | __ ldr(R0, compiler::Address(THR, Thread::bool_false_offset())); |
89 | __ b(&store_abi_regs_modified_bool); |
90 | __ Bind(&abi_regs_modified); |
91 | __ ldr(R0, compiler::Address(THR, Thread::bool_true_offset())); |
92 | __ Bind(&store_abi_regs_modified_bool); |
93 | __ ldr(TMP, compiler::Address( |
94 | FP, (kCallerSpSlotFromFp + 5) * compiler::target::kWordSize)); |
95 | __ str(R0, compiler::FieldAddress(TMP, Array::element_offset(0))); |
96 | |
97 | // Let the test know whether the non-TTS abi registers were preserved. |
98 | compiler::Label rest_regs_modified, store_rest_regs_modified_bool; |
99 | __ LoadImmediate(TMP, 0); |
100 | for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) { |
101 | if (((1 << i) & kDartAvailableCpuRegs) == 0) continue; |
102 | if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue; |
103 | if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue; |
104 | __ add(TMP, TMP, compiler::Operand(static_cast<Register>(i))); |
105 | } |
106 | __ cmp(TMP, compiler::Operand(sum)); |
107 | __ BranchIf(NOT_EQUAL, &rest_regs_modified); |
108 | __ ldr(R0, compiler::Address(THR, Thread::bool_false_offset())); |
109 | __ b(&store_rest_regs_modified_bool); |
110 | __ Bind(&rest_regs_modified); |
111 | __ ldr(R0, compiler::Address(THR, Thread::bool_true_offset())); |
112 | __ Bind(&store_rest_regs_modified_bool); |
113 | __ ldr(TMP, compiler::Address( |
114 | FP, (kCallerSpSlotFromFp + 4) * compiler::target::kWordSize)); |
115 | __ str(R0, compiler::FieldAddress(TMP, Array::element_offset(0))); |
116 | |
117 | __ LoadObject(R0, Object::null_object()); |
118 | __ LeaveDartFrame(); |
119 | __ Ret(); |
120 | } |
121 | |
122 | } // namespace dart |
123 | |
124 | #endif // defined(TARGET_ARCH_ARM64) |
125 | |