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_ARM)
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
18namespace dart {
19
20void 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) - kHeapObjectTag;
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 __ ldr(TypeTestABI::kSubtypeTestCacheReg,
60 compiler::Address(PP, sub_type_cache_offset));
61 __ blx(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 __ mov(TMP, compiler::Operand(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 __ LeaveDartFrameAndReturn();
119}
120
121} // namespace dart
122
123#endif // defined(TARGET_ARCH_ARM)
124