1// Copyright (c) 2014, 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 "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64.
6#if defined(TARGET_ARCH_ARM64)
7
8#include "vm/code_patcher.h"
9#include "vm/cpu.h"
10#include "vm/instructions.h"
11#include "vm/object.h"
12
13namespace dart {
14
15class PoolPointerCall : public ValueObject {
16 public:
17 PoolPointerCall(uword pc, const Code& code)
18 : end_(pc), object_pool_(ObjectPool::Handle(code.GetObjectPool())) {
19 // Last instruction: blr ip0.
20 ASSERT(*(reinterpret_cast<uint32_t*>(end_) - 1) == 0xd63f0200);
21 InstructionPattern::DecodeLoadWordFromPool(end_ - 2 * Instr::kInstrSize,
22 &reg_, &index_);
23 }
24
25 intptr_t pp_index() const { return index_; }
26
27 CodePtr Target() const {
28 return static_cast<CodePtr>(object_pool_.ObjectAt(pp_index()));
29 }
30
31 void SetTarget(const Code& target) const {
32 object_pool_.SetObjectAt(pp_index(), target);
33 // No need to flush the instruction cache, since the code is not modified.
34 }
35
36 private:
37 static const int kCallPatternSize = 3 * Instr::kInstrSize;
38 uword end_;
39 const ObjectPool& object_pool_;
40 Register reg_;
41 intptr_t index_;
42 DISALLOW_IMPLICIT_CONSTRUCTORS(PoolPointerCall);
43};
44
45CodePtr CodePatcher::GetStaticCallTargetAt(uword return_address,
46 const Code& code) {
47 ASSERT(code.ContainsInstructionAt(return_address));
48 PoolPointerCall call(return_address, code);
49 return call.Target();
50}
51
52void CodePatcher::PatchStaticCallAt(uword return_address,
53 const Code& code,
54 const Code& new_target) {
55 PatchPoolPointerCallAt(return_address, code, new_target);
56}
57
58void CodePatcher::PatchPoolPointerCallAt(uword return_address,
59 const Code& code,
60 const Code& new_target) {
61 ASSERT(code.ContainsInstructionAt(return_address));
62 PoolPointerCall call(return_address, code);
63 call.SetTarget(new_target);
64}
65
66void CodePatcher::InsertDeoptimizationCallAt(uword start) {
67 UNREACHABLE();
68}
69
70CodePtr CodePatcher::GetInstanceCallAt(uword return_address,
71 const Code& caller_code,
72 Object* data) {
73 ASSERT(caller_code.ContainsInstructionAt(return_address));
74 ICCallPattern call(return_address, caller_code);
75 if (data != NULL) {
76 *data = call.Data();
77 }
78 return call.TargetCode();
79}
80
81void CodePatcher::PatchInstanceCallAt(uword return_address,
82 const Code& caller_code,
83 const Object& data,
84 const Code& target) {
85 auto thread = Thread::Current();
86 thread->isolate_group()->RunWithStoppedMutators([&]() {
87 PatchInstanceCallAtWithMutatorsStopped(thread, return_address, caller_code,
88 data, target);
89 });
90}
91
92void CodePatcher::PatchInstanceCallAtWithMutatorsStopped(
93 Thread* thread,
94 uword return_address,
95 const Code& caller_code,
96 const Object& data,
97 const Code& target) {
98 ASSERT(caller_code.ContainsInstructionAt(return_address));
99 ICCallPattern call(return_address, caller_code);
100 call.SetData(data);
101 call.SetTargetCode(target);
102}
103
104FunctionPtr CodePatcher::GetUnoptimizedStaticCallAt(uword return_address,
105 const Code& code,
106 ICData* ic_data_result) {
107 ASSERT(code.ContainsInstructionAt(return_address));
108 ICCallPattern static_call(return_address, code);
109 ICData& ic_data = ICData::Handle();
110 ic_data ^= static_call.Data();
111 if (ic_data_result != NULL) {
112 *ic_data_result = ic_data.raw();
113 }
114 return ic_data.GetTargetAt(0);
115}
116
117void CodePatcher::PatchSwitchableCallAt(uword return_address,
118 const Code& caller_code,
119 const Object& data,
120 const Code& target) {
121 auto thread = Thread::Current();
122 // Ensure all threads are suspended as we update data and target pair.
123 thread->isolate_group()->RunWithStoppedMutators([&]() {
124 PatchSwitchableCallAtWithMutatorsStopped(thread, return_address,
125 caller_code, data, target);
126 });
127}
128
129void CodePatcher::PatchSwitchableCallAtWithMutatorsStopped(
130 Thread* thread,
131 uword return_address,
132 const Code& caller_code,
133 const Object& data,
134 const Code& target) {
135 ASSERT(caller_code.ContainsInstructionAt(return_address));
136 if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
137 BareSwitchableCallPattern call(return_address, caller_code);
138 call.SetData(data);
139 call.SetTarget(target);
140 } else {
141 SwitchableCallPattern call(return_address, caller_code);
142 call.SetData(data);
143 call.SetTarget(target);
144 }
145}
146
147CodePtr CodePatcher::GetSwitchableCallTargetAt(uword return_address,
148 const Code& caller_code) {
149 ASSERT(caller_code.ContainsInstructionAt(return_address));
150 if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
151 BareSwitchableCallPattern call(return_address, caller_code);
152 return call.target();
153 } else {
154 SwitchableCallPattern call(return_address, caller_code);
155 return call.target();
156 }
157}
158
159ObjectPtr CodePatcher::GetSwitchableCallDataAt(uword return_address,
160 const Code& caller_code) {
161 ASSERT(caller_code.ContainsInstructionAt(return_address));
162 if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
163 BareSwitchableCallPattern call(return_address, caller_code);
164 return call.data();
165 } else {
166 SwitchableCallPattern call(return_address, caller_code);
167 return call.data();
168 }
169}
170
171void CodePatcher::PatchNativeCallAt(uword return_address,
172 const Code& caller_code,
173 NativeFunction target,
174 const Code& trampoline) {
175 Thread::Current()->isolate_group()->RunWithStoppedMutators([&]() {
176 ASSERT(caller_code.ContainsInstructionAt(return_address));
177 NativeCallPattern call(return_address, caller_code);
178 call.set_target(trampoline);
179 call.set_native_function(target);
180 });
181}
182
183CodePtr CodePatcher::GetNativeCallAt(uword return_address,
184 const Code& caller_code,
185 NativeFunction* target) {
186 ASSERT(caller_code.ContainsInstructionAt(return_address));
187 NativeCallPattern call(return_address, caller_code);
188 *target = call.native_function();
189 return call.target();
190}
191
192} // namespace dart
193
194#endif // defined TARGET_ARCH_ARM64
195