6#if defined(TARGET_ARCH_X64)
20static const int16_t kCallPatternJIT[] = {
21 0x41, 0xff, 0x54, 0x24, -1,
25static const int16_t kCallPatternAOT[] = {
32static const intptr_t kLoadCodeFromPoolInstructionLength = 3;
33static const intptr_t kLoadCodeFromPoolDisp8PatternLength =
34 kLoadCodeFromPoolInstructionLength + 1;
35static const intptr_t kLoadCodeFromPoolDisp32PatternLength =
36 kLoadCodeFromPoolInstructionLength + 4;
40 kLoadCodeFromPoolDisp8JIT[kLoadCodeFromPoolDisp8PatternLength] = {
49 kLoadCodeFromPoolDisp32JIT[kLoadCodeFromPoolDisp32PatternLength] = {
50 0x4d, 0x8b, 0xa7, -1, -1, -1, -1,
55 kLoadCodeFromPoolDisp8AOT[kLoadCodeFromPoolDisp8PatternLength] = {
64 kLoadCodeFromPoolDisp32AOT[kLoadCodeFromPoolDisp32PatternLength] = {
65 0x4d, 0x8b, 0x9f, -1, -1, -1, -1,
68static void MatchCallPattern(
uword* pc) {
69 const int16_t* call_pattern =
70 FLAG_precompiled_mode ? kCallPatternAOT : kCallPatternJIT;
71 const intptr_t call_pattern_length = FLAG_precompiled_mode
77 *pc -= call_pattern_length;
79 FATAL(
"Expected `call [%s + offs]` at %" Px,
80 FLAG_precompiled_mode ?
"TMP" :
"CODE_REG", *pc);
84static void MatchCodeLoadFromPool(
uword* pc, intptr_t* code_index) {
85 const int16_t* load_code_disp8_pattern = FLAG_precompiled_mode
86 ? kLoadCodeFromPoolDisp8AOT
87 : kLoadCodeFromPoolDisp8JIT;
88 const int16_t* load_code_disp32_pattern = FLAG_precompiled_mode
89 ? kLoadCodeFromPoolDisp32AOT
90 : kLoadCodeFromPoolDisp32JIT;
93 kLoadCodeFromPoolDisp8PatternLength)) {
94 *pc -= kLoadCodeFromPoolDisp8PatternLength;
98 kLoadCodeFromPoolDisp32PatternLength)) {
99 *pc -= kLoadCodeFromPoolDisp32PatternLength;
103 FATAL(
"Expected `movq %s, [PP + imm8|imm32]` at %" Px,
104 FLAG_precompiled_mode ?
"TMP" :
"CODE_REG", *pc);
108class UnoptimizedCall :
public ValueObject {
110 UnoptimizedCall(
uword return_address,
const Code&
code)
111 : object_pool_(ObjectPool::Handle(
code.GetObjectPool())),
113 argument_index_(-1) {
114 uword pc = return_address;
116 MatchCallPattern(&pc);
117 MatchCodeLoadFromPool(&pc, &code_index_);
121 static int16_t load_argument_disp8[] = {
122 0x49, 0x8b, 0x5f, -1,
124 static int16_t load_argument_disp32[] = {
125 0x49, 0x8b, 0x9f, -1, -1, -1, -1,
136 FATAL(
"Failed to decode at %" Px, pc);
140 intptr_t argument_index()
const {
return argument_index_; }
144 code ^= object_pool_.ObjectAt(code_index_);
148 void set_target(
const Code&
target)
const {
149 object_pool_.SetObjectAt(code_index_,
target);
154 const ObjectPool& object_pool_;
155 intptr_t code_index_;
156 intptr_t argument_index_;
163class NativeCall :
public UnoptimizedCall {
165 NativeCall(
uword return_address,
const Code&
code)
166 : UnoptimizedCall(return_address,
code) {}
170 object_pool_.RawValueAt(argument_index()));
174 object_pool_.SetRawValueAt(argument_index(),
reinterpret_cast<uword>(func));
181class InstanceCall :
public UnoptimizedCall {
183 InstanceCall(
uword return_address,
const Code&
code)
184 : UnoptimizedCall(return_address,
code) {
187 ASSERT(test_data.IsArray() || test_data.IsICData() ||
188 test_data.IsMegamorphicCache());
189 if (test_data.IsICData()) {
190 ASSERT(ICData::Cast(test_data).NumArgsTested() > 0);
195 ObjectPtr
data()
const {
return object_pool_.ObjectAt(argument_index()); }
196 void set_data(
const Object&
data)
const {
198 object_pool_.SetObjectAt(argument_index(),
data);
205class UnoptimizedStaticCall :
public UnoptimizedCall {
207 UnoptimizedStaticCall(
uword return_address,
const Code& caller_code)
208 : UnoptimizedCall(return_address, caller_code) {
211 test_ic_data ^= ic_data();
212 ASSERT(test_ic_data.NumArgsTested() >= 0);
216 ObjectPtr ic_data()
const {
return object_pool_.ObjectAt(argument_index()); }
224class PoolPointerCall :
public ValueObject {
226 explicit PoolPointerCall(
uword return_address,
const Code& caller_code)
227 : object_pool_(ObjectPool::Handle(caller_code.GetObjectPool())),
229 uword pc = return_address;
231 MatchCallPattern(&pc);
232 MatchCodeLoadFromPool(&pc, &code_index_);
238 code ^= object_pool_.ObjectAt(code_index_);
242 void SetTarget(
const Code&
target)
const {
243 object_pool_.SetObjectAt(code_index_,
target);
248 const ObjectPool& object_pool_;
249 intptr_t code_index_;
260class SwitchableCallBase :
public ValueObject {
262 explicit SwitchableCallBase(
const ObjectPool& object_pool)
263 : object_pool_(object_pool), target_index_(-1), data_index_(-1) {}
265 intptr_t data_index()
const {
return data_index_; }
266 intptr_t target_index()
const {
return target_index_; }
268 ObjectPtr
data()
const {
return object_pool_.ObjectAt(data_index()); }
270 void SetData(
const Object&
data)
const {
272 object_pool_.SetObjectAt(data_index(),
data);
277 const ObjectPool& object_pool_;
278 intptr_t target_index_;
279 intptr_t data_index_;
289class SwitchableCall :
public SwitchableCallBase {
291 SwitchableCall(
uword return_address,
const Code& caller_code)
292 : SwitchableCallBase(ObjectPool::Handle(caller_code.GetObjectPool())) {
293 ASSERT(caller_code.ContainsInstructionAt(return_address));
294 uword pc = return_address;
297 static int16_t call_pattern[] = {
303 FATAL(
"Failed to decode at %" Px, pc);
307 static int16_t load_data_disp8[] = {
308 0x49, 0x8b, 0x5f, -1,
310 static int16_t load_data_disp32[] = {
311 0x49, 0x8b, 0x9f, -1, -1, -1, -1,
321 FATAL(
"Failed to decode at %" Px, pc);
326 static int16_t load_entry_pattern[] = {
327 0x49, 0x8b, 0x4c, 0x24, -1,
333 FATAL(
"Failed to decode at %" Px, pc);
337 static int16_t load_code_disp8[] = {
338 0x4d, 0x8b, 0x67, -1,
340 static int16_t load_code_disp32[] = {
341 0x4d, 0x8b, 0xa7, -1, -1, -1, -1,
351 FATAL(
"Failed to decode at %" Px, pc);
356 void SetTarget(
const Code&
target)
const {
358 object_pool_.SetObjectAt(target_index(),
target);
362 uword target_entry()
const {
364 .MonomorphicEntryPoint();
372class BareSwitchableCall :
public SwitchableCallBase {
374 explicit BareSwitchableCall(
uword return_address)
375 : SwitchableCallBase(ObjectPool::Handle(
376 IsolateGroup::Current()->object_store()->global_object_pool())) {
377 uword pc = return_address;
380 static int16_t call_pattern[] = {
386 FATAL(
"Failed to decode at %" Px, pc);
390 static int16_t load_data_disp8[] = {
391 0x49, 0x8b, 0x5f, -1,
393 static int16_t load_data_disp32[] = {
394 0x49, 0x8b, 0x9f, -1, -1, -1, -1,
404 FATAL(
"Failed to decode at %" Px, pc);
409 static int16_t load_code_disp8[] = {
410 0x49, 0x8b, 0x4f, -1,
412 static int16_t load_code_disp32[] = {
413 0x49, 0x8b, 0x8f, -1, -1, -1, -1,
423 FATAL(
"Failed to decode at %" Px, pc);
425 ASSERT(object_pool_.TypeAt(target_index_) ==
426 ObjectPool::EntryType::kImmediate);
429 void SetTarget(
const Code&
target)
const {
430 ASSERT(object_pool_.TypeAt(target_index()) ==
431 ObjectPool::EntryType::kImmediate);
432 object_pool_.SetRawValueAt(target_index(),
target.MonomorphicEntryPoint());
435 uword target_entry()
const {
return object_pool_.RawValueAt(target_index()); }
440 ASSERT(
code.ContainsInstructionAt(return_address));
441 PoolPointerCall
call(return_address,
code);
442 return call.Target();
447 const Code& new_target) {
453 const Code& new_target) {
454 ASSERT(
code.ContainsInstructionAt(return_address));
455 PoolPointerCall
call(return_address,
code);
456 call.SetTarget(new_target);
460 const Code& caller_code,
462 ASSERT(caller_code.ContainsInstructionAt(return_address));
463 InstanceCall
call(return_address, caller_code);
464 if (
data !=
nullptr) {
467 return call.target();
471 const Code& caller_code,
475 thread->isolate_group()->RunWithStoppedMutators([&]() {
483 uword return_address,
484 const Code& caller_code,
487 ASSERT(caller_code.ContainsInstructionAt(return_address));
488 InstanceCall
call(return_address, caller_code);
498 const Code& caller_code,
499 ICData* ic_data_result) {
500 ASSERT(caller_code.ContainsInstructionAt(return_address));
501 UnoptimizedStaticCall static_call(return_address, caller_code);
503 ic_data ^= static_call.ic_data();
504 if (ic_data_result !=
nullptr) {
505 *ic_data_result = ic_data.ptr();
507 return ic_data.GetTargetAt(0);
511 const Code& caller_code,
516 thread->isolate_group()->RunWithStoppedMutators([&]() {
524 uword return_address,
525 const Code& caller_code,
528 if (FLAG_precompiled_mode) {
529 BareSwitchableCall
call(return_address);
533 SwitchableCall
call(return_address, caller_code);
540 const Code& caller_code) {
541 if (FLAG_precompiled_mode) {
542 BareSwitchableCall
call(return_address);
543 return call.target_entry();
545 SwitchableCall
call(return_address, caller_code);
546 return call.target_entry();
551 const Code& caller_code) {
552 if (FLAG_precompiled_mode) {
553 BareSwitchableCall
call(return_address);
556 SwitchableCall
call(return_address, caller_code);
562 const Code& caller_code,
564 const Code& trampoline) {
566 ASSERT(caller_code.ContainsInstructionAt(return_address));
567 NativeCall
call(return_address, caller_code);
568 call.set_target(trampoline);
574 const Code& caller_code,
576 ASSERT(caller_code.ContainsInstructionAt(return_address));
577 NativeCall
call(return_address, caller_code);
579 return call.target();
static void PatchInstanceCallAt(uword return_address, const Code &caller_code, const Object &data, const Code &target)
static void PatchPoolPointerCallAt(uword return_address, const Code &code, const Code &new_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)
static ObjectPtr RawCast(ObjectPtr obj)
static Thread * Current()
IsolateGroup * isolate_group() const
bool MatchesPattern(uword end, const int16_t *pattern, intptr_t size)
intptr_t IndexFromPPLoadDisp32(uword start)
static int8_t data[kExtLength]
void(* NativeFunction)(NativeArguments *arguments)
intptr_t IndexFromPPLoadDisp8(uword start)
#define ARRAY_SIZE(array)