Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 314 lines (272 sloc) 7.706 kB
e29c2ec now interpreting potential cold paths (work in progress)
Laurent Sansonetti authored
1 /*
2 * MacRuby Interpreter.
3 *
4 * This file is covered by the Ruby license. See COPYING for more details.
7d7d3e8 @ferrous26 Change ownership to The MacRuby Team and update copyrights
ferrous26 authored
5 *
6 * Copyright (C) 2012, The MacRuby Team. All rights reserved.
9595725 update copyrights to 2011
Laurent Sansonetti authored
7 * Copyright (C) 2008-2011, Apple Inc. All rights reserved.
e29c2ec now interpreting potential cold paths (work in progress)
Laurent Sansonetti authored
8 */
9
a6a5d3e started to trim out the static library
Laurent Sansonetti authored
10 #if !defined(MACRUBY_STATIC)
11
e29c2ec now interpreting potential cold paths (work in progress)
Laurent Sansonetti authored
12 #include "llvm.h"
d0898dd include/ruby/macruby.h -> macruby_internal.h
Laurent Sansonetti authored
13 #include "macruby_internal.h"
e29c2ec now interpreting potential cold paths (work in progress)
Laurent Sansonetti authored
14 #include "ruby/node.h"
15 #include "interpreter.h"
16 #include "vm.h"
17
18 #define PRIMITIVE static inline
19 #include "kernel.c"
20
21 // Will be set later, in vm.cpp.
22 RoxorInterpreter *RoxorInterpreter::shared = NULL;
23
24 RoxorInterpreter::RoxorInterpreter(void)
25 {
26 stack = (VALUE *)calloc(INTERPRETER_STACK_SIZE, sizeof(VALUE));
27 assert(stack != NULL);
28 }
29
30 RoxorInterpreter::~RoxorInterpreter(void)
31 {
32 free(stack);
33 }
34
35 extern "C" void rb_vm_prepare_method(Class klass, unsigned char dynamic_class,
36 SEL sel, Function *func, const rb_vm_arity_t arity, int flags);
37
38 #define value_as(val, type) ((type)interpret_value(val))
39
40 static inline Value *
41 call_arg(CallInst *insn, unsigned int i)
42 {
fc537f2 move to llvm 2.8
Laurent Sansonetti authored
43 #if LLVM_TOT
e29c2ec now interpreting potential cold paths (work in progress)
Laurent Sansonetti authored
44 return insn->getOperand(i + 1);
fc537f2 move to llvm 2.8
Laurent Sansonetti authored
45 #else
46 return insn->getArgOperand(i);
47 #endif
e29c2ec now interpreting potential cold paths (work in progress)
Laurent Sansonetti authored
48 }
49
50 static inline uint64_t
51 get_const_int(Value *val)
52 {
53 return cast<ConstantInt>(val)->getZExtValue();
54 }
55
56 // A macro to avoid stupid compiler warnings.
57 #define oops(msg, val) \
58 printf("interpreter: %s (ID: %d)\n", msg, val->getValueID()); \
59 val->dump(); \
60 abort();
61
62 VALUE
63 RoxorInterpreter::interpret_call(CallInst *call)
64 {
65 Function *called = call->getCalledFunction();
66
67 if (called == RoxorCompiler::shared->prepareMethodFunc) {
68 VALUE klass = value_as(call_arg(call, 0), VALUE);
69 uint8_t dynamic_class = value_as(call_arg(call, 1), uint8_t);
70 SEL sel = value_as(call_arg(call, 2), SEL);
71 Function *func = value_as(call_arg(call, 3), Function *);
e8584b2 fixed the interpretation of arities in 32-bit mode + misc cleaning
Laurent Sansonetti authored
72 uint64_t arity_data = get_const_int(call_arg(call, 4));
e29c2ec now interpreting potential cold paths (work in progress)
Laurent Sansonetti authored
73 rb_vm_arity_t arity;
74 memcpy(&arity, &arity_data, sizeof(rb_vm_arity_t));
75 int flags = value_as(call_arg(call, 5), int);
76
77 rb_vm_prepare_method((Class)klass, dynamic_class, sel, func, arity,
78 flags);
79 return Qnil;
80 }
81 else if (called == RoxorCompiler::shared->dispatchFunc) {
82 VALUE top = value_as(call_arg(call, 0), VALUE);
83 VALUE self = value_as(call_arg(call, 1), VALUE);
84 void *sel = value_as(call_arg(call, 2), SEL);
85 void *block = value_as(call_arg(call, 3), void *);
86 uint8_t opt = value_as(call_arg(call, 4), uint8_t);
87 int argc = value_as(call_arg(call, 5), int);
88 VALUE *argv = value_as(call_arg(call, 6), VALUE *);
89
3cabadf add backtracing support for interpreted dispatch calls + cleanup usel…
Laurent Sansonetti authored
90 MDNode *node = call->getMetadata(RoxorCompiler::shared->dbg_mdkind);
91 if (node != NULL) {
92 std::string path;
9b5bce3 when calculating a backtrace path from a -e script, omit the current …
Laurent Sansonetti authored
93 DILocation loc(node);
94 RoxorCompiler::shared->generate_location_path(path, loc);
3cabadf add backtracing support for interpreted dispatch calls + cleanup usel…
Laurent Sansonetti authored
95
96 Frame frame;
c6300f9 add support in the interpreter for the rb_vm_current_block() primitiv…
Laurent Sansonetti authored
97 if (sel != NULL) {
98 frame.name = (const char *)sel;
99 }
3cabadf add backtracing support for interpreted dispatch calls + cleanup usel…
Laurent Sansonetti authored
100 frame.path = path;
101 frame.line = loc.getLineNumber();
102 frames.push_back(frame);
103 }
104
105 struct Finally {
106 RoxorInterpreter *ir;
107 bool pop;
108 Finally(RoxorInterpreter *_ir, bool _pop) {
109 ir = _ir;
110 pop = _pop;
111 }
112 ~Finally() {
113 if (pop) {
114 ir->frames.pop_back();
115 }
116 }
117 } finalizer(this, node != NULL);
118
e29c2ec now interpreting potential cold paths (work in progress)
Laurent Sansonetti authored
119 return vm_dispatch(top, self, sel, block, opt, argc, argv);
120 }
55268be make sure rb_singleton_class() can be interpreted
Laurent Sansonetti authored
121 else if (called == RoxorCompiler::shared->singletonClassFunc) {
122 VALUE klass = value_as(call_arg(call, 0), VALUE);
123
124 return rb_singleton_class(klass);
125 }
7b14592 @takaokouji fixed below.
takaokouji authored
126 else if (called == RoxorCompiler::shared->setCurrentOuterFunc) {
127 rb_vm_outer_t *outer_stack = value_as(call_arg(call, 0), rb_vm_outer_t *);
128
129 rb_vm_set_current_outer(outer_stack);
130 return Qnil;
131 }
46374f1 fix a bug in the interpreter where the vm_get_block() primitive would…
Laurent Sansonetti authored
132 else if (called == RoxorCompiler::shared->getBlockFunc) {
133 VALUE block = value_as(call_arg(call, 0), VALUE);
134 return (VALUE)vm_get_block(block);
135 }
c6300f9 add support in the interpreter for the rb_vm_current_block() primitiv…
Laurent Sansonetti authored
136 else if (called == RoxorCompiler::shared->currentBlockFunc) {
137 return (VALUE)rb_vm_current_block();
138 }
e29c2ec now interpreting potential cold paths (work in progress)
Laurent Sansonetti authored
139
140 oops("unrecognized call instruction:", call);
141 }
142
3cabadf add backtracing support for interpreted dispatch calls + cleanup usel…
Laurent Sansonetti authored
143 bool
144 RoxorInterpreter::frame_at_index(unsigned int idx, void *addr,
145 std::string *name, std::string *path, unsigned int *line)
146 {
147 if ((uintptr_t)addr < (uintptr_t)(void *)&vm_dispatch
148 || (uintptr_t)addr > (uintptr_t)(void *)&vm_dispatch + 5000) {
149 // Likely not an interpreted dispatch call.
150 return false;
151 }
152 if (idx >= frames.size()) {
153 // Not enough frames!
154 return false;
155 }
156
157 Frame &frame = frames[idx];
158 *name = frame.name;
159 *path = frame.path;
160 *line = frame.line;
161 return true;
162 }
163
e29c2ec now interpreting potential cold paths (work in progress)
Laurent Sansonetti authored
164 #define return_if_cached(__insn) \
165 std::map<Instruction *, VALUE>::iterator __i = insns.find(__insn); \
166 if (__i != insns.end()) { \
167 return __i->second; \
168 } \
169
170 VALUE
171 RoxorInterpreter::interpret_instruction(Instruction *insn)
172 {
173 switch (insn->getOpcode()) {
174 case Instruction::Br:
175 {
176 BranchInst *br = static_cast<BranchInst *>(insn);
177 if (br->isUnconditional()) {
178 BasicBlock *bb = br->getSuccessor(0);
179 assert(bb != NULL);
180 return interpret_basicblock(bb);
181 }
182 break;
183 }
184
185 case Instruction::Ret:
186 {
187 ReturnInst *ret = static_cast<ReturnInst *>(insn);
188 Value *retval = ret->getReturnValue();
189 assert(retval != NULL);
190 return interpret_value(retval);
191 }
192
193 case Instruction::Call:
194 {
195 return_if_cached(insn);
196 VALUE ret = interpret_call(static_cast<CallInst *>(insn));
197 insns[insn] = ret;
198 return ret;
199 }
200
201 case Instruction::Alloca:
202 {
203 return_if_cached(insn);
204 // Assuming the allocated type is VALUE.
205 AllocaInst *allocai = static_cast<AllocaInst *>(insn);
206 const size_t n = get_const_int(allocai->getArraySize());
207 assert(n > 0 && stack_p + n < INTERPRETER_STACK_SIZE);
208 VALUE *mem = &stack[stack_p];
209 stack_p += n;
210 insns[insn] = (VALUE)mem;
211 return (VALUE)mem;
212 }
213
214 case Instruction::Store:
215 {
216 StoreInst *store = static_cast<StoreInst *>(insn);
217 Value *slot = store->getOperand(1);
218 GetElementPtrInst *ptr = dyn_cast<GetElementPtrInst>(slot);
219 if (ptr == NULL) {
220 break;
221 }
222 if (ptr->getNumIndices() != 1) {
223 break;
224 }
225 const size_t off = get_const_int(*ptr->idx_begin());
226 VALUE storage = interpret_instruction(cast<AllocaInst>
227 (ptr->getPointerOperand()));
228 VALUE val = interpret_value(store->getOperand(0));
229 ((VALUE *)storage)[off] = val;
230 return val;
231 }
232
233 // Evaluated later.
234 case Instruction::GetElementPtr:
235 return Qnil;
236 }
237
238 oops("unrecognized instruction:", insn);
239 }
240
241 VALUE
242 RoxorInterpreter::interpret_value(Value *val)
243 {
244 unsigned val_id = val->getValueID();
245 switch (val_id) {
246 case Value::ConstantPointerNullVal:
247 return 0;
248
249 case Value::ConstantExprVal:
250 val = static_cast<ConstantExpr *>(val)->getOperand(0);
251 // fall through
252 case Value::ConstantIntVal:
e8584b2 fixed the interpretation of arities in 32-bit mode + misc cleaning
Laurent Sansonetti authored
253 {
254 ConstantInt *ci = static_cast<ConstantInt *>(val);
255 const unsigned w = ci->getBitWidth();
256 #if __LP64__
257 if (w > 64) {
258 break;
259 }
260 #else
261 if (w > 32) {
262 break;
263 }
264 #endif
265 return ci->getZExtValue();
266 }
e29c2ec now interpreting potential cold paths (work in progress)
Laurent Sansonetti authored
267
268 case Value::ArgumentVal:
269 switch (static_cast<Argument *>(val)->getArgNo()) {
270 case 0:
271 return self_arg;
272 case 1:
273 return (VALUE)sel_arg;
274 }
275 break;
276
277 default:
278 if (val_id >= Value::InstructionVal) {
279 return interpret_instruction(static_cast<Instruction *>(val));
280 }
281 break;
282 }
283
284 oops("unrecognized value:", val);
285 }
286
287 VALUE
288 RoxorInterpreter::interpret_basicblock(BasicBlock *bb)
289 {
290 for (BasicBlock::iterator insn = bb->begin(); insn != bb->end(); ++insn) {
291 Instruction *i = &*insn;
292 VALUE v = interpret_instruction(i);
293 if (i->isTerminator()) {
294 return v;
295 }
296 }
297
298 oops("malformed block:", bb);
299 }
300
301 VALUE
302 RoxorInterpreter::interpret(Function *func, VALUE self, SEL sel)
303 {
304 self_arg = self;
305 sel_arg = sel;
306 stack_p = 0;
307 insns.clear();
308
309 BasicBlock &b = func->getEntryBlock();
310 return interpret_basicblock(&b);
311 }
a6a5d3e started to trim out the static library
Laurent Sansonetti authored
312
313 #endif // !MACRUBY_STATIC
Something went wrong with that request. Please try again.