diff options
Diffstat (limited to 'trunk/compile.c')
-rw-r--r-- | trunk/compile.c | 5053 |
1 files changed, 0 insertions, 5053 deletions
diff --git a/trunk/compile.c b/trunk/compile.c deleted file mode 100644 index 41d1a9247f..0000000000 --- a/trunk/compile.c +++ /dev/null @@ -1,5053 +0,0 @@ -/********************************************************************** - - compile.c - ruby node tree -> VM instruction sequence - - $Author$ - created at: 04/01/01 03:42:15 JST - - Copyright (C) 2004-2007 Koichi Sasada - -**********************************************************************/ - -#include "ruby/ruby.h" -#include "ruby/node.h" - -#define USE_INSN_STACK_INCREASE 1 -#include "vm_core.h" -#include "compile.h" -#include "insns.inc" -#include "insns_info.inc" - -#ifdef HAVE_STDARG_PROTOTYPES -#include <stdarg.h> -#define va_init_list(a,b) va_start(a,b) -#else -#include <varargs.h> -#define va_init_list(a,b) va_start(a) -#endif - -VALUE iseq_load(VALUE self, VALUE data, VALUE parent, VALUE opt); - -/* types */ - -typedef struct iseq_link_element { - enum { - ISEQ_ELEMENT_NONE = INT2FIX(0x00), - ISEQ_ELEMENT_LABEL = INT2FIX(0x01), - ISEQ_ELEMENT_INSN = INT2FIX(0x02), - ISEQ_ELEMENT_ADJUST = INT2FIX(0x03) - } type; - struct iseq_link_element *next; - struct iseq_link_element *prev; -} LINK_ELEMENT; - -typedef struct iseq_link_anchor { - LINK_ELEMENT anchor; - LINK_ELEMENT *last; -} LINK_ANCHOR; - -typedef struct iseq_label_data { - LINK_ELEMENT link; - int label_no; - int position; - int sc_state; - int set; - int sp; -} LABEL; - -typedef struct iseq_insn_data { - LINK_ELEMENT link; - enum ruby_vminsn_type insn_id; - int line_no; - int operand_size; - int sc_state; - VALUE *operands; -} INSN; - -typedef struct iseq_adjust_data { - LINK_ELEMENT link; - LABEL *label; - int line_no; -} ADJUST; - -struct ensure_range { - LABEL *begin; - LABEL *end; - struct ensure_range *next; -}; - -struct iseq_compile_data_ensure_node_stack { - NODE *ensure_node; - struct iseq_compile_data_ensure_node_stack *prev; - struct ensure_range *erange; -}; - -#include "optinsn.inc" -#if OPT_INSTRUCTIONS_UNIFICATION -#include "optunifs.inc" -#endif - -/* for debug */ -#if CPDEBUG < 0 -#define ISEQ_ARG iseq, -#define ISEQ_ARG_DECLARE rb_iseq_t *iseq, -#else -#define ISEQ_ARG -#define ISEQ_ARG_DECLARE -#endif - -#if CPDEBUG -#define gl_node_level iseq->compile_data->node_level -#if 0 -static void debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor); -#endif -#endif - -static void dump_disasm_list(LINK_ELEMENT *elem); - -static int insn_data_length(INSN *iobj); -static int insn_data_line_no(INSN *iobj); -static int calc_sp_depth(int depth, INSN *iobj); - -static void ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem); - -static INSN *new_insn_body(rb_iseq_t *iseq, int line_no, int insn_id, int argc, ...); -static LABEL *new_label_body(rb_iseq_t *iseq, int line); -static ADJUST *new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line); - -static int iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * n, int); -static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor); -static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor); -static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor); - -static int iseq_set_local_table(rb_iseq_t *iseq, ID *tbl); -static int iseq_set_exception_local_table(rb_iseq_t *iseq); -static int iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *anchor, NODE * node); - -static int iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor); -static int iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor); -static int iseq_set_exception_table(rb_iseq_t *iseq); -static int iseq_set_optargs_table(rb_iseq_t *iseq); - -/* - * To make Array to LinkedList, use link_anchor - */ - -static void -verify_list(ISEQ_ARG_DECLARE const char *info, LINK_ANCHOR *anchor) -{ -#if CPDEBUG - int flag = 0; - LINK_ELEMENT *list, *plist; - - if (!compile_debug) return; - - list = anchor->anchor.next; - plist = &anchor->anchor; - while (list) { - if (plist != list->prev) { - flag += 1; - } - plist = list; - list = list->next; - } - - if (anchor->last != plist && anchor->last != 0) { - flag |= 0x70000; - } - - if (flag != 0) { - rb_bug("list verify error: %08x (%s)", flag, info); - } -#endif -} -#if CPDEBUG < 0 -#define verify_list(info, anchor) verify_list(iseq, info, anchor) -#endif - -/* - * elem1, elem2 => elem1, elem2, elem - */ -static void -ADD_ELEM(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor, LINK_ELEMENT *elem) -{ - elem->prev = anchor->last; - anchor->last->next = elem; - anchor->last = elem; - verify_list("add", anchor); -} -#if CPDEBUG < 0 -#define ADD_ELEM(anchor, elem) ADD_ELEM(iseq, anchor, elem) -#endif - -static int -iseq_add_mark_object(rb_iseq_t *iseq, VALUE v) -{ - if (!SPECIAL_CONST_P(v)) { - rb_ary_push(iseq->mark_ary, v); - } - return COMPILE_OK; -} - -#define ruby_sourcefile RSTRING_PTR(iseq->filename) - -static int -iseq_add_mark_object_compile_time(rb_iseq_t *iseq, VALUE v) -{ - if (!SPECIAL_CONST_P(v)) { - rb_ary_push(iseq->compile_data->mark_ary, v); - } - return COMPILE_OK; -} - -VALUE -iseq_compile(VALUE self, NODE *node) -{ - DECL_ANCHOR(ret); - rb_iseq_t *iseq; - INIT_ANCHOR(ret); - GetISeqPtr(self, iseq); - - if (node == 0) { - COMPILE(ret, "nil", node); - iseq_set_local_table(iseq, 0); - } - else if (nd_type(node) == NODE_SCOPE) { - /* iseq type of top, method, class, block */ - iseq_set_local_table(iseq, node->nd_tbl); - iseq_set_arguments(iseq, ret, node->nd_args); - - switch (iseq->type) { - case ISEQ_TYPE_BLOCK: { - LABEL *start = iseq->compile_data->start_label = NEW_LABEL(0); - LABEL *end = iseq->compile_data->end_label = NEW_LABEL(0); - - ADD_LABEL(ret, start); - COMPILE(ret, "block body", node->nd_body); - ADD_LABEL(ret, end); - - /* wide range catch handler must put at last */ - ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, 0, start); - ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, 0, end); - break; - } - case ISEQ_TYPE_CLASS: { - ADD_TRACE(ret, nd_line(node), RUBY_EVENT_CLASS); - COMPILE(ret, "scoped node", node->nd_body); - ADD_TRACE(ret, nd_line(node), RUBY_EVENT_END); - break; - } - case ISEQ_TYPE_METHOD: { - ADD_TRACE(ret, nd_line(node), RUBY_EVENT_CALL); - COMPILE(ret, "scoped node", node->nd_body); - ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RETURN); - break; - } - default: { - COMPILE(ret, "scoped node", node->nd_body); - break; - } - } - } - else { - switch (iseq->type) { - case ISEQ_TYPE_METHOD: - case ISEQ_TYPE_CLASS: - case ISEQ_TYPE_BLOCK: - case ISEQ_TYPE_EVAL: - case ISEQ_TYPE_TOP: - rb_compile_error(ERROR_ARGS "compile/should not be reached: %s:%d", - __FILE__, __LINE__); - break; - case ISEQ_TYPE_RESCUE: - iseq_set_exception_local_table(iseq); - COMPILE(ret, "rescue", node); - break; - case ISEQ_TYPE_ENSURE: - iseq_set_exception_local_table(iseq); - COMPILE_POPED(ret, "ensure", node); - break; - case ISEQ_TYPE_DEFINED_GUARD: - iseq_set_local_table(iseq, 0); - COMPILE(ret, "defined guard", node); - break; - default: - rb_bug("unknown scope"); - } - } - - if (iseq->type == ISEQ_TYPE_RESCUE || iseq->type == ISEQ_TYPE_ENSURE) { - ADD_INSN2(ret, 0, getdynamic, INT2FIX(2), INT2FIX(0)); - ADD_INSN1(ret, 0, throw, INT2FIX(0) /* continue throw */ ); - } - else { - ADD_INSN(ret, iseq->compile_data->last_line, leave); - } - - return iseq_setup(iseq, ret); -} - -int -iseq_translate_threaded_code(rb_iseq_t *iseq) -{ -#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE - extern const void **vm_get_insns_address_table(void); -#if OPT_DIRECT_THREADED_CODE - const void * const *table = vm_get_insns_address_table(); -#else - const void * const *table = vm_get_insns_address_table(); -#endif - int i; - - iseq->iseq_encoded = ALLOC_N(VALUE, iseq->iseq_size); - MEMCPY(iseq->iseq_encoded, iseq->iseq, VALUE, iseq->iseq_size); - - for (i = 0; i < iseq->iseq_size; /* */ ) { - int insn = iseq->iseq_encoded[i]; - int len = insn_len(insn); - iseq->iseq_encoded[i] = (VALUE)table[insn]; - i += len; - } -#else - iseq->iseq_encoded = iseq->iseq; -#endif - return COMPILE_OK; -} - -/*********************************************/ -/* definition of data structure for compiler */ -/*********************************************/ - -static void * -compile_data_alloc(rb_iseq_t *iseq, size_t size) -{ - void *ptr = 0; - struct iseq_compile_data_storage *storage = - iseq->compile_data->storage_current; - - if (storage->pos + size > storage->size) { - unsigned long alloc_size = storage->size * 2; - - retry: - if (alloc_size < size) { - alloc_size *= 2; - goto retry; - } - storage->next = (void *)ALLOC_N(char, alloc_size + - sizeof(struct - iseq_compile_data_storage)); - storage = iseq->compile_data->storage_current = storage->next; - storage->next = 0; - storage->pos = 0; - storage->size = alloc_size; - storage->buff = (char *)(&storage->buff + 1); - } - - ptr = (void *)&storage->buff[storage->pos]; - storage->pos += size; - return ptr; -} - -static INSN * -compile_data_alloc_insn(rb_iseq_t *iseq) -{ - return (INSN *)compile_data_alloc(iseq, sizeof(INSN)); -} - -static LABEL * -compile_data_alloc_label(rb_iseq_t *iseq) -{ - return (LABEL *)compile_data_alloc(iseq, sizeof(LABEL)); -} - -static ADJUST * -compile_data_alloc_adjust(rb_iseq_t *iseq) -{ - return (ADJUST *)compile_data_alloc(iseq, sizeof(ADJUST)); -} - -/* - * elem1, elemX => elem1, elem2, elemX - */ -static void -INSERT_ELEM_NEXT(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2) -{ - elem2->next = elem1->next; - elem2->prev = elem1; - elem1->next = elem2; - if (elem2->next) { - elem2->next->prev = elem2; - } -} - -#if 0 /* unused */ -/* - * elemX, elem1 => elemX, elem2, elem1 - */ -static void -INSERT_ELEM_PREV(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2) -{ - elem2->prev = elem1->prev; - elem2->next = elem1; - elem1->prev = elem2; - if (elem2->prev) { - elem2->prev->next = elem2; - } -} -#endif - -/* - * elemX, elem1, elemY => elemX, elem2, elemY - */ -static void -REPLACE_ELEM(LINK_ELEMENT *elem1, LINK_ELEMENT *elem2) -{ - elem2->prev = elem1->prev; - elem2->next = elem1->next; - if (elem1->prev) { - elem1->prev->next = elem2; - } - if (elem1->next) { - elem1->next->prev = elem2; - } -} - -static void -REMOVE_ELEM(LINK_ELEMENT *elem) -{ - elem->prev->next = elem->next; - if (elem->next) { - elem->next->prev = elem->prev; - } -} - -static LINK_ELEMENT * -FIRST_ELEMENT(LINK_ANCHOR *anchor) -{ - return anchor->anchor.next; -} - -#if 0 /* unused */ -static LINK_ELEMENT * -LAST_ELEMENT(LINK_ANCHOR *anchor) -{ - return anchor->last; -} -#endif - -static LINK_ELEMENT * -POP_ELEMENT(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor) -{ - LINK_ELEMENT *elem = anchor->last; - anchor->last = anchor->last->prev; - anchor->last->next = 0; - verify_list("pop", anchor); - return elem; -} -#if CPDEBUG < 0 -#define POP_ELEMENT(anchor) POP_ELEMENT(iseq, anchor) -#endif - -#if 0 /* unused */ -static LINK_ELEMENT * -SHIFT_ELEMENT(LINK_ANCHOR *anchor) -{ - LINK_ELEMENT *elem = anchor->anchor.next; - if (elem) { - anchor->anchor.next = elem->next; - } - return elem; -} -#endif - -#if 0 /* unused */ -static int -LIST_SIZE(LINK_ANCHOR *anchor) -{ - LINK_ELEMENT *elem = anchor->anchor.next; - int size = 0; - while (elem) { - size += 1; - elem = elem->next; - } - return size; -} -#endif - -static int -LIST_SIZE_ZERO(LINK_ANCHOR *anchor) -{ - if (anchor->anchor.next == 0) { - return 1; - } - else { - return 0; - } -} - -/* - * anc1: e1, e2, e3 - * anc2: e4, e5 - *#=> - * anc1: e1, e2, e3, e4, e5 - * anc2: e4, e5 (broken) - */ -static void -APPEND_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2) -{ - if (anc2->anchor.next) { - anc1->last->next = anc2->anchor.next; - anc2->anchor.next->prev = anc1->last; - anc1->last = anc2->last; - } - verify_list("append", anc1); -} -#if CPDEBUG < 0 -#define APPEND_LIST(anc1, anc2) APPEND_LIST(iseq, anc1, anc2) -#endif - -/* - * anc1: e1, e2, e3 - * anc2: e4, e5 - *#=> - * anc1: e4, e5, e1, e2, e3 - * anc2: e4, e5 (broken) - */ -static void -INSERT_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2) -{ - if (anc2->anchor.next) { - LINK_ELEMENT *first = anc1->anchor.next; - anc1->anchor.next = anc2->anchor.next; - anc1->anchor.next->prev = &anc1->anchor; - anc2->last->next = first; - if (first) { - first->prev = anc2->last; - } - else { - anc1->last = anc2->last; - } - } - - verify_list("append", anc1); -} -#if CPDEBUG < 0 -#define INSERT_LIST(anc1, anc2) INSERT_LIST(iseq, anc1, anc2) -#endif - -#if 0 /* unused */ -/* - * anc1: e1, e2, e3 - * anc2: e4, e5 - *#=> - * anc1: e4, e5 - * anc2: e1, e2, e3 - */ -static void -SWAP_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc1, LINK_ANCHOR *anc2) -{ - LINK_ANCHOR tmp = *anc2; - - /* it has bug */ - *anc2 = *anc1; - *anc1 = tmp; - - verify_list("swap1", anc1); - verify_list("swap2", anc2); -} -#if CPDEBUG < 0 -#define SWAP_LIST(anc1, anc2) SWAP_LIST(iseq, anc1, anc2) -#endif - -static LINK_ANCHOR * -REVERSE_LIST(ISEQ_ARG_DECLARE LINK_ANCHOR *anc) -{ - LINK_ELEMENT *first, *last, *elem, *e; - first = &anc->anchor; - elem = first->next; - last = anc->last; - - if (elem != 0) { - anc->anchor.next = last; - anc->last = elem; - } - else { - /* null list */ - return anc; - } - while (elem) { - e = elem->next; - elem->next = elem->prev; - elem->prev = e; - elem = e; - } - - first->next = last; - last->prev = first; - anc->last->next = 0; - - verify_list("reverse", anc); - return anc; -} -#if CPDEBUG < 0 -#define REVERSE_LIST(anc) REVERSE_LIST(iseq, anc) -#endif -#endif - -#if CPDEBUG && 0 -static void -debug_list(ISEQ_ARG_DECLARE LINK_ANCHOR *anchor) -{ - LINK_ELEMENT *list = FIRST_ELEMENT(anchor); - printf("----\n"); - printf("anch: %p, frst: %p, last: %p\n", &anchor->anchor, - anchor->anchor.next, anchor->last); - while (list) { - printf("curr: %p, next: %p, prev: %p, type: %d\n", list, list->next, - list->prev, FIX2INT(list->type)); - list = list->next; - } - printf("----\n"); - - dump_disasm_list(anchor->anchor.next); - verify_list("debug list", anchor); -} -#if CPDEBUG < 0 -#define debug_list(anc) debug_list(iseq, anc) -#endif -#endif - -static LABEL * -new_label_body(rb_iseq_t *iseq, int line) -{ - LABEL *labelobj = compile_data_alloc_label(iseq); - - labelobj->link.type = ISEQ_ELEMENT_LABEL; - labelobj->link.next = 0; - - labelobj->label_no = iseq->compile_data->label_no++; - labelobj->sc_state = 0; - labelobj->sp = -1; - return labelobj; -} - -static ADJUST * -new_adjust_body(rb_iseq_t *iseq, LABEL *label, int line) -{ - ADJUST *adjust = compile_data_alloc_adjust(iseq); - adjust->link.type = ISEQ_ELEMENT_ADJUST; - adjust->link.next = 0; - adjust->label = label; - adjust->line_no = line; - return adjust; -} - -static INSN * -new_insn_core(rb_iseq_t *iseq, int line_no, - int insn_id, int argc, VALUE *argv) -{ - INSN *iobj = compile_data_alloc_insn(iseq); - - iobj->link.type = ISEQ_ELEMENT_INSN; - iobj->link.next = 0; - iobj->insn_id = insn_id; - iobj->line_no = line_no; - iobj->operands = argv; - iobj->operand_size = argc; - iobj->sc_state = 0; - return iobj; -} - -static INSN * -new_insn_body(rb_iseq_t *iseq, int line_no, int insn_id, int argc, ...) -{ - VALUE *operands = 0; - va_list argv; - if (argc > 0) { - int i; - va_init_list(argv, argc); - operands = (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * argc); - for (i = 0; i < argc; i++) { - VALUE v = va_arg(argv, VALUE); - operands[i] = v; - } - va_end(argv); - } - return new_insn_core(iseq, line_no, insn_id, argc, operands); -} - -static INSN * -new_insn_send(rb_iseq_t *iseq, int line_no, - VALUE id, VALUE argc, VALUE block, VALUE flag) -{ - INSN *iobj = 0; - VALUE *operands = - (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * 5); - operands[0] = id; - operands[1] = argc; - operands[2] = block; - operands[3] = flag; - operands[4] = 0; - iobj = new_insn_core(iseq, line_no, BIN(send), 5, operands); - return iobj; -} - -static VALUE -new_child_iseq(rb_iseq_t *iseq, NODE *node, - VALUE name, VALUE parent, VALUE type) -{ - VALUE ret; - - debugs("[new_child_iseq]> ---------------------------------------\n"); - ret = rb_iseq_new_with_opt(node, name, iseq_filename(iseq->self), - parent, type, iseq->compile_data->option); - debugs("[new_child_iseq]< ---------------------------------------\n"); - iseq_add_mark_object(iseq, ret); - return ret; -} - -static int -iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor) -{ - /* debugs("[compile step 2] (iseq_array_to_linkedlist)\n"); */ - - if (compile_debug > 5) - dump_disasm_list(FIRST_ELEMENT(anchor)); - - debugs("[compile step 3.1 (iseq_optimize)]\n"); - iseq_optimize(iseq, anchor); - - if (compile_debug > 5) - dump_disasm_list(FIRST_ELEMENT(anchor)); - - if (iseq->compile_data->option->instructions_unification) { - debugs("[compile step 3.2 (iseq_insns_unification)]\n"); - iseq_insns_unification(iseq, anchor); - if (compile_debug > 5) - dump_disasm_list(FIRST_ELEMENT(anchor)); - } - - if (iseq->compile_data->option->stack_caching) { - debugs("[compile step 3.3 (iseq_set_sequence_stackcaching)]\n"); - iseq_set_sequence_stackcaching(iseq, anchor); - if (compile_debug > 5) - dump_disasm_list(FIRST_ELEMENT(anchor)); - } - - debugs("[compile step 4.1 (iseq_set_sequence)]\n"); - iseq_set_sequence(iseq, anchor); - if (compile_debug > 5) - dump_disasm_list(FIRST_ELEMENT(anchor)); - - debugs("[compile step 4.2 (iseq_set_exception_table)]\n"); - iseq_set_exception_table(iseq); - - debugs("[compile step 4.3 (set_optargs_table)] \n"); - iseq_set_optargs_table(iseq); - - debugs("[compile step 5 (iseq_translate_threaded_code)] \n"); - iseq_translate_threaded_code(iseq); - - if (compile_debug > 1) { - VALUE str = ruby_iseq_disasm(iseq->self); - printf("%s\n", StringValueCStr(str)); - fflush(stdout); - } - debugs("[compile step: finish]\n"); - - return 0; -} - -static int -iseq_set_exception_local_table(rb_iseq_t *iseq) -{ - ID id_dollar_bang; - - CONST_ID(id_dollar_bang, "#$!"); - iseq->local_table = (ID *)ALLOC_N(ID *, 1); - iseq->local_table_size = 1; - iseq->local_size = iseq->local_table_size + 1; - iseq->local_table[0] = id_dollar_bang; - return COMPILE_OK; -} - -static int -get_dyna_var_idx_at_raw(rb_iseq_t *iseq, ID id) -{ - int i; - - for (i = 0; i < iseq->local_table_size; i++) { - if (iseq->local_table[i] == id) { - return i; - } - } - return -1; -} - -static int -get_local_var_idx(rb_iseq_t *iseq, ID id) -{ - int idx = get_dyna_var_idx_at_raw(iseq->local_iseq, id); - - if (idx < 0) { - rb_bug("get_local_var_idx: %d", idx); - } - - return idx; -} - -static int -get_dyna_var_idx(rb_iseq_t *iseq, ID id, int *level, int *ls) -{ - int lv = 0, idx = -1; - - while (iseq) { - idx = get_dyna_var_idx_at_raw(iseq, id); - if (idx >= 0) { - break; - } - iseq = iseq->parent_iseq; - lv++; - } - - if (idx < 0) { - rb_bug("get_dyna_var_idx: -1"); - } - - *level = lv; - *ls = iseq->local_size; - return idx; -} - -static int -iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *optargs, NODE *node_args) -{ - debugs("iseq_set_arguments: %s\n", node_args ? "" : "0"); - - if (node_args) { - NODE *node_aux = node_args->nd_next; - NODE *node_opt = node_args->nd_opt; - ID rest_id = 0; - int last_comma = 0; - ID block_id = 0; - NODE *node_init = 0; - - if (nd_type(node_args) != NODE_ARGS) { - rb_bug("iseq_set_arguments: NODE_ARGS is expected, but %s", - ruby_node_name(nd_type(node_args))); - } - - /* - * new argument infromation: - * NODE_ARGS [m: int, o: NODE_OPT_ARG, ->] - * NODE_ARGS_AUX [r: ID, b: ID, ->] - * NODE_ARGS_AUX [Pst: id, Plen: int, init: NODE*] - * optarg information: - * NODE_OPT_ARGS [idx, expr, next ->] - * init arg: - * NODE_AND(m_init, p_init) - * if "r" is 1, it's means "{|x,|}" type block parameter. - */ - - iseq->argc = node_args->nd_frml; - debugs(" - argc: %d\n", iseq->argc); - - if (node_aux) { - rest_id = node_aux->nd_rest; - if (rest_id == 1) { - last_comma = 1; - rest_id = 0; - } - block_id = (ID)node_aux->nd_body; - node_aux = node_aux->nd_next; - - if (node_aux) { - ID post_start_id = node_aux->nd_pid; - iseq->arg_post_start = get_dyna_var_idx_at_raw(iseq, post_start_id); - iseq->arg_post_len = node_aux->nd_plen; - node_init = node_aux->nd_next; - } - } - - if (node_opt) { - NODE *node = node_opt; - LABEL *label; - VALUE labels = rb_ary_new(); - int i = 0, j; - - while (node) { - label = NEW_LABEL(nd_line(node)); - rb_ary_push(labels, (VALUE)label | 1); - ADD_LABEL(optargs, label); - COMPILE_POPED(optargs, "optarg", node->nd_body); - node = node->nd_next; - i += 1; - } - - /* last label */ - label = NEW_LABEL(nd_line(node_args)); - rb_ary_push(labels, (VALUE)label | 1); - ADD_LABEL(optargs, label); - i += 1; - - iseq->arg_opts = i; - iseq->arg_opt_table = ALLOC_N(VALUE, i); - MEMCPY(iseq->arg_opt_table, RARRAY_PTR(labels), VALUE, i); - for (j = 0; j < i; j++) { - iseq->arg_opt_table[j] &= ~1; - } - } - else { - iseq->arg_opts = 0; - } - - if (node_init) { - if (node_init->nd_1st) { /* m_init */ - COMPILE_POPED(optargs, "init arguments (m)", node_init->nd_1st); - } - if (node_init->nd_2nd) { /* p_init */ - COMPILE_POPED(optargs, "init arguments (p)", node_init->nd_2nd); - } - } - - if (rest_id) { - iseq->arg_rest = get_dyna_var_idx_at_raw(iseq, rest_id); - - if (iseq->arg_rest == -1) { - rb_bug("arg_rest: -1"); - } - - if (iseq->arg_post_start == 0) { - iseq->arg_post_start = iseq->arg_rest + 1; - } - } - - if (block_id) { - iseq->arg_block = get_dyna_var_idx_at_raw(iseq, block_id); - } - - if (iseq->arg_opts != 0 || iseq->arg_post_len != 0 || - iseq->arg_rest != -1 || iseq->arg_block != -1) { - iseq->arg_simple = 0; - - /* set arg_size: size of arguments */ - if (iseq->arg_block != -1) { - iseq->arg_size = iseq->arg_block + 1; - } - else if (iseq->arg_post_len) { - iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len; - } - else if (iseq->arg_rest != -1) { - iseq->arg_size = iseq->arg_rest + 1; - } - else if (iseq->arg_opts) { - iseq->arg_size = iseq->argc + iseq->arg_opts - 1; - } - else { - iseq->arg_size = iseq->argc; - } - } - else { - iseq->arg_simple = 1; - iseq->arg_size = iseq->argc; - } - - if (iseq->type == ISEQ_TYPE_BLOCK) { - if (iseq->arg_opts == 0 && iseq->arg_post_len == 0 && iseq->arg_rest == -1) { - if (iseq->argc == 1 && last_comma == 0) { - /* {|a|} */ - iseq->arg_simple |= 0x02; - } - } - } - } - else { - iseq->arg_simple = 1; - } - - return COMPILE_OK; -} - -static int -iseq_set_local_table(rb_iseq_t *iseq, ID *tbl) -{ - int size; - - if (tbl) { - size = *tbl; - tbl++; - } - else { - size = 0; - } - - if (size > 0) { - iseq->local_table = (ID *)ALLOC_N(ID *, size); - MEMCPY(iseq->local_table, tbl, ID *, size); - } - - iseq->local_size = iseq->local_table_size = size; - iseq->local_size += 1; - /* - if (lfp == dfp ) { // top, class, method - dfp[-1]: svar - else { // block - dfp[-1]: cref - } - */ - - debugs("iseq_set_local_table: %d, %d\n", iseq->local_size, iseq->local_table_size); - return COMPILE_OK; -} - -/** - ruby insn object array -> raw instruction sequence - */ -static int -iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor) -{ - LABEL *lobj; - INSN *iobj; - struct iseq_insn_info_entry *insn_info_table; - LINK_ELEMENT *list; - VALUE *generated_iseq; - - int k, pos, sp, stack_max = 0, line = 0; - - /* set label position */ - list = FIRST_ELEMENT(anchor); - k = pos = 0; - while (list) { - switch (list->type) { - case ISEQ_ELEMENT_INSN: - { - iobj = (INSN *)list; - line = iobj->line_no; - pos += insn_data_length(iobj); - k++; - break; - } - case ISEQ_ELEMENT_LABEL: - { - lobj = (LABEL *)list; - lobj->position = pos; - lobj->set = Qtrue; - break; - } - case ISEQ_ELEMENT_NONE: - { - /* ignore */ - break; - } - case ISEQ_ELEMENT_ADJUST: - { - ADJUST *adjust = (ADJUST *)list; - if (adjust->line_no != -1) { - pos += 2 /* insn + 1 operand */; - k++; - } - break; - } - default: - dump_disasm_list(FIRST_ELEMENT(anchor)); - dump_disasm_list(list); - rb_compile_error(RSTRING_PTR(iseq->filename), line, - "error: set_sequence"); - break; - } - list = list->next; - } - - /* make instruction sequence */ - generated_iseq = ALLOC_N(VALUE, pos); - insn_info_table = ALLOC_N(struct iseq_insn_info_entry, k); - - list = FIRST_ELEMENT(anchor); - k = pos = sp = 0; - - while (list) { - switch (list->type) { - case ISEQ_ELEMENT_INSN: - { - int j, len, insn; - const char *types; - VALUE *operands; - - iobj = (INSN *)list; - - /* update sp */ - sp = calc_sp_depth(sp, iobj); - if (sp > stack_max) { - stack_max = sp; - } - - /* fprintf(stderr, "insn: %-16s, sp: %d\n", insn_name(iobj->insn_id), sp); */ - - operands = iobj->operands; - insn = iobj->insn_id; - generated_iseq[pos] = insn; - types = insn_op_types(insn); - len = insn_len(insn); - - /* operand check */ - if (iobj->operand_size != len - 1) { - dump_disasm_list(list); - rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no, - "operand size miss! (%d for %d)", - iobj->operand_size, len - 1); - return 0; - } - - for (j = 0; types[j]; j++) { - char type = types[j]; - /* printf("--> [%c - (%d-%d)]\n", type, k, j); */ - switch (type) { - case TS_OFFSET: - { - /* label(destination position) */ - lobj = (LABEL *)operands[j]; - if (lobj->set != Qtrue) { - rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no, - "unknown label"); - } - if (lobj->sp == -1) { - lobj->sp = sp; - } - generated_iseq[pos + 1 + j] = - lobj->position - (pos + len); - break; - } - case TS_CDHASH: - { - /* - * [obj, label, ...] - */ - int i; - VALUE lits = operands[j]; - VALUE map = rb_hash_new(); - - for (i=0; i < RARRAY_LEN(lits); i+=2) { - VALUE obj = rb_ary_entry(lits, i); - VALUE lv = rb_ary_entry(lits, i+1); - lobj = (LABEL *)(lv & ~1); - - if (lobj->set != Qtrue) { - rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no, - "unknown label"); - } - rb_hash_aset(map, obj, INT2FIX(lobj->position - (pos+len))); - } - generated_iseq[pos + 1 + j] = map; - iseq_add_mark_object(iseq, map); - break; - } - case TS_LINDEX: - case TS_DINDEX: - case TS_NUM: /* ulong */ - generated_iseq[pos + 1 + j] = FIX2INT(operands[j]); - break; - case TS_ISEQ: /* iseq */ - { - VALUE v = operands[j]; - rb_iseq_t *block = 0; - if (v) { - GetISeqPtr(v, block); - } - generated_iseq[pos + 1 + j] = (VALUE)block; - break; - } - case TS_VALUE: /* VALUE */ - { - VALUE v = operands[j]; - generated_iseq[pos + 1 + j] = v; - /* to mark ruby object */ - iseq_add_mark_object(iseq, v); - break; - } - case TS_IC: /* inline cache */ - { - VALUE v = (VALUE)NEW_INLINE_CACHE_ENTRY(); - generated_iseq[pos + 1 + j] = v; - iseq_add_mark_object(iseq, v); - break; - } - case TS_ID: /* ID */ - generated_iseq[pos + 1 + j] = SYM2ID(operands[j]); - break; - case TS_GENTRY: - { - struct global_entry *entry = - (struct global_entry *)(operands[j] & (~1)); - generated_iseq[pos + 1 + j] = (VALUE)entry; - } - break; - default: - rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no, - "unknown operand type: %c", type); - return 0; - } - } - insn_info_table[k].line_no = iobj->line_no; - insn_info_table[k].position = pos; - insn_info_table[k].sp = sp; - pos += len; - k++; - break; - } - case ISEQ_ELEMENT_LABEL: - { - lobj = (LABEL *)list; - if (lobj->sp == -1) { - lobj->sp = sp; - } - else { - sp = lobj->sp; - } - break; - } - case ISEQ_ELEMENT_ADJUST: - { - ADJUST *adjust = (ADJUST *)list; - int orig_sp = sp; - - if (adjust->label) { - sp = adjust->label->sp; - } - else { - sp = 0; - } - - if (adjust->line_no != -1) { - if (orig_sp - sp > 0) { - insn_info_table[k].line_no = adjust->line_no; - insn_info_table[k].position = pos; - insn_info_table[k].sp = sp; - k++; - generated_iseq[pos++] = BIN(adjuststack); - generated_iseq[pos++] = orig_sp - sp; - } - else if (orig_sp - sp == 0) { - /* jump to next insn */ - insn_info_table[k].line_no = adjust->line_no; - insn_info_table[k].position = pos; - insn_info_table[k].sp = sp; - k++; - generated_iseq[pos++] = BIN(jump); - generated_iseq[pos++] = 0; - } - else { - rb_bug("iseq_set_sequence: adjust bug"); - } - } - break; - } - default: - /* ignore */ - break; - } - list = list->next; - } - -#if 0 /* XXX */ - /* this check need dead code elimination */ - if (sp != 1) { - rb_bug("SP is not 0 on %s (%d)\n", RSTRING_PTR(iseq->name), sp); - } -#endif - - iseq->iseq = (void *)generated_iseq; - iseq->iseq_size = pos; - iseq->insn_info_table = insn_info_table; - iseq->insn_info_size = k; - iseq->stack_max = stack_max; - - return COMPILE_OK; -} - -static int -label_get_position(LABEL *lobj) -{ - return lobj->position; -} - -static int -label_get_sp(LABEL *lobj) -{ - return lobj->sp; -} - -static int -iseq_set_exception_table(rb_iseq_t *iseq) -{ - VALUE *tptr, *ptr; - int tlen, i; - struct iseq_catch_table_entry *entry; - - tlen = RARRAY_LEN(iseq->compile_data->catch_table_ary); - tptr = RARRAY_PTR(iseq->compile_data->catch_table_ary); - - iseq->catch_table = tlen ? ALLOC_N(struct iseq_catch_table_entry, tlen) : 0; - iseq->catch_table_size = tlen; - - for (i = 0; i < tlen; i++) { - ptr = RARRAY_PTR(tptr[i]); - entry = &iseq->catch_table[i]; - entry->type = ptr[0] & 0xffff; - entry->start = label_get_position((LABEL *)(ptr[1] & ~1)); - entry->end = label_get_position((LABEL *)(ptr[2] & ~1)); - entry->iseq = ptr[3]; - - /* register iseq as mark object */ - if (entry->iseq != 0) { - iseq_add_mark_object(iseq, entry->iseq); - } - - /* stack depth */ - if (ptr[4]) { - LABEL *lobj = (LABEL *)(ptr[4] & ~1); - entry->cont = label_get_position(lobj); - entry->sp = label_get_sp(lobj); - - /* TODO: Dirty Hack! Fix me */ - if (entry->type == CATCH_TYPE_RESCUE || - entry->type == CATCH_TYPE_BREAK || - entry->type == CATCH_TYPE_NEXT) { - entry->sp--; - } - } - else { - entry->cont = 0; - } - } - - iseq->compile_data->catch_table_ary = 0; /* free */ - return COMPILE_OK; -} - -/* - * set optional argument table - * def foo(a, b=expr1, c=expr2) - * => - * b: - * expr1 - * c: - * expr2 - */ -static int -iseq_set_optargs_table(rb_iseq_t *iseq) -{ - int i; - - if (iseq->arg_opts != 0) { - for (i = 0; i < iseq->arg_opts; i++) { - iseq->arg_opt_table[i] = - label_get_position((LABEL *)iseq->arg_opt_table[i]); - } - } - return COMPILE_OK; -} - -static LINK_ELEMENT * -get_destination_insn(INSN *iobj) -{ - LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0); - LINK_ELEMENT *list; - - list = lobj->link.next; - while (list) { - if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) { - break; - } - list = list->next; - } - return list; -} - -static LINK_ELEMENT * -get_next_insn(INSN *iobj) -{ - LINK_ELEMENT *list = iobj->link.next; - - while (list) { - if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) { - return list; - } - list = list->next; - } - return 0; -} - -static LINK_ELEMENT * -get_prev_insn(INSN *iobj) -{ - LINK_ELEMENT *list = iobj->link.prev; - - while (list) { - if (list->type == ISEQ_ELEMENT_INSN || list->type == ISEQ_ELEMENT_ADJUST) { - return list; - } - list = list->prev; - } - return 0; -} - -static int -iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt) -{ - INSN *iobj = (INSN *)list; - again: - if (iobj->insn_id == BIN(jump)) { - INSN *niobj, *diobj, *piobj; - /* - * useless jump elimination: - * jump LABEL1 - * ... - * LABEL1: - * jump LABEL2 - * - * => in this case, first jump instruction should jump tp - * LABEL2 directly - */ - diobj = (INSN *)get_destination_insn(iobj); - niobj = (INSN *)get_next_insn(iobj); - - if (diobj == niobj) { - /* - * jump LABEL - * LABEL: - * => - * LABEL: - */ - REMOVE_ELEM(&iobj->link); - } - else if (iobj != diobj && diobj->insn_id == BIN(jump)) { - if (OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) { - OPERAND_AT(iobj, 0) = OPERAND_AT(diobj, 0); - goto again; - } - } - else if (diobj->insn_id == BIN(leave)) { - /* - * jump LABEL - * ... - * LABEL: - * leave - * => - * leave - * ... - * LABEL: - * leave - */ - INSN *eiobj = new_insn_core(iseq, iobj->line_no, BIN(leave), - diobj->operand_size, diobj->operands); - INSN *popiobj = new_insn_core(iseq, iobj->line_no, - BIN(pop), 0, 0); - /* replace */ - REPLACE_ELEM((LINK_ELEMENT *)iobj, (LINK_ELEMENT *)eiobj); - INSERT_ELEM_NEXT((LINK_ELEMENT *)eiobj, (LINK_ELEMENT *)popiobj); - iobj = popiobj; - } - /* - * useless jump elimination (if/unless destination): - * if L1 - * jump L2 - * L1: - * ... - * L2: - * - * ==> - * unless L2 - * L1: - * ... - * L2: - */ - else if ((piobj = (INSN *)get_prev_insn(iobj)) != 0 && - (piobj->insn_id == BIN(branchif) || - piobj->insn_id == BIN(branchunless))) { - if (niobj == (INSN *)get_destination_insn(piobj)) { - piobj->insn_id = (piobj->insn_id == BIN(branchif)) - ? BIN(branchunless) : BIN(branchif); - OPERAND_AT(piobj, 0) = OPERAND_AT(iobj, 0); - REMOVE_ELEM(&iobj->link); - } - } - } - - if (iobj->insn_id == BIN(branchif) || - iobj->insn_id == BIN(branchunless)) { - /* - * if L1 - * ... - * L1: - * jump L2 - * => - * if L2 - */ - INSN *nobj = (INSN *)get_destination_insn(iobj); - if (nobj->insn_id == BIN(jump)) { - OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0); - } - } - - if (do_tailcallopt && iobj->insn_id == BIN(leave)) { - /* - * send ... - * leave - * => - * send ..., ... | VM_CALL_TAILCALL_BIT, ... - * leave # unreachable - */ - INSN *piobj = (INSN *)get_prev_insn((INSN *)list); - - if (piobj->insn_id == BIN(send) && - piobj->operands[2] == 0 /* block */ - ) { - piobj->operands[3] = INT2FIX(FIX2INT(piobj->operands[3]) | VM_CALL_TAILCALL_BIT); - } - } - return COMPILE_OK; -} - -static int -insn_set_specialized_instruction(INSN *iobj, int insn_id) -{ - iobj->insn_id = insn_id; - iobj->operand_size = 0; - return COMPILE_OK; -} - -static int -insn_set_specialized_instruction_with_ic(INSN *iobj, int insn_id, int n) -{ - int i; - iobj->insn_id = insn_id; - iobj->operand_size = n; - - /* max of n is 4 */ - for (i=0; i<n; i++) { - iobj->operands[i] = Qnil; - } - - return COMPILE_OK; -} - - -static int -iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj) -{ - if (iobj->insn_id == BIN(send)) { - ID mid = SYM2ID(OPERAND_AT(iobj, 0)); - int argc = FIX2INT(OPERAND_AT(iobj, 1)); - VALUE block = OPERAND_AT(iobj, 2); - VALUE flag = OPERAND_AT(iobj, 3); - - /* TODO: should be more sophisticated search */ - if (block == 0 && flag == INT2FIX(0)) { - if (argc == 0) { - if (mid == idLength) { - insn_set_specialized_instruction(iobj, BIN(opt_length)); - } - else if (mid == idSucc) { - insn_set_specialized_instruction(iobj, BIN(opt_succ)); - } - else if (mid == idNot) { - insn_set_specialized_instruction_with_ic(iobj, BIN(opt_not), 1); - } - } - else if (argc == 1) { - if (0) { - } - else if (mid == idPLUS) { - insn_set_specialized_instruction(iobj, BIN(opt_plus)); - } - else if (mid == idMINUS) { - insn_set_specialized_instruction(iobj, BIN(opt_minus)); - } - else if (mid == idMULT) { - insn_set_specialized_instruction(iobj, BIN(opt_mult)); - } - else if (mid == idDIV) { - insn_set_specialized_instruction(iobj, BIN(opt_div)); - } - else if (mid == idMOD) { - insn_set_specialized_instruction(iobj, BIN(opt_mod)); - } - else if (mid == idEq) { - insn_set_specialized_instruction_with_ic(iobj, BIN(opt_eq), 1); - } - else if (mid == idNeq) { - insn_set_specialized_instruction_with_ic(iobj, BIN(opt_neq), 2); - } - else if (mid == idLT) { - insn_set_specialized_instruction(iobj, BIN(opt_lt)); - } - else if (mid == idLE) { - insn_set_specialized_instruction(iobj, BIN(opt_le)); - } - else if (mid == idGT) { - insn_set_specialized_instruction(iobj, BIN(opt_gt)); - } - else if (mid == idGE) { - insn_set_specialized_instruction(iobj, BIN(opt_ge)); - } - else if (mid == idLTLT) { - insn_set_specialized_instruction(iobj, BIN(opt_ltlt)); - } - else if (mid == idAREF) { - insn_set_specialized_instruction(iobj, BIN(opt_aref)); - } - } - } - - if (argc > 0) { - if (mid == idSend || mid == id__send__ ) { - OPERAND_AT(iobj, 3) |= INT2FIX(VM_CALL_SEND_BIT); - } - } - } - return COMPILE_OK; -} - -static int -iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor) -{ - LINK_ELEMENT *list; - const int do_peepholeopt = iseq->compile_data->option->peephole_optimization; - const int do_tailcallopt = iseq->compile_data->option->tailcall_optimization; - const int do_si = iseq->compile_data->option->specialized_instruction; - const int do_ou = iseq->compile_data->option->operands_unification; - list = FIRST_ELEMENT(anchor); - - while (list) { - if (list->type == ISEQ_ELEMENT_INSN) { - if (do_peepholeopt) { - iseq_peephole_optimize(iseq, list, do_tailcallopt); - } - if (do_si) { - iseq_specialized_instruction(iseq, (INSN *)list); - } - if (do_ou) { - insn_operands_unification((INSN *)list); - } - } - list = list->next; - } - return COMPILE_OK; -} - -#if OPT_INSTRUCTIONS_UNIFICATION -static INSN * -new_unified_insn(rb_iseq_t *iseq, - int insn_id, int size, LINK_ELEMENT *seq_list) -{ - INSN *iobj = 0; - LINK_ELEMENT *list = seq_list; - int i, argc = 0; - VALUE *operands = 0, *ptr = 0; - - - /* count argc */ - for (i = 0; i < size; i++) { - iobj = (INSN *)list; - argc += iobj->operand_size; - list = list->next; - } - - if (argc > 0) { - ptr = operands = - (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * argc); - } - - /* copy operands */ - list = seq_list; - for (i = 0; i < size; i++) { - iobj = (INSN *)list; - MEMCPY(ptr, iobj->operands, VALUE, iobj->operand_size); - ptr += iobj->operand_size; - list = list->next; - } - - return new_insn_core(iseq, iobj->line_no, insn_id, argc, operands); -} -#endif - -/* - * This scheme can get more performance if do this optimize with - * label address resolving. - * It's future work (if compile time was bottle neck). - */ -static int -iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor) -{ -#if OPT_INSTRUCTIONS_UNIFICATION - LINK_ELEMENT *list; - INSN *iobj, *niobj; - int id, j, k; - - list = FIRST_ELEMENT(anchor); - while (list) { - if (list->type == ISEQ_ELEMENT_INSN) { - iobj = (INSN *)list; - id = iobj->insn_id; - if (unified_insns_data[id] != 0) { - const int *const *entry = unified_insns_data[id]; - for (j = 1; j < (int)entry[0]; j++) { - const int *unified = entry[j]; - LINK_ELEMENT *li = list->next; - for (k = 2; k < unified[1]; k++) { - if (li->type != ISEQ_ELEMENT_INSN || - ((INSN *)li)->insn_id != unified[k]) { - goto miss; - } - li = li->next; - } - /* matched */ - niobj = - new_unified_insn(iseq, unified[0], unified[1] - 1, - list); - - /* insert to list */ - niobj->link.prev = (LINK_ELEMENT *)iobj->link.prev; - niobj->link.next = li; - if (li) { - li->prev = (LINK_ELEMENT *)niobj; - } - - list->prev->next = (LINK_ELEMENT *)niobj; - list = (LINK_ELEMENT *)niobj; - break; - miss:; - } - } - } - list = list->next; - } -#endif - return COMPILE_OK; -} - -#if OPT_STACK_CACHING - -#define SC_INSN(insn, stat) sc_insn_info[(insn)][(stat)] -#define SC_NEXT(insn) sc_insn_next[insn] - -#include "opt_sc.inc" - -static int -insn_set_sc_state(rb_iseq_t *iseq, INSN *iobj, int state) -{ - int nstate; - int insn_id; - - insn_id = iobj->insn_id; - iobj->insn_id = SC_INSN(insn_id, state); - nstate = SC_NEXT(iobj->insn_id); - - if (insn_id == BIN(jump) || - insn_id == BIN(branchif) || insn_id == BIN(branchunless)) { - LABEL *lobj = (LABEL *)OPERAND_AT(iobj, 0); - - if (lobj->sc_state != 0) { - if (lobj->sc_state != nstate) { - dump_disasm_list((LINK_ELEMENT *)iobj); - dump_disasm_list((LINK_ELEMENT *)lobj); - printf("\n-- %d, %d\n", lobj->sc_state, nstate); - rb_compile_error(RSTRING_PTR(iseq->filename), iobj->lineno, - "insn_set_sc_state error\n"); - return 0; - } - } - else { - lobj->sc_state = nstate; - } - if (insn_id == BIN(jump)) { - nstate = SCS_XX; - } - } - else if (insn_id == BIN(leave)) { - nstate = SCS_XX; - } - - return nstate; -} - -static int -label_set_sc_state(LABEL *lobj, int state) -{ - if (lobj->sc_state != 0) { - if (lobj->sc_state != state) { - state = lobj->sc_state; - } - } - else { - lobj->sc_state = state; - } - - return state; -} - - -#endif - -static int -iseq_set_sequence_stackcaching(rb_iseq_t *iseq, LINK_ANCHOR *anchor) -{ -#if OPT_STACK_CACHING - LINK_ELEMENT *list; - int state, insn_id; - - /* initialize */ - state = SCS_XX; - list = FIRST_ELEMENT(anchor); - /* dump_disasm_list(list); */ - - /* for each list element */ - while (list) { - redo_point: - switch (list->type) { - case ISEQ_ELEMENT_INSN: - { - INSN *iobj = (INSN *)list; - insn_id = iobj->insn_id; - - /* dump_disasm_list(list); */ - - switch (insn_id) { - case BIN(nop): - { - /* exception merge point */ - if (state != SCS_AX) { - INSN *rpobj = - new_insn_body(iseq, 0, BIN(reput), 0); - - /* replace this insn */ - REPLACE_ELEM(list, (LINK_ELEMENT *)rpobj); - list = (LINK_ELEMENT *)rpobj; - goto redo_point; - } - break; - } - case BIN(swap): - { - if (state == SCS_AB || state == SCS_BA) { - state = (state == SCS_AB ? SCS_BA : SCS_AB); - - REMOVE_ELEM(list); - list = list->next; - goto redo_point; - } - break; - } - case BIN(pop): - { - switch (state) { - case SCS_AX: - case SCS_BX: - state = SCS_XX; - break; - case SCS_AB: - state = SCS_AX; - break; - case SCS_BA: - state = SCS_BX; - break; - case SCS_XX: - goto normal_insn; - default: - rb_compile_error(RSTRING_PTR(iseq->filename), iobj->line_no, - "unreachable"); - } - /* remove useless pop */ - REMOVE_ELEM(list); - list = list->next; - goto redo_point; - } - default:; - /* none */ - } /* end of switch */ - normal_insn: - state = insn_set_sc_state(iseq, iobj, state); - break; - } - case ISEQ_ELEMENT_LABEL: - { - LABEL *lobj; - lobj = (LABEL *)list; - - state = label_set_sc_state(lobj, state); - } - default: - break; - } - list = list->next; - } -#endif - return COMPILE_OK; -} - - - -static int -compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int *cntp) -{ - NODE *list = node->nd_next; - VALUE lit = node->nd_lit; - int cnt = 1; - - debugp_param("nd_lit", lit); - ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit); - - while (list) { - COMPILE(ret, "each string", list->nd_head); - cnt++; - list = list->nd_next; - } - *cntp = cnt; - - return COMPILE_OK; -} - -static int -compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node) -{ - int cnt; - compile_dstr_fragments(iseq, ret, node, &cnt); - ADD_INSN1(ret, nd_line(node), concatstrings, INT2FIX(cnt)); - return COMPILE_OK; -} - -static int -compile_dregx(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node) -{ - int cnt; - compile_dstr_fragments(iseq, ret, node, &cnt); - ADD_INSN2(ret, nd_line(node), toregexp, INT2FIX(node->nd_cflag), INT2FIX(cnt)); - return COMPILE_OK; -} - -static int -compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * cond, - LABEL *then_label, LABEL *else_label) -{ - switch (nd_type(cond)) { - case NODE_AND: - { - LABEL *label = NEW_LABEL(nd_line(cond)); - compile_branch_condition(iseq, ret, cond->nd_1st, label, - else_label); - ADD_LABEL(ret, label); - compile_branch_condition(iseq, ret, cond->nd_2nd, then_label, - else_label); - break; - } - case NODE_OR: - { - LABEL *label = NEW_LABEL(nd_line(cond)); - compile_branch_condition(iseq, ret, cond->nd_1st, then_label, - label); - ADD_LABEL(ret, label); - compile_branch_condition(iseq, ret, cond->nd_2nd, then_label, - else_label); - break; - } - case NODE_LIT: /* NODE_LIT is always not true */ - case NODE_TRUE: - case NODE_STR: - /* printf("useless conditon eliminate (%s)\n", ruby_node_name(nd_type(cond))); */ - ADD_INSNL(ret, nd_line(cond), jump, then_label); - break; - case NODE_FALSE: - case NODE_NIL: - /* printf("useless conditon eliminate (%s)\n", ruby_node_name(nd_type(cond))); */ - ADD_INSNL(ret, nd_line(cond), jump, else_label); - break; - default: - COMPILE(ret, "branch condition", cond); - ADD_INSNL(ret, nd_line(cond), branchunless, else_label); - ADD_INSNL(ret, nd_line(cond), jump, then_label); - break; - } - return COMPILE_OK; -} - -static int -compile_array_(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root, - VALUE opt_p, int poped) -{ - NODE *node = node_root; - int len = node->nd_alen, line = nd_line(node), i=0; - DECL_ANCHOR(anchor); - - INIT_ANCHOR(anchor); - if (nd_type(node) != NODE_ZARRAY) { - while (node) { - if (nd_type(node) != NODE_ARRAY) { - rb_bug("compile_array: This node is not NODE_ARRAY, but %s", - ruby_node_name(nd_type(node))); - } - - i++; - if (opt_p && nd_type(node->nd_head) != NODE_LIT) { - opt_p = Qfalse; - } - COMPILE_(anchor, "array element", node->nd_head, poped); - node = node->nd_next; - } - } - - if (len != i) { - if (0) { - rb_bug("node error: compile_array (%d: %d-%d)", - (int)nd_line(node_root), len, i); - } - len = i; - } - - if (opt_p == Qtrue) { - if (!poped) { - VALUE ary = rb_ary_new(); - node = node_root; - while (node) { - rb_ary_push(ary, node->nd_head->nd_lit); - node = node->nd_next; - } - - iseq_add_mark_object_compile_time(iseq, ary); - ADD_INSN1(ret, nd_line(node_root), duparray, ary); - } - } - else { - if (!poped) { - ADD_INSN1(anchor, line, newarray, INT2FIX(len)); - } - APPEND_LIST(ret, anchor); - } - return len; -} - -static VALUE -compile_array(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root, VALUE opt_p) -{ - return compile_array_(iseq, ret, node_root, opt_p, 0); -} - -static VALUE -case_when_optimizable_literal(NODE * node) -{ - switch (nd_type(node)) { - case NODE_LIT: { - VALUE v = node->nd_lit; - if (SYMBOL_P(v) || rb_obj_is_kind_of(v, rb_cNumeric)) { - return v; - } - break; - } - case NODE_STR: - return node->nd_lit; - } - return Qfalse; -} - -static VALUE -when_vals(rb_iseq_t *iseq, LINK_ANCHOR *cond_seq, NODE *vals, LABEL *l1, VALUE special_literals) -{ - while (vals) { - VALUE lit; - NODE* val; - - val = vals->nd_head; - - if (special_literals && - (lit = case_when_optimizable_literal(val)) != Qfalse) { - rb_ary_push(special_literals, lit); - rb_ary_push(special_literals, (VALUE)(l1) | 1); - } - else { - special_literals = Qfalse; - } - - COMPILE(cond_seq, "when cond", val); - ADD_INSN1(cond_seq, nd_line(val), topn, INT2FIX(1)); - ADD_SEND(cond_seq, nd_line(val), ID2SYM(idEqq), INT2FIX(1)); - ADD_INSNL(cond_seq, nd_line(val), branchif, l1); - vals = vals->nd_next; - } - return special_literals; -} - -static int -compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node) -{ - switch (nd_type(node)) { - case NODE_ATTRASGN: { - INSN *iobj; - VALUE dupidx; - - COMPILE_POPED(ret, "masgn lhs (NODE_ATTRASGN)", node); - POP_ELEMENT(ret); /* pop pop insn */ - iobj = (INSN *)POP_ELEMENT(ret); /* pop send insn */ - - dupidx = iobj->operands[1]; - dupidx = INT2FIX(FIX2INT(dupidx) + 1); - iobj->operands[1] = dupidx; - - ADD_INSN1(ret, nd_line(node), topn, dupidx); - ADD_ELEM(ret, (LINK_ELEMENT *)iobj); - ADD_INSN(ret, nd_line(node), pop); /* result */ - ADD_INSN(ret, nd_line(node), pop); /* rhs */ - break; - } - case NODE_MASGN: { - DECL_ANCHOR(anchor); - INIT_ANCHOR(anchor); - COMPILE_POPED(anchor, "nest masgn lhs", node); - REMOVE_ELEM(FIRST_ELEMENT(anchor)); - ADD_SEQ(ret, anchor); - break; - } - default: { - DECL_ANCHOR(anchor); - INIT_ANCHOR(anchor); - COMPILE_POPED(anchor, "masgn lhs", node); - REMOVE_ELEM(FIRST_ELEMENT(anchor)); - ADD_SEQ(ret, anchor); - } - } - - return COMPILE_OK; -} - -static void -compile_massign_opt_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *lhsn) -{ - if (lhsn) { - compile_massign_opt_lhs(iseq, ret, lhsn->nd_next); - compile_massign_lhs(iseq, ret, lhsn->nd_head); - } -} - -static int -compile_massign_opt(rb_iseq_t *iseq, LINK_ANCHOR *ret, - NODE *rhsn, NODE *orig_lhsn) -{ - VALUE mem[64]; - const int memsize = sizeof(mem) / sizeof(mem[0]); - int memindex = 0; - int llen = 0, rlen = 0; - int i; - NODE *lhsn = orig_lhsn; - -#define MEMORY(v) { \ - int i; \ - if (memindex == memsize) return 0; \ - for (i=0; i<memindex; i++) { \ - if (mem[i] == (v)) return 0; \ - } \ - mem[memindex++] = (v); \ -} - - if (rhsn == 0 || nd_type(rhsn) != NODE_ARRAY) { - return 0; - } - - while (lhsn) { - NODE *ln = lhsn->nd_head; - switch (nd_type(ln)) { - case NODE_LASGN: - MEMORY(ln->nd_vid); - break; - case NODE_DASGN: - case NODE_DASGN_CURR: - case NODE_IASGN: - case NODE_IASGN2: - case NODE_CVASGN: - MEMORY(ln->nd_vid); - break; - default: - return 0; - } - lhsn = lhsn->nd_next; - llen++; - } - - while (rhsn) { - if (llen <= rlen) { - COMPILE_POPED(ret, "masgn val (poped)", rhsn->nd_head); - } - else { - COMPILE(ret, "masgn val", rhsn->nd_head); - } - rhsn = rhsn->nd_next; - rlen++; - } - - if (llen > rlen) { - for (i=0; i<llen-rlen; i++) { - ADD_INSN(ret, nd_line(orig_lhsn), putnil); - } - } - - compile_massign_opt_lhs(iseq, ret, orig_lhsn); - return 1; -} - -static int -compile_massign(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node, int poped) -{ - NODE *rhsn = node->nd_value; - NODE *splatn = node->nd_args; - NODE *lhsn = node->nd_head; - int lhs_splat = (splatn && (VALUE)splatn != (VALUE)-1) ? 1 : 0; - - if (!poped || splatn || !compile_massign_opt(iseq, ret, rhsn, lhsn)) { - int llen = 0; - DECL_ANCHOR(lhsseq); - - INIT_ANCHOR(lhsseq); - - while (lhsn) { - compile_massign_lhs(iseq, lhsseq, lhsn->nd_head); - llen += 1; - lhsn = lhsn->nd_next; - } - - COMPILE(ret, "normal masgn rhs", rhsn); - - if (!poped) { - ADD_INSN(ret, nd_line(node), dup); - } - - ADD_INSN2(ret, nd_line(node), expandarray, - INT2FIX(llen), INT2FIX(lhs_splat)); - ADD_SEQ(ret, lhsseq); - - if (lhs_splat) { - if (nd_type(splatn) == NODE_POSTARG) { - /*a, b, *r, p1, p2 */ - NODE *postn = splatn->nd_2nd; - NODE *restn = splatn->nd_1st; - int num = postn->nd_alen; - int flag = 0x02 | (((VALUE)restn == (VALUE)-1) ? 0x00 : 0x01); - - ADD_INSN2(ret, nd_line(splatn), expandarray, - INT2FIX(num), INT2FIX(flag)); - - if ((VALUE)restn != (VALUE)-1) { - compile_massign_lhs(iseq, ret, restn); - } - while (postn) { - compile_massign_lhs(iseq, ret, postn->nd_head); - postn = postn->nd_next; - } - } - else { - /* a, b, *r */ - compile_massign_lhs(iseq, ret, splatn); - } - } - } - return COMPILE_OK; -} - -static int -compile_colon2(rb_iseq_t *iseq, NODE * node, - LINK_ANCHOR *pref, LINK_ANCHOR *body) -{ - switch (nd_type(node)) { - case NODE_CONST: - debugi("compile_colon2 - colon", node->nd_vid); - ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_vid)); - break; - case NODE_COLON3: - debugi("compile_colon2 - colon3", node->nd_mid); - ADD_INSN(body, nd_line(node), pop); - ADD_INSN1(body, nd_line(node), putobject, rb_cObject); - ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid)); - break; - case NODE_COLON2: - compile_colon2(iseq, node->nd_head, pref, body); - debugi("compile_colon2 - colon2", node->nd_mid); - ADD_INSN1(body, nd_line(node), getconstant, ID2SYM(node->nd_mid)); - break; - default: - COMPILE(pref, "const colon2 prefix", node); - break; - } - return COMPILE_OK; -} - -static VALUE -compile_cpath(LINK_ANCHOR *ret, rb_iseq_t *iseq, NODE *cpath) -{ - if (nd_type(cpath) == NODE_COLON3) { - /* toplevel class ::Foo */ - ADD_INSN1(ret, nd_line(cpath), putobject, rb_cObject); - return Qfalse; - } - else if (cpath->nd_head) { - /* Bar::Foo */ - COMPILE(ret, "nd_else->nd_head", cpath->nd_head); - return Qfalse; - } - else { - /* class at cbase Foo */ - ADD_INSN1(ret, nd_line(cpath), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE)); - return Qtrue; - } -} - -static int -defined_expr(rb_iseq_t *iseq, LINK_ANCHOR *ret, - NODE *node, LABEL **lfinish, VALUE needstr) -{ - const char *estr = 0; - enum node_type type; - - switch (type = nd_type(node)) { - - /* easy literals */ - case NODE_NIL: - estr = "nil"; - break; - case NODE_SELF: - estr = "self"; - break; - case NODE_TRUE: - estr = "true"; - break; - case NODE_FALSE: - estr = "false"; - break; - - case NODE_ARRAY:{ - NODE *vals = node; - - do { - defined_expr(iseq, ret, vals->nd_head, lfinish, Qfalse); - - if (!lfinish[1]) { - lfinish[1] = NEW_LABEL(nd_line(node)); - } - ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]); - } while ((vals = vals->nd_next) != NULL); - } - case NODE_STR: - case NODE_LIT: - case NODE_ZARRAY: - case NODE_AND: - case NODE_OR: - default: - estr = "expression"; - break; - - /* variables */ - case NODE_LVAR: - case NODE_DVAR: - estr = "local-variable"; - break; - - case NODE_IVAR: - ADD_INSN(ret, nd_line(node), putnil); - ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_IVAR), - ID2SYM(node->nd_vid), needstr); - return 1; - - case NODE_GVAR: - ADD_INSN(ret, nd_line(node), putnil); - ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_GVAR), - ((VALUE)node->nd_entry) | 1, needstr); - return 1; - - case NODE_CVAR: - ADD_INSN(ret, nd_line(node), putnil); - ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CVAR), - ID2SYM(node->nd_vid), needstr); - return 1; - - case NODE_CONST: - ADD_INSN(ret, nd_line(node), putnil); - ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST), - ID2SYM(node->nd_vid), needstr); - return 1; - case NODE_COLON2: - if (!lfinish[1]) { - lfinish[1] = NEW_LABEL(nd_line(node)); - } - defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse); - ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]); - - if (rb_is_const_id(node->nd_mid)) { - COMPILE(ret, "defined/colon2#nd_head", node->nd_head); - ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_CONST), - ID2SYM(node->nd_mid), needstr); - } - else { - COMPILE(ret, "defined/colon2#nd_head", node->nd_head); - ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD), - ID2SYM(node->nd_mid), needstr); - } - return 1; - case NODE_COLON3: - ADD_INSN1(ret, nd_line(node), putobject, rb_cObject); - ADD_INSN3(ret, nd_line(node), defined, - INT2FIX(DEFINED_CONST), ID2SYM(node->nd_mid), needstr); - return 1; - - /* method dispatch */ - case NODE_CALL: - case NODE_VCALL: - case NODE_FCALL: - case NODE_ATTRASGN:{ - int self = Qtrue; - - switch (type) { - case NODE_ATTRASGN: - if (node->nd_recv == (NODE *)1) break; - case NODE_CALL: - self = Qfalse; - break; - default: - /* through */; - } - if (!lfinish[1]) { - lfinish[1] = NEW_LABEL(nd_line(node)); - } - if (node->nd_args) { - defined_expr(iseq, ret, node->nd_args, lfinish, Qfalse); - ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]); - } - if (!self) { - LABEL *lstart = NEW_LABEL(nd_line(node)); - LABEL *lend = NEW_LABEL(nd_line(node)); - VALUE rescue = NEW_CHILD_ISEQVAL(NEW_NIL(), - rb_str_concat(rb_str_new2 - ("defined guard in "), - iseq->name), - ISEQ_TYPE_DEFINED_GUARD); - - defined_expr(iseq, ret, node->nd_recv, lfinish, Qfalse); - ADD_INSNL(ret, nd_line(node), branchunless, lfinish[1]); - - ADD_LABEL(ret, lstart); - COMPILE(ret, "defined/recv", node->nd_recv); - ADD_LABEL(ret, lend); - ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]); - ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_METHOD), - ID2SYM(node->nd_mid), needstr); - } - else { - ADD_INSN(ret, nd_line(node), putself); - ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_FUNC), - ID2SYM(node->nd_mid), needstr); - } - return 1; - } - - case NODE_YIELD: - ADD_INSN(ret, nd_line(node), putnil); - ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_YIELD), 0, - needstr); - return 1; - - case NODE_BACK_REF: - case NODE_NTH_REF: - ADD_INSN(ret, nd_line(node), putnil); - ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_REF), - INT2FIX((node->nd_nth << 1) | (type == NODE_BACK_REF)), - needstr); - return 1; - - case NODE_SUPER: - case NODE_ZSUPER: - ADD_INSN(ret, nd_line(node), putnil); - ADD_INSN3(ret, nd_line(node), defined, INT2FIX(DEFINED_ZSUPER), 0, - needstr); - return 1; - - case NODE_OP_ASGN1: - case NODE_OP_ASGN2: - case NODE_OP_ASGN_OR: - case NODE_OP_ASGN_AND: - case NODE_MASGN: - case NODE_LASGN: - case NODE_DASGN: - case NODE_DASGN_CURR: - case NODE_GASGN: - case NODE_IASGN: - case NODE_CDECL: - case NODE_CVDECL: - case NODE_CVASGN: - estr = "assignment"; - break; - } - - if (estr != 0) { - if (needstr != Qfalse) { - VALUE str = rb_str_new2(estr); - ADD_INSN1(ret, nd_line(node), putstring, str); - iseq_add_mark_object_compile_time(iseq, str); - } - else { - ADD_INSN1(ret, nd_line(node), putobject, Qtrue); - } - return 1; - } - return 0; -} - -#define BUFSIZE 0x100 - -static VALUE -make_name_for_block(rb_iseq_t *iseq) -{ - if (iseq->parent_iseq == 0) { - return rb_sprintf("block in %s", RSTRING_PTR(iseq->name)); - } - else { - int level = 1; - rb_iseq_t *ip = iseq; - while (ip->local_iseq != ip) { - ip = ip->parent_iseq; - level++; - } - return rb_sprintf("block (%d levels) in %s", level, RSTRING_PTR(ip->name)); - } -} - -static void -add_ensure_range(rb_iseq_t *iseq, struct ensure_range *erange, - LABEL *lstart, LABEL *lend) -{ - struct ensure_range *ne = - compile_data_alloc(iseq, sizeof(struct ensure_range)); - - while (erange->next != 0) { - erange = erange->next; - } - ne->next = 0; - ne->begin = lend; - ne->end = erange->end; - erange->end = lstart; - - erange->next = ne; -} - -static void -add_ensure_iseq(LINK_ANCHOR *ret, rb_iseq_t *iseq) -{ - struct iseq_compile_data_ensure_node_stack *enlp = - iseq->compile_data->ensure_node_stack; - struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp; - DECL_ANCHOR(ensure); - - INIT_ANCHOR(ensure); - while (enlp) { - DECL_ANCHOR(ensure_part); - LABEL *lstart = NEW_LABEL(0); - LABEL *lend = NEW_LABEL(0); - - INIT_ANCHOR(ensure_part); - add_ensure_range(iseq, enlp->erange, lstart, lend); - - iseq->compile_data->ensure_node_stack = enlp->prev; - ADD_LABEL(ensure_part, lstart); - COMPILE_POPED(ensure_part, "ensure part", enlp->ensure_node); - ADD_LABEL(ensure_part, lend); - - ADD_SEQ(ensure, ensure_part); - enlp = enlp->prev; - } - iseq->compile_data->ensure_node_stack = prev_enlp; - ADD_SEQ(ret, ensure); -} - -static VALUE -setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, unsigned long *flag) -{ - VALUE argc = INT2FIX(0); - int nsplat = 0; - DECL_ANCHOR(arg_block); - DECL_ANCHOR(args_splat); - - INIT_ANCHOR(arg_block); - INIT_ANCHOR(args_splat); - if (argn && nd_type(argn) == NODE_BLOCK_PASS) { - COMPILE(arg_block, "block", argn->nd_body); - *flag |= VM_CALL_ARGS_BLOCKARG_BIT; - argn = argn->nd_head; - } - - setup_argn: - if (argn) { - switch (nd_type(argn)) { - case NODE_SPLAT: { - COMPILE(args, "args (splat)", argn->nd_head); - argc = INT2FIX(1); - nsplat++; - *flag |= VM_CALL_ARGS_SPLAT_BIT; - break; - } - case NODE_ARGSCAT: - case NODE_ARGSPUSH: { - int next_is_array = (nd_type(argn->nd_head) == NODE_ARRAY); - DECL_ANCHOR(tmp); - - INIT_ANCHOR(tmp); - COMPILE(tmp, "args (cat: splat)", argn->nd_body); - if (next_is_array && nsplat == 0) { - /* none */ - } - else { - if (nd_type(argn) == NODE_ARGSCAT) { - ADD_INSN1(tmp, nd_line(argn), splatarray, Qfalse); - } - else { - ADD_INSN1(tmp, nd_line(argn), newarray, INT2FIX(1)); - } - } - INSERT_LIST(args_splat, tmp); - nsplat++; - *flag |= VM_CALL_ARGS_SPLAT_BIT; - - if (next_is_array) { - argc = INT2FIX(compile_array(iseq, args, argn->nd_head, Qfalse) + 1); - POP_ELEMENT(args); - } - else { - argn = argn->nd_head; - goto setup_argn; - } - break; - } - case NODE_ARRAY: { - argc = INT2FIX(compile_array(iseq, args, argn, Qfalse)); - POP_ELEMENT(args); - break; - } - default: { - rb_bug("setup_arg: unknown node: %s\n", ruby_node_name(nd_type(argn))); - } - } - } - - if (nsplat > 1) { - int i; - for (i=1; i<nsplat; i++) { - ADD_INSN(args_splat, nd_line(args), concatarray); - } - } - - if (!LIST_SIZE_ZERO(args_splat)) { - ADD_SEQ(args, args_splat); - } - - if (*flag & VM_CALL_ARGS_BLOCKARG_BIT) { - ADD_SEQ(args, arg_block); - } - return argc; -} - - -/** - compile each node - - self: InstructionSequence - node: Ruby compiled node - poped: This node will be poped - */ -static int -iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) -{ - enum node_type type; - - if (node == 0) { - if (!poped) { - debugs("node: NODE_NIL(implicit)\n"); - ADD_INSN(ret, iseq->compile_data->last_line, putnil); - } - return COMPILE_OK; - } - - iseq->compile_data->last_line = nd_line(node); - debug_node_start(node); - - type = nd_type(node); - - if (node->flags & NODE_FL_NEWLINE) { - ADD_TRACE(ret, nd_line(node), RUBY_EVENT_LINE); - } - - switch (type) { - case NODE_BLOCK:{ - while (node && nd_type(node) == NODE_BLOCK) { - COMPILE_(ret, "BLOCK body", node->nd_head, - (node->nd_next == 0 && poped == 0) ? 0 : 1); - node = node->nd_next; - } - if (node) { - COMPILE_(ret, "BLOCK next", node->nd_next, poped); - } - break; - } - case NODE_IF:{ - DECL_ANCHOR(cond_seq); - DECL_ANCHOR(then_seq); - DECL_ANCHOR(else_seq); - LABEL *then_label, *else_label, *end_label; - - INIT_ANCHOR(cond_seq); - INIT_ANCHOR(then_seq); - INIT_ANCHOR(else_seq); - then_label = NEW_LABEL(nd_line(node)); - else_label = NEW_LABEL(nd_line(node)); - end_label = NEW_LABEL(nd_line(node)); - - compile_branch_condition(iseq, cond_seq, node->nd_cond, - then_label, else_label); - COMPILE_(then_seq, "then", node->nd_body, poped); - COMPILE_(else_seq, "else", node->nd_else, poped); - - ADD_SEQ(ret, cond_seq); - - ADD_LABEL(ret, then_label); - ADD_SEQ(ret, then_seq); - ADD_INSNL(ret, nd_line(node), jump, end_label); - - ADD_LABEL(ret, else_label); - ADD_SEQ(ret, else_seq); - - ADD_LABEL(ret, end_label); - - break; - } - case NODE_CASE:{ - NODE *vals; - NODE *tempnode = node; - LABEL *endlabel, *elselabel; - DECL_ANCHOR(head); - DECL_ANCHOR(body_seq); - DECL_ANCHOR(cond_seq); - VALUE special_literals = rb_ary_new(); - - INIT_ANCHOR(head); - INIT_ANCHOR(body_seq); - INIT_ANCHOR(cond_seq); - if (node->nd_head == 0) { - COMPILE_(ret, "when", node->nd_body, poped); - break; - } - COMPILE(head, "case base", node->nd_head); - - node = node->nd_body; - type = nd_type(node); - - if (type != NODE_WHEN) { - COMPILE_ERROR((ERROR_ARGS "NODE_CASE: unexpected node. must be NODE_WHEN, but %s", ruby_node_name(type))); - } - - endlabel = NEW_LABEL(nd_line(node)); - elselabel = NEW_LABEL(nd_line(node)); - - ADD_SEQ(ret, head); /* case VAL */ - - while (type == NODE_WHEN) { - LABEL *l1; - - l1 = NEW_LABEL(nd_line(node)); - ADD_LABEL(body_seq, l1); - ADD_INSN(body_seq, nd_line(node), pop); - COMPILE_(body_seq, "when body", node->nd_body, poped); - ADD_INSNL(body_seq, nd_line(node), jump, endlabel); - - vals = node->nd_head; - if (vals) { - switch (nd_type(vals)) { - case NODE_ARRAY: - special_literals = when_vals(iseq, cond_seq, vals, l1, special_literals); - break; - case NODE_SPLAT: - case NODE_ARGSCAT: - case NODE_ARGSPUSH: - special_literals = 0; - COMPILE(cond_seq, "when/cond splat", vals); - ADD_INSN1(cond_seq, nd_line(vals), checkincludearray, Qtrue); - ADD_INSNL(cond_seq, nd_line(vals), branchif, l1); - break; - default: - rb_bug("NODE_CASE: unknown node (%s)", - ruby_node_name(nd_type(vals))); - } - } - else { - rb_bug("NODE_CASE: must be NODE_ARRAY, but 0"); - } - - node = node->nd_next; - if (!node) { - break; - } - type = nd_type(node); - } - /* else */ - if (node) { - ADD_LABEL(cond_seq, elselabel); - ADD_INSN(cond_seq, nd_line(node), pop); - COMPILE_(cond_seq, "else", node, poped); - ADD_INSNL(cond_seq, nd_line(node), jump, endlabel); - } - else { - debugs("== else (implicit)\n"); - ADD_LABEL(cond_seq, elselabel); - ADD_INSN(cond_seq, nd_line(tempnode), pop); - if (!poped) { - ADD_INSN(cond_seq, nd_line(tempnode), putnil); - } - ADD_INSNL(cond_seq, nd_line(tempnode), jump, endlabel); - } - - if (special_literals) { - ADD_INSN(ret, nd_line(tempnode), dup); - ADD_INSN2(ret, nd_line(tempnode), opt_case_dispatch, - special_literals, elselabel); - iseq_add_mark_object_compile_time(iseq, special_literals); - } - - ADD_SEQ(ret, cond_seq); - ADD_SEQ(ret, body_seq); - ADD_LABEL(ret, endlabel); - break; - } - case NODE_WHEN:{ - NODE *vals; - NODE *val; - NODE *orig_node = node; - LABEL *endlabel; - DECL_ANCHOR(body_seq); - - INIT_ANCHOR(body_seq); - endlabel = NEW_LABEL(nd_line(node)); - - while (node && nd_type(node) == NODE_WHEN) { - LABEL *l1 = NEW_LABEL(nd_line(node)); - ADD_LABEL(body_seq, l1); - COMPILE_(body_seq, "when", node->nd_body, poped); - ADD_INSNL(body_seq, nd_line(node), jump, endlabel); - - vals = node->nd_head; - if (vals && nd_type(vals) == NODE_ARRAY) { - while (vals) { - val = vals->nd_head; - COMPILE(ret, "when2", val); - ADD_INSNL(ret, nd_line(val), branchif, l1); - vals = vals->nd_next; - } - } - else if (nd_type(vals) == NODE_SPLAT || - nd_type(vals) == NODE_ARGSCAT || - nd_type(vals) == NODE_ARGSPUSH) { - - NODE *val = vals->nd_head; - - if (nd_type(vals) == NODE_ARGSCAT || nd_type(vals) == NODE_ARGSPUSH) { - NODE *vs = vals->nd_head; - val = vals->nd_body; - - while (vs) { - NODE* val = vs->nd_head; - COMPILE(ret, "when/argscat", val); - ADD_INSNL(ret, nd_line(val), branchif, l1); - vs = vs->nd_next; - } - } - - ADD_INSN(ret, nd_line(val), putnil); - COMPILE(ret, "when2/splat", val); - ADD_INSN1(ret, nd_line(val), checkincludearray, Qfalse); - ADD_INSN(ret, nd_line(val), pop); - ADD_INSNL(ret, nd_line(val), branchif, l1); - } - else { - rb_bug("err"); - } - node = node->nd_next; - } - /* else */ - COMPILE_(ret, "else", node, poped); - ADD_INSNL(ret, nd_line(orig_node), jump, endlabel); - - ADD_SEQ(ret, body_seq); - ADD_LABEL(ret, endlabel); - - break; - } - case NODE_OPT_N: - case NODE_WHILE: - case NODE_UNTIL:{ - LABEL *prev_start_label = iseq->compile_data->start_label; - LABEL *prev_end_label = iseq->compile_data->end_label; - LABEL *prev_redo_label = iseq->compile_data->redo_label; - VALUE prev_loopval_popped = iseq->compile_data->loopval_popped; - - struct iseq_compile_data_ensure_node_stack *enlp = - iseq->compile_data->ensure_node_stack; - - LABEL *next_label = iseq->compile_data->start_label = NEW_LABEL(nd_line(node)); /* next */ - LABEL *redo_label = iseq->compile_data->redo_label = NEW_LABEL(nd_line(node)); /* redo */ - LABEL *break_label = iseq->compile_data->end_label = NEW_LABEL(nd_line(node)); /* break */ - LABEL *end_label = NEW_LABEL(nd_line(node)); - - LABEL *next_catch_label = NEW_LABEL(nd_line(node)); - LABEL *tmp_label = NULL; - - iseq->compile_data->loopval_popped = 0; - iseq->compile_data->ensure_node_stack = 0; - - if (type == NODE_OPT_N || node->nd_state == 1) { - ADD_INSNL(ret, nd_line(node), jump, next_label); - } - else { - tmp_label = NEW_LABEL(nd_line(node)); - ADD_INSNL(ret, nd_line(node), jump, tmp_label); - } - ADD_INSN(ret, nd_line(node), putnil); - ADD_LABEL(ret, next_catch_label); - ADD_INSN(ret, nd_line(node), pop); - ADD_INSNL(ret, nd_line(node), jump, next_label); - if (tmp_label) ADD_LABEL(ret, tmp_label); - - ADD_LABEL(ret, redo_label); - COMPILE_POPED(ret, "while body", node->nd_body); - ADD_LABEL(ret, next_label); /* next */ - - if (type == NODE_WHILE) { - compile_branch_condition(iseq, ret, node->nd_cond, - redo_label, end_label); - } - else if (type == NODE_UNTIL) { - /* untile */ - compile_branch_condition(iseq, ret, node->nd_cond, - end_label, redo_label); - } - else { - ADD_CALL_RECEIVER(ret, nd_line(node)); - ADD_CALL(ret, nd_line(node), ID2SYM(idGets), INT2FIX(0)); - ADD_INSNL(ret, nd_line(node), branchif, redo_label); - /* opt_n */ - } - - ADD_LABEL(ret, end_label); - - if (node->nd_state == Qundef) { - /* ADD_INSN(ret, nd_line(node), putundef); */ - rb_bug("unsupported: putundef"); - } - else { - ADD_INSN(ret, nd_line(node), putnil); - } - - ADD_LABEL(ret, break_label); /* break */ - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - - ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, - 0, break_label); - ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, 0, - next_catch_label); - ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, 0, - iseq->compile_data->redo_label); - - iseq->compile_data->start_label = prev_start_label; - iseq->compile_data->end_label = prev_end_label; - iseq->compile_data->redo_label = prev_redo_label; - iseq->compile_data->loopval_popped = prev_loopval_popped; - iseq->compile_data->ensure_node_stack = enlp; - break; - } - case NODE_ITER: - case NODE_FOR:{ - VALUE prevblock = iseq->compile_data->current_block; - LABEL *retry_label = NEW_LABEL(nd_line(node)); - LABEL *retry_end_l = NEW_LABEL(nd_line(node)); - ID mid = 0; - - ADD_LABEL(ret, retry_label); - if (nd_type(node) == NODE_FOR) { - COMPILE(ret, "iter caller (for)", node->nd_iter); - - iseq->compile_data->current_block = - NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), - ISEQ_TYPE_BLOCK); - - mid = idEach; - ADD_SEND_R(ret, nd_line(node), ID2SYM(idEach), INT2FIX(0), - iseq->compile_data->current_block, INT2FIX(0)); - } - else { - iseq->compile_data->current_block = - NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), - ISEQ_TYPE_BLOCK); - COMPILE(ret, "iter caller", node->nd_iter); - } - ADD_LABEL(ret, retry_end_l); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - - iseq->compile_data->current_block = prevblock; - - ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, 0, retry_end_l); - - break; - } - case NODE_BREAK:{ - unsigned long level = 0; - - if (iseq->compile_data->redo_label != 0) { - /* while/until */ - LABEL *splabel = NEW_LABEL(0); - ADD_LABEL(ret, splabel); - ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label); - COMPILE_(ret, "break val (while/until)", node->nd_stts, iseq->compile_data->loopval_popped); - add_ensure_iseq(ret, iseq); - ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->end_label); - ADD_ADJUST_RESTORE(ret, splabel); - - if (!poped) { - ADD_INSN(ret, nd_line(node), putnil); - } - } - else if (iseq->type == ISEQ_TYPE_BLOCK) { - break_by_insn: - /* escape from block */ - COMPILE(ret, "break val (block)", node->nd_stts); - ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x02) /* TAG_BREAK */ ); - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - } - else if (iseq->type == ISEQ_TYPE_EVAL) { - break_in_eval: - COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with break")); - } - else { - rb_iseq_t *ip = iseq->parent_iseq; - while (ip) { - level++; - if (ip->compile_data->redo_label != 0) { - level = 0x8000; - if (ip->compile_data->loopval_popped == 0) { - /* need value */ - level |= 0x4000; - } - goto break_by_insn; - } - else if (ip->type == ISEQ_TYPE_BLOCK) { - level <<= 16; - goto break_by_insn; - } - else if (ip->type == ISEQ_TYPE_EVAL) { - goto break_in_eval; - } - ip = ip->parent_iseq; - } - COMPILE_ERROR((ERROR_ARGS "Invalid break")); - } - break; - } - case NODE_NEXT:{ - unsigned long level = 0; - - if (iseq->compile_data->redo_label != 0) { - LABEL *splabel = NEW_LABEL(0); - debugs("next in while loop\n"); - ADD_LABEL(ret, splabel); - COMPILE(ret, "next val/valid syntax?", node->nd_stts); - add_ensure_iseq(ret, iseq); - ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label); - ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->start_label); - ADD_ADJUST_RESTORE(ret, splabel); - } - else if (iseq->compile_data->end_label) { - LABEL *splabel = NEW_LABEL(0); - debugs("next in block\n"); - ADD_LABEL(ret, splabel); - ADD_ADJUST(ret, nd_line(node), iseq->compile_data->start_label); - COMPILE(ret, "next val", node->nd_stts); - add_ensure_iseq(ret, iseq); - ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->end_label); - ADD_ADJUST_RESTORE(ret, splabel); - - if (!poped) { - ADD_INSN(ret, nd_line(node), putnil); - } - } - else if (iseq->type == ISEQ_TYPE_EVAL) { - next_in_eval: - COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with next")); - } - else { - rb_iseq_t *ip; - ip = iseq; - while (ip) { - level = 0x8000 | 0x4000; - if (ip->compile_data->redo_label != 0) { - /* while loop */ - break; - } - else if (ip->type == ISEQ_TYPE_BLOCK) { - break; - } - else if (ip->type == ISEQ_TYPE_EVAL) { - goto next_in_eval; - } - ip = ip->parent_iseq; - } - if (ip != 0) { - COMPILE(ret, "next val", node->nd_stts); - ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x03) /* TAG_NEXT */ ); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - } - else { - COMPILE_ERROR((ERROR_ARGS "Invalid next")); - } - } - break; - } - case NODE_REDO:{ - if (iseq->compile_data->redo_label) { - LABEL *splabel = NEW_LABEL(0); - debugs("redo in while"); - ADD_LABEL(ret, splabel); - ADD_ADJUST(ret, nd_line(node), iseq->compile_data->redo_label); - add_ensure_iseq(ret, iseq); - ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->redo_label); - ADD_ADJUST_RESTORE(ret, splabel); - } - else if (iseq->type == ISEQ_TYPE_EVAL) { - redo_in_eval: - COMPILE_ERROR((ERROR_ARGS "Can't escape from eval with redo")); - } - else if (iseq->compile_data->start_label) { - LABEL *splabel = NEW_LABEL(0); - - debugs("redo in block"); - ADD_LABEL(ret, splabel); - add_ensure_iseq(ret, iseq); - ADD_ADJUST(ret, nd_line(node), iseq->compile_data->start_label); - ADD_INSNL(ret, nd_line(node), jump, iseq->compile_data->start_label); - ADD_ADJUST_RESTORE(ret, splabel); - - if (!poped) { - ADD_INSN(ret, nd_line(node), putnil); - } - } - else { - rb_iseq_t *ip; - unsigned long level; - level = 0x8000 | 0x4000; - ip = iseq; - while (ip) { - if (ip->compile_data->redo_label != 0) { - break; - } - else if (ip->type == ISEQ_TYPE_BLOCK) { - break; - } - else if (ip->type == ISEQ_TYPE_EVAL) { - goto redo_in_eval; - } - ip = ip->parent_iseq; - } - if (ip != 0) { - ADD_INSN(ret, nd_line(node), putnil); - ADD_INSN1(ret, nd_line(node), throw, INT2FIX(level | 0x05) /* TAG_REDO */ ); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - } - else { - COMPILE_ERROR((ERROR_ARGS "Invalid redo")); - } - } - break; - } - case NODE_RETRY:{ - if (iseq->type == ISEQ_TYPE_RESCUE) { - ADD_INSN(ret, nd_line(node), putnil); - ADD_INSN1(ret, nd_line(node), throw, INT2FIX(0x04) /* TAG_RETRY */ ); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - } - else { - COMPILE_ERROR((ERROR_ARGS "Invalid retry")); - } - break; - } - case NODE_BEGIN:{ - COMPILE_(ret, "NODE_BEGIN", node->nd_body, poped); - break; - } - case NODE_RESCUE:{ - LABEL *lstart = NEW_LABEL(nd_line(node)); - LABEL *lend = NEW_LABEL(nd_line(node)); - LABEL *lcont = NEW_LABEL(nd_line(node)); - VALUE rescue = NEW_CHILD_ISEQVAL( - node->nd_resq, - rb_str_concat(rb_str_new2("rescue in "), iseq->name), - ISEQ_TYPE_RESCUE); - - ADD_LABEL(ret, lstart); - COMPILE(ret, "rescue head", node->nd_head); - ADD_LABEL(ret, lend); - if (node->nd_else) { - ADD_INSN(ret, nd_line(node), pop); - COMPILE(ret, "rescue else", node->nd_else); - } - ADD_INSN(ret, nd_line(node), nop); - ADD_LABEL(ret, lcont); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - - /* resgister catch entry */ - ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lcont); - ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, 0, lstart); - break; - } - case NODE_RESBODY:{ - NODE *resq = node; - NODE *narg; - LABEL *label_miss, *label_hit; - - while (resq) { - label_miss = NEW_LABEL(nd_line(node)); - label_hit = NEW_LABEL(nd_line(node)); - - narg = resq->nd_args; - if (narg) { - switch (nd_type(narg)) { - case NODE_ARRAY: - while (narg) { - COMPILE(ret, "rescue arg", narg->nd_head); - ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0)); - ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1)); - ADD_INSNL(ret, nd_line(node), branchif, label_hit); - narg = narg->nd_next; - } - break; - case NODE_SPLAT: - case NODE_ARGSCAT: - case NODE_ARGSPUSH: - ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0)); - COMPILE(ret, "rescue/cond splat", narg); - ADD_INSN1(ret, nd_line(node), checkincludearray, Qtrue); - ADD_INSN(ret, nd_line(node), swap); - ADD_INSN(ret, nd_line(node), pop); - ADD_INSNL(ret, nd_line(node), branchif, label_hit); - break; - default: - rb_bug("NODE_RESBODY: unknown node (%s)", - ruby_node_name(nd_type(narg))); - } - } - else { - ADD_INSN1(ret, nd_line(node), putobject, - rb_eStandardError); - ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0)); - ADD_SEND(ret, nd_line(node), ID2SYM(idEqq), INT2FIX(1)); - ADD_INSNL(ret, nd_line(node), branchif, label_hit); - } - ADD_INSNL(ret, nd_line(node), jump, label_miss); - ADD_LABEL(ret, label_hit); - COMPILE(ret, "resbody body", resq->nd_body); - if (iseq->compile_data->option->tailcall_optimization) { - ADD_INSN(ret, nd_line(node), nop); - } - ADD_INSN(ret, nd_line(node), leave); - ADD_LABEL(ret, label_miss); - resq = resq->nd_head; - } - break; - } - case NODE_ENSURE:{ - DECL_ANCHOR(ensr); - VALUE ensure = NEW_CHILD_ISEQVAL(node->nd_ensr, - rb_str_concat(rb_str_new2 - ("ensure in "), - iseq->name), - ISEQ_TYPE_ENSURE); - LABEL *lstart = NEW_LABEL(nd_line(node)); - LABEL *lend = NEW_LABEL(nd_line(node)); - LABEL *lcont = NEW_LABEL(nd_line(node)); - struct ensure_range er = { 0 }; - struct iseq_compile_data_ensure_node_stack enl; - struct ensure_range *erange; - - INIT_ANCHOR(ensr); - er.begin = lstart; - er.end = lend; - enl.ensure_node = node->nd_ensr; - enl.prev = iseq->compile_data->ensure_node_stack; /* prev */ - enl.erange = &er; - COMPILE_POPED(ensr, "ensure ensr", node->nd_ensr); - - iseq->compile_data->ensure_node_stack = &enl; - - ADD_LABEL(ret, lstart); - COMPILE_(ret, "ensure head", node->nd_head, poped); - ADD_LABEL(ret, lend); - if (ensr->anchor.next == 0) { - ADD_INSN(ret, nd_line(node), nop); - } - else { - ADD_SEQ(ret, ensr); - } - ADD_LABEL(ret, lcont); - - erange = iseq->compile_data->ensure_node_stack->erange; - while (erange) { - ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end, - ensure, lcont); - erange = erange->next; - } - iseq->compile_data->ensure_node_stack = enl.prev; - break; - } - - case NODE_AND: - case NODE_OR:{ - LABEL *end_label = NEW_LABEL(nd_line(node)); - COMPILE(ret, "nd_1st", node->nd_1st); - if (!poped) { - ADD_INSN(ret, nd_line(node), dup); - } - if (type == NODE_AND) { - ADD_INSNL(ret, nd_line(node), branchunless, end_label); - } - else { - ADD_INSNL(ret, nd_line(node), branchif, end_label); - } - if (!poped) { - ADD_INSN(ret, nd_line(node), pop); - } - COMPILE_(ret, "nd_2nd", node->nd_2nd, poped); - ADD_LABEL(ret, end_label); - break; - } - - case NODE_MASGN:{ - compile_massign(iseq, ret, node, poped); - break; - } - - case NODE_LASGN:{ - ID id = node->nd_vid; - int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id); - - debugs("lvar: %s idx: %d\n", rb_id2name(id), idx); - COMPILE(ret, "rvalue", node->nd_value); - - if (!poped) { - ADD_INSN(ret, nd_line(node), dup); - } - ADD_INSN1(ret, nd_line(node), setlocal, INT2FIX(idx)); - - break; - } - case NODE_DASGN: - case NODE_DASGN_CURR:{ - int idx, lv, ls; - COMPILE(ret, "dvalue", node->nd_value); - debugp_param("dassn id", rb_str_new2(rb_id2name(node->nd_vid) ? rb_id2name(node->nd_vid) : "*")); - - if (!poped) { - ADD_INSN(ret, nd_line(node), dup); - } - - idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls); - - if (idx < 0) { - rb_bug("NODE_DASGN(_CURR): unknown id (%s)", rb_id2name(node->nd_vid)); - } - - ADD_INSN2(ret, nd_line(node), setdynamic, - INT2FIX(ls - idx), INT2FIX(lv)); - break; - } - case NODE_GASGN:{ - COMPILE(ret, "lvalue", node->nd_value); - - if (!poped) { - ADD_INSN(ret, nd_line(node), dup); - } - ADD_INSN1(ret, nd_line(node), setglobal, - (((long)node->nd_entry) | 1)); - break; - } - case NODE_IASGN: - case NODE_IASGN2:{ - COMPILE(ret, "lvalue", node->nd_value); - if (!poped) { - ADD_INSN(ret, nd_line(node), dup); - } - ADD_INSN1(ret, nd_line(node), setinstancevariable, - ID2SYM(node->nd_vid)); - break; - } - case NODE_CDECL:{ - COMPILE(ret, "lvalue", node->nd_value); - - if (!poped) { - ADD_INSN(ret, nd_line(node), dup); - } - - if (node->nd_vid) { - ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE)); - ADD_INSN1(ret, nd_line(node), setconstant, ID2SYM(node->nd_vid)); - } - else { - compile_cpath(ret, iseq, node->nd_else); - ADD_INSN1(ret, nd_line(node), setconstant, ID2SYM(node->nd_else->nd_mid)); - } - break; - } - case NODE_CVASGN:{ - COMPILE(ret, "cvasgn val", node->nd_value); - if (!poped) { - ADD_INSN(ret, nd_line(node), dup); - } - ADD_INSN1(ret, nd_line(node), setclassvariable, - ID2SYM(node->nd_vid)); - break; - } - case NODE_OP_ASGN1: { - DECL_ANCHOR(args); - VALUE argc; - unsigned long flag = 0; - ID id = node->nd_mid; - - /* - * a[x] (op)= y - * - * eval a # a - * eval x # a x - * dupn 2 # a x a x - * send :[] # a x a[x] - * eval y # a x a[x] y - * send op # a x a[x]+y - * send []= # ret - */ - - /* - * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head; - * NODE_OP_ASGN nd_recv - * nd_args->nd_head - * nd_args->nd_body - * nd_mid - */ - - COMPILE(ret, "NODE_OP_ASGN1 recv", node->nd_recv); - if (nd_type(node->nd_args->nd_body) != NODE_ZARRAY) { - INIT_ANCHOR(args); - argc = setup_args(iseq, args, node->nd_args->nd_body, &flag); - ADD_SEQ(ret, args); - } - else { - argc = INT2FIX(0); - } - ADD_INSN1(ret, nd_line(node), dupn, INT2FIX(FIX2INT(argc)+1)); - ADD_SEND_R(ret, nd_line(node), ID2SYM(idAREF), argc, Qfalse, LONG2FIX(flag)); - - if (id == 0 || id == 1) { - /* 0: or, 1: and - a[x] ||= y - - unless/if a[x] - a[x]= y - else - nil - end - */ - LABEL *label = NEW_LABEL(nd_line(node)); - LABEL *lfin = NEW_LABEL(nd_line(node)); - - if (id == 0) { - /* or */ - ADD_INSN(ret, nd_line(node), dup); - ADD_INSNL(ret, nd_line(node), branchif, label); - ADD_INSN(ret, nd_line(node), pop); - } - else { - /* and */ - ADD_INSN(ret, nd_line(node), dup); - ADD_INSNL(ret, nd_line(node), branchunless, label); - ADD_INSN(ret, nd_line(node), pop); - } - - COMPILE(ret, "NODE_OP_ASGN1 args->head: ", node->nd_args->nd_head); - if (flag & VM_CALL_ARGS_SPLAT_BIT) { - ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1)); - ADD_INSN(ret, nd_line(node), concatarray); - ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET), - argc, Qfalse, LONG2FIX(flag)); - } - else { - ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET), - INT2FIX(FIX2INT(argc) + 1), Qfalse, LONG2FIX(flag)); - } - ADD_INSNL(ret, nd_line(node), jump, lfin); - ADD_LABEL(ret, label); - if (id == 0 || id == 1) { /* 0: or, 1: and */ - ADD_INSN(ret, nd_line(node), swap); - ADD_INSN(ret, nd_line(node), pop); - ADD_INSN(ret, nd_line(node), swap); - ADD_INSN(ret, nd_line(node), pop); - } - ADD_LABEL(ret, lfin); - } - else { - COMPILE(ret, "NODE_OP_ASGN1 args->head: ", node->nd_args->nd_head); - ADD_SEND(ret, nd_line(node), ID2SYM(id), INT2FIX(1)); - if (flag & VM_CALL_ARGS_SPLAT_BIT) { - ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1)); - ADD_INSN(ret, nd_line(node), concatarray); - ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET), - argc, Qfalse, LONG2FIX(flag)); - } - else { - ADD_SEND_R(ret, nd_line(node), ID2SYM(idASET), - INT2FIX(FIX2INT(argc) + 1), Qfalse, LONG2FIX(flag)); - } - } - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - - break; - } - case NODE_OP_ASGN2:{ - ID atype = node->nd_next->nd_mid; - LABEL *lfin = NEW_LABEL(nd_line(node)); - LABEL *lcfin = NEW_LABEL(nd_line(node)); - /* - class C; attr_accessor :c; end - r = C.new - r.a &&= v # asgn2 - - eval r # r - dup # r r - eval r.a # r o - - # or - dup # r o o - if lcfin # r o - pop # r - eval v # r v - send a= # v - jump lfin # v - - lcfin: # r o - swap # o r - pop # o - - lfin: # v - - # and - dup # r o o - unless lcfin - pop # r - eval v # r v - send a= # v - jump lfin # v - - # others - eval v # r o v - send ?? # r w - send a= # w - - */ - - COMPILE(ret, "NODE_OP_ASGN2#recv", node->nd_recv); - ADD_INSN(ret, nd_line(node), dup); - ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_vid), - INT2FIX(0)); - - if (atype == 0 || atype == 1) { /* 0: OR or 1: AND */ - ADD_INSN(ret, nd_line(node), dup); - if (atype == 0) { - ADD_INSNL(ret, nd_line(node), branchif, lcfin); - } - else { - ADD_INSNL(ret, nd_line(node), branchunless, lcfin); - } - ADD_INSN(ret, nd_line(node), pop); - COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value); - ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_aid), - INT2FIX(1)); - ADD_INSNL(ret, nd_line(node), jump, lfin); - - ADD_LABEL(ret, lcfin); - ADD_INSN(ret, nd_line(node), swap); - ADD_INSN(ret, nd_line(node), pop); - - ADD_LABEL(ret, lfin); - } - else { - COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value); - ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_mid), - INT2FIX(1)); - ADD_SEND(ret, nd_line(node), ID2SYM(node->nd_next->nd_aid), - INT2FIX(1)); - } - - if (poped) { - /* we can apply more optimize */ - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_OP_ASGN_AND: - case NODE_OP_ASGN_OR:{ - LABEL *lfin = NEW_LABEL(nd_line(node)); - LABEL *lassign; - - if (nd_type(node) == NODE_OP_ASGN_OR) { - LABEL *lfinish[2]; - lfinish[0] = lfin; - lfinish[1] = 0; - defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse); - lassign = lfinish[1]; - if (!lassign) { - lassign = NEW_LABEL(nd_line(node)); - } - ADD_INSNL(ret, nd_line(node), branchunless, lassign); - } - else { - lassign = NEW_LABEL(nd_line(node)); - } - - COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head); - ADD_INSN(ret, nd_line(node), dup); - - if (nd_type(node) == NODE_OP_ASGN_AND) { - ADD_INSNL(ret, nd_line(node), branchunless, lfin); - } - else { - ADD_INSNL(ret, nd_line(node), branchif, lfin); - } - - ADD_INSN(ret, nd_line(node), pop); - ADD_LABEL(ret, lassign); - COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value); - ADD_LABEL(ret, lfin); - - if (poped) { - /* we can apply more optimize */ - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_CALL: - case NODE_FCALL: - case NODE_VCALL:{ /* VCALL: variable or call */ - /* - call: obj.method(...) - fcall: func(...) - vcall: func - */ - DECL_ANCHOR(recv); - DECL_ANCHOR(args); - ID mid = node->nd_mid; - VALUE argc; - unsigned long flag = 0; - VALUE parent_block = iseq->compile_data->current_block; - iseq->compile_data->current_block = Qfalse; - - INIT_ANCHOR(recv); - INIT_ANCHOR(args); -#if SUPPORT_JOKE - if (nd_type(node) == NODE_VCALL) { - if (mid == idBitblt) { - ADD_INSN(ret, nd_line(node), bitblt); - break; - } - else if (mid == idAnswer) { - ADD_INSN(ret, nd_line(node), answer); - break; - } - } - /* only joke */ - { - ID goto_id; - ID label_id; - VALUE label; - VALUE label_sym; - - - CONST_ID(goto_id, "__goto__"); - CONST_ID(label_id, "__label__"); - - if (nd_type(node) == NODE_FCALL && - (mid == goto_id || mid == label_id)) { - if (nd_type(node->nd_args->nd_head) == NODE_LIT && - SYMBOL_P(node->nd_args->nd_head->nd_lit)) { - - label_sym = label = node->nd_args->nd_head->nd_lit; - if ((label = - rb_hash_aref(iseq->compile_data, - label_sym)) == Qnil) { - rb_hash_aset(iseq->compile_data, label_sym, - label = NEW_LABEL(nd_line(node))); - } - } - else { - rb_bug("invalid goto/label format"); - } - - - if (mid == goto_id) { - ADD_INSNL(ret, nd_line(node), jump, label); - } - else { - ADD_LABEL(ret, label); - } - break; - } - } -#endif - /* reciever */ - if (type == NODE_CALL) { - COMPILE(recv, "recv", node->nd_recv); - } - else if (type == NODE_FCALL || type == NODE_VCALL) { - ADD_CALL_RECEIVER(recv, nd_line(node)); - } - - /* args */ - if (nd_type(node) != NODE_VCALL) { - argc = setup_args(iseq, args, node->nd_args, &flag); - } - else { - argc = INT2FIX(0); - } - - ADD_SEQ(ret, recv); - ADD_SEQ(ret, args); - - debugp_param("call args argc", argc); - debugp_param("call method", ID2SYM(mid)); - - switch (nd_type(node)) { - case NODE_VCALL: - flag |= VM_CALL_VCALL_BIT; - /* VCALL is funcall, so fall through */ - case NODE_FCALL: - flag |= VM_CALL_FCALL_BIT; - } - - ADD_SEND_R(ret, nd_line(node), ID2SYM(mid), - argc, parent_block, LONG2FIX(flag)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_SUPER: - case NODE_ZSUPER:{ - DECL_ANCHOR(args); - VALUE argc; - unsigned long flag = 0; - VALUE parent_block = iseq->compile_data->current_block; - - INIT_ANCHOR(args); - iseq->compile_data->current_block = Qfalse; - if (nd_type(node) == NODE_SUPER) { - argc = setup_args(iseq, args, node->nd_args, &flag); - } - else { - /* NODE_ZSUPER */ - int i; - rb_iseq_t *liseq = iseq->local_iseq; - - argc = INT2FIX(liseq->argc); - - /* normal arguments */ - for (i = 0; i < liseq->argc; i++) { - int idx = liseq->local_size - i; - ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx)); - } - - if (!liseq->arg_simple) { - if (liseq->arg_opts) { - /* optional arguments */ - int j; - for (j = 0; j < liseq->arg_opts - 1; j++) { - int idx = liseq->local_size - (i + j); - ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx)); - } - i += j; - argc = INT2FIX(i); - } - - if (liseq->arg_rest != -1) { - /* rest argument */ - int idx = liseq->local_size - liseq->arg_rest; - ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx)); - argc = INT2FIX(liseq->arg_rest + 1); - flag |= VM_CALL_ARGS_SPLAT_BIT; - } - - if (liseq->arg_post_len) { - /* post arguments */ - int post_len = liseq->arg_post_len; - int post_start = liseq->arg_post_start; - - if (liseq->arg_rest != -1) { - int j; - for (j=0; j<post_len; j++) { - int idx = liseq->local_size - (post_start + j); - ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx)); - } - ADD_INSN1(args, nd_line(node), newarray, INT2FIX(j)); - ADD_INSN (args, nd_line(node), concatarray); - /* argc is setteled at above */ - } - else { - int j; - for (j=0; j<post_len; j++) { - int idx = liseq->local_size - (post_start + j); - ADD_INSN1(args, nd_line(node), getlocal, INT2FIX(idx)); - } - argc = INT2FIX(post_len + post_start); - } - } - } - } - - /* dummy reciever */ - ADD_INSN1(ret, nd_line(node), putobject, - nd_type(node) == NODE_ZSUPER ? Qfalse : Qtrue); - ADD_SEQ(ret, args); - ADD_INSN3(ret, nd_line(node), invokesuper, - argc, parent_block, LONG2FIX(flag)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_ARRAY:{ - compile_array_(iseq, ret, node, Qtrue, poped); - break; - } - case NODE_ZARRAY:{ - if (!poped) { - ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(0)); - } - break; - } - case NODE_VALUES:{ - NODE *n = node; - while (n) { - COMPILE(ret, "values item", n->nd_head); - n = n->nd_next; - } - ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(node->nd_alen)); - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_HASH:{ - DECL_ANCHOR(list); - VALUE size = 0; - int type = node->nd_head ? nd_type(node->nd_head) : NODE_ZARRAY; - - INIT_ANCHOR(list); - switch (type) { - case NODE_ARRAY:{ - compile_array(iseq, list, node->nd_head, Qfalse); - size = OPERAND_AT(POP_ELEMENT(list), 0); - ADD_SEQ(ret, list); - break; - } - case NODE_ZARRAY: - size = INT2FIX(0); - break; - - default: - rb_bug("can't make hash with this node: %s", ruby_node_name(type)); - } - - ADD_INSN1(ret, nd_line(node), newhash, size); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_RETURN:{ - rb_iseq_t *is = iseq; - - while (is) { - if (is->type == ISEQ_TYPE_TOP || is->type == ISEQ_TYPE_CLASS) { - COMPILE_ERROR((ERROR_ARGS "Invalid return")); - break; - } - else { - LABEL *splabel = 0; - - if (is->type == ISEQ_TYPE_METHOD) { - splabel = NEW_LABEL(0); - ADD_LABEL(ret, splabel); - ADD_ADJUST(ret, nd_line(node), 0); - } - - COMPILE(ret, "return nd_stts (return val)", node->nd_stts); - - if (is->type == ISEQ_TYPE_METHOD) { - add_ensure_iseq(ret, iseq); - ADD_INSN(ret, nd_line(node), leave); - ADD_ADJUST_RESTORE(ret, splabel); - - if (!poped) { - ADD_INSN(ret, nd_line(node), putnil); - } - } - else { - ADD_INSN1(ret, nd_line(node), throw, INT2FIX(0x01) /* TAG_RETURN */ ); - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - } - break; - } - } - break; - } - case NODE_YIELD:{ - DECL_ANCHOR(args); - VALUE argc; - unsigned long flag = 0; - - INIT_ANCHOR(args); - if (iseq->type == ISEQ_TYPE_TOP || iseq->type == ISEQ_TYPE_CLASS) { - COMPILE_ERROR((ERROR_ARGS "Invalid yield")); - } - - if (node->nd_head) { - argc = setup_args(iseq, args, node->nd_head, &flag); - } - else { - argc = INT2FIX(0); - } - - ADD_SEQ(ret, args); - ADD_INSN2(ret, nd_line(node), invokeblock, argc, LONG2FIX(flag)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_LVAR:{ - if (!poped) { - ID id = node->nd_vid; - int idx = iseq->local_iseq->local_size - get_local_var_idx(iseq, id); - - debugs("id: %s idx: %d\n", rb_id2name(id), idx); - ADD_INSN1(ret, nd_line(node), getlocal, INT2FIX(idx)); - } - break; - } - case NODE_DVAR:{ - int lv, idx, ls; - debugi("nd_vid", node->nd_vid); - if (!poped) { - idx = get_dyna_var_idx(iseq, node->nd_vid, &lv, &ls); - if (idx < 0) { - rb_bug("unknown dvar (%s)", rb_id2name(node->nd_vid)); - } - ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(ls - idx), INT2FIX(lv)); - } - break; - } - case NODE_GVAR:{ - ADD_INSN1(ret, nd_line(node), getglobal, - (((long)node->nd_entry) | 1)); - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_IVAR:{ - debugi("nd_vid", node->nd_vid); - if (!poped) { - ADD_INSN1(ret, nd_line(node), getinstancevariable, - ID2SYM(node->nd_vid)); - } - break; - } - case NODE_CONST:{ - debugi("nd_vid", node->nd_vid); - - if (iseq->compile_data->option->inline_const_cache) { - LABEL *lstart = NEW_LABEL(nd_line(node)); - LABEL *lend = NEW_LABEL(nd_line(node)); - - ADD_LABEL(ret, lstart); - ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend); - ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_vid)); - ADD_INSN1(ret, nd_line(node), setinlinecache, lstart); - ADD_LABEL(ret, lend); - } - else { - ADD_INSN(ret, nd_line(node), putnil); - ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_vid)); - } - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_CVAR:{ - if (!poped) { - ADD_INSN1(ret, nd_line(node), getclassvariable, - ID2SYM(node->nd_vid)); - } - break; - } - case NODE_NTH_REF:{ - if (!poped) { - ADD_INSN2(ret, nd_line(node), getspecial, INT2FIX(1) /* '~' */, - INT2FIX(node->nd_nth << 1)); - } - break; - } - case NODE_BACK_REF:{ - if (!poped) { - ADD_INSN2(ret, nd_line(node), getspecial, INT2FIX(1) /* '~' */, - INT2FIX(0x01 | (node->nd_nth << 1))); - } - break; - } - case NODE_MATCH: - case NODE_MATCH2: - case NODE_MATCH3:{ - DECL_ANCHOR(recv); - DECL_ANCHOR(val); - - INIT_ANCHOR(recv); - INIT_ANCHOR(val); - switch(nd_type(node)) { - case NODE_MATCH: - ADD_INSN1(recv, nd_line(node), putobject, node->nd_lit); - ADD_INSN2(val, nd_line(node), getspecial, INT2FIX(0), - INT2FIX(0)); - break; - case NODE_MATCH2: - COMPILE(recv, "reciever", node->nd_recv); - COMPILE(val, "value", node->nd_value); - break; - case NODE_MATCH3: - COMPILE(recv, "reciever", node->nd_value); - COMPILE(val, "value", node->nd_recv); - break; - } - - if (iseq->compile_data->option->specialized_instruction) { - /* TODO: detect by node */ - if (recv->last == recv->anchor.next && - INSN_OF(recv->last) == BIN(putobject) && - nd_type(node) == NODE_MATCH2) { - ADD_SEQ(ret, val); - ADD_INSN1(ret, nd_line(node), opt_regexpmatch1, - OPERAND_AT(recv->last, 0)); - } - else { - ADD_SEQ(ret, recv); - ADD_SEQ(ret, val); - ADD_INSN(ret, nd_line(node), opt_regexpmatch2); - } - } - else { - ADD_SEQ(ret, recv); - ADD_SEQ(ret, val); - ADD_SEND(ret, nd_line(node), ID2SYM(idEqTilde), INT2FIX(1)); - } - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_LIT:{ - debugp_param("lit", node->nd_lit); - if (!poped) { - ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit); - } - break; - } - case NODE_STR:{ - debugp_param("nd_lit", node->nd_lit); - if (!poped) { - ADD_INSN1(ret, nd_line(node), putstring, node->nd_lit); - } - break; - } - case NODE_DSTR:{ - compile_dstr(iseq, ret, node); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_XSTR:{ - ADD_CALL_RECEIVER(ret, nd_line(node)); - ADD_INSN1(ret, nd_line(node), putobject, node->nd_lit); - ADD_CALL(ret, nd_line(node), ID2SYM(idBackquote), INT2FIX(1)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_DXSTR:{ - ADD_CALL_RECEIVER(ret, nd_line(node)); - compile_dstr(iseq, ret, node); - ADD_CALL(ret, nd_line(node), ID2SYM(idBackquote), INT2FIX(1)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_EVSTR:{ - COMPILE(ret, "nd_body", node->nd_body); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - else { - ADD_INSN(ret, nd_line(node), tostring); - } - break; - } - case NODE_DREGX:{ - compile_dregx(iseq, ret, node); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_DREGX_ONCE:{ - /* TODO: once? */ - LABEL *lstart = NEW_LABEL(nd_line(node)); - LABEL *lend = NEW_LABEL(nd_line(node)); - - ADD_LABEL(ret, lstart); - ADD_INSN2(ret, nd_line(node), onceinlinecache, 0, lend); - ADD_INSN(ret, nd_line(node), pop); - - compile_dregx(iseq, ret, node); - - ADD_INSN1(ret, nd_line(node), setinlinecache, lstart); - ADD_LABEL(ret, lend); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_ARGSCAT:{ - COMPILE(ret, "argscat head", node->nd_head); - COMPILE(ret, "argscat body", node->nd_body); - ADD_INSN(ret, nd_line(node), concatarray); - break; - } - case NODE_ARGSPUSH:{ - COMPILE(ret, "arsgpush head", node->nd_head); - COMPILE(ret, "argspush body", node->nd_body); - ADD_INSN1(ret, nd_line(node), newarray, INT2FIX(1)); - ADD_INSN(ret, nd_line(node), concatarray); - break; - } - case NODE_SPLAT:{ - COMPILE(ret, "splat", node->nd_head); - ADD_INSN1(ret, nd_line(node), splatarray, Qfalse); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_DEFN:{ - VALUE iseqval = NEW_ISEQVAL(node->nd_defn, - rb_str_dup(rb_id2str(node->nd_mid)), - ISEQ_TYPE_METHOD); - - debugp_param("defn/iseq", iseqval); - - ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); - ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE)); - ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->nd_mid)); - ADD_INSN1(ret, nd_line(node), putiseq, iseqval); - ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_method), INT2FIX(3)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - - debugp_param("defn", iseqval); - break; - } - case NODE_DEFS:{ - VALUE iseqval = NEW_ISEQVAL(node->nd_defn, - rb_str_dup(rb_id2str(node->nd_mid)), - ISEQ_TYPE_METHOD); - - debugp_param("defs/iseq", iseqval); - - ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); - COMPILE(ret, "defs: recv", node->nd_recv); - ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->nd_mid)); - ADD_INSN1(ret, nd_line(node), putiseq, iseqval); - ADD_SEND (ret, nd_line(node), ID2SYM(id_core_define_singleton_method), INT2FIX(3)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_ALIAS:{ - ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); - ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE)); - COMPILE(ret, "alias arg1", node->u1.node); - COMPILE(ret, "alias arg2", node->u2.node); - ADD_SEND(ret, nd_line(node), ID2SYM(id_core_set_method_alias), INT2FIX(3)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_VALIAS:{ - ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); - ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u1.id)); - ADD_INSN1(ret, nd_line(node), putobject, ID2SYM(node->u2.id)); - ADD_SEND(ret, nd_line(node), ID2SYM(id_core_set_variable_alias), INT2FIX(2)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_UNDEF:{ - ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); - ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE)); - COMPILE(ret, "undef arg", node->u2.node); - ADD_SEND(ret, nd_line(node), ID2SYM(id_core_undef_method), INT2FIX(2)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_CLASS:{ - VALUE iseqval = - NEW_CHILD_ISEQVAL( - node->nd_body, - rb_sprintf("<class:%s>", rb_id2name(node->nd_cpath->nd_mid)), - ISEQ_TYPE_CLASS); - compile_cpath(ret, iseq, node->nd_cpath); - COMPILE(ret, "super", node->nd_super); - ADD_INSN3(ret, nd_line(node), defineclass, - ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(0)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_MODULE:{ - VALUE iseqval = NEW_CHILD_ISEQVAL( - node->nd_body, - rb_sprintf("<module:%s>", rb_id2name(node->nd_cpath->nd_mid)), - ISEQ_TYPE_CLASS); - - compile_cpath(ret, iseq, node->nd_cpath); - ADD_INSN (ret, nd_line(node), putnil); /* dummy */ - ADD_INSN3(ret, nd_line(node), defineclass, - ID2SYM(node->nd_cpath->nd_mid), iseqval, INT2FIX(2)); - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_SCLASS:{ - ID singletonclass; - VALUE iseqval = - NEW_ISEQVAL(node->nd_body, rb_str_new2("singletonclass"), - ISEQ_TYPE_CLASS); - - COMPILE(ret, "sclass#recv", node->nd_recv); - ADD_INSN (ret, nd_line(node), putnil); - CONST_ID(singletonclass, "singletonclass"); - ADD_INSN3(ret, nd_line(node), defineclass, - ID2SYM(singletonclass), iseqval, INT2FIX(1)); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_COLON2:{ - if (rb_is_const_id(node->nd_mid)) { - /* constant */ - LABEL *lstart = NEW_LABEL(nd_line(node)); - LABEL *lend = NEW_LABEL(nd_line(node)); - DECL_ANCHOR(pref); - DECL_ANCHOR(body); - - INIT_ANCHOR(pref); - INIT_ANCHOR(body); - compile_colon2(iseq, node, pref, body); - if (LIST_SIZE_ZERO(pref)) { - if (iseq->compile_data->option->inline_const_cache) { - ADD_LABEL(ret, lstart); - ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend); - } - else { - ADD_INSN(ret, nd_line(node), putnil); - } - - ADD_SEQ(ret, body); - - if (iseq->compile_data->option->inline_const_cache) { - ADD_INSN1(ret, nd_line(node), setinlinecache, lstart); - ADD_LABEL(ret, lend); - } - } - else { - ADD_SEQ(ret, pref); - ADD_SEQ(ret, body); - } - } - else { - /* function call */ - ADD_CALL_RECEIVER(ret, nd_line(node)); - COMPILE(ret, "colon2#nd_head", node->nd_head); - ADD_CALL(ret, nd_line(node), ID2SYM(node->nd_mid), - INT2FIX(1)); - } - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_COLON3:{ - LABEL *lstart = NEW_LABEL(nd_line(node)); - LABEL *lend = NEW_LABEL(nd_line(node)); - debugi("colon3#nd_mid", node->nd_mid); - - /* add cache insn */ - if (iseq->compile_data->option->inline_const_cache) { - ADD_LABEL(ret, lstart); - ADD_INSN2(ret, nd_line(node), getinlinecache, 0, lend); - ADD_INSN(ret, nd_line(node), pop); - } - - ADD_INSN1(ret, nd_line(node), putobject, rb_cObject); - ADD_INSN1(ret, nd_line(node), getconstant, ID2SYM(node->nd_mid)); - - if (iseq->compile_data->option->inline_const_cache) { - ADD_INSN1(ret, nd_line(node), setinlinecache, lstart); - ADD_LABEL(ret, lend); - } - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_DOT2: - case NODE_DOT3:{ - int flag = type == NODE_DOT2 ? INT2FIX(0) : INT2FIX(1); - COMPILE(ret, "min", (NODE *) node->nd_beg); - COMPILE(ret, "max", (NODE *) node->nd_end); - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - ADD_INSN(ret, nd_line(node), pop); - } - else { - ADD_INSN1(ret, nd_line(node), newrange, flag); - } - break; - } - case NODE_FLIP2: - case NODE_FLIP3:{ - LABEL *lend = NEW_LABEL(nd_line(node)); - LABEL *lfin = NEW_LABEL(nd_line(node)); - LABEL *ltrue = NEW_LABEL(nd_line(node)); - VALUE key = rb_sprintf("flipflag/%s-%p-%d", - RSTRING_PTR(iseq->name), iseq, - iseq->compile_data->flip_cnt++); - - iseq_add_mark_object_compile_time(iseq, key); - ADD_INSN2(ret, nd_line(node), getspecial, key, INT2FIX(0)); - ADD_INSNL(ret, nd_line(node), branchif, lend); - - /* *flip == 0 */ - COMPILE(ret, "flip2 beg", node->nd_beg); - ADD_INSN(ret, nd_line(node), dup); - ADD_INSNL(ret, nd_line(node), branchunless, lfin); - if (nd_type(node) == NODE_FLIP3) { - ADD_INSN(ret, nd_line(node), dup); - ADD_INSN1(ret, nd_line(node), setspecial, key); - ADD_INSNL(ret, nd_line(node), jump, lfin); - } - else { - ADD_INSN1(ret, nd_line(node), setspecial, key); - } - - /* *flip == 1 */ - ADD_LABEL(ret, lend); - COMPILE(ret, "flip2 end", node->nd_end); - ADD_INSNL(ret, nd_line(node), branchunless, ltrue); - ADD_INSN1(ret, nd_line(node), putobject, Qfalse); - ADD_INSN1(ret, nd_line(node), setspecial, key); - - ADD_LABEL(ret, ltrue); - ADD_INSN1(ret, nd_line(node), putobject, Qtrue); - - ADD_LABEL(ret, lfin); - break; - } - case NODE_SELF:{ - if (!poped) { - ADD_INSN(ret, nd_line(node), putself); - } - break; - } - case NODE_NIL:{ - if (!poped) { - ADD_INSN(ret, nd_line(node), putnil); - } - break; - } - case NODE_TRUE:{ - if (!poped) { - ADD_INSN1(ret, nd_line(node), putobject, Qtrue); - } - break; - } - case NODE_FALSE:{ - if (!poped) { - ADD_INSN1(ret, nd_line(node), putobject, Qfalse); - } - break; - } - case NODE_ERRINFO:{ - if (!poped) { - if (iseq->type == ISEQ_TYPE_RESCUE) { - ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(0)); - } - else { - rb_iseq_t *ip = iseq; - int level = 0; - while (ip) { - if (ip->type == ISEQ_TYPE_RESCUE) { - break; - } - ip = ip->parent_iseq; - level++; - } - if (ip) { - ADD_INSN2(ret, nd_line(node), getdynamic, INT2FIX(2), INT2FIX(level)); - } - else { - ADD_INSN(ret, nd_line(node), putnil); - } - } - } - break; - } - case NODE_DEFINED:{ - if (!poped) { - LABEL *lfinish[2]; - lfinish[0] = NEW_LABEL(nd_line(node)); - lfinish[1] = 0; - defined_expr(iseq, ret, node->nd_head, lfinish, Qtrue); - if (lfinish[1]) { - ADD_INSNL(ret, nd_line(node), jump, lfinish[0]); - ADD_LABEL(ret, lfinish[1]); - ADD_INSN(ret, nd_line(node), putnil); - } - ADD_LABEL(ret, lfinish[0]); - } - break; - } - case NODE_POSTEXE:{ - LABEL *lstart = NEW_LABEL(nd_line(node)); - LABEL *lend = NEW_LABEL(nd_line(node)); - VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK); - - ADD_LABEL(ret, lstart); - ADD_INSN2(ret, nd_line(node), onceinlinecache, 0, lend); - ADD_INSN(ret, nd_line(node), pop); - - ADD_INSN1(ret, nd_line(node), putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE)); - ADD_INSN1(ret, nd_line(node), putiseq, block); - ADD_SEND (ret, nd_line(node), ID2SYM(id_core_set_postexe), INT2FIX(1)); - - ADD_INSN1(ret, nd_line(node), setinlinecache, lstart); - ADD_LABEL(ret, lend); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_DSYM:{ - compile_dstr(iseq, ret, node); - if (!poped) { - ADD_SEND(ret, nd_line(node), ID2SYM(idIntern), INT2FIX(0)); - } - else { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - case NODE_ATTRASGN:{ - DECL_ANCHOR(recv); - DECL_ANCHOR(args); - unsigned long flag = 0; - VALUE argc; - - INIT_ANCHOR(recv); - INIT_ANCHOR(args); - argc = setup_args(iseq, args, node->nd_args, &flag); - - if (node->nd_recv == (NODE *) 1) { - flag |= VM_CALL_FCALL_BIT; - ADD_INSN(recv, nd_line(node), putself); - } - else { - COMPILE(recv, "recv", node->nd_recv); - } - - debugp_param("argc", argc); - debugp_param("nd_mid", ID2SYM(node->nd_mid)); - - if (!poped) { - ADD_INSN(ret, nd_line(node), putnil); - ADD_SEQ(ret, recv); - ADD_SEQ(ret, args); - - if (flag & VM_CALL_ARGS_BLOCKARG_BIT) { - ADD_INSN1(ret, nd_line(node), topn, INT2FIX(1)); - ADD_INSN1(ret, nd_line(node), setn, INT2FIX(FIX2INT(argc) + 3)); - ADD_INSN (ret, nd_line(node), pop); - } - else { - ADD_INSN1(ret, nd_line(node), setn, INT2FIX(FIX2INT(argc) + 1)); - } - } - else { - ADD_SEQ(ret, recv); - ADD_SEQ(ret, args); - } - ADD_SEND_R(ret, nd_line(node), ID2SYM(node->nd_mid), argc, 0, LONG2FIX(flag)); - ADD_INSN(ret, nd_line(node), pop); - - break; - } - case NODE_OPTBLOCK:{ - /* for optimize */ - LABEL *redo_label = NEW_LABEL(0); - LABEL *next_label = NEW_LABEL(0); - - iseq->compile_data->start_label = next_label; - iseq->compile_data->redo_label = redo_label; - - ADD_LABEL(ret, redo_label); - COMPILE_(ret, "optblock body", node->nd_head, 1 /* pop */ ); - ADD_LABEL(ret, next_label); - ADD_INSN(ret, 0, opt_checkenv); - break; - } - case NODE_PRELUDE:{ - COMPILE_POPED(ret, "prelude", node->nd_head); - COMPILE_(ret, "body", node->nd_body, poped); - break; - } - case NODE_LAMBDA:{ - /* compile same as lambda{...} */ - VALUE block = NEW_CHILD_ISEQVAL(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK); - VALUE argc = INT2FIX(0); - ADD_CALL_RECEIVER(ret, nd_line(node)); - ADD_CALL_WITH_BLOCK(ret, nd_line(node), ID2SYM(idLambda), argc, block); - - if (poped) { - ADD_INSN(ret, nd_line(node), pop); - } - break; - } - default: - rb_bug("iseq_compile_each: unknown node: %s", ruby_node_name(type)); - return Qnil; - } - - debug_node_end(); - return COMPILE_OK; -} - -/***************************/ -/* instruction information */ -/***************************/ - -static int -insn_data_length(INSN *iobj) -{ - return insn_len(iobj->insn_id); -} - -static int -calc_sp_depth(int depth, INSN *insn) -{ - return insn_stack_increase(depth, insn->insn_id, insn->operands); -} - -static int -insn_data_line_no(INSN *iobj) -{ - return insn_len(iobj->line_no); -} - -static VALUE -insn_data_to_s_detail(INSN *iobj) -{ - VALUE str = rb_str_new(0, 0); - - str = rb_sprintf("%-16s", insn_name(iobj->insn_id)); - if (iobj->operands) { - const char *types = insn_op_types(iobj->insn_id); - int j; - - for (j = 0; types[j]; j++) { - char type = types[j]; - - switch (type) { - case TS_OFFSET: /* label(destination position) */ - { - LABEL *lobj = (LABEL *)OPERAND_AT(iobj, j); - rb_str_catf(str, "<L%03d>", lobj->label_no); - break; - } - break; - case TS_ISEQ: /* iseq */ - { - rb_iseq_t *iseq = (rb_iseq_t *)OPERAND_AT(iobj, j); - VALUE val = Qnil; - if (iseq) { - val = iseq->self; - } - rb_str_concat(str, rb_inspect(val)); - } - break; - case TS_LINDEX: - case TS_DINDEX: - case TS_NUM: /* ulong */ - case TS_VALUE: /* VALUE */ - rb_str_concat(str, rb_inspect(OPERAND_AT(iobj, j))); - break; - case TS_ID: /* ID */ - rb_str_concat(str, rb_inspect(OPERAND_AT(iobj, j))); - break; - case TS_GENTRY: - { - struct global_entry *entry = (struct global_entry *) - (OPERAND_AT(iobj, j) & (~1)); - rb_str_cat2(str, rb_id2name(entry->id)); - } - case TS_IC: /* method cache */ - rb_str_cat2(str, "<ic>"); - break; - case TS_CDHASH: /* case/when condition cache */ - rb_str_cat2(str, "<ch>"); - break; - default:{ - rb_raise(rb_eSyntaxError, "unknown operand type: %c", type); - } - } - if (types[j + 1]) { - rb_str_cat2(str, ", "); - } - } - } - return str; -} - -static void -dump_disasm_list(struct iseq_link_element *link) -{ - int pos = 0; - INSN *iobj; - LABEL *lobj; - VALUE str; - - printf("-- raw disasm--------\n"); - - while (link) { - switch (link->type) { - case ISEQ_ELEMENT_INSN: - { - iobj = (INSN *)link; - str = insn_data_to_s_detail(iobj); - printf("%04d %-65s(%4d)\n", pos, StringValueCStr(str), - insn_data_line_no(iobj)); - pos += insn_data_length(iobj); - break; - } - case ISEQ_ELEMENT_LABEL: - { - lobj = (LABEL *)link; - printf("<L%03d>\n", lobj->label_no); - break; - } - case ISEQ_ELEMENT_NONE: - { - printf("[none]\n"); - break; - } - case ISEQ_ELEMENT_ADJUST: - { - ADJUST *adjust = (ADJUST *)link; - printf("adjust: [label: %d]\n", adjust->label->label_no); - break; - } - default: - /* ignore */ - rb_raise(rb_eSyntaxError, "dump_disasm_list error: %ld\n", FIX2LONG(link->type)); - } - link = link->next; - } - printf("---------------------\n"); -} - -VALUE -insns_name_array(void) -{ - VALUE ary = rb_ary_new(); - int i; - for (i = 0; i < sizeof(insn_name_info) / sizeof(insn_name_info[0]); i++) { - rb_ary_push(ary, rb_str_new2(insn_name_info[i])); - } - return ary; -} - -static LABEL * -register_label(rb_iseq_t *iseq, struct st_table *labels_table, VALUE obj) -{ - LABEL *label = 0; - st_data_t tmp; - obj = rb_convert_type(obj, T_SYMBOL, "Symbol", "to_sym"); - - if (st_lookup(labels_table, obj, &tmp) == 0) { - label = NEW_LABEL(0); - st_insert(labels_table, obj, (st_data_t)label); - } - else { - label = (LABEL *)tmp; - } - return label; -} - -static VALUE -get_exception_sym2type(VALUE sym) -{ -#undef rb_intern -#define rb_intern(str) rb_intern_const(str) - static VALUE symRescue, symEnsure, symRetry; - static VALUE symBreak, symRedo, symNext; - - if (symRescue == 0) { - symRescue = ID2SYM(rb_intern("rescue")); - symEnsure = ID2SYM(rb_intern("ensure")); - symRetry = ID2SYM(rb_intern("retry")); - symBreak = ID2SYM(rb_intern("break")); - symRedo = ID2SYM(rb_intern("redo")); - symNext = ID2SYM(rb_intern("next")); - } - - if (sym == symRescue) return CATCH_TYPE_RESCUE; - if (sym == symEnsure) return CATCH_TYPE_ENSURE; - if (sym == symRetry) return CATCH_TYPE_RETRY; - if (sym == symBreak) return CATCH_TYPE_BREAK; - if (sym == symRedo) return CATCH_TYPE_REDO; - if (sym == symNext) return CATCH_TYPE_NEXT; - rb_raise(rb_eSyntaxError, "invalid exception symbol: %s", - RSTRING_PTR(rb_inspect(sym))); - return 0; -} - -static int -iseq_build_exception(rb_iseq_t *iseq, struct st_table *labels_table, - VALUE exception) -{ - int i; - - for (i=0; i<RARRAY_LEN(exception); i++) { - VALUE v, type, *ptr, eiseqval; - LABEL *lstart, *lend, *lcont; - int sp; - - RB_GC_GUARD(v) = rb_convert_type(RARRAY_PTR(exception)[i], T_ARRAY, - "Array", "to_ary"); - if (RARRAY_LEN(v) != 6) { - rb_raise(rb_eSyntaxError, "wrong exception entry"); - } - ptr = RARRAY_PTR(v); - type = get_exception_sym2type(ptr[0]); - if (ptr[1] == Qnil) { - eiseqval = 0; - } - else { - eiseqval = iseq_load(0, ptr[1], iseq->self, Qnil); - } - - lstart = register_label(iseq, labels_table, ptr[2]); - lend = register_label(iseq, labels_table, ptr[3]); - lcont = register_label(iseq, labels_table, ptr[4]); - sp = NUM2INT(ptr[5]); - - ADD_CATCH_ENTRY(type, lstart, lend, eiseqval, lcont); - } - return COMPILE_OK; -} - -struct st_table *insn_make_insn_table(void); - -static int -iseq_build_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor, - VALUE body, struct st_table *labels_table) -{ - /* TODO: body should be freezed */ - VALUE *ptr = RARRAY_PTR(body); - int len = RARRAY_LEN(body); - int i, j; - int line_no = 0; - /* - * index -> LABEL *label - */ - static struct st_table *insn_table; - - if (insn_table == 0) { - insn_table = insn_make_insn_table(); - } - - for (i=0; i<len; i++) { - VALUE obj = ptr[i]; - - if (SYMBOL_P(obj)) { - LABEL *label = register_label(iseq, labels_table, obj); - ADD_LABEL(anchor, label); - } - else if (FIXNUM_P(obj)) { - line_no = NUM2INT(obj); - } - else if (TYPE(obj) == T_ARRAY) { - VALUE *argv = 0; - int argc = RARRAY_LEN(obj) - 1; - VALUE insn_id; - VALUE insn; - - insn = (argc < 0) ? Qnil : RARRAY_PTR(obj)[0]; - if (st_lookup(insn_table, insn, &insn_id) == 0) { - /* TODO: exception */ - RB_GC_GUARD(insn) = rb_inspect(insn); - rb_compile_error(RSTRING_PTR(iseq->filename), line_no, - "unknown instruction: %s", RSTRING_PTR(insn)); - } - - if (argc != insn_len(insn_id)-1) { - rb_compile_error(RSTRING_PTR(iseq->filename), line_no, - "operand size mismatch"); - } - - if (argc > 0) { - argv = compile_data_alloc(iseq, sizeof(VALUE) * argc); - for (j=0; j<argc; j++) { - VALUE op = rb_ary_entry(obj, j+1); - switch (insn_op_type(insn_id, j)) { - case TS_OFFSET: { - LABEL *label = register_label(iseq, labels_table, op); - argv[j] = (VALUE)label; - break; - } - case TS_LINDEX: - case TS_DINDEX: - case TS_NUM: - (void)NUM2INT(op); - argv[j] = op; - break; - case TS_VALUE: - argv[j] = op; - iseq_add_mark_object(iseq, op); - break; - case TS_ISEQ: - { - if (op != Qnil) { - if (TYPE(op) == T_ARRAY) { - argv[j] = iseq_load(0, op, iseq->self, Qnil); - } - else if (CLASS_OF(op) == rb_cISeq) { - argv[j] = op; - } - else { - rb_raise(rb_eSyntaxError, "ISEQ is required"); - } - iseq_add_mark_object(iseq, argv[j]); - } - else { - argv[j] = 0; - } - } - break; - case TS_GENTRY: - op = rb_convert_type(op, T_SYMBOL, "Symbol", "to_sym"); - argv[j] = (VALUE)rb_global_entry(SYM2ID(op)); - break; - case TS_IC: - argv[j] = (VALUE)NEW_INLINE_CACHE_ENTRY(); - iseq_add_mark_object(iseq, argv[j]); - break; - case TS_ID: - argv[j] = rb_convert_type(op, T_SYMBOL, - "Symbol", "to_sym"); - break; - case TS_CDHASH: - { - int i; - op = rb_convert_type(op, T_ARRAY, "Array", "to_ary"); - op = rb_ary_dup(op); - for (i=0; i<RARRAY_LEN(op); i+=2) { - VALUE sym = rb_ary_entry(op, i+1); - LABEL *label = - register_label(iseq, labels_table, sym); - rb_ary_store(op, i+1, (VALUE)label | 1); - } - argv[j] = op; - } - break; - default: - rb_raise(rb_eSyntaxError, "unknown operand: %c", insn_op_type(insn_id, j)); - } - } - } - ADD_ELEM(anchor, - (LINK_ELEMENT*)new_insn_core(iseq, line_no, - insn_id, argc, argv)); - } - else { - rb_raise(rb_eTypeError, "unexpected object for instruction"); - } - } - st_free_table(labels_table); - iseq_setup(iseq, anchor); - return COMPILE_OK; -} - -#define CHECK_ARRAY(v) rb_convert_type(v, T_ARRAY, "Array", "to_ary") -#define CHECK_STRING(v) rb_convert_type(v, T_STRING, "String", "to_str") -#define CHECK_SYMBOL(v) rb_convert_type(v, T_SYMBOL, "Symbol", "to_sym") -static inline VALUE CHECK_INTEGER(VALUE v) {NUM2LONG(v); return v;} - -VALUE -iseq_build_from_ary(rb_iseq_t *iseq, VALUE locals, VALUE args, - VALUE exception, VALUE body) -{ - int i; - ID *tbl; - struct st_table *labels_table = st_init_numtable(); - - DECL_ANCHOR(anchor); - - INIT_ANCHOR(anchor); - - iseq->local_table_size = RARRAY_LEN(locals); - iseq->local_table = tbl = (ID *)ALLOC_N(ID *, iseq->local_table_size); - iseq->local_size = iseq->local_table_size + 1; - - for (i=0; i<RARRAY_LEN(locals); i++) { - VALUE lv = RARRAY_PTR(locals)[i]; - tbl[i] = FIXNUM_P(lv) ? FIX2INT(lv) : SYM2ID(CHECK_SYMBOL(lv)); - } - - /* args */ - if (FIXNUM_P(args)) { - iseq->arg_size = iseq->argc = FIX2INT(args); - iseq->arg_simple = 1; - } - else { - int i = 0; - VALUE argc = CHECK_INTEGER(rb_ary_entry(args, i++)); - VALUE arg_opt_labels = CHECK_ARRAY(rb_ary_entry(args, i++)); - VALUE arg_post_len = CHECK_INTEGER(rb_ary_entry(args, i++)); - VALUE arg_post_start = CHECK_INTEGER(rb_ary_entry(args, i++)); - VALUE arg_rest = CHECK_INTEGER(rb_ary_entry(args, i++)); - VALUE arg_block = CHECK_INTEGER(rb_ary_entry(args, i++)); - VALUE arg_simple = CHECK_INTEGER(rb_ary_entry(args, i++)); - - iseq->argc = FIX2INT(argc); - iseq->arg_rest = FIX2INT(arg_rest); - iseq->arg_post_len = FIX2INT(arg_post_len); - iseq->arg_post_start = FIX2INT(arg_post_start); - iseq->arg_block = FIX2INT(arg_block); - iseq->arg_opts = RARRAY_LEN(arg_opt_labels); - iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, iseq->arg_opts); - - if (iseq->arg_block != -1) { - iseq->arg_size = iseq->arg_block + 1; - } - else if (iseq->arg_post_len) { - iseq->arg_size = iseq->arg_post_start + iseq->arg_post_len; - } - else if (iseq->arg_rest != -1) { - iseq->arg_size = iseq->arg_rest + 1; - } - else { - iseq->arg_size = iseq->argc + (iseq->arg_opts ? iseq->arg_opts - 1 : 0); - } - - for (i=0; i<RARRAY_LEN(arg_opt_labels); i++) { - iseq->arg_opt_table[i] = - (VALUE)register_label(iseq, labels_table, - rb_ary_entry(arg_opt_labels, i)); - } - - iseq->arg_simple = NUM2INT(arg_simple); - } - - /* exception */ - iseq_build_exception(iseq, labels_table, exception); - - /* body */ - iseq_build_body(iseq, anchor, body, labels_table); - return iseq->self; -} |