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_X64) |
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 | intptr_t sum = 0; |
23 | for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) { |
24 | if (((1 << i) & kDartAvailableCpuRegs) == 0) continue; |
25 | if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue; |
26 | if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue; |
27 | __ movq(static_cast<Register>(i), compiler::Immediate(0x10 + 2 * i)); |
28 | sum += 0x10 + 2 * i; |
29 | } |
30 | |
31 | // Load the arguments into the right TTS calling convention registers. |
32 | __ movq(TypeTestABI::kInstanceReg, |
33 | compiler::Address( |
34 | RBP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize)); |
35 | __ movq(TypeTestABI::kInstantiatorTypeArgumentsReg, |
36 | compiler::Address( |
37 | RBP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize)); |
38 | __ movq(TypeTestABI::kFunctionTypeArgumentsReg, |
39 | compiler::Address( |
40 | RBP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize)); |
41 | __ movq(TypeTestABI::kDstTypeReg, |
42 | compiler::Address( |
43 | RBP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize)); |
44 | |
45 | const intptr_t sub_type_cache_index = __ object_pool_builder().AddObject( |
46 | Object::null_object(), compiler::ObjectPoolBuilderEntry::kPatchable); |
47 | const intptr_t sub_type_cache_offset = |
48 | ObjectPool::element_offset(sub_type_cache_index) - kHeapObjectTag; |
49 | const intptr_t dst_name_index = __ object_pool_builder().AddObject( |
50 | Symbols::OptimizedOut(), compiler::ObjectPoolBuilderEntry::kPatchable); |
51 | ASSERT((sub_type_cache_index + 1) == dst_name_index); |
52 | ASSERT(__ constant_pool_allowed()); |
53 | |
54 | // Call the TTS. |
55 | __ movq(TypeTestABI::kSubtypeTestCacheReg, |
56 | compiler::Address(PP, sub_type_cache_offset)); |
57 | __ call(compiler::FieldAddress( |
58 | TypeTestABI::kDstTypeReg, |
59 | AbstractType::type_test_stub_entry_point_offset())); |
60 | |
61 | // We have the guarantee that TTS preserve all registers except for one |
62 | // scratch register atm (if the TTS handles the type test successfully). |
63 | // |
64 | // Let the test know whether TTS abi registers were preserved. |
65 | compiler::Label abi_regs_modified, store_abi_regs_modified_bool; |
66 | __ cmpq(TypeTestABI::kInstanceReg, |
67 | compiler::Address( |
68 | RBP, (kCallerSpSlotFromFp + 3) * compiler::target::kWordSize)); |
69 | __ BranchIf(NOT_EQUAL, &abi_regs_modified); |
70 | __ cmpq(TypeTestABI::kInstantiatorTypeArgumentsReg, |
71 | compiler::Address( |
72 | RBP, (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize)); |
73 | __ BranchIf(NOT_EQUAL, &abi_regs_modified); |
74 | __ cmpq(TypeTestABI::kFunctionTypeArgumentsReg, |
75 | compiler::Address( |
76 | RBP, (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize)); |
77 | __ BranchIf(NOT_EQUAL, &abi_regs_modified); |
78 | __ cmpq(TypeTestABI::kDstTypeReg, |
79 | compiler::Address( |
80 | RBP, (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize)); |
81 | __ BranchIf(NOT_EQUAL, &abi_regs_modified); |
82 | __ movq(RAX, compiler::Address(THR, Thread::bool_false_offset())); |
83 | __ jmp(&store_abi_regs_modified_bool); |
84 | __ Bind(&abi_regs_modified); |
85 | __ movq(RAX, compiler::Address(THR, Thread::bool_true_offset())); |
86 | __ Bind(&store_abi_regs_modified_bool); |
87 | __ movq(TMP, compiler::Address(RBP, (kCallerSpSlotFromFp + 5) * |
88 | compiler::target::kWordSize)); |
89 | __ movq(compiler::FieldAddress(TMP, Array::element_offset(0)), RAX); |
90 | |
91 | // Let the test know whether the non-TTS abi registers were preserved. |
92 | compiler::Label rest_regs_modified, store_rest_regs_modified_bool; |
93 | __ movq(TMP, compiler::Immediate(0)); |
94 | for (intptr_t i = 0; i < kNumberOfCpuRegisters; ++i) { |
95 | if (((1 << i) & kDartAvailableCpuRegs) == 0) continue; |
96 | if (((1 << i) & TypeTestABI::kAbiRegisters) != 0) continue; |
97 | if (((1 << i) & TTSInternalRegs::kInternalRegisters) != 0) continue; |
98 | __ addq(TMP, static_cast<Register>(i)); |
99 | } |
100 | __ cmpq(TMP, compiler::Immediate(sum)); |
101 | __ BranchIf(NOT_EQUAL, &rest_regs_modified); |
102 | __ movq(RAX, compiler::Address(THR, Thread::bool_false_offset())); |
103 | __ jmp(&store_rest_regs_modified_bool); |
104 | __ Bind(&rest_regs_modified); |
105 | __ movq(RAX, compiler::Address(THR, Thread::bool_true_offset())); |
106 | __ Bind(&store_rest_regs_modified_bool); |
107 | __ movq(TMP, compiler::Address(RBP, (kCallerSpSlotFromFp + 4) * |
108 | compiler::target::kWordSize)); |
109 | __ movq(compiler::FieldAddress(TMP, Array::element_offset(0)), RAX); |
110 | |
111 | __ LoadObject(RAX, Object::null_object()); |
112 | __ LeaveDartFrame(); |
113 | __ Ret(); |
114 | } |
115 | |
116 | } // namespace dart |
117 | |
118 | #endif // defined(TARGET_ARCH_X64) |
119 | |