Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
code_patcher_riscv.cc
Go to the documentation of this file.
1// Copyright (c) 2021, 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_RISCV.
6#if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
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 ASSERT(*reinterpret_cast<uint16_t*>(end_ - 2) == 0x9082); // jalr ra
20 uint32_t load_entry = LoadUnaligned(reinterpret_cast<uint32_t*>(end_ - 6));
21#if XLEN == 32
22 ASSERT((load_entry == 0x00362083) || // lw ra, entry(code)
23 (load_entry == 0x00b62083)); // lw ra, unchecked_entry(code)
24#elif XLEN == 64
25 ASSERT((load_entry == 0x00763083) || // ld ra, entry(code)
26 (load_entry = 0x01763083)); // ld ra, unchecked_entry(code)
27#endif
28 InstructionPattern::DecodeLoadWordFromPool(end_ - 6, &reg_, &index_);
29 }
30
31 intptr_t pp_index() const { return index_; }
32
33 CodePtr Target() const {
34 return static_cast<CodePtr>(object_pool_.ObjectAt(pp_index()));
35 }
36
37 void SetTarget(const Code& target) const {
38 object_pool_.SetObjectAt(pp_index(), target);
39 // No need to flush the instruction cache, since the code is not modified.
40 }
41
42 private:
43 uword end_;
44 const ObjectPool& object_pool_;
45 Register reg_;
46 intptr_t index_;
47 DISALLOW_IMPLICIT_CONSTRUCTORS(PoolPointerCall);
48};
49
50CodePtr CodePatcher::GetStaticCallTargetAt(uword return_address,
51 const Code& code) {
52 ASSERT(code.ContainsInstructionAt(return_address));
53 PoolPointerCall call(return_address, code);
54 return call.Target();
55}
56
57void CodePatcher::PatchStaticCallAt(uword return_address,
58 const Code& code,
59 const Code& new_target) {
60 PatchPoolPointerCallAt(return_address, code, new_target);
61}
62
64 const Code& code,
65 const Code& new_target) {
66 ASSERT(code.ContainsInstructionAt(return_address));
67 PoolPointerCall call(return_address, code);
68 call.SetTarget(new_target);
69}
70
73}
74
75CodePtr CodePatcher::GetInstanceCallAt(uword return_address,
76 const Code& caller_code,
77 Object* data) {
78 ASSERT(caller_code.ContainsInstructionAt(return_address));
79 ICCallPattern call(return_address, caller_code);
80 if (data != nullptr) {
81 *data = call.Data();
82 }
83 return call.TargetCode();
84}
85
86void CodePatcher::PatchInstanceCallAt(uword return_address,
87 const Code& caller_code,
88 const Object& data,
89 const Code& target) {
90 auto thread = Thread::Current();
91 thread->isolate_group()->RunWithStoppedMutators([&]() {
92 PatchInstanceCallAtWithMutatorsStopped(thread, return_address, caller_code,
93 data, target);
94 });
95}
96
98 Thread* thread,
99 uword return_address,
100 const Code& caller_code,
101 const Object& data,
102 const Code& target) {
103 ASSERT(caller_code.ContainsInstructionAt(return_address));
104 ICCallPattern call(return_address, caller_code);
105 call.SetData(data);
106 call.SetTargetCode(target);
107}
108
109FunctionPtr CodePatcher::GetUnoptimizedStaticCallAt(uword return_address,
110 const Code& code,
111 ICData* ic_data_result) {
112 ASSERT(code.ContainsInstructionAt(return_address));
113 ICCallPattern static_call(return_address, code);
114 ICData& ic_data = ICData::Handle();
115 ic_data ^= static_call.Data();
116 if (ic_data_result != nullptr) {
117 *ic_data_result = ic_data.ptr();
118 }
119 return ic_data.GetTargetAt(0);
120}
121
122void CodePatcher::PatchSwitchableCallAt(uword return_address,
123 const Code& caller_code,
124 const Object& data,
125 const Code& target) {
126 auto thread = Thread::Current();
127 // Ensure all threads are suspended as we update data and target pair.
128 thread->isolate_group()->RunWithStoppedMutators([&]() {
129 PatchSwitchableCallAtWithMutatorsStopped(thread, return_address,
130 caller_code, data, target);
131 });
132}
133
135 Thread* thread,
136 uword return_address,
137 const Code& caller_code,
138 const Object& data,
139 const Code& target) {
140 if (FLAG_precompiled_mode) {
141 BareSwitchableCallPattern call(return_address);
142 call.SetData(data);
143 call.SetTarget(target);
144 } else {
145 SwitchableCallPattern call(return_address, caller_code);
146 call.SetData(data);
147 call.SetTarget(target);
148 }
149}
150
152 const Code& caller_code) {
153 if (FLAG_precompiled_mode) {
154 BareSwitchableCallPattern call(return_address);
155 return call.target_entry();
156 } else {
157 SwitchableCallPattern call(return_address, caller_code);
158 return call.target_entry();
159 }
160}
161
162ObjectPtr CodePatcher::GetSwitchableCallDataAt(uword return_address,
163 const Code& caller_code) {
164 if (FLAG_precompiled_mode) {
165 BareSwitchableCallPattern call(return_address);
166 return call.data();
167 } else {
168 SwitchableCallPattern call(return_address, caller_code);
169 return call.data();
170 }
171}
172
173void CodePatcher::PatchNativeCallAt(uword return_address,
174 const Code& caller_code,
176 const Code& trampoline) {
178 ASSERT(caller_code.ContainsInstructionAt(return_address));
179 NativeCallPattern call(return_address, caller_code);
180 call.set_target(trampoline);
181 call.set_native_function(target);
182 });
183}
184
185CodePtr CodePatcher::GetNativeCallAt(uword return_address,
186 const Code& caller_code,
188 ASSERT(caller_code.ContainsInstructionAt(return_address));
189 NativeCallPattern call(return_address, caller_code);
190 *target = call.native_function();
191 return call.target();
192}
193
194} // namespace dart
195
196#endif // defined TARGET_ARCH_RISCV
#define UNREACHABLE()
Definition assert.h:248
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)
Definition isolate.h:604
static Object & Handle()
Definition object.h:407
static Thread * Current()
Definition thread.h:361
IsolateGroup * isolate_group() const
Definition thread.h:540
#define ASSERT(E)
uint32_t * target
uintptr_t uword
Definition globals.h:501
static int8_t data[kExtLength]
void(* NativeFunction)(NativeArguments *arguments)
call(args)
Definition dom.py:159
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName)
Definition globals.h:593