-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMode.h
216 lines (171 loc) · 7.53 KB
/
Mode.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#ifndef MODE_H
#define MODE_H
#include "align.h"
class Message;
class Effect;
class Mode {
public:
// (PC, FP, SP)
CodePntr pc;
Frame* frame;
uintptr_t* sp;
Mode(const char* name);
const char* get_name();
virtual const char* tag() = 0;
virtual void step() = 0;
virtual void* do_execute_method(Object* target_object, MethodBlock *mb, std::vector<uintptr_t>& jargs, DummyFrame* dummy) = 0;
virtual Frame* push_frame(Object* object, MethodBlock* new_mb, uintptr_t* args,
SpmtThread* caller, CodePntr caller_pc, Frame* caller_frame, uintptr_t* caller_sp,
bool is_top) = 0;
virtual void pop_frame(Frame* frame) = 0;
virtual void before_signal_exception(Class *exception_class) = 0;
virtual void before_alloc_object();
virtual void after_alloc_object(Object* obj);
virtual void process_msg(Message* msg);
virtual void send_msg(Message* msg);
// 参数用无模式方式读取
void invoke_impl(Object* target_object, MethodBlock* new_mb, uintptr_t* args,
SpmtThread* caller, CodePntr caller_pc, Frame* caller_frame, uintptr_t* caller_sp,
bool is_top);
void reset_context();
void set_st(SpmtThread* st);
template <class T> T read(T* addr);
template <class T, class U> void write(T* addr, U value);
void fetch_and_interpret_an_instruction();
void load_from_array(uintptr_t* sp, Object* array, int index, int type_size);
void store_to_array(uintptr_t* sp, Object* array, int index, int type_size);
void load_from_array_to_c(uintptr_t* sp, Object* array, int index, int type_size);
void store_to_array_from_c(uintptr_t* sp, Object* array, int index, int type_size);
protected:
SpmtThread* m_st;
private:
virtual void do_invoke_method(Object* objectref, MethodBlock* new_mb) = 0;
virtual void do_method_return(int len) = 0;
virtual void do_get_field(Object* obj, FieldBlock* fb, uintptr_t* addr, int size, bool is_static = false) = 0;
virtual void do_put_field(Object* obj, FieldBlock* fb, uintptr_t* addr, int size, bool is_static = false) = 0;
virtual void do_array_load(Object* array, int index, int type_size) = 0;
virtual void do_array_store(Object* array, int index, int type_size) = 0;
virtual uint32_t mode_read(uint32_t* addr) = 0;
virtual void mode_write(uint32_t* addr, uint32_t value) = 0;
virtual void do_spec_barrier() = 0;
const char* m_name;
};
// 因为mode_read和mode_write都是以4字节为单位读写。所以对于读取1或2字节
// 的数值,需要把包含这1或2个字节的4字节整个都读出来,然后再从其中找到
// 我们需要的那1或2个字节。对于写1或2个字节,需要先把包含这1或2个字节的
// 4字节数据整个读出来,然后只改动其中你要写的那1或2个字节,其余部分保
// 持不变,然后再把这改动后的4个字节写回去。aligned_base用来计算你要读
// 写的1或2个字节以4字节对齐的起始地址。addr_diff计算两个地址相差几个字
// 节。addr_add将地址加上几个字节的偏移。
// 读出1字节,无论如何这1字节都包含在作为整体读出的4个字节之中。然而,
// 读出2字节,可能你读出的4字节只包含了这2字节中的1字节,你还要再读一个
// 4字节,从中取出另一个1字节,然后将这两个1字节拼接起来。
// to factor: T的大小对模板进行特化,以避免运行时判断类型大小。
template <class T>
T
Mode::read(T* addr)
{
if (sizeof (T) >= sizeof (uint32_t)) {
assert(sizeof (T) == 4 || sizeof (T) == 8);
T v;
uint32_t* dst = reinterpret_cast<uint32_t*>(&v);
uint32_t* src = reinterpret_cast<uint32_t*>(addr);
for (size_t i = 0; i < sizeof (T) / sizeof (uint32_t); i++) {
//*dst++ = *src++;
*dst++ = mode_read(src++);
}
return v;
}
else if (sizeof (T) == 1) {
void* base = aligned_base(addr, sizeof (uint32_t));
//uint32_t v = *(uint32_t*)base;
uint32_t v = mode_read((uint32_t*)base);
v >>= addr_diff(addr, base) * 8;
return (T)v;
}
else if (sizeof (T) == 2) {
void* base = aligned_base(addr, sizeof (uint32_t));
//uint32_t v = *(uint32_t*)base;
uint32_t v = mode_read((uint32_t*)base);
v >>= addr_diff(addr, base) * 8;
ptrdiff_t offset = addr_diff(addr, base);
if (offset == 3) {
// 读出下一个4字节
//uint32_t v2 = *((uint32_t*)base + 1);
uint32_t v2 = mode_read((uint32_t*)base+1);
v2 <<= 8;
v2 &= 0xffff;
v |= v2;
}
return (T)v;
}
else {
assert(false);
}
}
// 对于写2字节,先读出4字节,如果要写的2字节完全包含在这4字节中,就改写
// 这4字节中的相应部分,然后将4字节写回。如果要写的2字节中的1字节在下一
// 个4字节中,那么再读出下一个4字节,改写其中的1字节,写回。
template <class T, class U>
void
Mode::write(T* addr, U value)
{
//assert(sizeof (T) <= sizeof (U));
if (sizeof (T) >= sizeof (uint32_t)) {
assert(sizeof (T) == 4 || sizeof (T) == 8);
T v = value;
uint32_t* dst = reinterpret_cast<uint32_t*>(addr);
uint32_t* src = reinterpret_cast<uint32_t*>(&v);
for (size_t i = 0; i < sizeof (T) / sizeof (uint32_t); i++) {
//*dst++ = *src++;
mode_write(dst++, *src++);
}
}
else if (sizeof (T) == 1) {
uint32_t* base = (uint32_t*)aligned_base(addr, sizeof (uint32_t));
//uint32_t v = *base;
uint32_t v = mode_read(base);
void* p = addr_add(&v, addr_diff(addr, base));
*(T*)p = value; // 改动4字节中的2字节(或其中1的字节)
//*base = v; // 写回
mode_write(base, v);
}
else if (sizeof (T) == 2) {
uint16_t val = value;
uint32_t* base = (uint32_t*)aligned_base(addr, sizeof (uint32_t));
//uint32_t v = *base; // 读出4字节
uint32_t v = mode_read(base);
void* p = addr_add(&v, addr_diff(addr, base)); // 要写的2字节在4字节中的位置
*(T*)p = val; // 改动4字节中的2字节(或其中1的字节)
//*base = v; // 写回
mode_write(base, v);
ptrdiff_t offset = addr_diff(addr, base);
if (offset == 3) {
//uint32_t v2 = *(base + 1); // 读出另一个4字节
uint32_t v2 = mode_read(base + 1);
v2 &= 0xffffff00;
val >>= 8;
v2 |= val;
//*(base+1) = v2; // 写回
mode_write(base+1, v2);
}
}
else {
assert(false);
}
}
void
g_load_from_stable_array_to_c(uintptr_t* sp, Object* array, int index, int type_size);
#define throw_exception \
return m_st->do_throw_exception();
void show_triple(std::ostream& os, int id,
Frame* frame, uintptr_t* sp, CodePntr pc, Object* user,
bool more = false);
void log_invoke_return(MiniLogger& logger, bool is_invoke, int id, const char* tag,
Object* caller, MethodBlock* caller_mb,
Object* callee, MethodBlock* callee_mb);
void
show_invoke_return(std::ostream& os, bool is_invoke, int id, const char* tag,
Object* caller, MethodBlock* caller_mb,
Object* callee, MethodBlock* callee_mb);
#endif // MODE_H