Feature #10256 » 0001-rb_call_info_t-reduce-from-96-88-bytes-on-64-bit.patch
| compile.c | ||
|---|---|---|
| { | ||
|     rb_call_info_t *ci = (rb_call_info_t *)compile_data_alloc(iseq, sizeof(rb_call_info_t)); | ||
|     ci->mid = mid; | ||
|     /* ci->fn = no default */ | ||
|     ci->flag = flag; | ||
|     ci->orig_argc = argc; | ||
|     ci->argc = argc; | ||
| ... | ... | |
|     ci->class_serial = 0; | ||
|     ci->blockptr = 0; | ||
|     ci->recv = Qundef; | ||
|     ci->call = 0; /* TODO: should set default function? */ | ||
|     ci->aux.index = iseq->callinfo_size++; | ||
| vm_core.h | ||
|---|---|---|
| typedef struct rb_call_info_struct { | ||
|     /* fixed at compile time */ | ||
|     ID mid; | ||
|     unsigned int flag; | ||
|     uint16_t fn; /* temporary for method calling */ | ||
|     uint16_t flag; /* only uses 9 bits */ | ||
|     int orig_argc; | ||
|     rb_iseq_t *blockiseq; | ||
| ... | ... | |
| 	int missing_reason; /* used by method_missing */ | ||
| 	int inc_sp; /* used by cfunc */ | ||
|     } aux; | ||
|     VALUE (*call)(struct rb_thread_struct *th, struct rb_control_frame_struct *cfp, struct rb_call_info_struct *ci); | ||
| } rb_call_info_t; | ||
| #if 1 | ||
| vm_insnhelper.c | ||
|---|---|---|
|     ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class); | ||
|     ci->klass = klass; | ||
|     ci->call = vm_call_general; | ||
|     ci->fn = VM_CIFN_GENERAL; | ||
| #if OPT_INLINE_METHOD_CACHE | ||
|     ci->method_state = GET_GLOBAL_METHOD_STATE(); | ||
|     ci->class_serial = RCLASS_SERIAL(klass); | ||
| ... | ... | |
| 	ci->aux.opt_pc = 0; | ||
| 	CI_SET_FASTPATH(ci, | ||
| 			(UNLIKELY(ci->flag & VM_CALL_TAILCALL) ? | ||
| 			 vm_call_iseq_setup_tailcall : | ||
| 			 vm_call_iseq_setup_normal), | ||
| 			 VM_CIFN_ISEQ_SETUP_TAILCALL : | ||
| 			 VM_CIFN_ISEQ_SETUP_NORMAL), | ||
| 			(!is_lambda && | ||
| 			 !(ci->flag & VM_CALL_ARGS_SPLAT) && /* argc may differ for each calls */ | ||
| 			 !(ci->me->flag & NOEX_PROTECTED))); | ||
| ... | ... | |
|     if (!(ci->me->flag & NOEX_PROTECTED) && | ||
| 	!(ci->flag & VM_CALL_ARGS_SPLAT)) { | ||
| 	CI_SET_FASTPATH(ci, vm_call_cfunc_latter, 1); | ||
| 	CI_SET_FASTPATH(ci, VM_CIFN_CFUNC_LATTER, 1); | ||
|     } | ||
|     val = vm_call_cfunc_latter(th, reg_cfp, ci); | ||
| ... | ... | |
|     vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, ci->recv, ci->defined_class, | ||
| 		  VM_ENVVAL_BLOCK_PTR(ci->blockptr), 0, th->cfp->sp + ci->aux.inc_sp, 1, me); | ||
|     if (ci->call != vm_call_general) { | ||
| 	ci->call = vm_call_cfunc_with_frame; | ||
|     if (ci->fn != VM_CIFN_GENERAL) { | ||
| 	ci->fn = VM_CIFN_CFUNC_WITH_FRAME; | ||
|     } | ||
| } | ||
| #else /* OPT_CALL_CFUNC_WITHOUT_FRAME */ | ||
| ... | ... | |
| 	  normal_method_dispatch: | ||
| 	    switch (ci->me->def->type) { | ||
| 	      case VM_METHOD_TYPE_ISEQ:{ | ||
| 		CI_SET_FASTPATH(ci, vm_call_iseq_setup, enable_fastpath); | ||
| 		CI_SET_FASTPATH(ci, VM_CIFN_ISEQ_SETUP, enable_fastpath); | ||
| 		return vm_call_iseq_setup(th, cfp, ci); | ||
| 	      } | ||
| 	      case VM_METHOD_TYPE_NOTIMPLEMENTED: | ||
| 	      case VM_METHOD_TYPE_CFUNC: | ||
| 		CI_SET_FASTPATH(ci, vm_call_cfunc, enable_fastpath); | ||
| 		CI_SET_FASTPATH(ci, VM_CIFN_CFUNC, enable_fastpath); | ||
| 		return vm_call_cfunc(th, cfp, ci); | ||
| 	      case VM_METHOD_TYPE_ATTRSET:{ | ||
| 		rb_check_arity(ci->argc, 1, 1); | ||
| 		ci->aux.index = 0; | ||
| 		CI_SET_FASTPATH(ci, vm_call_attrset, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT)); | ||
| 		CI_SET_FASTPATH(ci, VM_CIFN_CALL_ATTRSET, | ||
| 			   enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT)); | ||
| 		return vm_call_attrset(th, cfp, ci); | ||
| 	      } | ||
| 	      case VM_METHOD_TYPE_IVAR:{ | ||
| 		rb_check_arity(ci->argc, 0, 0); | ||
| 		ci->aux.index = 0; | ||
| 		CI_SET_FASTPATH(ci, vm_call_ivar, enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT)); | ||
| 		CI_SET_FASTPATH(ci, VM_CIFN_IVAR, | ||
| 			  enable_fastpath && !(ci->flag & VM_CALL_ARGS_SPLAT)); | ||
| 		return vm_call_ivar(th, cfp, ci); | ||
| 	      } | ||
| 	      case VM_METHOD_TYPE_MISSING:{ | ||
| 		ci->aux.missing_reason = 0; | ||
| 		CI_SET_FASTPATH(ci, vm_call_method_missing, enable_fastpath); | ||
| 		CI_SET_FASTPATH(ci, VM_CIFN_METHOD_MISSING, enable_fastpath); | ||
| 		return vm_call_method_missing(th, cfp, ci); | ||
| 	      } | ||
| 	      case VM_METHOD_TYPE_BMETHOD:{ | ||
| 		CI_SET_FASTPATH(ci, vm_call_bmethod, enable_fastpath); | ||
| 		CI_SET_FASTPATH(ci, VM_CIFN_BMETHOD, enable_fastpath); | ||
| 		return vm_call_bmethod(th, cfp, ci); | ||
| 	      } | ||
| 	      case VM_METHOD_TYPE_ZSUPER:{ | ||
| ... | ... | |
| 	      case VM_METHOD_TYPE_OPTIMIZED:{ | ||
| 		switch (ci->me->def->body.optimize_type) { | ||
| 		  case OPTIMIZED_METHOD_TYPE_SEND: | ||
| 		    CI_SET_FASTPATH(ci, vm_call_opt_send, enable_fastpath); | ||
| 		    CI_SET_FASTPATH(ci, VM_CIFN_OPT_SEND, enable_fastpath); | ||
| 		    return vm_call_opt_send(th, cfp, ci); | ||
| 		  case OPTIMIZED_METHOD_TYPE_CALL: | ||
| 		    CI_SET_FASTPATH(ci, vm_call_opt_call, enable_fastpath); | ||
| 		    CI_SET_FASTPATH(ci, VM_CIFN_OPT_CALL, enable_fastpath); | ||
| 		    return vm_call_opt_call(th, cfp, ci); | ||
| 		  default: | ||
| 		    rb_bug("vm_call_method: unsupported optimized method type (%d)", | ||
| ... | ... | |
| 		} | ||
| 		me = rb_method_entry(refinement, ci->mid, &defined_class); | ||
| 		if (me) { | ||
| 		    if (ci->call == vm_call_super_method) { | ||
| 		    if (ci->fn == VM_CIFN_SUPER_METHOD) { | ||
| 			rb_control_frame_t *top_cfp = current_method_entry(th, cfp); | ||
| 			if (top_cfp->me && | ||
| 			    rb_method_definition_eq(me->def, top_cfp->me->def)) { | ||
| ... | ... | |
| 		    stat |= NOEX_VCALL; | ||
| 		} | ||
| 		ci->aux.missing_reason = stat; | ||
| 		CI_SET_FASTPATH(ci, vm_call_method_missing, 1); | ||
| 		CI_SET_FASTPATH(ci, VM_CIFN_METHOD_MISSING, 1); | ||
| 		return vm_call_method_missing(th, cfp, ci); | ||
| 	    } | ||
| 	    else if (!(ci->flag & VM_CALL_OPT_SEND) && (ci->me->flag & NOEX_MASK) & NOEX_PROTECTED) { | ||
| ... | ... | |
| 	} | ||
| 	else { | ||
| 	    ci->aux.missing_reason = stat; | ||
| 	    CI_SET_FASTPATH(ci, vm_call_method_missing, 1); | ||
| 	    CI_SET_FASTPATH(ci, VM_CIFN_METHOD_MISSING, 1); | ||
| 	    return vm_call_method_missing(th, cfp, ci); | ||
| 	} | ||
|     } | ||
| ... | ... | |
|     if (!ci->klass) { | ||
| 	/* bound instance method of module */ | ||
| 	ci->aux.missing_reason = NOEX_SUPER; | ||
| 	CI_SET_FASTPATH(ci, vm_call_method_missing, 1); | ||
| 	CI_SET_FASTPATH(ci, VM_CIFN_METHOD_MISSING, 1); | ||
| 	return; | ||
|     } | ||
|     /* TODO: use inline cache */ | ||
|     ci->me = rb_method_entry(ci->klass, ci->mid, &ci->defined_class); | ||
|     ci->call = vm_call_super_method; | ||
|     ci->fn = VM_CIFN_SUPER_METHOD; | ||
|     while (iseq && !iseq->klass) { | ||
| 	iseq = iseq->parent_iseq; | ||
| ... | ... | |
|     is->once.running_thread = NULL; | ||
|     return Qnil; | ||
| } | ||
| /* test w/o C99 support so we may ensure it works on non-C99 compilers: */ | ||
| #if 0 && (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) | ||
| #  define map_(en,fn) [en] = fn | ||
| #else | ||
| #  define map_(en,fn) fn | ||
| #endif | ||
| static inline vm_cifn | ||
| cifn_lookup(const rb_call_info_t *ci) | ||
| { | ||
|     static const vm_cifn fn_map[] = { | ||
| 	map_(VM_CIFN_GENERAL, vm_call_general), | ||
| 	map_(VM_CIFN_SUPER_METHOD, vm_call_super_method), | ||
| 	map_(VM_CIFN_CFUNC, vm_call_cfunc), | ||
| #if OPT_CALL_CFUNC_WITHOUT_FRAME | ||
| 	map_(VM_CIFN_CFUNC_LATTER, vm_call_cfunc_latter), | ||
| #endif | ||
| 	map_(VM_CIFN_CFUNC_WITH_FRAME, vm_call_cfunc_with_frame), | ||
| 	map_(VM_CIFN_ISEQ_SETUP, vm_call_iseq_setup), | ||
| 	map_(VM_CIFN_ISEQ_SETUP_NORMAL, vm_call_iseq_setup_normal), | ||
| 	map_(VM_CIFN_ISEQ_SETUP_TAILCALL, vm_call_iseq_setup_tailcall), | ||
| 	map_(VM_CIFN_CALL_ATTRSET, vm_call_attrset), | ||
| 	map_(VM_CIFN_IVAR, vm_call_ivar), | ||
| 	map_(VM_CIFN_BMETHOD, vm_call_bmethod), | ||
| 	map_(VM_CIFN_OPT_SEND, vm_call_opt_send), | ||
| 	map_(VM_CIFN_OPT_CALL, vm_call_opt_call), | ||
| 	map_(VM_CIFN_METHOD_MISSING, vm_call_method_missing) | ||
|     }; | ||
|     return fn_map[ci->fn]; | ||
| } | ||
| #undef map_ | ||
| vm_insnhelper.h | ||
|---|---|---|
|   } \ | ||
| } while (0) | ||
| typedef VALUE (*vm_cifn)(rb_thread_t *, rb_control_frame_t *, rb_call_info_t *); | ||
| static inline vm_cifn cifn_lookup(const rb_call_info_t *); | ||
| enum vm_cifn_type { | ||
|     VM_CIFN_GENERAL = 0, | ||
|     VM_CIFN_SUPER_METHOD, | ||
|     VM_CIFN_CFUNC, | ||
| #if OPT_CALL_CFUNC_WITHOUT_FRAME | ||
|     VM_CIFN_CFUNC_LATTER, | ||
| #endif | ||
|     VM_CIFN_CFUNC_WITH_FRAME, | ||
|     VM_CIFN_ISEQ_SETUP, | ||
|     VM_CIFN_ISEQ_SETUP_NORMAL, | ||
|     VM_CIFN_ISEQ_SETUP_TAILCALL, | ||
|     VM_CIFN_CALL_ATTRSET, | ||
|     VM_CIFN_IVAR, | ||
|     VM_CIFN_BMETHOD, | ||
|     VM_CIFN_OPT_SEND, | ||
|     VM_CIFN_OPT_CALL, | ||
|     VM_CIFN_METHOD_MISSING | ||
| }; | ||
| #define CALL_METHOD(ci) do { \ | ||
|     VALUE v = (*(ci)->call)(th, GET_CFP(), (ci)); \ | ||
|     VALUE v = (cifn_lookup((ci)))(th, GET_CFP(), (ci)); \ | ||
|     if (v == Qundef) { \ | ||
| 	RESTORE_REGS(); \ | ||
| 	NEXT_INSN(); \ | ||
| ... | ... | |
| #endif | ||
| #if OPT_CALL_FASTPATH | ||
| #define CI_SET_FASTPATH(ci, func, enabled) do { \ | ||
|     if (LIKELY(enabled)) ((ci)->call = (func)); \ | ||
| #define CI_SET_FASTPATH(ci, func_idx, enabled) do { \ | ||
|     if (LIKELY(enabled)) ((ci)->fn = (func_idx)); \ | ||
| } while (0) | ||
| #else | ||
| #define CI_SET_FASTPATH(ci, func, enabled) /* do nothing */ | ||
| -  | ||