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