forked from rubinius/rubinius
-
Notifications
You must be signed in to change notification settings - Fork 0
/
instructions_util.hpp
131 lines (99 loc) · 3.18 KB
/
instructions_util.hpp
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
#ifndef RBX_INSTRUCTIONS_UTIL_HPP
#define RBX_INSTRUCTIONS_UTIL_HPP
#define SPECIFIC (static_cast<SubClass*>(this))
namespace rubinius {
template <class SubClass>
class VisitInstructions {
protected:
opcode* stream_;
int size_;
int next_ip_;
public:
void set_stream(opcode* stream, int size) {
stream_ = stream;
size_ = size;
}
void set_stream(VMMethod* vmm) {
set_stream(vmm->opcodes, vmm->total);
}
void visit(opcode code, opcode arg1, opcode arg2) { }
#define HANDLE_INST0(code, name) \
void visit_ ## name() { SPECIFIC->visit(code, -1, -1); }
#define HANDLE_INST1(code, name) \
void visit_ ## name(opcode arg1) { SPECIFIC->visit(code, arg1, -1); }
#define HANDLE_INST2(code, name) \
void visit_ ## name(opcode arg1, opcode arg2) { SPECIFIC->visit(code, arg1, arg2); }
#include "vm/gen/instruction_visitors.hpp"
#undef HANDLE_INST0
#undef HANDLE_INST1
#undef HANDLE_INST2
void at_ip(int ip) { }
bool before(opcode op, opcode arg1 = 0, opcode arg2 = 0) { return true; }
int dispatch(int ip) {
SPECIFIC->at_ip(ip);
switch(stream_[ip]) {
#define HANDLE_INST0(code, name) \
case code: \
next_ip_ = ip + 1; \
if(SPECIFIC->before(stream_[ip])) { \
SPECIFIC->visit_ ## name(); } return next_ip_;
#define HANDLE_INST1(code, name) \
case code: \
next_ip_ = ip + 2; \
if(SPECIFIC->before(stream_[ip], stream_[ip + 1])) { \
SPECIFIC->visit_ ## name(stream_[ip + 1]); } return next_ip_;
#define HANDLE_INST2(code, name) \
case code: \
next_ip_ = ip + 3; \
if(SPECIFIC->before(stream_[ip], stream_[ip + 1], stream_[ip + 2])) { \
SPECIFIC->visit_ ## name(stream_[ip + 1], stream_[ip + 2]); } return next_ip_;
#include "vm/gen/instruction_visitors.hpp"
#undef HANDLE_INST0
#undef HANDLE_INST1
#undef HANDLE_INST2
default:
abort();
return -1;
}
}
opcode next_op() {
if(next_ip_ >= size_) return 0;
return stream_[next_ip_];
}
opcode next_op_operand(size_t which) {
if(next_ip_ >= size_) return 0;
return stream_[next_ip_ + 1 + which];
}
static int opcode_size(opcode op) {
#undef HANDLE_INST0
#undef HANDLE_INST1
#undef HANDLE_INST2
switch(op) {
#define HANDLE_INST0(code, name) case code: return 1;
#define HANDLE_INST1(code, name) case code: return 2;
#define HANDLE_INST2(code, name) case code: return 3;
#include "vm/gen/instruction_visitors.hpp"
#undef HANDLE_INST0
#undef HANDLE_INST1
#undef HANDLE_INST2
}
return -1;
}
void skip_next_op() {
if(next_ip_ >= size_) return;
opcode op = stream_[next_ip_];
next_ip_ += opcode_size(op);
}
void drive(opcode* stream, int size, int start = 0) {
set_stream(stream, size);
int ip = start;
while(ip < size) {
ip = dispatch(ip);
}
}
void drive(VMMethod* vmm) {
drive(vmm->opcodes, vmm->total);
}
};
}
#endif