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
18namespace dart {
19
20void 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