static NODE * new_assign(NODE * lnode, NODE * rhs) { switch (nd_type(lnode)) { case NODE_LASGN:{ return NEW_NODE(NODE_LASGN, lnode->nd_vid, rhs, lnode->nd_cnt); /* NEW_LASGN(lnode->nd_vid, rhs); */ } case NODE_GASGN:{ return NEW_GASGN(lnode->nd_vid, rhs); } case NODE_DASGN:{ return NEW_DASGN(lnode->nd_vid, rhs); } case NODE_ATTRASGN:{ NODE *args = 0; if (lnode->nd_args) { args = NEW_ARRAY(lnode->nd_args->nd_head); args->nd_next = NEW_ARRAY(rhs); args->nd_alen = 2; } else { args = NEW_ARRAY(rhs); } return NEW_ATTRASGN(lnode->nd_recv, lnode->nd_mid, args); } default: rb_bug("unimplemented (block inlining): %s", ruby_node_name(nd_type(lnode))); } return 0; }
int rb_node_arity(NODE* body) { switch (nd_type(body)) { case NODE_CFUNC: if (body->nd_argc < 0) return -1; return body->nd_argc; case NODE_ZSUPER: return -1; case NODE_ATTRSET: return 1; case NODE_IVAR: return 0; case NODE_BMETHOD: return rb_proc_arity(body->nd_cval); case RUBY_VM_METHOD_NODE: { rb_iseq_t *iseq; GetISeqPtr((VALUE)body->nd_body, iseq); if (iseq->arg_rest == -1 && iseq->arg_opts == 0) { return iseq->argc; } else { return -(iseq->argc + 1 + iseq->arg_post_len); } } default: rb_raise(rb_eArgError, "invalid node 0x%x", nd_type(body)); } }
rb_alloc_func_t rb_get_alloc_func(VALUE klass) { NODE *n; Check_Type(klass, T_CLASS); n = rb_method_node(CLASS_OF(klass), ID_ALLOCATOR); if (!n) return 0; if (nd_type(n) != NODE_METHOD) return 0; n = n->nd_body; if (nd_type(n) != NODE_CFUNC) return 0; return (rb_alloc_func_t)n->nd_cfnc; }
static inline void vm_send_optimize(rb_control_frame_t * const reg_cfp, NODE ** const mn, rb_num_t * const flag, rb_num_t * const num, ID * const id, const VALUE klass) { if (*mn && nd_type((*mn)->nd_body) == NODE_CFUNC) { NODE *node = (*mn)->nd_body; extern VALUE rb_f_send(int argc, VALUE *argv, VALUE recv); if (node->nd_cfnc == rb_f_send) { int i = *num - 1; VALUE sym = TOPN(i); *id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym); /* shift arguments */ if (i > 0) { MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i); } *mn = rb_method_node(klass, *id); *num -= 1; DEC_SP(1); *flag |= VM_CALL_FCALL_BIT; } } }
static VALUE f_hijack(VALUE self) { VALUE proc, ary; struct BLOCK* blk; NODE* nd; NODE* block; NODE* args; NODE* body; int argc; ID mid; if (!rb_block_given_p()) return Qnil; proc = rb_block_proc(); Data_Get_Struct(proc, struct BLOCK, blk); nd = find_def_node(blk->body); if (!nd->nd_defn) return Qnil; if (nd_type(nd->nd_defn) != NODE_SCOPE) return Qnil; /* * nd_mid: an id of the name of the method * nd_defn: scope node for the method */ mid = nd->nd_mid; block = nd->nd_defn->nd_next; proc = Data_Wrap_Struct(rb_cProc, blk_mark, blk_free, block); return proc; }
static void rb_export_method(VALUE klass, ID name, ID noex) { NODE *fbody; VALUE origin; if (klass == rb_cObject) { rb_secure(4); } fbody = search_method(klass, name, &origin); if (!fbody && TYPE(klass) == T_MODULE) { fbody = search_method(rb_cObject, name, &origin); } if (!fbody || !fbody->nd_body) { rb_print_undef(klass, name, 0); } if (fbody->nd_body->nd_noex != noex) { if (nd_type(fbody->nd_body->nd_body) == NODE_CFUNC) { rb_vm_check_redefinition_opt_method(fbody); } if (klass == origin) { fbody->nd_body->nd_noex = noex; } else { rb_add_method(klass, name, NEW_ZSUPER(), noex); } } }
static int clone_method(ID mid, NODE *body, VALUE nklass) { NODE *fbody = body->nd_body; if (fbody) { VALUE nbody; switch (nd_type(fbody)) { case NODE_SCOPE: fbody = rb_copy_node_scope(fbody, ruby_cref); break; case NODE_BMETHOD: nbody = rb_block_dup(fbody->nd_cval, nklass, (VALUE)ruby_cref); fbody = NEW_BMETHOD(nbody); break; case NODE_DMETHOD: nbody = rb_method_dup(fbody->nd_cval, nklass, (VALUE)ruby_cref); fbody = NEW_DMETHOD(nbody); break; } } st_insert(RCLASS(nklass)->m_tbl, mid, (st_data_t)NEW_METHOD(fbody, body->nd_noex)); return ST_CONTINUE; }
/* The name of the ruby source file where the code associated with the node are defined */ VALUE rb_node_file(VALUE self) { NODE* _node; Data_Get_Struct(self,NODE,_node); #ifdef RUBY1_8 if (nd_file(_node) == NULL ) { return rb_str_new2(""); } return rb_str_new2(nd_file(_node) ); #endif #ifdef RUBY1_9 if (nd_type(_node) == RUBY_VM_METHOD_NODE) { VALUE iseqval = (VALUE)(_node->nd_body); rb_iseq_t__* ptr; Data_Get_Struct(iseqval, rb_iseq_t__, ptr); return ptr->filename; } return rb_str_new2(""); #endif }
static VALUE proc_arity(VALUE self) { rb_proc_t *proc; rb_iseq_t *iseq; GetProcPtr(self, proc); iseq = proc->block.iseq; if (iseq) { if (BUILTIN_TYPE(iseq) != T_NODE) { if (iseq->arg_rest < 0) { return INT2FIX(iseq->argc); } else { return INT2FIX(-(iseq->argc + 1 + iseq->arg_post_len)); } } else { NODE *node = (NODE *)iseq; if (nd_type(node) == NODE_IFUNC && node->nd_cfnc == bmcall) { /* method(:foo).to_proc.arity */ return INT2FIX(method_arity(node->nd_tval)); } } } return INT2FIX(-1); }
NODE * ruby_debug_print_node(int level, int debug_level, const char *header, const NODE *node) { if (level < debug_level) { fprintf(stderr, "DBG> %s: %s (%lu)\n", header, ruby_node_name(nd_type(node)), nd_line(node)); } return (NODE *)node; }
void rb_alias(VALUE klass, ID name, ID def) { NODE *orig_fbody, *node, *method; VALUE singleton = 0; st_data_t data; rb_frozen_class_p(klass); if (klass == rb_cObject) { rb_secure(4); } orig_fbody = search_method(klass, def, 0); if (!orig_fbody || !orig_fbody->nd_body) { if (TYPE(klass) == T_MODULE) { orig_fbody = search_method(rb_cObject, def, 0); } } if (!orig_fbody || !orig_fbody->nd_body) { rb_print_undef(klass, def, 0); } if (FL_TEST(klass, FL_SINGLETON)) { singleton = rb_iv_get(klass, "__attached__"); } orig_fbody->nd_cnt++; if (st_lookup(RCLASS_M_TBL(klass), name, &data)) { node = (NODE *)data; if (node) { if (RTEST(ruby_verbose) && node->nd_cnt == 0 && node->nd_body) { rb_warning("discarding old %s", rb_id2name(name)); } if (nd_type(node->nd_body->nd_body) == NODE_CFUNC) { rb_vm_check_redefinition_opt_method(node); } } } st_insert(RCLASS_M_TBL(klass), name, (st_data_t) NEW_FBODY( method = NEW_METHOD(orig_fbody->nd_body->nd_body, orig_fbody->nd_body->nd_clss, NOEX_WITH_SAFE(orig_fbody->nd_body->nd_noex)), def)); method->nd_file = (void *)def; rb_clear_cache_by_id(name); if (!ruby_running) return; if (singleton) { rb_funcall(singleton, singleton_added, 1, ID2SYM(name)); } else { rb_funcall(klass, added, 1, ID2SYM(name)); } }
int rb_node_arity(NODE* body) { int n; switch (nd_type(body)) { case NODE_CFUNC: if (body->nd_argc < 0) return -1; return body->nd_argc; case NODE_ZSUPER: return -1; case NODE_ATTRSET: return 1; case NODE_IVAR: return 0; case NODE_BMETHOD: return rb_proc_arity(body->nd_cval); case NODE_SCOPE: body = body->nd_next; /* skip NODE_SCOPE */ if (nd_type(body) == NODE_BLOCK) body = body->nd_head; if (!body) return 0; n = body->nd_frml ? RARRAY_LEN(body->nd_frml) : 0; if (body->nd_opt || body->nd_rest) n = -n - 1; return n; case RUBY_VM_METHOD_NODE:{ rb_iseq_t *iseq; GetISeqPtr((VALUE)body->nd_body, iseq); if (iseq->arg_rest == 0 && iseq->arg_opts == 0) { return iseq->argc; } else { return -iseq->argc - 1; } } default: rb_raise(rb_eArgError, "invalid node 0x%x", nd_type(body)); } }
static struct RNode* find_def_node(struct RNode* nd) { while (nd) { switch (nd_type(nd)) { case NODE_DEFN: case NODE_DEFS: return nd; case NODE_BEGIN: nd = nd->nd_body; break; case NODE_NEWLINE: nd = nd->nd_next; break; default: print_node_name(nd_type(nd)); return NULL; } } return NULL; }
static VALUE compiled_location(VALUE self) { struct METHOD *data; VALUE name = rb_funcall(self, rb_intern("name"), 0); Data_Get_Struct(self, struct METHOD, data); if (nd_type(data->body) != NODE_CFUNC) { return Qnil; } return file_and_offset(*data->body->nd_cfnc, StringValueCStr(name)); }
int rb_node_arity(NODE* body) { // TODO should be replaced by the roxor.cpp's stuff switch (nd_type(body)) { case NODE_CFUNC: if (body->nd_argc < 0) { return -1; } return body->nd_argc; case NODE_ZSUPER: return -1; case NODE_ATTRSET: return 1; case NODE_IVAR: return 0; case NODE_BMETHOD: return rb_proc_arity(body->nd_cval); default: rb_raise(rb_eArgError, "invalid node 0x%x", nd_type(body)); } }
static int cn_i(void *vstart, void *vend, size_t stride, void *n) { size_t *nodes = (size_t *)n; VALUE v = (VALUE)vstart; for (; v != (VALUE)vend; v += stride) { if (RBASIC(v)->flags && BUILTIN_TYPE(v) == T_NODE) { size_t s = nd_type((NODE *)v); nodes[s]++; } } return 0; }
static VALUE mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope) { VALUE method; NODE *body; struct METHOD *data; VALUE rclass = klass; ID oid = id; again: if ((body = rb_get_method_body(klass, id, 0)) == 0) { rb_print_undef(rclass, oid, 0); } if (scope && (body->nd_noex & NOEX_MASK) != NOEX_PUBLIC) { rb_print_undef(rclass, oid, (body->nd_noex & NOEX_MASK)); } klass = body->nd_clss; body = body->nd_body; if (nd_type(body) == NODE_ZSUPER) { klass = RCLASS_SUPER(klass); goto again; } while (rclass != klass && (RCLASS_SINGLETON(rclass) || TYPE(rclass) == T_ICLASS)) { rclass = RCLASS_SUPER(rclass); } if (TYPE(klass) == T_ICLASS) klass = RBASIC(klass)->klass; method = Data_Make_Struct(mclass, struct METHOD, bm_mark, -1, data); data->oclass = klass; GC_WB(&data->recv, obj); data->id = id; data->body = body; data->rclass = rclass; data->oid = oid; #if !WITH_OBJC OBJ_INFECT(method, klass); #endif return method; }
static rb_iseq_t * get_method_iseq(VALUE method) { struct METHOD *data; NODE *body; rb_iseq_t *iseq; Data_Get_Struct(method, struct METHOD, data); body = data->body; switch (nd_type(body)) { case RUBY_VM_METHOD_NODE: GetISeqPtr((VALUE)body->nd_body, iseq); if (RUBY_VM_NORMAL_ISEQ_P(iseq)) break; default: return 0; } return iseq; }
static VALUE rb_mod_modfunc(int argc, VALUE *argv, VALUE module) { int i; ID id; NODE *fbody; if (TYPE(module) != T_MODULE) { rb_raise(rb_eTypeError, "module_function must be called for modules"); } secure_visibility(module); if (argc == 0) { SCOPE_SET(NOEX_MODFUNC); return module; } set_method_visibility(module, argc, argv, NOEX_PRIVATE); for (i = 0; i < argc; i++) { VALUE m = module; id = rb_to_id(argv[i]); for (;;) { fbody = search_method(m, id, &m); if (fbody == 0) { fbody = search_method(rb_cObject, id, &m); } if (fbody == 0 || fbody->nd_body == 0) { rb_bug("undefined method `%s'; can't happen", rb_id2name(id)); } if (nd_type(fbody->nd_body->nd_body) != NODE_ZSUPER) { break; /* normal case: need not to follow 'super' link */ } m = RCLASS_SUPER(m); if (!m) break; } rb_add_method(rb_singleton_class(module), id, fbody->nd_body->nd_body, NOEX_PUBLIC); } return module; }
static void remove_method(VALUE klass, ID mid) { st_data_t data; NODE *body = 0; if (klass == rb_cObject) { rb_secure(4); } if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) { rb_raise(rb_eSecurityError, "Insecure: can't remove method"); } if (OBJ_FROZEN(klass)) rb_error_frozen("class/module"); if (mid == object_id || mid == __send__ || mid == idInitialize) { rb_warn("removing `%s' may cause serious problem", rb_id2name(mid)); } if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) { body = (NODE *)data; if (!body || !body->nd_body) body = 0; else { st_delete(RCLASS_M_TBL(klass), &mid, &data); } } if (!body) { rb_name_error(mid, "method `%s' not defined in %s", rb_id2name(mid), rb_class2name(klass)); } if (nd_type(body->nd_body->nd_body) == NODE_CFUNC) { rb_vm_check_redefinition_opt_method(body); } rb_clear_cache_for_undef(klass, mid); if (FL_TEST(klass, FL_SINGLETON)) { rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1, ID2SYM(mid)); } else { rb_funcall(klass, removed, 1, ID2SYM(mid)); } }
/* * Return the source file and line number of the given object and method. */ VALUE Looksee_source_location(VALUE self, VALUE unbound_method) { if (!rb_obj_is_kind_of(unbound_method, rb_cUnboundMethod)) rb_raise(rb_eTypeError, "expected UnboundMethod, got %s", rb_obj_classname(unbound_method)); struct METHOD *method; Data_Get_Struct(unbound_method, struct METHOD, method); NODE *node; switch (nd_type(method->body)) { // Can't be a FBODY or ZSUPER. case NODE_SCOPE: node = method->body->nd_defn; break; case NODE_BMETHOD: { struct BLOCK *block; Data_Get_Struct(method->body->nd_orig, struct BLOCK, block); (node = block->frame.node) || (node = block->body); // Proc#to_s suggests this may be NULL sometimes. if (!node) return Qnil; } break; case NODE_DMETHOD: { struct METHOD *original_method; NODE *body = method->body; Data_Get_Struct(body->nd_orig, struct METHOD, original_method); node = original_method->body->nd_defn; } break; default: return Qnil; } VALUE file = rb_str_new2(node->nd_file); VALUE line = INT2NUM(nd_line(node)); VALUE location = rb_ary_new2(2); rb_ary_store(location, 0, file); rb_ary_store(location, 1, line); return location; }
static VALUE mnew(VALUE klass, VALUE obj, ID id, VALUE mklass) { VALUE method; NODE *body; struct METHOD *data; VALUE rklass = klass; ID oid = id; again: if ((body = rb_get_method_body(klass, id, 0)) == 0) { print_undef(rklass, oid); } klass = body->nd_clss; body = body->nd_body; if (nd_type(body) == NODE_ZSUPER) { klass = RCLASS(klass)->super; goto again; } while (rklass != klass && (FL_TEST(rklass, FL_SINGLETON) || TYPE(rklass) == T_ICLASS)) { rklass = RCLASS(rklass)->super; } if (TYPE(klass) == T_ICLASS) klass = RBASIC(klass)->klass; method = Data_Make_Struct(mklass, struct METHOD, bm_mark, -1, data); data->klass = klass; data->recv = obj; data->id = id; data->body = body; data->rklass = rklass; data->oid = oid; OBJ_INFECT(method, klass); return method; }
static char * load_lock(const char *ftptr) { st_data_t data; st_table *loading_tbl = get_loading_table(); if (!loading_tbl || !st_lookup(loading_tbl, (st_data_t)ftptr, &data)) { /* loading ruby library should be serialized. */ if (!loading_tbl) { GET_VM()->loading_table = loading_tbl = st_init_strtable(); } /* partial state */ ftptr = ruby_strdup(ftptr); data = (st_data_t)rb_thread_shield_new(); st_insert(loading_tbl, (st_data_t)ftptr, data); return (char *)ftptr; } else if (RB_TYPE_P((VALUE)data, T_NODE) && nd_type((VALUE)data) == NODE_MEMO) { NODE *memo = RNODE(data); void (*init)(void) = (void (*)(void))memo->nd_cfnc; data = (st_data_t)rb_thread_shield_new(); st_insert(loading_tbl, (st_data_t)ftptr, data); (*init)(); return (char *)""; } if (RTEST(ruby_verbose)) { rb_warning("loading in progress, circular require considered harmful - %s", ftptr); rb_backtrace_print_to(rb_stderr); } switch (rb_thread_shield_wait((VALUE)data)) { case Qfalse: data = (st_data_t)ftptr; st_insert(loading_tbl, data, (st_data_t)rb_thread_shield_new()); return 0; case Qnil: return 0; } return (char *)ftptr; }
char * nd_type_str(VALUE obj) { switch(nd_type(obj)) { #define ND(type) case NODE_##type: return #type; ND(METHOD); ND(FBODY); ND(CFUNC); ND(SCOPE); ND(BLOCK); ND(IF); ND(CASE); ND(WHEN); ND(OPT_N); ND(WHILE); ND(UNTIL); ND(ITER); ND(FOR); ND(BREAK); ND(NEXT); ND(REDO); ND(RETRY); ND(BEGIN); ND(RESCUE); ND(RESBODY); ND(ENSURE); ND(AND); ND(OR); ND(NOT); ND(MASGN); ND(LASGN); ND(DASGN); ND(DASGN_CURR); ND(GASGN); ND(IASGN); ND(CDECL); ND(CVASGN); ND(CVDECL); ND(OP_ASGN1); ND(OP_ASGN2); ND(OP_ASGN_AND); ND(OP_ASGN_OR); ND(CALL); ND(FCALL); ND(VCALL); ND(SUPER); ND(ZSUPER); ND(ARRAY); ND(ZARRAY); ND(HASH); ND(RETURN); ND(YIELD); ND(LVAR); ND(DVAR); ND(GVAR); ND(IVAR); ND(CONST); ND(CVAR); ND(NTH_REF); ND(BACK_REF); ND(MATCH); ND(MATCH2); ND(MATCH3); ND(LIT); ND(STR); ND(DSTR); ND(XSTR); ND(DXSTR); ND(EVSTR); ND(DREGX); ND(DREGX_ONCE); ND(ARGS); ND(ARGSCAT); ND(ARGSPUSH); ND(SPLAT); ND(TO_ARY); ND(SVALUE); ND(BLOCK_ARG); ND(BLOCK_PASS); ND(DEFN); ND(DEFS); ND(ALIAS); ND(VALIAS); ND(UNDEF); ND(CLASS); ND(MODULE); ND(SCLASS); ND(COLON2); ND(COLON3) ND(CREF); ND(DOT2); ND(DOT3); ND(FLIP2); ND(FLIP3); ND(ATTRSET); ND(SELF); ND(NIL); ND(TRUE); ND(FALSE); ND(DEFINED); ND(NEWLINE); ND(POSTEXE); ND(ALLOCA); ND(DMETHOD); ND(BMETHOD); ND(MEMO); ND(IFUNC); ND(DSYM); ND(ATTRASGN); ND(LAST); default: return "unknown"; } }
static bool attribute_p(VALUE self, char* name) { if (!method_p(self, name)) return false; VALUE rb_id = rb_intern(name); VALUE rb_method = rb_funcall(self, rb_intern("method"), 1, ID2SYM(rb_id)); if (TYPE(rb_method) == T_DATA) { VALUE klass = CLASS_OF(rb_method); if (klass == rb_cMethod) { METHOD* method; Data_Get_Struct(rb_method, METHOD, method); if (method && nd_type(method->body) == NODE_IVAR) return true; } } return RTEST(rb_funcall(Johnson_SpiderMonkey_JSLandProxy(), rb_intern("js_property?"), 2, self, ID2SYM(rb_id))); }
static NODE * build_Array_each_node(rb_iseq_t *iseq, NODE * node, NODE * lnode, VALUE param_vars, VALUE local_vars) { /* Special block for Array#each ary.each{|e| BODY } => {|e, _self| _i = 0 while _i < _self.length e = _self[_i] redo_point: BODY next_point: _i = _i.succ end } ary.each{ BODY } => {|_i, _self| _i = 0 while _i < _self.length redo_point: BODY next_point: _i = _i.succ end } */ ID _self = rb_intern("#_self"); ID _i = rb_intern("#_i"); if (iseq->argc == 0) { ID _e = rb_intern("#_e"); rb_ary_push(param_vars, ID2SYM(_e)); rb_ary_push(param_vars, ID2SYM(_self)); iseq->argc += 2; rb_ary_push(local_vars, ID2SYM(_i)); node = new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))), NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT, new_ary(NEW_CALL (NEW_DVAR(_self), idLength, 0), 0)), new_block(NEW_OPTBLOCK(node), NEW_DASGN(_i, NEW_CALL(NEW_DVAR(_i), idSucc, 0))), Qundef)); } else { ID e = SYM2ID(rb_ary_entry(param_vars, 0)); NODE *assign; rb_ary_push(param_vars, ID2SYM(_self)); iseq->argc++; rb_ary_push(local_vars, ID2SYM(_i)); if (nd_type(lnode) == NODE_DASGN_CURR) { assign = NEW_DASGN(e, NEW_CALL(NEW_DVAR(_self), idAREF, new_ary(NEW_DVAR(_i), 0))); } else { assign = new_assign(lnode, NEW_CALL(NEW_DVAR(_self), idAREF, new_ary(NEW_DVAR(_i), 0))); } node = new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))), NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT, new_ary(NEW_CALL (NEW_DVAR(_self), idLength, 0), 0)), new_block(assign, new_block (NEW_OPTBLOCK (node), NEW_DASGN (_i, NEW_CALL (NEW_DVAR (_i), idSucc, 0)))), Qundef)); } return node; }
static NODE * build_Range_each_node(rb_iseq_t *iseq, NODE * node, NODE * lnode, VALUE param_vars, VALUE local_vars, ID mid) { /* Special Block for Range#each {|e, _last| _e = e while _e < _last e = _e next_point: BODY redo_point: _e = _e.succ end } {|e, _last| while e < _last BODY redo_point: e = e.succ end } */ ID _last = rb_intern("#_last"); if (iseq->argc == 0) { ID e = rb_intern("#e"); rb_ary_push(param_vars, ID2SYM(e)); rb_ary_push(param_vars, ID2SYM(_last)); iseq->argc += 2; node = NEW_WHILE(NEW_CALL(NEW_DVAR(e), mid, new_ary(NEW_DVAR(_last), 0)), new_block(NEW_OPTBLOCK(node), NEW_DASGN(e, NEW_CALL(NEW_DVAR(e), idSucc, 0))), Qundef); } else { ID _e = rb_intern("#_e"); ID e = SYM2ID(rb_ary_entry(param_vars, 0)); NODE *assign; rb_ary_push(param_vars, ID2SYM(_last)); rb_ary_push(local_vars, ID2SYM(_e)); iseq->argc++; if (nd_type(lnode) == NODE_DASGN_CURR) { assign = NEW_DASGN(e, NEW_DVAR(_e)); } else { assign = new_assign(lnode, NEW_DVAR(_e)); } node = new_block(NEW_DASGN(_e, NEW_DVAR(e)), NEW_WHILE(NEW_CALL (NEW_DVAR(_e), mid, new_ary(NEW_DVAR(_last), 0)), new_block(assign, new_block(NEW_OPTBLOCK(node), NEW_DASGN(_e, NEW_CALL (NEW_DVAR(_e), idSucc, 0)))), Qundef)); } return node; }
static NODE * build_Integer_times_node(rb_iseq_t *iseq, NODE * node, NODE * lnode, VALUE param_vars, VALUE local_vars) { /* Special Block for Integer#times {|e, _self| _e = e while(e < _self) e = _e redo_point: BODY next_point: _e = _e.succ end } {|e, _self| while(e < _self) BODY next_point: e = e.succ end } */ ID _self = rb_intern("#_self"); if (iseq->argc == 0) { ID e = rb_intern("#e"); rb_ary_push(param_vars, ID2SYM(e)); rb_ary_push(param_vars, ID2SYM(_self)); iseq->argc += 2; node = NEW_WHILE(NEW_CALL (NEW_DVAR(e), idLT, new_ary(NEW_DVAR(_self), 0)), new_block(NEW_OPTBLOCK(node), NEW_DASGN(e, NEW_CALL(NEW_DVAR(e), idSucc, 0))), Qundef); } else { ID _e = rb_intern("#_e"); ID e = SYM2ID(rb_ary_entry(param_vars, 0)); NODE *assign; rb_ary_push(param_vars, ID2SYM(_self)); rb_ary_push(local_vars, ID2SYM(_e)); iseq->argc++; if (nd_type(lnode) == NODE_DASGN_CURR) { assign = NEW_DASGN(e, NEW_DVAR(_e)); } else { assign = new_assign(lnode, NEW_DVAR(_e)); } node = new_block(NEW_DASGN(_e, NEW_DVAR(e)), NEW_WHILE(NEW_CALL (NEW_DVAR(_e), idLT, new_ary(NEW_DVAR(_self), 0)), new_block(assign, new_block(NEW_OPTBLOCK(node), NEW_DASGN(_e, NEW_CALL (NEW_DVAR(_e), idSucc, 0)))), Qundef)); } return node; }
void rb_node_release(NODE *node) { if (node == NULL || node == (NODE *)-1) { return; } // static int c = 0; // printf("%d RELEASE %s %p\n", ++c, ruby_node_name(nd_type(node)), node); switch (nd_type(node)) { case NODE_IF: /* 1,2,3 */ case NODE_FOR: case NODE_ITER: case NODE_WHEN: case NODE_MASGN: case NODE_RESCUE: case NODE_RESBODY: case NODE_CLASS: case NODE_BLOCK_PASS: rb_node_release(node->u2.node); /* fall through */ case NODE_BLOCK: /* 1,3 */ case NODE_OPTBLOCK: case NODE_ARRAY: case NODE_ENSURE: case NODE_CALL: case NODE_DEFS: case NODE_OP_ASGN1: case NODE_ARGS: rb_node_release(node->u1.node); /* fall through */ case NODE_SUPER: /* 3 */ case NODE_FCALL: case NODE_DEFN: case NODE_ARGS_AUX: rb_node_release(node->u3.node); break; case NODE_WHILE: /* 1,2 */ case NODE_UNTIL: case NODE_AND: case NODE_OR: case NODE_CASE: case NODE_SCLASS: case NODE_DOT2: case NODE_DOT3: case NODE_FLIP2: case NODE_FLIP3: case NODE_MATCH2: case NODE_MATCH3: case NODE_OP_ASGN_OR: case NODE_OP_ASGN_AND: case NODE_MODULE: case NODE_ARGSCAT: rb_node_release(node->u1.node); /* fall through */ case NODE_FBODY: /* 2 */ case NODE_GASGN: case NODE_LASGN: case NODE_DASGN: case NODE_DASGN_CURR: case NODE_IASGN: case NODE_IASGN2: case NODE_CVASGN: case NODE_OPT_N: case NODE_EVSTR: case NODE_UNDEF: case NODE_POSTEXE: rb_node_release(node->u2.node); break; case NODE_HASH: /* 1 */ case NODE_DEFINED: case NODE_RETURN: case NODE_BREAK: case NODE_NEXT: case NODE_YIELD: case NODE_COLON2: case NODE_SPLAT: case NODE_TO_ARY: rb_node_release(node->u1.node); break; case NODE_SCOPE: /* 2,3 */ case NODE_CDECL: case NODE_OPT_ARG: rb_node_release(node->u3.node); rb_node_release(node->u2.node); break; } // c--; // Some NODE structures are apparently reused somewhere in parserland. const int count = auto_zone_retain_count(__auto_zone, node); if (count > 0) { node->u1.node = node->u2.node = node->u3.node = NULL; GC_RELEASE(node); } }
static inline VALUE vm_call0(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid, int argc, const VALUE *argv, const NODE *body, int nosuper) { VALUE val; rb_block_t *blockptr = 0; if (0) printf("id: %s, nd: %s, argc: %d, passed: %p\n", rb_id2name(id), ruby_node_name(nd_type(body)), argc, (void *)th->passed_block); if (th->passed_block) { blockptr = th->passed_block; th->passed_block = 0; } again: switch (nd_type(body)) { case RUBY_VM_METHOD_NODE:{ rb_control_frame_t *reg_cfp; VALUE iseqval = (VALUE)body->nd_body; int i; rb_vm_set_finish_env(th); reg_cfp = th->cfp; CHECK_STACK_OVERFLOW(reg_cfp, argc + 1); *reg_cfp->sp++ = recv; for (i = 0; i < argc; i++) { *reg_cfp->sp++ = argv[i]; } vm_setup_method(th, reg_cfp, argc, blockptr, 0, iseqval, recv); val = vm_exec(th); break; } case NODE_CFUNC: { EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); { rb_control_frame_t *reg_cfp = th->cfp; rb_control_frame_t *cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1); cfp->method_id = oid; cfp->method_class = klass; val = call_cfunc(body->nd_cfnc, recv, body->nd_argc, argc, argv); if (reg_cfp != th->cfp + 1) { SDR2(reg_cfp); SDR2(th->cfp-5); rb_bug("cfp consistency error - call0"); th->cfp = reg_cfp; } vm_pop_frame(th); } EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass); break; } case NODE_ATTRSET:{ if (argc != 1) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); } val = rb_ivar_set(recv, body->nd_vid, argv[0]); break; } case NODE_IVAR: { if (argc != 0) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); } val = rb_attr_get(recv, body->nd_vid); break; } case NODE_BMETHOD:{ val = vm_call_bmethod(th, oid, body->nd_cval, recv, klass, argc, (VALUE *)argv, blockptr); break; } case NODE_ZSUPER:{ klass = RCLASS_SUPER(klass); if (!klass || !(body = rb_method_node(klass, id))) { return method_missing(recv, id, argc, argv, 0); } RUBY_VM_CHECK_INTS(); nosuper = CALL_SUPER; body = body->nd_body; goto again; } default: rb_bug("unsupported: vm_call0(%s)", ruby_node_name(nd_type(body))); } RUBY_VM_CHECK_INTS(); return val; }