Flutter Engine
The Flutter Engine
code_patcher_ia32.cc
Go to the documentation of this file.
1// Copyright (c) 2012, 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_IA32.
6#if defined(TARGET_ARCH_IA32)
7
9#include "vm/code_patcher.h"
10#include "vm/cpu.h"
11#include "vm/dart_entry.h"
12#include "vm/instructions.h"
13#include "vm/object.h"
14#include "vm/raw_object.h"
15
16namespace dart {
17
18// The expected pattern of a Dart unoptimized call (static and instance):
19// mov ECX, ic-data
20// mov EDI, target-code-object
21// call target_address (stub)
22// <- return address
23class UnoptimizedCall : public ValueObject {
24 public:
25 UnoptimizedCall(uword return_address, const Code& code)
26 : code_(code), start_(return_address - kPatternSize) {
27 ASSERT(IsValid());
28 }
29
30 ObjectPtr ic_data() const {
31 return LoadUnaligned(reinterpret_cast<ObjectPtr*>(start_ + 1));
32 }
33
34 static constexpr int kMovInstructionSize = 5;
35 static constexpr int kCallInstructionSize = 3;
36 static constexpr int kPatternSize =
37 2 * kMovInstructionSize + kCallInstructionSize;
38
39 private:
40 bool IsValid() {
41 uint8_t* code_bytes = reinterpret_cast<uint8_t*>(start_);
42 return (code_bytes[0] == 0xB9) &&
43 (code_bytes[2 * kMovInstructionSize] == 0xFF);
44 }
45
46 uword return_address() const { return start_ + kPatternSize; }
47
48 uword call_address() const { return start_ + 2 * kMovInstructionSize; }
49
50 protected:
51 const Code& code_;
52 uword start_;
53
54 private:
55 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedCall);
56};
57
58class NativeCall : public UnoptimizedCall {
59 public:
60 NativeCall(uword return_address, const Code& code)
61 : UnoptimizedCall(return_address, code) {}
62
63 NativeFunction native_function() const {
64 return LoadUnaligned(reinterpret_cast<NativeFunction*>(start_ + 1));
65 }
66
67 void set_native_function(NativeFunction func) const {
69 WritableInstructionsScope writable(start_ + 1, sizeof(func));
70 StoreUnaligned(reinterpret_cast<NativeFunction*>(start_ + 1), func);
71 });
72 }
73
74 private:
76};
77
78// b9xxxxxxxx mov ecx,<data>
79// bfyyyyyyyy mov edi,<target>
80// ff5707 call [edi+<monomorphic-entry-offset>]
81class InstanceCall : public UnoptimizedCall {
82 public:
83 InstanceCall(uword return_address, const Code& code)
84 : UnoptimizedCall(return_address, code) {
85#if defined(DEBUG)
86 Object& test_data = Object::Handle(data());
87 ASSERT(test_data.IsArray() || test_data.IsICData() ||
88 test_data.IsMegamorphicCache());
89 if (test_data.IsICData()) {
90 ASSERT(ICData::Cast(test_data).NumArgsTested() > 0);
91 }
92#endif // DEBUG
93 }
94
95 ObjectPtr data() const {
96 return LoadUnaligned(reinterpret_cast<ObjectPtr*>(start_ + 1));
97 }
98 void set_data(const Object& data) const {
99 // N.B. The pointer is embedded in the Instructions object, but visited
100 // through the Code object.
101 code_.StorePointerUnaligned(reinterpret_cast<ObjectPtr*>(start_ + 1),
102 data.ptr(), Thread::Current());
103 }
104
105 CodePtr target() const {
106 return LoadUnaligned(reinterpret_cast<CodePtr*>(start_ + 6));
107 }
108 void set_target(const Code& target) const {
109 // N.B. The pointer is embedded in the Instructions object, but visited
110 // through the Code object.
111 code_.StorePointerUnaligned(reinterpret_cast<CodePtr*>(start_ + 6),
112 target.ptr(), Thread::Current());
113 }
114
115 private:
116 DISALLOW_IMPLICIT_CONSTRUCTORS(InstanceCall);
117};
118
119class UnoptimizedStaticCall : public UnoptimizedCall {
120 public:
121 UnoptimizedStaticCall(uword return_address, const Code& code)
122 : UnoptimizedCall(return_address, code) {
123#if defined(DEBUG)
124 ICData& test_ic_data = ICData::Handle();
125 test_ic_data ^= ic_data();
126 ASSERT(test_ic_data.NumArgsTested() >= 0);
127#endif // DEBUG
128 }
129
130 private:
131 DISALLOW_IMPLICIT_CONSTRUCTORS(UnoptimizedStaticCall);
132};
133
134// The expected pattern of a dart static call:
135// mov EDX, arguments_descriptor_array (optional in polymorphic calls)
136// mov EDI, Immediate(code_object)
137// call [EDI + entry_point_offset]
138// <- return address
139class StaticCall : public ValueObject {
140 public:
141 StaticCall(uword return_address, const Code& code)
142 : code_(code),
143 start_(return_address - (kMovInstructionSize + kCallInstructionSize)) {
144 ASSERT(IsValid());
145 }
146
147 bool IsValid() {
148 uint8_t* code_bytes = reinterpret_cast<uint8_t*>(start_);
149 return (code_bytes[0] == 0xBF) && (code_bytes[5] == 0xFF);
150 }
151
152 CodePtr target() const {
153 return LoadUnaligned(reinterpret_cast<CodePtr*>(start_ + 1));
154 }
155
156 void set_target(const Code& target) const {
157 // N.B. The pointer is embedded in the Instructions object, but visited
158 // through the Code object.
159 code_.StorePointerUnaligned(reinterpret_cast<CodePtr*>(start_ + 1),
160 target.ptr(), Thread::Current());
161 }
162
163 static constexpr int kMovInstructionSize = 5;
164 static constexpr int kCallInstructionSize = 3;
165
166 private:
167 uword return_address() const {
168 return start_ + kMovInstructionSize + kCallInstructionSize;
169 }
170
171 uword call_address() const { return start_ + kMovInstructionSize; }
172
173 const Code& code_;
174 uword start_;
175
177};
178
179CodePtr CodePatcher::GetStaticCallTargetAt(uword return_address,
180 const Code& code) {
181 ASSERT(code.ContainsInstructionAt(return_address));
182 StaticCall call(return_address, code);
183 return call.target();
184}
185
186void CodePatcher::PatchStaticCallAt(uword return_address,
187 const Code& code,
188 const Code& new_target) {
189 auto thread = Thread::Current();
190 auto zone = thread->zone();
191 const Instructions& instrs = Instructions::Handle(zone, code.instructions());
192 thread->isolate_group()->RunWithStoppedMutators([&]() {
193 WritableInstructionsScope writable(instrs.PayloadStart(), instrs.Size());
194 ASSERT(code.ContainsInstructionAt(return_address));
195 StaticCall call(return_address, code);
196 call.set_target(new_target);
197 });
198}
199
201 UNREACHABLE();
202}
203
204CodePtr CodePatcher::GetInstanceCallAt(uword return_address,
205 const Code& caller_code,
206 Object* data) {
207 ASSERT(caller_code.ContainsInstructionAt(return_address));
208 InstanceCall call(return_address, caller_code);
209 if (data != nullptr) {
210 *data = call.data();
211 }
212 return call.target();
213}
214
215void CodePatcher::PatchInstanceCallAt(uword return_address,
216 const Code& caller_code,
217 const Object& data,
218 const Code& target) {
219 auto thread = Thread::Current();
220 thread->isolate_group()->RunWithStoppedMutators([&]() {
221 PatchInstanceCallAtWithMutatorsStopped(thread, return_address, caller_code,
222 data, target);
223 });
224}
225
227 Thread* thread,
228 uword return_address,
229 const Code& caller_code,
230 const Object& data,
231 const Code& target) {
232 auto zone = thread->zone();
233 ASSERT(caller_code.ContainsInstructionAt(return_address));
234 const Instructions& instrs =
235 Instructions::Handle(zone, caller_code.instructions());
236 WritableInstructionsScope writable(instrs.PayloadStart(), instrs.Size());
237 InstanceCall call(return_address, caller_code);
238 call.set_data(data);
239 call.set_target(target);
240}
241
242FunctionPtr CodePatcher::GetUnoptimizedStaticCallAt(uword return_address,
243 const Code& caller_code,
244 ICData* ic_data_result) {
245 ASSERT(caller_code.ContainsInstructionAt(return_address));
246 UnoptimizedStaticCall static_call(return_address, caller_code);
247 ICData& ic_data = ICData::Handle();
248 ic_data ^= static_call.ic_data();
249 if (ic_data_result != nullptr) {
250 *ic_data_result = ic_data.ptr();
251 }
252 return ic_data.GetTargetAt(0);
253}
254
255void CodePatcher::PatchSwitchableCallAt(uword return_address,
256 const Code& caller_code,
257 const Object& data,
258 const Code& target) {
259 // Switchable instance calls only generated for precompilation.
260 UNREACHABLE();
261}
262
264 Thread* thread,
265 uword return_address,
266 const Code& caller_code,
267 const Object& data,
268 const Code& target) {
269 // Switchable instance calls only generated for precompilation.
270 UNREACHABLE();
271}
272
274 const Code& caller_code) {
275 // Switchable instance calls only generated for precompilation.
276 UNREACHABLE();
277 return 0;
278}
279
280ObjectPtr CodePatcher::GetSwitchableCallDataAt(uword return_address,
281 const Code& caller_code) {
282 // Switchable instance calls only generated for precompilation.
283 UNREACHABLE();
284 return Object::null();
285}
286
287void CodePatcher::PatchNativeCallAt(uword return_address,
288 const Code& caller_code,
290 const Code& trampoline) {
291 UNREACHABLE();
292}
293
294CodePtr CodePatcher::GetNativeCallAt(uword return_address,
295 const Code& caller_code,
297 UNREACHABLE();
298 return nullptr;
299}
300
301} // namespace dart
302
303#endif // defined TARGET_ARCH_IA32
#define UNREACHABLE()
Definition: assert.h:248
static void PatchInstanceCallAt(uword return_address, const Code &caller_code, const Object &data, const Code &target)
static CodePtr GetStaticCallTargetAt(uword return_address, const Code &code)
static void PatchSwitchableCallAtWithMutatorsStopped(Thread *thread, uword return_address, const Code &caller_code, const Object &data, const Code &target)
static void PatchInstanceCallAtWithMutatorsStopped(Thread *thread, uword return_address, const Code &caller_code, const Object &data, const Code &target)
static void PatchSwitchableCallAt(uword return_address, const Code &caller_code, const Object &data, const Code &target)
static FunctionPtr GetUnoptimizedStaticCallAt(uword return_address, const Code &code, ICData *ic_data)
static uword GetSwitchableCallTargetEntryAt(uword return_address, const Code &caller_code)
static ObjectPtr GetSwitchableCallDataAt(uword return_address, const Code &caller_code)
static void InsertDeoptimizationCallAt(uword start)
static CodePtr GetInstanceCallAt(uword return_address, const Code &caller_code, Object *data)
static CodePtr GetNativeCallAt(uword return_address, const Code &caller_code, NativeFunction *target)
static void PatchStaticCallAt(uword return_address, const Code &code, const Code &new_target)
static void PatchNativeCallAt(uword return_address, const Code &caller_code, NativeFunction target, const Code &trampoline)
void RunWithStoppedMutators(T single_current_mutator, S otherwise, bool use_force_growth_in_otherwise=false)
Definition: isolate.h:611
static ObjectPtr null()
Definition: object.h:433
static Object & Handle()
Definition: object.h:407
static Thread * Current()
Definition: thread.h:362
IsolateGroup * isolate_group() const
Definition: thread.h:541
#define ASSERT(E)
uint32_t * target
Definition: dart_vm.cc:33
uintptr_t uword
Definition: globals.h:501
static T LoadUnaligned(const T *ptr)
Definition: unaligned.h:14
static void StoreUnaligned(T *ptr, T value)
Definition: unaligned.h:22
static int8_t data[kExtLength]
void(* NativeFunction)(NativeArguments *arguments)
def call(args)
Definition: dom.py:159
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName)
Definition: globals.h:593