|
Ruby
1.9.3p385(2013-02-06revision39114)
|
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 #ifdef __llvm__ 00410 #define RB_LLVM_GUARD(v) RB_GC_GUARD(v) 00411 RB_LLVM_GUARD(reg_cfp); 00412 #endif 00413 00414 vm_pop_frame(th); 00415 00416 EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass); 00417 00418 return val; 00419 } 00420 00421 static inline VALUE 00422 vm_call_bmethod(rb_thread_t *th, VALUE recv, int argc, const VALUE *argv, 00423 const rb_block_t *blockptr, const rb_method_entry_t *me) 00424 { 00425 rb_proc_t *proc; 00426 VALUE val; 00427 00428 EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, recv, me->called_id, me->klass); 00429 00430 /* control block frame */ 00431 th->passed_me = me; 00432 GetProcPtr(me->def->body.proc, proc); 00433 val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr); 00434 00435 EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, recv, me->called_id, me->klass); 00436 00437 return val; 00438 } 00439 00440 static inline void 00441 vm_method_missing_args(rb_thread_t *th, VALUE *argv, 00442 int num, const rb_block_t *blockptr, int opt) 00443 { 00444 rb_control_frame_t * const reg_cfp = th->cfp; 00445 MEMCPY(argv, STACK_ADDR_FROM_TOP(num + 1), VALUE, num + 1); 00446 th->method_missing_reason = opt; 00447 th->passed_block = blockptr; 00448 POPN(num + 1); 00449 } 00450 00451 static inline VALUE 00452 vm_method_missing(rb_thread_t *th, ID id, VALUE recv, 00453 int num, const rb_block_t *blockptr, int opt) 00454 { 00455 VALUE *argv = ALLOCA_N(VALUE, num + 1); 00456 vm_method_missing_args(th, argv, num, blockptr, opt); 00457 argv[0] = ID2SYM(id); 00458 return rb_funcall2(recv, idMethodMissing, num + 1, argv); 00459 } 00460 00461 static inline void 00462 vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp, 00463 VALUE recv, int argc, const rb_block_t *blockptr, VALUE flag, 00464 const rb_method_entry_t *me) 00465 { 00466 int opt_pc, i; 00467 VALUE *sp, *rsp = cfp->sp - argc; 00468 rb_iseq_t *iseq = me->def->body.iseq; 00469 00470 VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, rsp, &blockptr); 00471 00472 /* stack overflow check */ 00473 CHECK_STACK_OVERFLOW(cfp, iseq->stack_max); 00474 00475 sp = rsp + iseq->arg_size; 00476 00477 if (LIKELY(!(flag & VM_CALL_TAILCALL_BIT))) { 00478 if (0) printf("local_size: %d, arg_size: %d\n", 00479 iseq->local_size, iseq->arg_size); 00480 00481 /* clear local variables */ 00482 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { 00483 *sp++ = Qnil; 00484 } 00485 00486 vm_push_frame(th, iseq, 00487 VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, 00488 iseq->iseq_encoded + opt_pc, sp, 0, 0); 00489 00490 cfp->sp = rsp - 1 /* recv */; 00491 } 00492 else { 00493 VALUE *p_rsp; 00494 th->cfp++; /* pop cf */ 00495 p_rsp = th->cfp->sp; 00496 00497 /* copy arguments */ 00498 for (i=0; i < (sp - rsp); i++) { 00499 p_rsp[i] = rsp[i]; 00500 } 00501 00502 sp -= rsp - p_rsp; 00503 00504 /* clear local variables */ 00505 for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { 00506 *sp++ = Qnil; 00507 } 00508 00509 vm_push_frame(th, iseq, 00510 VM_FRAME_MAGIC_METHOD, recv, (VALUE) blockptr, 00511 iseq->iseq_encoded + opt_pc, sp, 0, 0); 00512 } 00513 } 00514 00515 static inline VALUE 00516 vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp, 00517 int num, const rb_block_t *blockptr, VALUE flag, 00518 ID id, const rb_method_entry_t *me, VALUE recv) 00519 { 00520 VALUE val; 00521 00522 start_method_dispatch: 00523 00524 if (me != 0) { 00525 if ((me->flag == 0)) { 00526 normal_method_dispatch: 00527 switch (me->def->type) { 00528 case VM_METHOD_TYPE_ISEQ:{ 00529 vm_setup_method(th, cfp, recv, num, blockptr, flag, me); 00530 return Qundef; 00531 } 00532 case VM_METHOD_TYPE_NOTIMPLEMENTED: 00533 case VM_METHOD_TYPE_CFUNC:{ 00534 val = vm_call_cfunc(th, cfp, num, recv, blockptr, me); 00535 break; 00536 } 00537 case VM_METHOD_TYPE_ATTRSET:{ 00538 if (num != 1) { 00539 rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", num); 00540 } 00541 val = rb_ivar_set(recv, me->def->body.attr.id, *(cfp->sp - 1)); 00542 cfp->sp -= 2; 00543 break; 00544 } 00545 case VM_METHOD_TYPE_IVAR:{ 00546 if (num != 0) { 00547 rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", num); 00548 } 00549 val = rb_attr_get(recv, me->def->body.attr.id); 00550 cfp->sp -= 1; 00551 break; 00552 } 00553 case VM_METHOD_TYPE_MISSING:{ 00554 VALUE *argv = ALLOCA_N(VALUE, num+1); 00555 argv[0] = ID2SYM(me->def->original_id); 00556 MEMCPY(argv+1, cfp->sp - num, VALUE, num); 00557 cfp->sp += - num - 1; 00558 th->passed_block = blockptr; 00559 val = rb_funcall2(recv, rb_intern("method_missing"), num+1, argv); 00560 break; 00561 } 00562 case VM_METHOD_TYPE_BMETHOD:{ 00563 VALUE *argv = ALLOCA_N(VALUE, num); 00564 MEMCPY(argv, cfp->sp - num, VALUE, num); 00565 cfp->sp += - num - 1; 00566 val = vm_call_bmethod(th, recv, num, argv, blockptr, me); 00567 break; 00568 } 00569 case VM_METHOD_TYPE_ZSUPER:{ 00570 VALUE klass = RCLASS_SUPER(me->klass); 00571 me = rb_method_entry(klass, id); 00572 00573 if (me != 0) { 00574 goto normal_method_dispatch; 00575 } 00576 else { 00577 goto start_method_dispatch; 00578 } 00579 } 00580 case VM_METHOD_TYPE_OPTIMIZED:{ 00581 switch (me->def->body.optimize_type) { 00582 case OPTIMIZED_METHOD_TYPE_SEND: { 00583 rb_control_frame_t *reg_cfp = cfp; 00584 rb_num_t i = num - 1; 00585 VALUE sym; 00586 00587 if (num == 0) { 00588 rb_raise(rb_eArgError, "no method name given"); 00589 } 00590 00591 sym = TOPN(i); 00592 id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym); 00593 /* shift arguments */ 00594 if (i > 0) { 00595 MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i); 00596 } 00597 me = rb_method_entry(CLASS_OF(recv), id); 00598 num -= 1; 00599 DEC_SP(1); 00600 flag |= VM_CALL_FCALL_BIT | VM_CALL_OPT_SEND_BIT; 00601 00602 goto start_method_dispatch; 00603 } 00604 case OPTIMIZED_METHOD_TYPE_CALL: { 00605 rb_proc_t *proc; 00606 int argc = num; 00607 VALUE *argv = ALLOCA_N(VALUE, num); 00608 GetProcPtr(recv, proc); 00609 MEMCPY(argv, cfp->sp - num, VALUE, num); 00610 cfp->sp -= num + 1; 00611 00612 val = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, blockptr); 00613 break; 00614 } 00615 default: 00616 rb_bug("eval_invoke_method: unsupported optimized method type (%d)", 00617 me->def->body.optimize_type); 00618 } 00619 break; 00620 } 00621 default:{ 00622 rb_bug("eval_invoke_method: unsupported method type (%d)", me->def->type); 00623 break; 00624 } 00625 } 00626 } 00627 else { 00628 int noex_safe; 00629 00630 if (!(flag & VM_CALL_FCALL_BIT) && 00631 (me->flag & NOEX_MASK) & NOEX_PRIVATE) { 00632 int stat = NOEX_PRIVATE; 00633 00634 if (flag & VM_CALL_VCALL_BIT) { 00635 stat |= NOEX_VCALL; 00636 } 00637 val = vm_method_missing(th, id, recv, num, blockptr, stat); 00638 } 00639 else if (!(flag & VM_CALL_OPT_SEND_BIT) && (me->flag & NOEX_MASK) & NOEX_PROTECTED) { 00640 VALUE defined_class = me->klass; 00641 00642 if (RB_TYPE_P(defined_class, T_ICLASS)) { 00643 defined_class = RBASIC(defined_class)->klass; 00644 } 00645 00646 if (!rb_obj_is_kind_of(cfp->self, defined_class)) { 00647 val = vm_method_missing(th, id, recv, num, blockptr, NOEX_PROTECTED); 00648 } 00649 else { 00650 goto normal_method_dispatch; 00651 } 00652 } 00653 else if ((noex_safe = NOEX_SAFE(me->flag)) > th->safe_level && 00654 (noex_safe > 2)) { 00655 rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(id)); 00656 } 00657 else { 00658 goto normal_method_dispatch; 00659 } 00660 } 00661 } 00662 else { 00663 /* method missing */ 00664 int stat = 0; 00665 if (flag & VM_CALL_VCALL_BIT) { 00666 stat |= NOEX_VCALL; 00667 } 00668 if (flag & VM_CALL_SUPER_BIT) { 00669 stat |= NOEX_SUPER; 00670 } 00671 if (id == idMethodMissing) { 00672 VALUE *argv = ALLOCA_N(VALUE, num); 00673 vm_method_missing_args(th, argv, num - 1, 0, stat); 00674 rb_raise_method_missing(th, num, argv, recv, stat); 00675 } 00676 else { 00677 val = vm_method_missing(th, id, recv, num, blockptr, stat); 00678 } 00679 } 00680 00681 RUBY_VM_CHECK_INTS(); 00682 return val; 00683 } 00684 00685 /* yield */ 00686 00687 static inline int 00688 block_proc_is_lambda(const VALUE procval) 00689 { 00690 rb_proc_t *proc; 00691 00692 if (procval) { 00693 GetProcPtr(procval, proc); 00694 return proc->is_lambda; 00695 } 00696 else { 00697 return 0; 00698 } 00699 } 00700 00701 static inline VALUE 00702 vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, 00703 VALUE self, int argc, const VALUE *argv, 00704 const rb_block_t *blockargptr) 00705 { 00706 NODE *ifunc = (NODE *) block->iseq; 00707 VALUE val, arg, blockarg; 00708 int lambda = block_proc_is_lambda(block->proc); 00709 00710 if (lambda) { 00711 arg = rb_ary_new4(argc, argv); 00712 } 00713 else if (argc == 0) { 00714 arg = Qnil; 00715 } 00716 else { 00717 arg = argv[0]; 00718 } 00719 00720 if (blockargptr) { 00721 if (blockargptr->proc) { 00722 blockarg = blockargptr->proc; 00723 } 00724 else { 00725 blockarg = rb_vm_make_proc(th, blockargptr, rb_cProc); 00726 } 00727 } 00728 else { 00729 blockarg = Qnil; 00730 } 00731 00732 vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, 00733 self, (VALUE)block->dfp, 00734 0, th->cfp->sp, block->lfp, 1); 00735 00736 if (blockargptr) { 00737 th->cfp->lfp[0] = GC_GUARDED_PTR((VALUE)blockargptr); 00738 } 00739 val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg); 00740 00741 th->cfp++; 00742 return val; 00743 } 00744 00745 00746 /*-- 00747 * @brief on supplied all of optional, rest and post parameters. 00748 * @pre iseq is block style (not lambda style) 00749 */ 00750 static inline int 00751 vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t *iseq, 00752 int argc, VALUE *argv) 00753 { 00754 rb_num_t opt_pc = 0; 00755 int i; 00756 const int m = iseq->argc; 00757 const int r = iseq->arg_rest; 00758 int len = iseq->arg_post_len; 00759 int start = iseq->arg_post_start; 00760 int rsize = argc > m ? argc - m : 0; /* # of arguments which did not consumed yet */ 00761 int psize = rsize > len ? len : rsize; /* # of post arguments */ 00762 int osize = 0; /* # of opt arguments */ 00763 VALUE ary; 00764 00765 /* reserves arguments for post parameters */ 00766 rsize -= psize; 00767 00768 if (iseq->arg_opts) { 00769 const int opts = iseq->arg_opts - 1; 00770 if (rsize > opts) { 00771 osize = opts; 00772 opt_pc = iseq->arg_opt_table[opts]; 00773 } 00774 else { 00775 osize = rsize; 00776 opt_pc = iseq->arg_opt_table[rsize]; 00777 } 00778 } 00779 rsize -= osize; 00780 00781 if (0) { 00782 printf(" argc: %d\n", argc); 00783 printf(" len: %d\n", len); 00784 printf("start: %d\n", start); 00785 printf("rsize: %d\n", rsize); 00786 } 00787 00788 if (r == -1) { 00789 /* copy post argument */ 00790 MEMMOVE(&argv[start], &argv[m+osize], VALUE, psize); 00791 } 00792 else { 00793 ary = rb_ary_new4(rsize, &argv[r]); 00794 00795 /* copy post argument */ 00796 MEMMOVE(&argv[start], &argv[m+rsize+osize], VALUE, psize); 00797 argv[r] = ary; 00798 } 00799 00800 for (i=psize; i<len; i++) { 00801 argv[start + i] = Qnil; 00802 } 00803 00804 return (int)opt_pc; 00805 } 00806 00807 static inline int 00808 vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq, 00809 int orig_argc, VALUE *argv, 00810 const rb_block_t *blockptr) 00811 { 00812 int i; 00813 int argc = orig_argc; 00814 const int m = iseq->argc; 00815 VALUE ary, arg0; 00816 int opt_pc = 0; 00817 00818 th->mark_stack_len = argc; 00819 00820 /* 00821 * yield [1, 2] 00822 * => {|a|} => a = [1, 2] 00823 * => {|a, b|} => a, b = [1, 2] 00824 */ 00825 arg0 = argv[0]; 00826 if (!(iseq->arg_simple & 0x02) && /* exclude {|a|} */ 00827 (m + iseq->arg_post_len) > 0 && /* this process is meaningful */ 00828 argc == 1 && !NIL_P(ary = rb_check_array_type(arg0))) { /* rhs is only an array */ 00829 th->mark_stack_len = argc = RARRAY_LENINT(ary); 00830 00831 CHECK_STACK_OVERFLOW(th->cfp, argc); 00832 00833 MEMCPY(argv, RARRAY_PTR(ary), VALUE, argc); 00834 } 00835 else { 00836 argv[0] = arg0; 00837 } 00838 00839 for (i=argc; i<m; i++) { 00840 argv[i] = Qnil; 00841 } 00842 00843 if (iseq->arg_rest == -1 && iseq->arg_opts == 0) { 00844 const int arg_size = iseq->arg_size; 00845 if (arg_size < argc) { 00846 /* 00847 * yield 1, 2 00848 * => {|a|} # truncate 00849 */ 00850 th->mark_stack_len = argc = arg_size; 00851 } 00852 } 00853 else { 00854 int r = iseq->arg_rest; 00855 00856 if (iseq->arg_post_len || 00857 iseq->arg_opts) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */ 00858 opt_pc = vm_yield_setup_block_args_complex(th, iseq, argc, argv); 00859 } 00860 else { 00861 if (argc < r) { 00862 /* yield 1 00863 * => {|a, b, *r|} 00864 */ 00865 for (i=argc; i<r; i++) { 00866 argv[i] = Qnil; 00867 } 00868 argv[r] = rb_ary_new(); 00869 } 00870 else { 00871 argv[r] = rb_ary_new4(argc-r, &argv[r]); 00872 } 00873 } 00874 00875 th->mark_stack_len = iseq->arg_size; 00876 } 00877 00878 /* {|&b|} */ 00879 if (iseq->arg_block != -1) { 00880 VALUE procval = Qnil; 00881 00882 if (blockptr) { 00883 if (blockptr->proc == 0) { 00884 procval = rb_vm_make_proc(th, blockptr, rb_cProc); 00885 } 00886 else { 00887 procval = blockptr->proc; 00888 } 00889 } 00890 00891 argv[iseq->arg_block] = procval; 00892 } 00893 00894 th->mark_stack_len = 0; 00895 return opt_pc; 00896 } 00897 00898 static inline int 00899 vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq, 00900 int argc, VALUE *argv, 00901 const rb_block_t *blockptr, int lambda) 00902 { 00903 if (0) { /* for debug */ 00904 printf(" argc: %d\n", argc); 00905 printf("iseq argc: %d\n", iseq->argc); 00906 printf("iseq opts: %d\n", iseq->arg_opts); 00907 printf("iseq rest: %d\n", iseq->arg_rest); 00908 printf("iseq post: %d\n", iseq->arg_post_len); 00909 printf("iseq blck: %d\n", iseq->arg_block); 00910 printf("iseq smpl: %d\n", iseq->arg_simple); 00911 printf(" lambda: %s\n", lambda ? "true" : "false"); 00912 } 00913 00914 if (lambda) { 00915 /* call as method */ 00916 int opt_pc; 00917 VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, argv, &blockptr); 00918 return opt_pc; 00919 } 00920 else { 00921 return vm_yield_setup_block_args(th, iseq, argc, argv, blockptr); 00922 } 00923 } 00924 00925 static VALUE 00926 vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_num_t flag) 00927 { 00928 const rb_block_t *block = GET_BLOCK_PTR(); 00929 rb_iseq_t *iseq; 00930 int argc = (int)num; 00931 VALUE type = GET_ISEQ()->local_iseq->type; 00932 00933 if ((type != ISEQ_TYPE_METHOD && type != ISEQ_TYPE_CLASS) || block == 0) { 00934 rb_vm_localjump_error("no block given (yield)", Qnil, 0); 00935 } 00936 iseq = block->iseq; 00937 00938 argc = caller_setup_args(th, GET_CFP(), flag, argc, 0, 0); 00939 00940 if (BUILTIN_TYPE(iseq) != T_NODE) { 00941 int opt_pc; 00942 const int arg_size = iseq->arg_size; 00943 VALUE * const rsp = GET_SP() - argc; 00944 SET_SP(rsp); 00945 00946 CHECK_STACK_OVERFLOW(GET_CFP(), iseq->stack_max); 00947 opt_pc = vm_yield_setup_args(th, iseq, argc, rsp, 0, 00948 block_proc_is_lambda(block->proc)); 00949 00950 vm_push_frame(th, iseq, 00951 VM_FRAME_MAGIC_BLOCK, block->self, (VALUE) block->dfp, 00952 iseq->iseq_encoded + opt_pc, rsp + arg_size, block->lfp, 00953 iseq->local_size - arg_size); 00954 00955 return Qundef; 00956 } 00957 else { 00958 VALUE val = vm_yield_with_cfunc(th, block, block->self, argc, STACK_ADDR_FROM_TOP(argc), 0); 00959 POPN(argc); /* TODO: should put before C/yield? */ 00960 return val; 00961 } 00962 } 00963 00964 /* svar */ 00965 00966 static inline NODE * 00967 lfp_svar_place(rb_thread_t *th, VALUE *lfp) 00968 { 00969 VALUE *svar; 00970 00971 if (lfp && th->local_lfp != lfp) { 00972 svar = &lfp[-1]; 00973 } 00974 else { 00975 svar = &th->local_svar; 00976 } 00977 if (NIL_P(*svar)) { 00978 *svar = (VALUE)NEW_IF(Qnil, Qnil, Qnil); 00979 } 00980 return (NODE *)*svar; 00981 } 00982 00983 static VALUE 00984 lfp_svar_get(rb_thread_t *th, VALUE *lfp, rb_num_t key) 00985 { 00986 NODE *svar = lfp_svar_place(th, lfp); 00987 00988 switch (key) { 00989 case 0: 00990 return svar->u1.value; 00991 case 1: 00992 return svar->u2.value; 00993 default: { 00994 const VALUE ary = svar->u3.value; 00995 00996 if (NIL_P(ary)) { 00997 return Qnil; 00998 } 00999 else { 01000 return rb_ary_entry(ary, key - DEFAULT_SPECIAL_VAR_COUNT); 01001 } 01002 } 01003 } 01004 } 01005 01006 static void 01007 lfp_svar_set(rb_thread_t *th, VALUE *lfp, rb_num_t key, VALUE val) 01008 { 01009 NODE *svar = lfp_svar_place(th, lfp); 01010 01011 switch (key) { 01012 case 0: 01013 svar->u1.value = val; 01014 return; 01015 case 1: 01016 svar->u2.value = val; 01017 return; 01018 default: { 01019 VALUE ary = svar->u3.value; 01020 01021 if (NIL_P(ary)) { 01022 svar->u3.value = ary = rb_ary_new(); 01023 } 01024 rb_ary_store(ary, key - DEFAULT_SPECIAL_VAR_COUNT, val); 01025 } 01026 } 01027 } 01028 01029 static inline VALUE 01030 vm_getspecial(rb_thread_t *th, VALUE *lfp, rb_num_t key, rb_num_t type) 01031 { 01032 VALUE val; 01033 01034 if (type == 0) { 01035 val = lfp_svar_get(th, lfp, key); 01036 } 01037 else { 01038 VALUE backref = lfp_svar_get(th, lfp, 1); 01039 01040 if (type & 0x01) { 01041 switch (type >> 1) { 01042 case '&': 01043 val = rb_reg_last_match(backref); 01044 break; 01045 case '`': 01046 val = rb_reg_match_pre(backref); 01047 break; 01048 case '\'': 01049 val = rb_reg_match_post(backref); 01050 break; 01051 case '+': 01052 val = rb_reg_match_last(backref); 01053 break; 01054 default: 01055 rb_bug("unexpected back-ref"); 01056 } 01057 } 01058 else { 01059 val = rb_reg_nth_match((int)(type >> 1), backref); 01060 } 01061 } 01062 return val; 01063 } 01064 01065 static NODE * 01066 vm_get_cref0(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp) 01067 { 01068 while (1) { 01069 if (lfp == dfp) { 01070 if (!RUBY_VM_NORMAL_ISEQ_P(iseq)) return NULL; 01071 return iseq->cref_stack; 01072 } 01073 else if (dfp[-1] != Qnil) { 01074 return (NODE *)dfp[-1]; 01075 } 01076 dfp = GET_PREV_DFP(dfp); 01077 } 01078 } 01079 01080 static NODE * 01081 vm_get_cref(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp) 01082 { 01083 NODE *cref = vm_get_cref0(iseq, lfp, dfp); 01084 01085 if (cref == 0) { 01086 rb_bug("vm_get_cref: unreachable"); 01087 } 01088 return cref; 01089 } 01090 01091 static NODE * 01092 vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr) 01093 { 01094 rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp); 01095 NODE *cref = NEW_BLOCK(klass); 01096 cref->nd_visi = noex; 01097 01098 if (blockptr) { 01099 cref->nd_next = vm_get_cref0(blockptr->iseq, blockptr->lfp, blockptr->dfp); 01100 } 01101 else if (cfp) { 01102 cref->nd_next = vm_get_cref0(cfp->iseq, cfp->lfp, cfp->dfp); 01103 } 01104 01105 return cref; 01106 } 01107 01108 static inline VALUE 01109 vm_get_cbase(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp) 01110 { 01111 NODE *cref = vm_get_cref(iseq, lfp, dfp); 01112 VALUE klass = Qundef; 01113 01114 while (cref) { 01115 if ((klass = cref->nd_clss) != 0) { 01116 break; 01117 } 01118 cref = cref->nd_next; 01119 } 01120 01121 return klass; 01122 } 01123 01124 static inline VALUE 01125 vm_get_const_base(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp) 01126 { 01127 NODE *cref = vm_get_cref(iseq, lfp, dfp); 01128 VALUE klass = Qundef; 01129 01130 while (cref) { 01131 if (!(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) && 01132 (klass = cref->nd_clss) != 0) { 01133 break; 01134 } 01135 cref = cref->nd_next; 01136 } 01137 01138 return klass; 01139 } 01140 01141 static inline void 01142 vm_check_if_namespace(VALUE klass) 01143 { 01144 VALUE str; 01145 switch (TYPE(klass)) { 01146 case T_CLASS: 01147 case T_MODULE: 01148 break; 01149 default: 01150 str = rb_inspect(klass); 01151 rb_raise(rb_eTypeError, "%s is not a class/module", 01152 StringValuePtr(str)); 01153 } 01154 } 01155 01156 static inline VALUE 01157 vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq, 01158 VALUE orig_klass, ID id, int is_defined) 01159 { 01160 VALUE val; 01161 01162 if (orig_klass == Qnil) { 01163 /* in current lexical scope */ 01164 const NODE *root_cref = vm_get_cref(iseq, th->cfp->lfp, th->cfp->dfp); 01165 const NODE *cref; 01166 VALUE klass = orig_klass; 01167 01168 while (root_cref && root_cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) { 01169 root_cref = root_cref->nd_next; 01170 } 01171 cref = root_cref; 01172 while (cref && cref->nd_next) { 01173 if (cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) { 01174 klass = Qnil; 01175 } 01176 else { 01177 klass = cref->nd_clss; 01178 } 01179 cref = cref->nd_next; 01180 01181 if (!NIL_P(klass)) { 01182 VALUE am = 0; 01183 st_data_t data; 01184 search_continue: 01185 if (RCLASS_CONST_TBL(klass) && 01186 st_lookup(RCLASS_CONST_TBL(klass), id, &data)) { 01187 val = ((rb_const_entry_t*)data)->value; 01188 if (val == Qundef) { 01189 if (am == klass) break; 01190 am = klass; 01191 if (is_defined) return 1; 01192 rb_autoload_load(klass, id); 01193 goto search_continue; 01194 } 01195 else { 01196 if (is_defined) { 01197 return 1; 01198 } 01199 else { 01200 return val; 01201 } 01202 } 01203 } 01204 } 01205 } 01206 01207 /* search self */ 01208 if (root_cref && !NIL_P(root_cref->nd_clss)) { 01209 klass = root_cref->nd_clss; 01210 } 01211 else { 01212 klass = CLASS_OF(th->cfp->self); 01213 } 01214 01215 if (is_defined) { 01216 return rb_const_defined(klass, id); 01217 } 01218 else { 01219 return rb_const_get(klass, id); 01220 } 01221 } 01222 else { 01223 vm_check_if_namespace(orig_klass); 01224 if (is_defined) { 01225 return rb_public_const_defined_from(orig_klass, id); 01226 } 01227 else { 01228 return rb_public_const_get_from(orig_klass, id); 01229 } 01230 } 01231 } 01232 01233 static inline VALUE 01234 vm_get_cvar_base(NODE *cref) 01235 { 01236 VALUE klass; 01237 01238 while (cref && cref->nd_next && 01239 (NIL_P(cref->nd_clss) || FL_TEST(cref->nd_clss, FL_SINGLETON) || 01240 (cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL))) { 01241 cref = cref->nd_next; 01242 01243 if (!cref->nd_next) { 01244 rb_warn("class variable access from toplevel"); 01245 } 01246 } 01247 01248 klass = cref->nd_clss; 01249 01250 if (NIL_P(klass)) { 01251 rb_raise(rb_eTypeError, "no class variables available"); 01252 } 01253 return klass; 01254 } 01255 01256 static VALUE 01257 vm_search_const_defined_class(const VALUE cbase, ID id) 01258 { 01259 if (rb_const_defined_at(cbase, id)) return cbase; 01260 if (cbase == rb_cObject) { 01261 VALUE tmp = RCLASS_SUPER(cbase); 01262 while (tmp) { 01263 if (rb_const_defined_at(tmp, id)) return tmp; 01264 tmp = RCLASS_SUPER(tmp); 01265 } 01266 } 01267 return 0; 01268 } 01269 01270 #ifndef USE_IC_FOR_IVAR 01271 #define USE_IC_FOR_IVAR 1 01272 #endif 01273 01274 static VALUE 01275 vm_getivar(VALUE obj, ID id, IC ic) 01276 { 01277 #if USE_IC_FOR_IVAR 01278 if (TYPE(obj) == T_OBJECT) { 01279 VALUE val = Qundef; 01280 VALUE klass = RBASIC(obj)->klass; 01281 01282 if (LIKELY(ic->ic_class == klass && 01283 ic->ic_vmstat == GET_VM_STATE_VERSION())) { 01284 long index = ic->ic_value.index; 01285 long len = ROBJECT_NUMIV(obj); 01286 VALUE *ptr = ROBJECT_IVPTR(obj); 01287 01288 if (index < len) { 01289 val = ptr[index]; 01290 } 01291 } 01292 else { 01293 st_data_t index; 01294 long len = ROBJECT_NUMIV(obj); 01295 VALUE *ptr = ROBJECT_IVPTR(obj); 01296 struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); 01297 01298 if (iv_index_tbl) { 01299 if (st_lookup(iv_index_tbl, id, &index)) { 01300 if ((long)index < len) { 01301 val = ptr[index]; 01302 } 01303 ic->ic_class = klass; 01304 ic->ic_value.index = index; 01305 ic->ic_vmstat = GET_VM_STATE_VERSION(); 01306 } 01307 } 01308 } 01309 if (UNLIKELY(val == Qundef)) { 01310 rb_warning("instance variable %s not initialized", rb_id2name(id)); 01311 val = Qnil; 01312 } 01313 return val; 01314 } 01315 else { 01316 return rb_ivar_get(obj, id); 01317 } 01318 #else 01319 return rb_ivar_get(obj, id); 01320 #endif 01321 } 01322 01323 static void 01324 vm_setivar(VALUE obj, ID id, VALUE val, IC ic) 01325 { 01326 #if USE_IC_FOR_IVAR 01327 if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) { 01328 rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); 01329 } 01330 01331 rb_check_frozen(obj); 01332 01333 if (TYPE(obj) == T_OBJECT) { 01334 VALUE klass = RBASIC(obj)->klass; 01335 st_data_t index; 01336 01337 if (LIKELY(ic->ic_class == klass && 01338 ic->ic_vmstat == GET_VM_STATE_VERSION())) { 01339 long index = ic->ic_value.index; 01340 long len = ROBJECT_NUMIV(obj); 01341 VALUE *ptr = ROBJECT_IVPTR(obj); 01342 01343 if (index < len) { 01344 ptr[index] = val; 01345 return; /* inline cache hit */ 01346 } 01347 } 01348 else { 01349 struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); 01350 01351 if (iv_index_tbl && st_lookup(iv_index_tbl, (st_data_t)id, &index)) { 01352 ic->ic_class = klass; 01353 ic->ic_value.index = index; 01354 ic->ic_vmstat = GET_VM_STATE_VERSION(); 01355 } 01356 /* fall through */ 01357 } 01358 } 01359 rb_ivar_set(obj, id, val); 01360 #else 01361 rb_ivar_set(obj, id, val); 01362 #endif 01363 } 01364 01365 static inline const rb_method_entry_t * 01366 vm_method_search(VALUE id, VALUE klass, IC ic) 01367 { 01368 rb_method_entry_t *me; 01369 #if OPT_INLINE_METHOD_CACHE 01370 if (LIKELY(klass == ic->ic_class && 01371 GET_VM_STATE_VERSION() == ic->ic_vmstat)) { 01372 me = ic->ic_value.method; 01373 } 01374 else { 01375 me = rb_method_entry(klass, id); 01376 ic->ic_class = klass; 01377 ic->ic_value.method = me; 01378 ic->ic_vmstat = GET_VM_STATE_VERSION(); 01379 } 01380 #else 01381 me = rb_method_entry(klass, id); 01382 #endif 01383 return me; 01384 } 01385 01386 static inline VALUE 01387 vm_search_normal_superclass(VALUE klass, VALUE recv) 01388 { 01389 if (BUILTIN_TYPE(klass) == T_CLASS) { 01390 return RCLASS_SUPER(klass); 01391 } 01392 else if (BUILTIN_TYPE(klass) == T_MODULE) { 01393 VALUE k = CLASS_OF(recv); 01394 while (k) { 01395 if (BUILTIN_TYPE(k) == T_ICLASS && RBASIC(k)->klass == klass) { 01396 return RCLASS_SUPER(k); 01397 } 01398 k = RCLASS_SUPER(k); 01399 } 01400 return rb_cObject; 01401 } 01402 else { 01403 rb_bug("vm_search_normal_superclass: should not be reach here"); 01404 } 01405 } 01406 01407 static void 01408 vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *iseq, 01409 VALUE recv, VALUE sigval, 01410 ID *idp, VALUE *klassp) 01411 { 01412 ID id; 01413 VALUE klass; 01414 01415 while (iseq && !iseq->klass) { 01416 iseq = iseq->parent_iseq; 01417 } 01418 01419 if (iseq == 0) { 01420 rb_raise(rb_eNoMethodError, "super called outside of method"); 01421 } 01422 01423 id = iseq->defined_method_id; 01424 01425 if (iseq != iseq->local_iseq) { 01426 /* defined by Module#define_method() */ 01427 rb_control_frame_t *lcfp = GET_CFP(); 01428 01429 if (!sigval) { 01430 /* zsuper */ 01431 rb_raise(rb_eRuntimeError, "implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly."); 01432 } 01433 01434 while (lcfp->iseq != iseq) { 01435 rb_thread_t *th = GET_THREAD(); 01436 VALUE *tdfp = GET_PREV_DFP(lcfp->dfp); 01437 while (1) { 01438 lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(lcfp); 01439 if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(th, lcfp)) { 01440 rb_raise(rb_eNoMethodError, 01441 "super called outside of method"); 01442 } 01443 if (lcfp->dfp == tdfp) { 01444 break; 01445 } 01446 } 01447 } 01448 01449 /* temporary measure for [Bug #2420] [Bug #3136] */ 01450 if (!lcfp->me) { 01451 rb_raise(rb_eNoMethodError, "super called outside of method"); 01452 } 01453 01454 id = lcfp->me->def->original_id; 01455 klass = vm_search_normal_superclass(lcfp->me->klass, recv); 01456 } 01457 else { 01458 klass = vm_search_normal_superclass(iseq->klass, recv); 01459 } 01460 01461 *idp = id; 01462 *klassp = klass; 01463 } 01464 01465 static VALUE 01466 vm_throw(rb_thread_t *th, rb_control_frame_t *reg_cfp, 01467 rb_num_t throw_state, VALUE throwobj) 01468 { 01469 int state = (int)(throw_state & 0xff); 01470 int flag = (int)(throw_state & 0x8000); 01471 rb_num_t level = throw_state >> 16; 01472 01473 if (state != 0) { 01474 VALUE *pt = 0; 01475 if (flag != 0) { 01476 pt = (void *) 1; 01477 } 01478 else { 01479 if (state == TAG_BREAK) { 01480 rb_control_frame_t *cfp = GET_CFP(); 01481 VALUE *dfp = GET_DFP(); 01482 int is_orphan = 1; 01483 rb_iseq_t *base_iseq = GET_ISEQ(); 01484 01485 search_parent: 01486 if (cfp->iseq->type != ISEQ_TYPE_BLOCK) { 01487 if (cfp->iseq->type == ISEQ_TYPE_CLASS) { 01488 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 01489 dfp = cfp->dfp; 01490 goto search_parent; 01491 } 01492 dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp); 01493 base_iseq = base_iseq->parent_iseq; 01494 01495 while ((VALUE *) cfp < th->stack + th->stack_size) { 01496 if (cfp->dfp == dfp) { 01497 goto search_parent; 01498 } 01499 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 01500 } 01501 rb_bug("VM (throw): can't find break base."); 01502 } 01503 01504 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) { 01505 /* lambda{... break ...} */ 01506 is_orphan = 0; 01507 pt = cfp->dfp; 01508 state = TAG_RETURN; 01509 } 01510 else { 01511 dfp = GC_GUARDED_PTR_REF((VALUE *) *dfp); 01512 01513 while ((VALUE *)cfp < th->stack + th->stack_size) { 01514 if (cfp->dfp == dfp) { 01515 VALUE epc = cfp->pc - cfp->iseq->iseq_encoded; 01516 rb_iseq_t *iseq = cfp->iseq; 01517 int i; 01518 01519 for (i=0; i<iseq->catch_table_size; i++) { 01520 struct iseq_catch_table_entry *entry = &iseq->catch_table[i]; 01521 01522 if (entry->type == CATCH_TYPE_BREAK && 01523 entry->start < epc && entry->end >= epc) { 01524 if (entry->cont == epc) { 01525 goto found; 01526 } 01527 else { 01528 break; 01529 } 01530 } 01531 } 01532 break; 01533 01534 found: 01535 pt = dfp; 01536 is_orphan = 0; 01537 break; 01538 } 01539 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 01540 } 01541 } 01542 01543 if (is_orphan) { 01544 rb_vm_localjump_error("break from proc-closure", throwobj, TAG_BREAK); 01545 } 01546 } 01547 else if (state == TAG_RETRY) { 01548 rb_num_t i; 01549 pt = GC_GUARDED_PTR_REF((VALUE *) * GET_DFP()); 01550 for (i = 0; i < level; i++) { 01551 pt = GC_GUARDED_PTR_REF((VALUE *) * pt); 01552 } 01553 } 01554 else if (state == TAG_RETURN) { 01555 rb_control_frame_t *cfp = GET_CFP(); 01556 VALUE *dfp = GET_DFP(); 01557 VALUE *lfp = GET_LFP(); 01558 int in_class_frame = 0; 01559 01560 /* check orphan and get dfp */ 01561 while ((VALUE *) cfp < th->stack + th->stack_size) { 01562 if (!lfp) { 01563 lfp = cfp->lfp; 01564 } 01565 if (cfp->dfp == lfp && cfp->iseq->type == ISEQ_TYPE_CLASS) { 01566 in_class_frame = 1; 01567 lfp = 0; 01568 } 01569 01570 if (cfp->lfp == lfp) { 01571 if (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_LAMBDA) { 01572 VALUE *tdfp = dfp; 01573 01574 if (in_class_frame) { 01575 /* lambda {class A; ... return ...; end} */ 01576 dfp = cfp->dfp; 01577 goto valid_return; 01578 } 01579 01580 while (lfp != tdfp) { 01581 if (cfp->dfp == tdfp) { 01582 /* in lambda */ 01583 dfp = cfp->dfp; 01584 goto valid_return; 01585 } 01586 tdfp = GC_GUARDED_PTR_REF((VALUE *)*tdfp); 01587 } 01588 } 01589 } 01590 01591 if (cfp->dfp == lfp && cfp->iseq->type == ISEQ_TYPE_METHOD) { 01592 dfp = lfp; 01593 goto valid_return; 01594 } 01595 01596 cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); 01597 } 01598 01599 rb_vm_localjump_error("unexpected return", throwobj, TAG_RETURN); 01600 01601 valid_return: 01602 pt = dfp; 01603 } 01604 else { 01605 rb_bug("isns(throw): unsupport throw type"); 01606 } 01607 } 01608 th->state = state; 01609 return (VALUE)NEW_THROW_OBJECT(throwobj, (VALUE) pt, state); 01610 } 01611 else { 01612 /* continue throw */ 01613 VALUE err = throwobj; 01614 01615 if (FIXNUM_P(err)) { 01616 th->state = FIX2INT(err); 01617 } 01618 else if (SYMBOL_P(err)) { 01619 th->state = TAG_THROW; 01620 } 01621 else if (BUILTIN_TYPE(err) == T_NODE) { 01622 th->state = GET_THROWOBJ_STATE(err); 01623 } 01624 else { 01625 th->state = TAG_RAISE; 01626 /*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/ 01627 } 01628 return err; 01629 } 01630 } 01631 01632 static inline void 01633 vm_expandarray(rb_control_frame_t *cfp, VALUE ary, rb_num_t num, int flag) 01634 { 01635 int is_splat = flag & 0x01; 01636 rb_num_t space_size = num + is_splat; 01637 VALUE *base = cfp->sp, *ptr; 01638 volatile VALUE tmp_ary; 01639 rb_num_t len; 01640 01641 if (TYPE(ary) != T_ARRAY) { 01642 ary = rb_ary_to_ary(ary); 01643 } 01644 01645 cfp->sp += space_size; 01646 01647 tmp_ary = ary; 01648 ptr = RARRAY_PTR(ary); 01649 len = (rb_num_t)RARRAY_LEN(ary); 01650 01651 if (flag & 0x02) { 01652 /* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */ 01653 rb_num_t i = 0, j; 01654 01655 if (len < num) { 01656 for (i=0; i<num-len; i++) { 01657 *base++ = Qnil; 01658 } 01659 } 01660 for (j=0; i<num; i++, j++) { 01661 VALUE v = ptr[len - j - 1]; 01662 *base++ = v; 01663 } 01664 if (is_splat) { 01665 *base = rb_ary_new4(len - j, ptr); 01666 } 01667 } 01668 else { 01669 /* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */ 01670 rb_num_t i; 01671 VALUE *bptr = &base[space_size - 1]; 01672 01673 for (i=0; i<num; i++) { 01674 if (len <= i) { 01675 for (; i<num; i++) { 01676 *bptr-- = Qnil; 01677 } 01678 break; 01679 } 01680 *bptr-- = ptr[i]; 01681 } 01682 if (is_splat) { 01683 if (num > len) { 01684 *bptr = rb_ary_new(); 01685 } 01686 else { 01687 *bptr = rb_ary_new4(len - num, ptr + num); 01688 } 01689 } 01690 } 01691 } 01692 01693 static inline int 01694 check_cfunc(const rb_method_entry_t *me, VALUE (*func)()) 01695 { 01696 if (me && me->def->type == VM_METHOD_TYPE_CFUNC && 01697 me->def->body.cfunc.func == func) { 01698 return 1; 01699 } 01700 else { 01701 return 0; 01702 } 01703 } 01704 01705 static 01706 #ifndef NO_BIG_INLINE 01707 inline 01708 #endif 01709 VALUE 01710 opt_eq_func(VALUE recv, VALUE obj, IC ic) 01711 { 01712 if (FIXNUM_2_P(recv, obj) && 01713 BASIC_OP_UNREDEFINED_P(BOP_EQ)) { 01714 return (recv == obj) ? Qtrue : Qfalse; 01715 } 01716 else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { 01717 if (HEAP_CLASS_OF(recv) == rb_cFloat && 01718 HEAP_CLASS_OF(obj) == rb_cFloat && 01719 BASIC_OP_UNREDEFINED_P(BOP_EQ)) { 01720 double a = RFLOAT_VALUE(recv); 01721 double b = RFLOAT_VALUE(obj); 01722 01723 if (isnan(a) || isnan(b)) { 01724 return Qfalse; 01725 } 01726 return (a == b) ? Qtrue : Qfalse; 01727 } 01728 else if (HEAP_CLASS_OF(recv) == rb_cString && 01729 HEAP_CLASS_OF(obj) == rb_cString && 01730 BASIC_OP_UNREDEFINED_P(BOP_EQ)) { 01731 return rb_str_equal(recv, obj); 01732 } 01733 } 01734 01735 { 01736 const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ic); 01737 01738 if (check_cfunc(me, rb_obj_equal)) { 01739 return recv == obj ? Qtrue : Qfalse; 01740 } 01741 } 01742 01743 return Qundef; 01744 } 01745 01746
1.7.6.1