|
Ruby 1.9.2p290(2011-07-09revision32553)
|
00001 /********************************************************************** 00002 00003 vm_insnhelper.c - instruction helper functions. 00004 00005 $Author: yugui $ 00006 00007 Copyright (C) 2007 Koichi Sasada 00008 00009 **********************************************************************/ 00010 00011 /* finish iseq array */ 00012 #include "insns.inc" 00013 #include <math.h> 00014 00015 /* control stack frame */ 00016 00017 #ifndef INLINE 00018 #define INLINE inline 00019 #endif 00020 00021 static rb_control_frame_t *vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_control_frame_t *cfp); 00022 00023 static inline rb_control_frame_t * 00024 vm_push_frame(rb_thread_t * th, const rb_iseq_t * iseq, 00025 VALUE type, VALUE self, VALUE specval, 00026 const VALUE *pc, VALUE *sp, VALUE *lfp, 00027 int local_size) 00028 { 00029 rb_control_frame_t * const cfp = th->cfp - 1; 00030 int i; 00031 00032 if ((void *)(sp + local_size) >= (void *)cfp) { 00033 rb_exc_raise(sysstack_error); 00034 } 00035 th->cfp = cfp; 00036 /* setup vm value stack */ 00037 00038 /* nil initialize */ 00039 for (i=0; i < local_size; i++) { 00040 *sp = Qnil; 00041 sp++; 00042 } 00043 00044 /* set special val */ 00045 *sp = GC_GUARDED_PTR(specval); 00046 00047 if (lfp == 0) { 00048 lfp = sp; 00049 } 00050 00051 /* setup vm control frame stack */ 00052 00053 cfp->pc = (VALUE *)pc; 00054 cfp->sp = sp + 1; 00055 cfp->bp = sp + 1; 00056 cfp->iseq = (rb_iseq_t *) iseq; 00057 cfp->flag = type; 00058 cfp->self = self; 00059 cfp->lfp = lfp; 00060 cfp->dfp = sp; 00061 cfp->block_iseq = 0; 00062 cfp->proc = 0; 00063 cfp->me = 0; 00064 00065 #define COLLECT_PROFILE 0 00066 #if COLLECT_PROFILE 00067 cfp->prof_time_self = clock(); 00068 cfp->prof_time_chld = 0; 00069 #endif 00070 00071 if (VMDEBUG == 2) { 00072 SDR(); 00073 } 00074 00075 return cfp; 00076 } 00077 00078 static inline void 00079 vm_pop_frame(rb_thread_t *th) 00080 { 00081 #if COLLECT_PROFILE 00082 rb_control_frame_t *cfp = th->cfp; 00083 00084 if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq)) { 00085 VALUE current_time = clock(); 00086 rb_control_frame_t *cfp = th->cfp; 00087 cfp->prof_time_self = current_time - cfp->prof_time_self; 00088 (cfp+1)->prof_time_chld += cfp->prof_time_self; 00089 00090 cfp->iseq->profile.count++; 00091 cfp->iseq->profile.time_cumu = cfp->prof_time_self; 00092 cfp->iseq->profile.time_self = cfp->prof_time_self - cfp->prof_time_chld; 00093 } 00094 else if (0 /* c method? */) { 00095 00096 } 00097 #endif 00098 th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); 00099 00100 if (VMDEBUG == 2) { 00101 SDR(); 00102 } 00103 } 00104 00105 /* method dispatch */ 00106 00107 NORETURN(static void argument_error(const rb_iseq_t *iseq, int miss_argc, int correct_argc)); 00108 static void 00109 argument_error(const rb_iseq_t *iseq, int miss_argc, int correct_argc) 00110 { 00111 VALUE mesg = rb_sprintf("wrong number of arguments (%d for %d)", miss_argc, correct_argc); 00112 VALUE exc = rb_exc_new3(rb_eArgError, mesg); 00113 VALUE bt = rb_make_backtrace(); 00114 VALUE err_line = 0; 00115 00116 if (iseq) { 00117 int line_no = 1; 00118 00119 if (iseq->insn_info_size) { 00120 line_no = iseq->insn_info_table[0].line_no; 00121 } 00122 00123 err_line = rb_sprintf("%s:%d:in `%s'", 00124 RSTRING_PTR(iseq->filename), 00125 line_no, RSTRING_PTR(iseq->name)); 00126 rb_funcall(bt, rb_intern("unshift"), 1, err_line); 00127 } 00128 00129 rb_funcall(exc, rb_intern("set_backtrace"), 1, bt); 00130 rb_exc_raise(exc); 00131 } 00132 00133 #define VM_CALLEE_SETUP_ARG(ret, th, iseq, orig_argc, orig_argv, block) \ 00134 if (LIKELY(iseq->arg_simple & 0x01)) { \ 00135 /* simple check */ \ 00136 if (orig_argc != iseq->argc) { \ 00137 argument_error(iseq, orig_argc, iseq->argc); \ 00138 } \ 00139 ret = 0; \ 00140 } \ 00141 else { \ 00142 ret = vm_callee_setup_arg_complex(th, iseq, orig_argc, orig_argv, block); \ 00143 } 00144 00145 static inline int 00146 vm_callee_setup_arg_complex(rb_thread_t *th, const rb_iseq_t * iseq, 00147 int orig_argc, VALUE * orig_argv, 00148 const rb_block_t **block) 00149 { 00150 const int m = iseq->argc; 00151 int argc = orig_argc; 00152 VALUE *argv = orig_argv; 00153 rb_num_t opt_pc = 0; 00154 00155 th->mark_stack_len = argc + iseq->arg_size; 00156 00157 /* mandatory */ 00158 if (argc < (m + iseq->arg_post_len)) { /* check with post arg */ 00159 argument_error(iseq, argc, m + iseq->arg_post_len); 00160 } 00161 00162 argv += m; 00163 argc -= m; 00164 00165 /* post arguments */ 00166 if (iseq->arg_post_len) { 00167 if (!(orig_argc < iseq->arg_post_start)) { 00168 VALUE *new_argv = ALLOCA_N(VALUE, argc); 00169 MEMCPY(new_argv, argv, VALUE, argc); 00170 argv = new_argv; 00171 } 00172 00173 MEMCPY(&orig_argv[iseq->arg_post_start], &argv[argc -= iseq->arg_post_len], 00174 VALUE, iseq->arg_post_len); 00175 } 00176 00177 /* opt arguments */ 00178 if (iseq->arg_opts) { 00179 const int opts = iseq->arg_opts - 1 /* no opt */; 00180 00181 if (iseq->arg_rest == -1 && argc > opts) { 00182 argument_error(iseq, orig_argc, m + opts + iseq->arg_post_len); 00183 } 00184 00185 if (argc > opts) { 00186 argc -= opts; 00187 argv += opts; 00188 opt_pc = iseq->arg_opt_table[opts]; /* no opt */ 00189 } 00190 else { 00191 int i; 00192 for (i = argc; i<opts; i++) { 00193 orig_argv[i + m] = Qnil; 00194 } 00195 opt_pc = iseq->arg_opt_table[argc]; 00196 argc = 0; 00197 } 00198 } 00199 00200 /* rest arguments */ 00201 if (iseq->arg_rest != -1) { 00202 orig_argv[iseq->arg_rest] = rb_ary_new4(argc, argv); 00203 argc = 0; 00204 } 00205 00206 /* block arguments */ 00207 if (block && iseq->arg_block != -1) { 00208 VALUE blockval = Qnil; 00209 const rb_block_t *blockptr = *block; 00210 00211 if (argc != 0) { 00212 argument_error(iseq, orig_argc, m + iseq->arg_post_len); 00213 } 00214 00215 if (blockptr) { 00216 /* make Proc object */ 00217 if (blockptr->proc == 0) { 00218 rb_proc_t *proc; 00219 blockval = rb_vm_make_proc(th, blockptr, rb_cProc); 00220 GetProcPtr(blockval, proc); 00221 *block = &proc->block; 00222 } 00223 else { 00224 blockval = blockptr->proc; 00225 } 00226 } 00227 00228 orig_argv[iseq->arg_block] = blockval; /* Proc or nil */ 00229 } 00230 00231 th->mark_stack_len = 0; 00232 return (int)opt_pc; 00233 } 00234 00235 static inline int 00236 caller_setup_args(const rb_thread_t *th, rb_control_frame_t *cfp, VALUE flag, 00237 int argc, rb_iseq_t *blockiseq, rb_block_t **block) 00238 { 00239 rb_block_t *blockptr = 0; 00240 00241 if (block) { 00242 if (flag & VM_CALL_ARGS_BLOCKARG_BIT) { 00243 rb_proc_t *po; 00244 VALUE proc; 00245 00246 proc = *(--cfp->sp); 00247 00248 if (proc != Qnil) { 00249 if (!rb_obj_is_proc(proc)) { 00250 VALUE b = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc"); 00251 if (NIL_P(b) || !rb_obj_is_proc(b)) { 00252 rb_raise(rb_eTypeError, 00253 "wrong argument type %s (expected Proc)", 00254 rb_obj_classname(proc)); 00255 } 00256 proc = b; 00257 } 00258 GetProcPtr(proc, po); 00259 blockptr = &po->block; 00260 RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp)->proc = proc; 00261 *block = blockptr; 00262 } 00263 } 00264 else if (blockiseq) { 00265 blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP(cfp); 00266 blockptr->iseq = blockiseq; 00267 blockptr->proc = 0; 00268 *block = blockptr; 00269 } 00270 } 00271 00272 /* expand top of stack? */ 00273 if (flag & VM_CALL_ARGS_SPLAT_BIT) { 00274 VALUE ary = *(cfp->sp - 1); 00275 VALUE *ptr; 00276 int i; 00277 VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_a"); 00278 00279 if (NIL_P(tmp)) { 00280 /* do nothing */ 00281 } 00282 else { 00283 long len = RARRAY_LEN(tmp); 00284 ptr = RARRAY_PTR(tmp); 00285 cfp->sp -= 1; 00286 00287 CHECK_STACK_OVERFLOW(cfp, len); 00288 00289 for (i = 0; i < len; i++) { 00290 *cfp->sp++ = ptr[i]; 00291 } 00292 argc += i-1; 00293 } 00294 } 00295 00296 return argc; 00297 } 00298 00299 static inline VALUE 00300 call_cfunc(VALUE (*func)(), VALUE recv, 00301 int len, int argc, const VALUE *argv) 00302 { 00303 /* printf("len: %d, argc: %d\n", len, argc); */ 00304 00305 if (len >= 0 && argc != len) { 00306 rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)", 00307 argc, len); 00308 } 00309 00310 switch (len) { 00311 case -2: 00312 return (*func) (recv, rb_ary_new4(argc, argv)); 00313 break; 00314 case -1: 00315 return (*func) (argc, argv, recv); 00316 break; 00317 case 0: 00318 return (*func) (recv); 00319 break; 00320 case 1: 00321 return (*func) (recv, argv[0]); 00322 break; 00323 case 2: 00324 return (*func) (recv, argv[0], argv[1]); 00325 break; 00326 case 3: 00327 return (*func) (recv, argv[0], argv[1], argv[2]); 00328 break; 00329 case 4: 00330 return (*func) (recv, argv[0], argv[1], argv[2], argv[3]); 00331 break; 00332 case 5: 00333 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4]); 00334 break; 00335 case 6: 00336 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], 00337 argv[5]); 00338 break; 00339 case 7: 00340 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], 00341 argv[5], argv[6]); 00342 break; 00343 case 8: 00344 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], 00345 argv[5], argv[6], argv[7]); 00346 break; 00347 case 9: 00348 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], 00349 argv[5], argv[6], argv[7], argv[8]); 00350 break; 00351 case 10: 00352 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], 00353 argv[5], argv[6], argv[7], argv[8], argv[9]); 00354 break; 00355 case 11: 00356 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], 00357 argv[5], argv[6], argv[7], argv[8], argv[9], 00358 argv[10]); 00359 break; 00360 case 12: 00361 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], 00362 argv[5], argv[6], argv[7], argv[8], argv[9], 00363 argv[10], argv[11]); 00364 break; 00365 case 13: 00366 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], 00367 argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], 00368 argv[11], argv[12]); 00369 break; 00370 case 14: 00371 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], 00372 argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], 00373 argv[11], argv[12], argv[13]); 00374 break; 00375 case 15: 00376 return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4], 00377 argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], 00378 argv[11], argv[12], argv[13], argv[14]); 00379 break; 00380 default: 00381 rb_raise(rb_eArgError, "too many arguments(%d)", len); 00382 return Qundef; /* not reached */ 00383 } 00384 } 00385 00386 static inline VALUE 00387 vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, 00388 int num, VALUE recv, const rb_block_t *blockptr, 00389 const rb_method_entry_t *me) 00390 { 00391 VALUE val = 0; 00392 const rb_method_definition_t *def = me->def; 00393 rb_control_frame_t *cfp; 00394 00395 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass); 00396 00397 cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, 00398 recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1); 00399 cfp->me = me; 00400 reg_cfp->sp -= num + 1; 00401 00402 val = call_cfunc(def->body.cfunc.func, recv, (int)def->body.cfunc.argc, num, reg_cfp->sp + 1); 00403 00404 if (reg_cfp != th->cfp + 1) { 00405 rb_bug("cfp consistency error - send"); 00406 } 00407 00408 vm_pop_frame(th); 00409 00410 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass); 00411 00412 return val; 00413 } 00414 00415 static inline VALUE 00416 vm_call_bmethod(rb_thread_t *th, VALUE recv, int argc, const VALUE *argv, 00417 const rb_block_t *blockptr, const rb_method_entry_t *me) 00418 { 00419 rb_proc_t *proc; 00420 VALUE val; 00421 00422 /* control block frame */ 00423 th->passed_me = me; 00424 00425 GetProcPtr(me->def->body.proc, proc); 00426 val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr); 00427 return val; 00428 } 00429 00430 static inline void 00431 vm_method_missing_args(rb_thread_t *th, VALUE *argv, 00432 int num, const rb_block_t *blockptr, int opt) 00433 { 00434 rb_control_frame_t * const reg_cfp = th->cfp; 00435 MEMCPY(argv, STACK_ADDR_FROM_TOP(num + 1), VALUE, num + 1); 00436 th->method_missing_reason = opt; 00437 th->passed_block = blockptr; 00438 POPN(num + 1); 00439 } 00440 00441 static inline VALUE 00442 vm_method_missing(rb_thread_t *th, ID id, VALUE recv, 00443 int num, const rb_block_t *blockptr, int opt) 00444 { 00445 VALUE *argv = ALLOCA_N(VALUE, num + 1); 00446 vm_method_missing_args(th, argv, num, blockptr, opt); 00447 argv[0] = ID2SYM(id); 00448 return rb_funcall2(recv, idMethodMissing, num + 1, argv); 00449 } 00450 00451 static inline void 00452 vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp, 00453 VALUE recv, int argc, const rb_block_t *blockptr, VALUE flag, 00454 const rb_method_entry_t *me) 00455 { 00456 int opt_pc, i; 00457 VALUE *sp, *rsp = cfp->sp - argc; 00458 rb_iseq_t *iseq = me->def->body.iseq; 00459 00460 VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, rsp, &blockptr); 00461 00462 /* stack overflow check */ 00463 CHECK_STACK_OVERFLOW(cfp, iseq->stack_max); 00464 00465 sp = rsp + iseq->arg_size; 00466 00467 if (LIKELY(!(flag & VM_CALL_TAILCALL_BIT))) { 00468 if (0) printf("local_size: %d, arg_size: %d\n", 00469 iseq->local_size, iseq->arg_size); 00470 00471 /* clear local variables */ 00472 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { 00473 *sp++ = Qnil; 00474 } 00475 00476 vm_push_frame(th, iseq, 00477 VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, 00478 iseq->iseq_encoded + opt_pc, sp, 0, 0); 00479 00480 cfp->sp = rsp - 1 /* recv */; 00481 } 00482 else { 00483 VALUE *p_rsp; 00484 th->cfp++; /* pop cf */ 00485 p_rsp = th->cfp->sp; 00486 00487 /* copy arguments */ 00488 for (i=0; i < (sp - rsp); i++) { 00489 p_rsp[i] = rsp[i]; 00490 } 00491 00492 sp -= rsp - p_rsp; 00493 00494 /* clear local variables */ 00495 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { 00496 *sp++ = Qnil; 00497 } 00498 00499 vm_push_frame(th, iseq, 00500 VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, 00501 iseq->iseq_encoded + opt_pc, sp, 0, 0); 00502 } 00503 } 00504 00505 static inline VALUE 00506 vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, 00507 int num, const rb_block_t *blockptr, VALUE flag, 00508 ID id, const rb_method_entry_t *me, VALUE recv) 00509 { 00510 VALUE val; 00511 00512 start_method_dispatch: 00513 00514 if (me != 0) { 00515 if ((me->flag == 0)) { 00516 normal_method_dispatch: 00517 switch (me->def->type) { 00518 case VM_METHOD_TYPE_ISEQ:{ 00519 vm_setup_method(th, cfp, recv, num, blockptr, flag, me); 00520 return Qundef; 00521 } 00522 case VM_METHOD_TYPE_NOTIMPLEMENTED: 00523 case VM_METHOD_TYPE_CFUNC:{ 00524 val = vm_call_cfunc(th, cfp, num, recv, blockptr, me); 00525 break; 00526 } 00527 case VM_METHOD_TYPE_ATTRSET:{ 00528 if (num != 1) { 00529 rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", num); 00530 } 00531 val = rb_ivar_set(recv, me->def->body.attr.id, *(cfp->sp - 1)); 00532 cfp->sp -= 2; 00533 break; 00534 } 00535 case VM_METHOD_TYPE_IVAR:{ 00536 if (num != 0) { 00537 rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", num); 00538 } 00539 val = rb_attr_get(recv, me->def->body.attr.id); 00540 cfp->sp -= 1; 00541 break; 00542 } 00543 case VM_METHOD_TYPE_MISSING:{ 00544 VALUE *argv = ALLOCA_N(VALUE, num+1); 00545 argv[0] = ID2SYM(me->def->original_id); 00546 MEMCPY(argv+1, cfp->sp - num, VALUE, num); 00547 cfp->sp += - num - 1; 00548 val = rb_funcall2(recv, rb_intern("method_missing"), num+1, argv); 00549 break; 00550 } 00551 case VM_METHOD_TYPE_BMETHOD:{ 00552 VALUE *argv = ALLOCA_N(VALUE, num); 00553 MEMCPY(argv, cfp->sp - num, VALUE, num); 00554 cfp->sp += - num - 1; 00555 val = vm_call_bmethod(th, recv, num, argv, blockptr, me); 00556 break; 00557 } 00558 case VM_METHOD_TYPE_ZSUPER:{ 00559 VALUE klass = RCLASS_SUPER(me->klass); 00560 me = rb_method_entry(klass, id); 00561 00562 if (me != 0) { 00563 goto normal_method_dispatch; 00564 } 00565 else { 00566 goto start_method_dispatch; 00567 } 00568 } 00569 case VM_METHOD_TYPE_OPTIMIZED:{ 00570 switch (me->def->body.optimize_type) { 00571 case OPTIMIZED_METHOD_TYPE_SEND: { 00572 rb_control_frame_t *reg_cfp = cfp; 00573 rb_num_t i = num - 1; 00574 VALUE sym; 00575 00576 if (num == 0) { 00577 rb_raise(rb_eArgError, "no method name given"); 00578 } 00579 00580 sym = TOPN(i); 00581 id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym); 00582 /* shift arguments */ 00583 if (i > 0) { 00584 MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i); 00585 } 00586 me = rb_method_entry(CLASS_OF(recv), id); 00587 num -= 1; 00588 DEC_SP(1); 00589 flag |= VM_CALL_FCALL_BIT | VM_CALL_OPT_SEND_BIT; 00590 00591 goto start_method_dispatch; 00592 } 00593 case OPTIMIZED_METHOD_TYPE_CALL: { 00594 rb_proc_t *proc; 00595 int argc = num; 00596 VALUE *argv = ALLOCA_N(VALUE, num); 00597 GetProcPtr(recv, proc); 00598 MEMCPY(argv, cfp->sp - num, VALUE, num); 00599 cfp->sp -= num + 1; 00600 00601 val = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, blockptr); 00602 break; 00603 } 00604 default: 00605 rb_bug("eval_invoke_method: unsupported optimized method type (%d)", 00606 me->def->body.optimize_type); 00607 } 00608 break; 00609 } 00610 default:{ 00611 rb_bug("eval_invoke_method: unsupported method type (%d)", me->def->type); 00612 break; 00613 } 00614 } 00615 } 00616 else { 00617 int noex_safe; 00618 00619 if (!(flag & VM_CALL_FCALL_BIT) && 00620 (me->flag & NOEX_MASK) & NOEX_PRIVATE) { 00621 int stat = NOEX_PRIVATE; 00622 00623 if (flag & VM_CALL_VCALL_BIT) { 00624 stat |= NOEX_VCALL; 00625 } 00626 val = vm_method_missing(th, id, recv, num, blockptr, stat); 00627 } 00628 else if (!(flag & VM_CALL_OPT_SEND_BIT) && (me->flag & NOEX_MASK) & NOEX_PROTECTED) { 00629 VALUE defined_class = me->klass; 00630 00631 if (TYPE(defined_class) == T_ICLASS) { 00632 defined_class = RBASIC(defined_class)->klass; 00633 } 00634 00635 if (!rb_obj_is_kind_of(cfp->self, defined_class)) { 00636 val = vm_method_missing(th, id, recv, num, blockptr, NOEX_PROTECTED); 00637 } 00638 else { 00639 goto normal_method_dispatch; 00640 } 00641 } 00642 else if ((noex_safe = NOEX_SAFE(me->flag)) > th->safe_level && 00643 (noex_safe > 2)) { 00644 rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(id)); 00645 } 00646 else { 00647 goto normal_method_dispatch; 00648 } 00649 } 00650 } 00651 else { 00652 /* method missing */ 00653 int stat = 0; 00654 if (flag & VM_CALL_VCALL_BIT) { 00655 stat |= NOEX_VCALL; 00656 } 00657 if (flag & VM_CALL_SUPER_BIT) { 00658 stat |= NOEX_SUPER; 00659 } 00660 if (id == idMethodMissing) { 00661 VALUE *argv = ALLOCA_N(VALUE, num); 00662 vm_method_missing_args(th, argv, num - 1, 0, stat); 00663 rb_raise_method_missing(th, num, argv, recv, stat); 00664 } 00665 else { 00666 val = vm_method_missing(th, id, recv, num, blockptr, stat); 00667 } 00668 } 00669 00670 RUBY_VM_CHECK_INTS(); 00671 return val; 00672 } 00673 00674 /* yield */ 00675 00676 static inline int 00677 block_proc_is_lambda(const VALUE procval) 00678 { 00679 rb_proc_t *proc; 00680 00681 if (procval) { 00682 GetProcPtr(procval, proc); 00683 return proc->is_lambda; 00684 } 00685 else { 00686 return 0; 00687 } 00688 } 00689 00690 static inline VALUE 00691 vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, 00692 VALUE self, int argc, const VALUE *argv, 00693 const rb_block_t *blockargptr) 00694 { 00695 NODE *ifunc = (NODE *) block->iseq; 00696 VALUE val, arg, blockarg; 00697 int lambda = block_proc_is_lambda(block->proc); 00698 00699 if (lambda) { 00700 arg = rb_ary_new4(argc, argv); 00701 } 00702 else if (argc == 0) { 00703 arg = Qnil; 00704 } 00705 else { 00706 arg = argv[0]; 00707 } 00708 00709 if (blockargptr) { 00710 if (blockargptr->proc) { 00711 blockarg = blockargptr->proc; 00712 } 00713 else { 00714 blockarg = rb_vm_make_proc(th, blockargptr, rb_cProc); 00715 } 00716 } 00717 else { 00718 blockarg = Qnil; 00719 } 00720 00721 vm_push_frame(th, 0, VM_FRAME_MAGIC_IFUNC, 00722 self, (VALUE)block->dfp, 00723 0, th->cfp->sp, block->lfp, 1); 00724 00725 if (blockargptr) { 00726 th->cfp->lfp[0] = GC_GUARDED_PTR((VALUE)blockargptr); 00727 } 00728 val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg); 00729 00730 th->cfp++; 00731 return val; 00732 } 00733 00734 00735 /*-- 00736 * @brief on supplied all of optional, rest and post parameters. 00737 * @pre iseq is block style (not lambda style) 00738 */ 00739 static inline int 00740 vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t *iseq, 00741 int argc, VALUE *argv) 00742 { 00743 rb_num_t opt_pc = 0; 00744 int i; 00745 const int m = iseq->argc; 00746 const int r = iseq->arg_rest; 00747 int len = iseq->arg_post_len; 00748 int start = iseq->arg_post_start; 00749 int rsize = argc > m ? argc - m : 0; /* # of arguments which did not consumed yet */ 00750 int psize = rsize > len ? len : rsize; /* # of post arguments */ 00751 int osize = 0; /* # of opt arguments */ 00752 VALUE ary; 00753 00754 /* reserves arguments for post parameters */ 00755 rsize -= psize; 00756 00757 if (iseq->arg_opts) { 00758 const int opts = iseq->arg_opts - 1; 00759 if (rsize > opts) { 00760 osize = opts; 00761 opt_pc = iseq->arg_opt_table[opts]; 00762 } 00763 else { 00764 osize = rsize; 00765 opt_pc = iseq->arg_opt_table[rsize]; 00766 } 00767 } 00768 rsize -= osize; 00769 00770 if (0) { 00771 printf(" argc: %d\n", argc); 00772 printf(" len: %d\n", len); 00773 printf("start: %d\n", start); 00774 printf("rsize: %d\n", rsize); 00775 } 00776 00777 if (r == -1) { 00778 /* copy post argument */ 00779 MEMMOVE(&argv[start], &argv[m+osize], VALUE, psize); 00780 } 00781 else { 00782 ary = rb_ary_new4(rsize, &argv[r]); 00783 00784 /* copy post argument */ 00785 MEMMOVE(&argv[start], &argv[m+rsize+osize], VALUE, psize); 00786 argv[r] = ary; 00787 } 00788 00789 for (i=psize; i<len; i++) { 00790 argv[start + i] = Qnil; 00791 } 00792 00793 return (int)opt_pc; 00794 } 00795 00796 static inline int 00797 vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq, 00798 int orig_argc, VALUE *argv, 00799 const rb_block_t *blockptr) 00800 { 00801 int i; 00802 int argc = orig_argc; 00803 const int m = iseq->argc; 00804 VALUE ary, arg0; 00805 int opt_pc = 0; 00806 00807 th->mark_stack_len = argc; 00808 00809 /* 00810 * yield [1, 2] 00811 * => {|a|} => a = [1, 2] 00812 * => {|a, b|} => a, b = [1, 2] 00813 */ 00814 arg0 = argv[0]; 00815 if (!(iseq->arg_simple & 0x02) && /* exclude {|a|} */ 00816 (m + iseq->arg_post_len) > 0 && /* this process is meaningful */ 00817 argc == 1 && !NIL_P(ary = rb_check_array_type(arg0))) { /* rhs is only an array */ 00818 th->mark_stack_len = argc = RARRAY_LENINT(ary); 00819 00820 CHECK_STACK_OVERFLOW(th->cfp, argc); 00821 00822 MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc); 00823 } 00824 else { 00825 argv[0] = arg0; 00826 } 00827 00828 for (i=argc; i<m; i++) { 00829 argv[i] = Qnil; 00830 } 00831 00832 if (iseq->arg_rest == -1 && iseq->arg_opts == 0) { 00833 const int arg_size = iseq->arg_size; 00834 if (arg_size < argc) { 00835 /* 00836 * yield 1, 2 00837 * => {|a|} # truncate 00838 */ 00839 th->mark_stack_len = argc = arg_size; 00840 } 00841 } 00842 else { 00843 int r = iseq->arg_rest; 00844 00845 if (iseq->arg_post_len || 00846 iseq->arg_opts) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */ 00847 opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv); 00848 } 00849 else { 00850 if (argc < r) { 00851 /* yield 1 00852 * => {|a, b, *r|} 00853 */ 00854 for (i=argc; i<r; i++) { 00855 argv[i] = Qnil; 00856 } 00857 argv[r] = rb_ary_new(); 00858 } 00859 else { 00860 argv[r] = rb_ary_new4(argc-r, &argv[r]); 00861 } 00862 } 00863 00864 th->mark_stack_len = iseq->arg_size; 00865 } 00866 00867 /* {|&b|} */ 00868 if (iseq->arg_block != -1) { 00869 VALUE procval = Qnil; 00870 00871 if (blockptr) { 00872 if (blockptr->proc == 0) { 00873 procval = rb_vm_make_proc(th, blockptr, rb_cProc); 00874 } 00875 else { 00876 procval = blockptr->proc; 00877 } 00878 } 00879 00880 argv[iseq->arg_block] = procval; 00881 } 00882 00883 th->mark_stack_len = 0; 00884 return opt_pc; 00885 } 00886 00887 static inline int 00888 vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq, 00889 int argc, VALUE *argv, 00890 const rb_block_t *blockptr, int lambda) 00891 { 00892 if (0) { /* for debug */ 00893 printf(" argc: %d\n", argc); 00894 printf("iseq argc: %d\n", iseq->argc); 00895 printf("iseq opts: %d\n", iseq->arg_opts); 00896 printf("iseq rest: %d\n", iseq->arg_rest); 00897 printf("iseq post: %d\n", iseq->arg_post_len); 00898 printf("iseq blck: %d\n", iseq->arg_block); 00899 printf("iseq smpl: %d\n", iseq->arg_simple); 00900 printf(" lambda: %s\n", lambda ? "true" : "false"); 00901 } 00902 00903 if (lambda) { 00904 /* call as method */ 00905 int opt_pc; 00906 VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, argv, &blockptr); 00907 return opt_pc; 00908 } 00909 else { 00910 return vm_yield_setup_block_args(th, iseq, argc, argv, blockptr); 00911 } 00912 } 00913 00914 static VALUE 00915 vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_num_t flag) 00916 { 00917 const rb_block_t *block = GET_BLOCK_PTR(); 00918 rb_iseq_t *iseq; 00919 int argc = (int)num; 00920 VALUE type = GET_ISEQ()->local_iseq->type; 00921 00922 if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) { 00923 rb_vm_localjump_error("no block given (yield)", Qnil, 0); 00924 } 00925 iseq = block->iseq; 00926 00927 argc = caller_setup_args(th, GET_CFP(), flag, argc, 0, 0); 00928 00929 if (BUILTIN_TYPE(iseq) != T_NODE) { 00930 int opt_pc; 00931 const int arg_size = iseq->arg_size; 00932 VALUE * const rsp = GET_SP() - argc; 00933 SET_SP(rsp); 00934 00935 CHECK_STACK_OVERFLOW(GET_CFP(), iseq->stack_max); 00936 opt_pc = vm_yield_setup_args(th, iseq, argc, rsp, 0, 00937 block_proc_is_lambda(block->proc)); 00938 00939 vm_push_frame(th, iseq, 00940 VM_FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp, 00941 iseq->iseq_encoded + opt_pc, rsp + arg_size, block->lfp, 00942 iseq->local_size - arg_size); 00943 00944 return Qundef; 00945 } 00946 else { 00947 VALUE val = vm_yield_with_cfunc(th, block, block->self, argc, STACK_ADDR_FROM_TOP(argc), 0); 00948 POPN(argc); /* TODO: should put before C/yield? */ 00949 return val; 00950 } 00951 } 00952 00953 /* svar */ 00954 00955 static inline NODE * 00956 lfp_svar_place(rb_thread_t *th, VALUE *lfp) 00957 { 00958 VALUE *svar; 00959 00960 if (lfp && th->local_lfp != lfp) { 00961 svar = &lfp[-1]; 00962 } 00963 else { 00964 svar = &th->local_svar; 00965 } 00966 if (NIL_P(*svar)) { 00967 *svar = (VALUE)NEW_IF(Qnil, Qnil, Qnil); 00968 } 00969 return (NODE *)*svar; 00970 } 00971 00972 static VALUE 00973 lfp_svar_get(rb_thread_t *th, VALUE *lfp, VALUE key) 00974 { 00975 NODE *svar = lfp_svar_place(th, lfp); 00976 00977 switch (key) { 00978 case 0: 00979 return svar->u1.value; 00980 case 1: 00981 return svar->u2.value; 00982 default: { 00983 const VALUE hash = svar->u3.value; 00984 00985 if (hash == Qnil) { 00986 return Qnil; 00987 } 00988 else { 00989 return rb_hash_lookup(hash, key); 00990 } 00991 } 00992 } 00993 } 00994 00995 static void 00996 lfp_svar_set(rb_thread_t *th, VALUE *lfp, VALUE key, VALUE val) 00997 { 00998 NODE *svar = lfp_svar_place(th, lfp); 00999 01000 switch (key) { 01001 case 0: 01002 svar->u1.value = val; 01003 return; 01004 case 1: 01005 svar->u2.value = val; 01006 return; 01007 default: { 01008 VALUE hash = svar->u3.value; 01009 01010 if (hash == Qnil) { 01011 svar->u3.value = hash = rb_hash_new(); 01012 } 01013 rb_hash_aset(hash, key, val); 01014 } 01015 } 01016 } 01017 01018 static inline VALUE 01019 vm_getspecial(rb_thread_t *th, VALUE *lfp, VALUE key, rb_num_t type) 01020 { 01021 VALUE val; 01022 01023 if (type == 0) { 01024 VALUE k = key; 01025 if (FIXNUM_P(key)) { 01026 k = FIX2INT(key); 01027 } 01028 val = lfp_svar_get(th, lfp, k); 01029 } 01030 else { 01031 VALUE backref = lfp_svar_get(th, lfp, 1); 01032 01033 if (type & 0x01) { 01034 switch (type >> 1) { 01035 case '&': 01036 val = rb_reg_last_match(backref); 01037 break; 01038 case '`': 01039 val = rb_reg_match_pre(backref); 01040 break; 01041 case '\'': 01042 val = rb_reg_match_post(backref); 01043 break; 01044 case '+': 01045 val = rb_reg_match_last(backref); 01046 break; 01047 default: 01048 rb_bug("unexpected back-ref"); 01049 } 01050 } 01051 else { 01052 val = rb_reg_nth_match((int)(type >> 1), backref); 01053 } 01054 } 01055 return val; 01056 } 01057 01058 static NODE * 01059 vm_get_cref0(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp) 01060 { 01061 while (1) { 01062 if (lfp == dfp) { 01063 return iseq->cref_stack; 01064 } 01065 else if (dfp[-1] != Qnil) { 01066 return (NODE *)dfp[-1]; 01067 } 01068 dfp = GET_PREV_DFP(dfp); 01069 } 01070 } 01071 01072 static NODE * 01073 vm_get_cref(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp) 01074 { 01075 NODE *cref = vm_get_cref0(iseq, lfp, dfp); 01076 01077 if (cref == 0) { 01078 rb_bug("vm_get_cref: unreachable"); 01079 } 01080 return cref; 01081 } 01082 01083 static NODE * 01084 vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr) 01085 { 01086 rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp); 01087 NODE *cref = NEW_BLOCK(klass); 01088 cref->nd_file = 0; 01089 cref->nd_visi = noex; 01090 01091 if (blockptr) { 01092 cref->nd_next = vm_get_cref0(blockptr->iseq, blockptr->lfp, blockptr->dfp); 01093 } 01094 else if (cfp) { 01095 cref->nd_next = vm_get_cref0(cfp->iseq, cfp->lfp, cfp->dfp); 01096 } 01097 01098 return cref; 01099 } 01100 01101 static inline VALUE 01102 vm_get_cbase(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp) 01103 { 01104 NODE *cref = vm_get_cref(iseq, lfp, dfp); 01105 VALUE klass = Qundef; 01106 01107 while (cref) { 01108 if ((klass = cref->nd_clss) != 0) { 01109 break; 01110 } 01111 cref = cref->nd_next; 01112 } 01113 01114 return klass; 01115 } 01116 01117 static inline VALUE 01118 vm_get_const_base(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp) 01119 { 01120 NODE *cref = vm_get_cref(iseq, lfp, dfp); 01121 VALUE klass = Qundef; 01122 01123 while (cref) { 01124 if (!(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) && 01125 (klass = cref->nd_clss) != 0) { 01126 break; 01127 } 01128 cref = cref->nd_next; 01129 } 01130 01131 return klass; 01132 } 01133 01134 static inline void 01135 vm_check_if_namespace(VALUE klass) 01136 { 01137 VALUE str; 01138 switch (TYPE(klass)) { 01139 case T_CLASS: 01140 case T_MODULE: 01141 break; 01142 default: 01143 str = rb_inspect(klass); 01144 rb_raise(rb_eTypeError, "%s is not a class/module", 01145 StringValuePtr(str)); 01146 } 01147 } 01148 01149 static inline VALUE 01150 vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq, 01151 VALUE orig_klass, ID id, int is_defined) 01152 { 01153 VALUE val; 01154 01155 if (orig_klass == Qnil) { 01156 /* in current lexical scope */ 01157 const NODE *cref = vm_get_cref(iseq, th->cfp->lfp, th->cfp->dfp); 01158 const NODE *root_cref = NULL; 01159 VALUE klass = orig_klass; 01160 01161 while (cref && cref->nd_next) { 01162 if (!(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL)) { 01163 klass = cref->nd_clss; 01164 if (root_cref == NULL) 01165 root_cref = cref; 01166 } 01167 cref = cref->nd_next; 01168 01169 if (!NIL_P(klass)) { 01170 VALUE am = 0; 01171 search_continue: 01172 if (RCLASS_IV_TBL(klass) && 01173 st_lookup(RCLASS_IV_TBL(klass), id, &val)) { 01174 if (val == Qundef) { 01175 if (am == klass) break; 01176 am = klass; 01177 rb_autoload_load(klass, id); 01178 goto search_continue; 01179 } 01180 else { 01181 if (is_defined) { 01182 return 1; 01183 } 01184 else { 01185 return val; 01186 } 01187 } 01188 } 01189 } 01190 } 01191 01192 /* search self */ 01193 if (root_cref && !NIL_P(root_cref->nd_clss)) { 01194 klass = root_cref->nd_clss; 01195 } 01196 else { 01197 klass = CLASS_OF(th->cfp->self); 01198 } 01199 01200 if (is_defined) { 01201 return rb_const_defined(klass, id); 01202 } 01203 else { 01204 return rb_const_get(klass, id); 01205 } 01206 } 01207 else { 01208 vm_check_if_namespace(orig_klass); 01209 if (is_defined) { 01210 return rb_const_defined_from(orig_klass, id); 01211 } 01212 else { 01213 return rb_const_get_from(orig_klass, id); 01214 } 01215 } 01216 } 01217 01218 static inline VALUE 01219 vm_get_cvar_base(NODE *cref) 01220 { 01221 VALUE klass; 01222 01223 while (cref && cref->nd_next && 01224 (NIL_P(cref->nd_clss) || FL_TEST(cref->nd_clss, FL_SINGLETON) || 01225 (cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL))) { 01226 cref = cref->nd_next; 01227 01228 if (!cref->nd_next) { 01229 rb_warn("class variable access from toplevel"); 01230 } 01231 } 01232 01233 klass = cref->nd_clss; 01234 01235 if (NIL_P(klass)) { 01236 rb_raise(rb_eTypeError, "no class variables available"); 01237 } 01238 return klass; 01239 } 01240 01241 01242 #ifndef USE_IC_FOR_IVAR 01243 #define USE_IC_FOR_IVAR 1 01244 #endif 01245 01246 static VALUE 01247 vm_getivar(VALUE obj, ID id, IC ic) 01248 { 01249 #if USE_IC_FOR_IVAR 01250 if (TYPE(obj) == T_OBJECT) { 01251 VALUE val = Qundef; 01252 VALUE klass = RBASIC(obj)->klass; 01253 01254 if (ic->ic_class == klass) { 01255 long index = ic->ic_value.index; 01256 long len = ROBJECT_NUMIV(obj); 01257 VALUE *ptr = ROBJECT_IVPTR(obj); 01258 01259 if (index < len) { 01260 val = ptr[index]; 01261 } 01262 } 01263 else { 01264 st_data_t index; 01265 long len = ROBJECT_NUMIV(obj); 01266 VALUE *ptr = ROBJECT_IVPTR(obj); 01267 struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); 01268 01269 if (iv_index_tbl) { 01270 if (st_lookup(iv_index_tbl, id, &index)) { 01271 if ((long)index < len) { 01272 val = ptr[index]; 01273 } 01274 ic->ic_class = klass; 01275 ic->ic_value.index = index; 01276 } 01277 } 01278 } 01279 if (UNLIKELY(val == Qundef)) { 01280 rb_warning("instance variable %s not initialized", rb_id2name(id)); 01281 val = Qnil; 01282 } 01283 return val; 01284 } 01285 else { 01286 return rb_ivar_get(obj, id); 01287 } 01288 #else 01289 return rb_ivar_get(obj, id); 01290 #endif 01291 } 01292 01293 static void 01294 vm_setivar(VALUE obj, ID id, VALUE val, IC ic) 01295 { 01296 #if USE_IC_FOR_IVAR 01297 if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) { 01298 rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); 01299 } 01300 if (OBJ_FROZEN(obj)) { 01301 rb_error_frozen("object"); 01302 } 01303 01304 if (TYPE(obj) == T_OBJECT) { 01305 VALUE klass = RBASIC(obj)->klass; 01306 st_data_t index; 01307 01308 if (ic->ic_class == klass) { 01309 long index = ic->ic_value.index; 01310 long len = ROBJECT_NUMIV(obj); 01311 VALUE *ptr = ROBJECT_IVPTR(obj); 01312 01313 if (index < len) { 01314 ptr[index] = val; 01315 return; /* inline cache hit */ 01316 } 01317 } 01318 else { 01319 struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); 01320 01321 if (iv_index_tbl && st_lookup(iv_index_tbl, (st_data_t)id, &index)) { 01322 ic->ic_class = klass; 01323 ic->ic_value.index = index; 01324 } 01325 /* fall through */ 01326 } 01327 } 01328 rb_ivar_set(obj, id, val); 01329 #else 01330 rb_ivar_set(obj, id, val); 01331 #endif 01332 } 01333 01334 static inline const rb_method_entry_t * 01335 vm_method_search(VALUE id, VALUE klass, IC ic) 01336 { 01337 rb_method_entry_t *me; 01338 #if OPT_INLINE_METHOD_CACHE 01339 if (LIKELY(klass == ic->ic_class) && 01340 LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) { 01341 me = ic->ic_value.method; 01342 } 01343 else { 01344 me = rb_method_entry(klass, id); 01345 ic->ic_class = klass; 01346 ic->ic_value.method = me; 01347 ic->ic_vmstat = GET_VM_STATE_VERSION(); 01348 } 01349 #else 01350 me = rb_method_entry(klass, id); 01351 #endif 01352 return me; 01353 } 01354 01355 static inline VALUE 01356 vm_search_normal_superclass(VALUE klass, VALUE recv) 01357 { 01358 if (BUILTIN_TYPE(klass) == T_CLASS) { 01359 return RCLASS_SUPER(klass); 01360 } 01361 else if (BUILTIN_TYPE(klass) == T_MODULE) { 01362 VALUE k = CLASS_OF(recv); 01363 while (k) { 01364 if (BUILTIN_TYPE(k) == T_ICLASS && RBASIC(k)->klass == klass) { 01365 return RCLASS_SUPER(k); 01366 } 01367 k = RCLASS_SUPER(k); 01368 } 01369 return rb_cObject; 01370 } 01371 else { 01372 rb_bug("vm_search_normal_superclass: should not be reach here"); 01373 } 01374 } 01375 01376 static void 01377 vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *ip, 01378 VALUE recv, VALUE sigval, 01379 ID *idp, VALUE *klassp) 01380 { 01381 ID id; 01382 VALUE klass; 01383 01384 while (ip && !ip->klass) { 01385 ip = ip->parent_iseq; 01386 } 01387 01388 if (ip == 0) { 01389 rb_raise(rb_eNoMethodError, "super called outside of method"); 01390 } 01391 01392 id = ip->defined_method_id; 01393 01394 if (ip != ip->local_iseq) { 01395 /* defined by Module#define_method() */ 01396 rb_control_frame_t *lcfp = GET_CFP(); 01397 01398 if (!sigval) { 01399 /* zsuper */ 01400 rb_raise(rb_eRuntimeError, "implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly."); 01401 } 01402 01403 while (lcfp->iseq != ip) { 01404 VALUE *tdfp = GET_PREV_DFP(lcfp->dfp); 01405 while (1) { 01406 lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp); 01407 if (lcfp->dfp == tdfp) { 01408 break; 01409 } 01410 } 01411 } 01412 01413 /* temporary measure for [Bug #2420] [Bug #3136] */ 01414 if (!lcfp->me) { 01415 rb_raise(rb_eNoMethodError, "super called outside of method"); 01416 } 01417 01418 id = lcfp->me->def->original_id; 01419 klass = vm_search_normal_superclass(lcfp->me->klass, recv); 01420 } 01421 else { 01422 klass = vm_search_normal_superclass(ip->klass, recv); 01423 } 01424 01425 *idp = id; 01426 *klassp = klass; 01427 } 01428 01429 static VALUE 01430 vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp, 01431 rb_num_t throw_state, VALUE throwobj) 01432 { 01433 int state = (int)(throw_state & 0xff); 01434 int flag = (int)(throw_state & 0x8000); 01435 rb_num_t level = throw_state >> 16; 01436 01437 if (state != 0) { 01438 VALUE *pt = 0; 01439 if (flag != 0) { 01440 pt = (void *) 1; 01441 } 01442 else { 01443 if (state == TAG_BREAK) { 01444 rb_control_frame_t *cfp = GET_CFP(); 01445 VALUE *dfp = GET_DFP(); 01446 int is_orphan = 1; 01447 rb_iseq_t *base_iseq = GET_ISEQ(); 01448 01449 search_parent: 01450 if (cfp->iseq->type != ISEQ_TYPE_BLOCK) { 01451 if (cfp->iseq->type == ISEQ_TYPE_CLASS) { 01452 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 01453 dfp = cfp->dfp; 01454 goto search_parent; 01455 } 01456 dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp); 01457 base_iseq = base_iseq->parent_iseq; 01458 01459 while ((VALUE *) cfp < th->stack + th->stack_size) { 01460 if (cfp->dfp == dfp) { 01461 goto search_parent; 01462 } 01463 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 01464 } 01465 rb_bug("VM (throw): can't find break base."); 01466 } 01467 01468 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) { 01469 /* lambda{... break ...} */ 01470 is_orphan = 0; 01471 pt = cfp->dfp; 01472 state = TAG_RETURN; 01473 } 01474 else { 01475 dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp); 01476 01477 while ((VALUE *)cfp < th->stack + th->stack_size) { 01478 if (cfp->dfp == dfp) { 01479 VALUE epc = cfp->pc - cfp->iseq->iseq_encoded; 01480 rb_iseq_t *iseq = cfp->iseq; 01481 int i; 01482 01483 for (i=0; i<iseq->catch_table_size; i++) { 01484 struct iseq_catch_table_entry *entry = &iseq->catch_table[i]; 01485 01486 if (entry->type == CATCH_TYPE_BREAK && 01487 entry->start < epc && entry->end >= epc) { 01488 if (entry->cont == epc) { 01489 goto found; 01490 } 01491 else { 01492 break; 01493 } 01494 } 01495 } 01496 break; 01497 01498 found: 01499 pt = dfp; 01500 is_orphan = 0; 01501 break; 01502 } 01503 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 01504 } 01505 } 01506 01507 if (is_orphan) { 01508 rb_vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK); 01509 } 01510 } 01511 else if (state == TAG_RETRY) { 01512 rb_num_t i; 01513 pt = GC_GUARDED_PTR_REF((VALUE *) * GET_DFP()); 01514 for (i = 0; i < level; i++) { 01515 pt = GC_GUARDED_PTR_REF((VALUE *) * pt); 01516 } 01517 } 01518 else if (state == TAG_RETURN) { 01519 rb_control_frame_t *cfp = GET_CFP(); 01520 VALUE *dfp = GET_DFP(); 01521 VALUE *lfp = GET_LFP(); 01522 01523 /* check orphan and get dfp */ 01524 while ((VALUE *) cfp < th->stack + th->stack_size) { 01525 if (!lfp) { 01526 lfp = cfp->lfp; 01527 } 01528 if (cfp->dfp == lfp && cfp->iseq->type == ISEQ_TYPE_CLASS) { 01529 lfp = 0; 01530 } 01531 01532 if (cfp->lfp == lfp) { 01533 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) { 01534 VALUE *tdfp = dfp; 01535 01536 while (lfp != tdfp) { 01537 if (cfp->dfp == tdfp) { 01538 /* in lambda */ 01539 dfp = cfp->dfp; 01540 goto valid_return; 01541 } 01542 tdfp = GC_GUARDED_PTR_REF((VALUE *)*tdfp); 01543 } 01544 } 01545 } 01546 01547 if (cfp->dfp == lfp && cfp->iseq->type == ISEQ_TYPE_METHOD) { 01548 dfp = lfp; 01549 goto valid_return; 01550 } 01551 01552 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 01553 } 01554 01555 rb_vm_localjump_error("unexpected return", throwobj, TAG_RETURN); 01556 01557 valid_return: 01558 pt = dfp; 01559 } 01560 else { 01561 rb_bug("isns(throw): unsupport throw type"); 01562 } 01563 } 01564 th->state = state; 01565 return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE) pt, state); 01566 } 01567 else { 01568 /* continue throw */ 01569 VALUE err = throwobj; 01570 01571 if (FIXNUM_P(err)) { 01572 th->state = FIX2INT(err); 01573 } 01574 else if (SYMBOL_P(err)) { 01575 th->state = TAG_THROW; 01576 } 01577 else if (BUILTIN_TYPE(err) == T_NODE) { 01578 th->state = GET_THROWOBJ_STATE(err); 01579 } 01580 else { 01581 th->state = TAG_RAISE; 01582 /*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/ 01583 } 01584 return err; 01585 } 01586 } 01587 01588 static inline void 01589 vm_expandarray(rb_control_frame_t *cfp, VALUE ary, rb_num_t num, int flag) 01590 { 01591 int is_splat = flag & 0x01; 01592 rb_num_t space_size = num + is_splat; 01593 VALUE *base = cfp->sp, *ptr; 01594 volatile VALUE tmp_ary; 01595 rb_num_t len; 01596 01597 if (TYPE(ary) != T_ARRAY) { 01598 ary = rb_ary_to_ary(ary); 01599 } 01600 01601 cfp->sp += space_size; 01602 01603 tmp_ary = ary; 01604 ptr = RARRAY_PTR(ary); 01605 len = (rb_num_t)RARRAY_LEN(ary); 01606 01607 if (flag & 0x02) { 01608 /* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */ 01609 rb_num_t i = 0, j; 01610 01611 if (len < num) { 01612 for (i=0; i<num-len; i++) { 01613 *base++ = Qnil; 01614 } 01615 } 01616 for (j=0; i<num; i++, j++) { 01617 VALUE v = ptr[len - j - 1]; 01618 *base++ = v; 01619 } 01620 if (is_splat) { 01621 *base = rb_ary_new4(len - j, ptr); 01622 } 01623 } 01624 else { 01625 /* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */ 01626 rb_num_t i; 01627 VALUE *bptr = &base[space_size - 1]; 01628 01629 for (i=0; i<num; i++) { 01630 if (len <= i) { 01631 for (; i<num; i++) { 01632 *bptr-- = Qnil; 01633 } 01634 break; 01635 } 01636 *bptr-- = ptr[i]; 01637 } 01638 if (is_splat) { 01639 if (num > len) { 01640 *bptr = rb_ary_new(); 01641 } 01642 else { 01643 *bptr = rb_ary_new4(len - num, ptr + num); 01644 } 01645 } 01646 } 01647 } 01648 01649 static inline int 01650 check_cfunc(const rb_method_entry_t *me, VALUE (*func)()) 01651 { 01652 if (me && me->def->type == VM_METHOD_TYPE_CFUNC && 01653 me->def->body.cfunc.func == func) { 01654 return 1; 01655 } 01656 else { 01657 return 0; 01658 } 01659 } 01660 01661 static 01662 #ifndef NO_BIG_INLINE 01663 inline 01664 #endif 01665 VALUE 01666 opt_eq_func(VALUE recv, VALUE obj, IC ic) 01667 { 01668 if (FIXNUM_2_P(recv, obj) && 01669 BASIC_OP_UNREDEFINED_P(BOP_EQ)) { 01670 return (recv == obj) ? Qtrue : Qfalse; 01671 } 01672 else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { 01673 if (HEAP_CLASS_OF(recv) == rb_cFloat && 01674 HEAP_CLASS_OF(obj) == rb_cFloat && 01675 BASIC_OP_UNREDEFINED_P(BOP_EQ)) { 01676 double a = RFLOAT_VALUE(recv); 01677 double b = RFLOAT_VALUE(obj); 01678 01679 if (isnan(a) || isnan(b)) { 01680 return Qfalse; 01681 } 01682 return (a == b) ? Qtrue : Qfalse; 01683 } 01684 else if (HEAP_CLASS_OF(recv) == rb_cString && 01685 HEAP_CLASS_OF(obj) == rb_cString && 01686 BASIC_OP_UNREDEFINED_P(BOP_EQ)) { 01687 return rb_str_equal(recv, obj); 01688 } 01689 } 01690 01691 { 01692 const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ic); 01693 extern VALUE rb_obj_equal(VALUE obj1, VALUE obj2); 01694 01695 if (check_cfunc(me, rb_obj_equal)) { 01696 return recv == obj ? Qtrue : Qfalse; 01697 } 01698 } 01699 01700 return Qundef; 01701 } 01702 01703 struct opt_case_dispatch_i_arg { 01704 VALUE obj; 01705 int label; 01706 }; 01707 01708 static int 01709 opt_case_dispatch_i(st_data_t key, st_data_t data, st_data_t p) 01710 { 01711 struct opt_case_dispatch_i_arg *arg = (void *)p; 01712 01713 if (RTEST(rb_funcall((VALUE)key, idEqq, 1, arg->obj))) { 01714 arg->label = FIX2INT((VALUE)data); 01715 return ST_STOP; 01716 } 01717 else { 01718 return ST_CONTINUE; 01719 } 01720 } 01721 01722
1.7.3