1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13: #include "ruby/ruby.h"
14: #include "ruby/node.h"
15:
16:
17: #include "gc.h"
18: #include "vm_core.h"
19:
20: #include "insns.inc"
21: #include "insns_info.inc"
22:
23:
24: void iseq_compile(VALUE self, NODE *node);
25: int iseq_translate_threaded_code(rb_iseq_t *iseq);
26:
27: VALUE rb_cISeq;
28:
29: static void
30: compile_data_free(struct iseq_compile_data *compile_data)
31: {
32: if (compile_data) {
33: struct iseq_compile_data_storage *cur, *next;
34: cur = compile_data->storage_head;
35: while (cur) {
36: next = cur->next;
37: ruby_xfree(cur);
38: cur = next;
39: }
40: ruby_xfree(compile_data);
41: }
42: }
43:
44: static void
45: iseq_free(void *ptr)
46: {
47: rb_iseq_t *iseq;
48: RUBY_FREE_ENTER("iseq");
49:
50: if (ptr) {
51: iseq = ptr;
52:
53:
54:
55:
56: if (iseq->iseq != iseq->iseq_encoded) {
57: RUBY_FREE_UNLESS_NULL(iseq->iseq_encoded);
58: }
59:
60: RUBY_FREE_UNLESS_NULL(iseq->iseq);
61: RUBY_FREE_UNLESS_NULL(iseq->insn_info_table);
62: RUBY_FREE_UNLESS_NULL(iseq->local_table);
63: RUBY_FREE_UNLESS_NULL(iseq->catch_table);
64: RUBY_FREE_UNLESS_NULL(iseq->arg_opt_table);
65: compile_data_free(iseq->compile_data);
66: ruby_xfree(ptr);
67: }
68: RUBY_FREE_LEAVE("iseq");
69: }
70:
71: static void
72: iseq_mark(void *ptr)
73: {
74: rb_iseq_t *iseq;
75: RUBY_MARK_ENTER("iseq");
76:
77: if (ptr) {
78: iseq = ptr;
79: RUBY_GC_INFO("%s @ %s\n", RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
80: RUBY_MARK_UNLESS_NULL(iseq->mark_ary);
81: RUBY_MARK_UNLESS_NULL(iseq->name);
82: RUBY_MARK_UNLESS_NULL(iseq->filename);
83: RUBY_MARK_UNLESS_NULL((VALUE)iseq->cref_stack);
84: RUBY_MARK_UNLESS_NULL(iseq->klass);
85:
86:
87:
88: if (iseq->compile_data != 0) {
89: RUBY_MARK_UNLESS_NULL(iseq->compile_data->mark_ary);
90: RUBY_MARK_UNLESS_NULL(iseq->compile_data->err_info);
91: RUBY_MARK_UNLESS_NULL(iseq->compile_data->catch_table_ary);
92: }
93: }
94: RUBY_MARK_LEAVE("iseq");
95: }
96:
97: static VALUE
98: iseq_alloc(VALUE klass)
99: {
100: VALUE volatile obj;
101: rb_iseq_t *iseq;
102:
103: obj = Data_Make_Struct(klass, rb_iseq_t, iseq_mark, iseq_free, iseq);
104: MEMZERO(iseq, rb_iseq_t, 1);
105: return obj;
106: }
107:
108: static void
109: set_relation(rb_iseq_t *iseq, const VALUE parent)
110: {
111: const int type = iseq->type;
112: rb_thread_t *th = GET_THREAD();
113:
114:
115: if (type == ISEQ_TYPE_TOP) {
116:
117: iseq->cref_stack = NEW_BLOCK(th->top_wrapper ? th->top_wrapper : rb_cObject);
118: iseq->cref_stack->nd_file = 0;
119: iseq->cref_stack->nd_visi = NOEX_PRIVATE;
120: }
121: else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
122: iseq->cref_stack = NEW_BLOCK(0);
123: iseq->cref_stack->nd_file = 0;
124: }
125: else if (RTEST(parent)) {
126: rb_iseq_t *piseq;
127: GetISeqPtr(parent, piseq);
128: iseq->cref_stack = piseq->cref_stack;
129: }
130:
131: if (type == ISEQ_TYPE_TOP ||
132: type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
133: iseq->local_iseq = iseq;
134: }
135: else if (RTEST(parent)) {
136: rb_iseq_t *piseq;
137: GetISeqPtr(parent, piseq);
138: iseq->local_iseq = piseq->local_iseq;
139: }
140:
141: if (RTEST(parent)) {
142: rb_iseq_t *piseq;
143: GetISeqPtr(parent, piseq);
144: iseq->parent_iseq = piseq;
145: }
146: }
147:
148: static VALUE
149: prepare_iseq_build(rb_iseq_t *iseq,
150: VALUE name, VALUE filename,
151: VALUE parent, VALUE type, VALUE block_opt,
152: const rb_compile_option_t *option)
153: {
154: OBJ_FREEZE(name);
155: OBJ_FREEZE(filename);
156:
157: iseq->name = name;
158: iseq->filename = filename;
159: iseq->defined_method_id = 0;
160: iseq->mark_ary = rb_ary_new();
161: RBASIC(iseq->mark_ary)->klass = 0;
162:
163: iseq->type = type;
164: iseq->arg_rest = -1;
165: iseq->arg_block = -1;
166: iseq->klass = 0;
167:
168:
169:
170:
171:
172:
173:
174: iseq->compile_data = ALLOC(struct iseq_compile_data);
175: MEMZERO(iseq->compile_data, struct iseq_compile_data, 1);
176: iseq->compile_data->mark_ary = rb_ary_new();
177: RBASIC(iseq->compile_data->mark_ary)->klass = 0;
178:
179: iseq->compile_data->storage_head = iseq->compile_data->storage_current =
180: (struct iseq_compile_data_storage *)
181: ALLOC_N(char, INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE +
182: sizeof(struct iseq_compile_data_storage));
183:
184: iseq->compile_data->catch_table_ary = rb_ary_new();
185: iseq->compile_data->storage_head->pos = 0;
186: iseq->compile_data->storage_head->next = 0;
187: iseq->compile_data->storage_head->size =
188: INITIAL_ISEQ_COMPILE_DATA_STORAGE_BUFF_SIZE;
189: iseq->compile_data->storage_head->buff =
190: (char *)(&iseq->compile_data->storage_head->buff + 1);
191: iseq->compile_data->option = option;
192:
193: set_relation(iseq, parent);
194:
195: return Qtrue;
196: }
197:
198: static VALUE
199: cleanup_iseq_build(rb_iseq_t *iseq)
200: {
201: struct iseq_compile_data *data = iseq->compile_data;
202: VALUE err = data->err_info;
203: iseq->compile_data = 0;
204: compile_data_free(data);
205:
206: if (RTEST(err)) {
207: rb_funcall2(err, rb_intern("set_backtrace"), 1, &iseq->filename);
208: rb_exc_raise(err);
209: }
210: return Qtrue;
211: }
212:
213: static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
214: OPT_INLINE_CONST_CACHE,
215: OPT_PEEPHOLE_OPTIMIZATION,
216: OPT_TAILCALL_OPTIMIZATION,
217: OPT_SPECIALISED_INSTRUCTION,
218: OPT_OPERANDS_UNIFICATION,
219: OPT_INSTRUCTIONS_UNIFICATION,
220: OPT_STACK_CACHING,
221: OPT_TRACE_INSTRUCTION,
222: };
223: static const rb_compile_option_t COMPILE_OPTION_FALSE;
224:
225: static void
226: make_compile_option(rb_compile_option_t *option, VALUE opt)
227: {
228: if (opt == Qnil) {
229: *option = COMPILE_OPTION_DEFAULT;
230: }
231: else if (opt == Qfalse) {
232: *option = COMPILE_OPTION_FALSE;
233: }
234: else if (opt == Qtrue) {
235: memset(option, 1, sizeof(rb_compile_option_t));
236: }
237: else if (CLASS_OF(opt) == rb_cHash) {
238: *option = COMPILE_OPTION_DEFAULT;
239:
240: #define SET_COMPILE_OPTION(o, h, mem) \
241: { VALUE flag = rb_hash_aref(h, ID2SYM(rb_intern(#mem))); \
242: if (flag == Qtrue) { o->mem = 1; } \
243: else if (flag == Qfalse) { o->mem = 0; } \
244: }
245: SET_COMPILE_OPTION(option, opt, inline_const_cache);
246: SET_COMPILE_OPTION(option, opt, peephole_optimization);
247: SET_COMPILE_OPTION(option, opt, tailcall_optimization);
248: SET_COMPILE_OPTION(option, opt, specialized_instruction);
249: SET_COMPILE_OPTION(option, opt, operands_unification);
250: SET_COMPILE_OPTION(option, opt, instructions_unification);
251: SET_COMPILE_OPTION(option, opt, stack_caching);
252: SET_COMPILE_OPTION(option, opt, trace_instruction);
253: #undef SET_COMPILE_OPTION
254: }
255: else {
256: rb_raise(rb_eTypeError, "Compile option must be Hash/true/false/nil");
257: }
258: }
259:
260: static VALUE
261: make_compile_option_value(rb_compile_option_t *option)
262: {
263: VALUE opt = rb_hash_new();
264: #define SET_COMPILE_OPTION(o, h, mem) \
265: rb_hash_aset(h, ID2SYM(rb_intern(#mem)), o->mem ? Qtrue : Qfalse)
266: {
267: SET_COMPILE_OPTION(option, opt, inline_const_cache);
268: SET_COMPILE_OPTION(option, opt, peephole_optimization);
269: SET_COMPILE_OPTION(option, opt, tailcall_optimization);
270: SET_COMPILE_OPTION(option, opt, specialized_instruction);
271: SET_COMPILE_OPTION(option, opt, operands_unification);
272: SET_COMPILE_OPTION(option, opt, instructions_unification);
273: SET_COMPILE_OPTION(option, opt, stack_caching);
274: }
275: #undef SET_COMPILE_OPTION
276: return opt;
277: }
278:
279: VALUE
280: rb_iseq_new(NODE *node, VALUE name, VALUE filename,
281: VALUE parent, VALUE type)
282: {
283: return rb_iseq_new_with_opt(node, name, filename, parent, type,
284: &COMPILE_OPTION_DEFAULT);
285: }
286:
287: static VALUE
288: rb_iseq_new_with_bopt_and_opt(NODE *node, VALUE name, VALUE filename,
289: VALUE parent, VALUE type, VALUE bopt,
290: const rb_compile_option_t *option)
291: {
292: rb_iseq_t *iseq;
293: VALUE self = iseq_alloc(rb_cISeq);
294:
295: GetISeqPtr(self, iseq);
296: iseq->self = self;
297:
298: prepare_iseq_build(iseq, name, filename, parent, type, bopt, option);
299: iseq_compile(self, node);
300: cleanup_iseq_build(iseq);
301: return self;
302: }
303:
304: VALUE
305: rb_iseq_new_with_opt(NODE *node, VALUE name, VALUE filename,
306: VALUE parent, VALUE type,
307: const rb_compile_option_t *option)
308: {
309: return rb_iseq_new_with_bopt_and_opt(node, name, filename, parent, type,
310: Qfalse, option);
311: }
312:
313: VALUE
314: rb_iseq_new_with_bopt(NODE *node, VALUE name, VALUE filename,
315: VALUE parent, VALUE type, VALUE bopt)
316: {
317: return rb_iseq_new_with_bopt_and_opt(node, name, filename, parent, type,
318: bopt, &COMPILE_OPTION_DEFAULT);
319: }
320:
321: VALUE iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args,
322: VALUE exception, VALUE body);
323:
324: #define CHECK_ARRAY(v) rb_convert_type(v, T_ARRAY, "Array", "to_ary")
325: #define CHECK_STRING(v) rb_convert_type(v, T_STRING, "String", "to_str")
326: #define CHECK_SYMBOL(v) rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym")
327: #define CHECK_INTEGER(v) (NUM2LONG(v), v)
328: VALUE
329: iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt)
330: {
331: VALUE iseqval = iseq_alloc(rb_cISeq);
332:
333: VALUE magic, version1, version2, format_type, misc;
334: VALUE name, filename, line;
335: VALUE type, body, locals, args, exception;
336:
337: VALUE iseq_type;
338: struct st_table *type_map = 0;
339: rb_iseq_t *iseq;
340: rb_compile_option_t option;
341:
342:
343:
344:
345:
346:
347: data = CHECK_ARRAY(data);
348:
349: magic = CHECK_STRING(rb_ary_entry(data, 0));
350: version1 = CHECK_INTEGER(rb_ary_entry(data, 1));
351: version2 = CHECK_INTEGER(rb_ary_entry(data, 2));
352: format_type = CHECK_INTEGER(rb_ary_entry(data, 3));
353: misc = rb_ary_entry(data, 4);
354:
355: name = CHECK_STRING(rb_ary_entry(data, 5));
356: filename = CHECK_STRING(rb_ary_entry(data, 6));
357: line = CHECK_ARRAY(rb_ary_entry(data, 7));
358:
359: type = CHECK_SYMBOL(rb_ary_entry(data, 8));
360: locals = CHECK_ARRAY(rb_ary_entry(data, 9));
361:
362: args = rb_ary_entry(data, 10);
363: if (FIXNUM_P(args) || (args = CHECK_ARRAY(args))) {
364:
365: }
366:
367: exception = CHECK_ARRAY(rb_ary_entry(data, 11));
368: body = CHECK_ARRAY(rb_ary_entry(data, 12));
369:
370: GetISeqPtr(iseqval, iseq);
371: iseq->self = iseqval;
372:
373: if (type_map == 0) {
374: type_map = st_init_numtable();
375: st_insert(type_map, ID2SYM(rb_intern("top")), ISEQ_TYPE_TOP);
376: st_insert(type_map, ID2SYM(rb_intern("method")), ISEQ_TYPE_METHOD);
377: st_insert(type_map, ID2SYM(rb_intern("block")), ISEQ_TYPE_BLOCK);
378: st_insert(type_map, ID2SYM(rb_intern("class")), ISEQ_TYPE_CLASS);
379: st_insert(type_map, ID2SYM(rb_intern("rescue")), ISEQ_TYPE_RESCUE);
380: st_insert(type_map, ID2SYM(rb_intern("ensure")), ISEQ_TYPE_ENSURE);
381: st_insert(type_map, ID2SYM(rb_intern("eval")), ISEQ_TYPE_EVAL);
382: }
383:
384: if (st_lookup(type_map, type, &iseq_type) == 0) {
385: const char *typename = rb_id2name(type);
386: if (typename)
387: rb_raise(rb_eTypeError, "unsupport type: :%s", typename);
388: else
389: rb_raise(rb_eTypeError, "unsupport type: %p", (void *)type);
390: }
391:
392: if (parent == Qnil) {
393: parent = 0;
394: }
395:
396: make_compile_option(&option, opt);
397: prepare_iseq_build(iseq, name, filename,
398: parent, iseq_type, 0, &option);
399:
400: iseq_build_from_ary(iseq, locals, args, exception, body);
401:
402: cleanup_iseq_build(iseq);
403: return iseqval;
404: }
405:
406: static VALUE
407: iseq_s_load(int argc, VALUE *argv, VALUE self)
408: {
409: VALUE data, opt=Qnil;
410: rb_scan_args(argc, argv, "11", &data, &opt);
411:
412: return iseq_load(self, data, 0, opt);
413: }
414:
415: static NODE *
416: compile_string(VALUE str, VALUE file, VALUE line)
417: {
418: VALUE parser = rb_parser_new();
419: NODE *node = rb_parser_compile_string(parser, StringValueCStr(file),
420: str, NUM2INT(line));
421:
422: if (!node) {
423: rb_exc_raise(GET_THREAD()->errinfo);
424: }
425: return node;
426: }
427:
428: VALUE
429: rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE line, VALUE opt)
430: {
431: rb_compile_option_t option;
432: NODE *node = compile_string(src, file, line);
433: rb_thread_t *th = GET_THREAD();
434: make_compile_option(&option, opt);
435:
436: if (th->base_block) {
437: return rb_iseq_new_with_opt(node, th->base_block->iseq->name,
438: file, th->base_block->iseq->self,
439: ISEQ_TYPE_EVAL, &option);
440: }
441: else {
442: return rb_iseq_new_with_opt(node, rb_str_new2("<compiled>"), file, Qfalse,
443: ISEQ_TYPE_TOP, &option);
444: }
445: }
446:
447: VALUE
448: rb_iseq_compile(VALUE src, VALUE file, VALUE line)
449: {
450: return rb_iseq_compile_with_option(src, file, line, Qnil);
451: }
452:
453: static VALUE
454: iseq_s_compile(int argc, VALUE *argv, VALUE self)
455: {
456: VALUE src, file = Qnil, line = INT2FIX(1), opt = Qnil;
457:
458: rb_secure(1);
459:
460: rb_scan_args(argc, argv, "13", &src, &file, &line, &opt);
461: file = file == Qnil ? rb_str_new2("<compiled>") : file;
462: line = line == Qnil ? INT2FIX(1) : line;
463:
464: return rb_iseq_compile_with_option(src, file, line, opt);
465: }
466:
467: static VALUE
468: iseq_s_compile_file(int argc, VALUE *argv, VALUE self)
469: {
470: VALUE file, line = INT2FIX(1), opt = Qnil;
471: VALUE parser;
472: VALUE f;
473: NODE *node;
474: const char *fname;
475: rb_compile_option_t option;
476:
477: rb_secure(1);
478: rb_scan_args(argc, argv, "11", &file, &opt);
479: fname = StringValueCStr(file);
480:
481: f = rb_file_open(fname, "r");
482:
483: parser = rb_parser_new();
484: node = rb_parser_compile_file(parser, fname, f, NUM2INT(line));
485: make_compile_option(&option, opt);
486: return rb_iseq_new_with_opt(node, rb_str_new2("<main>"), file, Qfalse,
487: ISEQ_TYPE_TOP, &option);
488: }
489:
490: static VALUE
491: iseq_s_compile_option_set(VALUE self, VALUE opt)
492: {
493: rb_compile_option_t option;
494: rb_secure(1);
495: make_compile_option(&option, opt);
496: COMPILE_OPTION_DEFAULT = option;
497: return opt;
498: }
499:
500: static VALUE
501: iseq_s_compile_option_get(VALUE self)
502: {
503: return make_compile_option_value(&COMPILE_OPTION_DEFAULT);
504: }
505:
506: static rb_iseq_t *
507: iseq_check(VALUE val)
508: {
509: rb_iseq_t *iseq;
510: GetISeqPtr(val, iseq);
511: if (!iseq->name) {
512: rb_raise(rb_eTypeError, "uninitialized InstructionSequence");
513: }
514: return iseq;
515: }
516:
517: static VALUE
518: iseq_eval(VALUE self)
519: {
520: rb_secure(1);
521: return rb_iseq_eval(self);
522: }
523:
524: static VALUE
525: iseq_inspect(VALUE self)
526: {
527: char buff[0x100];
528: rb_iseq_t *iseq = iseq_check(self);
529:
530: snprintf(buff, sizeof(buff), "<ISeq:%s@%s>",
531: RSTRING_PTR(iseq->name), RSTRING_PTR(iseq->filename));
532:
533: return rb_str_new2(buff);
534: }
535:
536: VALUE iseq_data_to_ary(rb_iseq_t *iseq);
537:
538: static VALUE
539: iseq_to_a(VALUE self)
540: {
541: rb_iseq_t *iseq = iseq_check(self);
542: rb_secure(1);
543: return iseq_data_to_ary(iseq);
544: }
545:
546:
547:
548:
549: static struct iseq_insn_info_entry *
550: get_insn_info(const rb_iseq_t *iseq, const unsigned long pos)
551: {
552: unsigned long i, size = iseq->insn_info_size;
553: struct iseq_insn_info_entry *table = iseq->insn_info_table;
554:
555: for (i = 0; i < size; i++) {
556: if (table[i].position == pos) {
557: return &table[i];
558: }
559: }
560:
561: return 0;
562: }
563:
564: static unsigned short
565: find_line_no(rb_iseq_t *iseq, unsigned long pos)
566: {
567: struct iseq_insn_info_entry *entry = get_insn_info(iseq, pos);
568: if (entry) {
569: return entry->line_no;
570: }
571: else {
572: return 0;
573: }
574: }
575:
576: static unsigned short
577: find_prev_line_no(rb_iseq_t *iseqdat, unsigned long pos)
578: {
579: unsigned long i, size = iseqdat->insn_info_size;
580: struct iseq_insn_info_entry *iiary = iseqdat->insn_info_table;
581:
582: for (i = 0; i < size; i++) {
583: if (iiary[i].position == pos) {
584: if (i > 0) {
585: return iiary[i - 1].line_no;