2007-06-24 21:19:22 +04:00
/**********************************************************************
2008-11-14 14:31:10 +03:00
vm_insnhelper . c - instruction helper functions .
2007-06-24 21:19:22 +04:00
$ Author $
Copyright ( C ) 2007 Koichi Sasada
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* finish iseq array */
# include "insns.inc"
2008-01-17 20:06:51 +03:00
# include <math.h>
2010-10-26 21:27:32 +04:00
# include "constant.h"
2011-05-18 17:41:54 +04:00
# include "internal.h"
* probes.d: add DTrace probe declarations. [ruby-core:27448]
* array.c (empty_ary_alloc, ary_new): added array create DTrace probe.
* compile.c (rb_insns_name): allowing DTrace probes to access
instruction sequence name.
* Makefile.in: translate probes.d file to appropriate header file.
* common.mk: declare dependencies on the DTrace header.
* configure.in: add a test for existence of DTrace.
* eval.c (setup_exception): add a probe for when an exception is
raised.
* gc.c: Add DTrace probes for mark begin and end, and sweep begin and
end.
* hash.c (empty_hash_alloc): Add a probe for hash allocation.
* insns.def: Add probes for function entry and return.
* internal.h: function declaration for compile.c change.
* load.c (rb_f_load): add probes for `load` entry and exit, require
entry and exit, and wrapping search_required for load path search.
* object.c (rb_obj_alloc): added a probe for general object creation.
* parse.y (yycompile0): added a probe around parse and compile phase.
* string.c (empty_str_alloc, str_new): DTrace probes for string
allocation.
* test/dtrace/*: tests for DTrace probes.
* vm.c (vm_invoke_proc): add probes for function return on exception
raise, hash create, and instruction sequence execution.
* vm_core.h: add probe declarations for function entry and exit.
* vm_dump.c: add probes header file.
* vm_eval.c (vm_call0_cfunc, vm_call0_cfunc_with_frame): add probe on
function entry and return.
* vm_exec.c: expose instruction number to instruction name function.
* vm_insnshelper.c: add function entry and exit probes for cfunc
methods.
* vm_insnhelper.h: vm usage information is always collected, so
uncomment the functions.
12 19:14:50 2012 Akinori MUSHA <knu@iDaemons.org>
* configure.in (isinf, isnan): isinf() and isnan() are macros on
DragonFly which cannot be found by AC_REPLACE_FUNCS(). This
workaround enforces the fact that they exist on DragonFly.
12 15:59:38 2012 Shugo Maeda <shugo@ruby-lang.org>
* vm_core.h (rb_call_info_t::refinements), compile.c (new_callinfo),
vm_insnhelper.c (vm_search_method): revert r37616 because it's too
slow. [ruby-dev:46477]
* test/ruby/test_refinement.rb (test_inline_method_cache): skip
the test until the bug is fixed efficiently.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-11-13 01:52:12 +04:00
# include "probes.h"
2012-11-18 20:30:10 +04:00
# include "probes_helper.h"
2008-01-17 20:06:51 +03:00
2007-06-24 21:19:22 +04:00
/* control stack frame */
2007-08-06 15:36:30 +04:00
# ifndef INLINE
# define INLINE inline
# endif
2009-01-19 06:03:09 +03:00
static rb_control_frame_t * vm_get_ruby_level_caller_cfp ( rb_thread_t * th , rb_control_frame_t * cfp ) ;
2012-12-25 13:57:07 +04:00
static void
vm_stackoverflow ( void )
{
rb_exc_raise ( sysstack_error ) ;
}
2007-06-24 21:19:22 +04:00
static inline rb_control_frame_t *
2012-06-11 07:14:59 +04:00
vm_push_frame ( rb_thread_t * th ,
const rb_iseq_t * iseq ,
VALUE type ,
VALUE self ,
2012-08-02 15:08:44 +04:00
VALUE klass ,
2012-06-11 07:14:59 +04:00
VALUE specval ,
const VALUE * pc ,
VALUE * sp ,
2012-07-04 06:11:37 +04:00
int local_size ,
const rb_method_entry_t * me )
2007-06-24 21:19:22 +04:00
{
2012-06-11 07:14:59 +04:00
rb_control_frame_t * const cfp = th - > cfp - 1 ;
2007-06-24 21:19:22 +04:00
int i ;
2012-06-11 07:14:59 +04:00
/* check stack overflow */
2009-11-07 14:59:16 +03:00
if ( ( void * ) ( sp + local_size ) > = ( void * ) cfp ) {
2012-12-25 13:57:07 +04:00
vm_stackoverflow ( ) ;
2009-11-07 14:59:16 +03:00
}
2009-11-07 05:45:08 +03:00
th - > cfp = cfp ;
2012-06-11 07:14:59 +04:00
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
/* setup vm value stack */
2009-02-22 17:23:33 +03:00
2012-06-11 07:14:59 +04:00
/* initialize local variables */
2007-06-24 21:19:22 +04:00
for ( i = 0 ; i < local_size ; i + + ) {
2012-06-11 07:14:59 +04:00
* sp + + = Qnil ;
2007-06-24 21:19:22 +04:00
}
/* set special val */
2012-06-11 07:14:59 +04:00
* sp = specval ;
2007-06-24 21:19:22 +04:00
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
/* setup vm control frame stack */
2008-05-19 22:47:56 +04:00
cfp - > pc = ( VALUE * ) pc ;
2007-06-24 21:19:22 +04:00
cfp - > sp = sp + 1 ;
2012-09-28 08:05:36 +04:00
# if VM_DEBUG_BP_CHECK
cfp - > bp_check = sp + 1 ;
# endif
2012-06-11 07:14:59 +04:00
cfp - > ep = sp ;
2008-05-19 22:47:56 +04:00
cfp - > iseq = ( rb_iseq_t * ) iseq ;
2007-11-09 04:29:24 +03:00
cfp - > flag = type ;
2007-06-24 21:19:22 +04:00
cfp - > self = self ;
2010-08-19 01:03:32 +04:00
cfp - > block_iseq = 0 ;
2007-06-24 21:19:22 +04:00
cfp - > proc = 0 ;
2012-07-04 06:11:37 +04:00
cfp - > me = me ;
2012-08-02 15:08:44 +04:00
if ( klass ) {
cfp - > klass = klass ;
}
else {
rb_control_frame_t * prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( cfp ) ;
if ( RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P ( th , prev_cfp ) ) {
cfp - > klass = Qnil ;
}
else {
cfp - > klass = prev_cfp - > klass ;
}
}
2007-06-24 21:19:22 +04:00
2007-08-12 23:12:55 +04:00
if ( VMDEBUG = = 2 ) {
SDR ( ) ;
}
2007-06-24 21:19:22 +04:00
return cfp ;
}
static inline void
2008-05-22 20:19:14 +04:00
vm_pop_frame ( rb_thread_t * th )
2007-06-24 21:19:22 +04:00
{
th - > cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( th - > cfp ) ;
2007-08-12 23:12:55 +04:00
if ( VMDEBUG = = 2 ) {
SDR ( ) ;
}
2007-06-24 21:19:22 +04:00
}
/* method dispatch */
2012-03-15 01:10:16 +04:00
static inline VALUE
2012-03-15 05:39:00 +04:00
rb_arg_error_new ( int argc , int min , int max )
{
2012-03-15 01:10:16 +04:00
VALUE err_mess = 0 ;
if ( min = = max ) {
err_mess = rb_sprintf ( " wrong number of arguments (%d for %d) " , argc , min ) ;
}
else if ( max = = UNLIMITED_ARGUMENTS ) {
err_mess = rb_sprintf ( " wrong number of arguments (%d for %d+) " , argc , min ) ;
}
else {
err_mess = rb_sprintf ( " wrong number of arguments (%d for %d..%d) " , argc , min , max ) ;
}
return rb_exc_new3 ( rb_eArgError , err_mess ) ;
}
2007-06-24 21:19:22 +04:00
2012-03-15 01:10:16 +04:00
NORETURN ( static void argument_error ( const rb_iseq_t * iseq , int miss_argc , int min_argc , int max_argc ) ) ;
2010-05-04 07:50:39 +04:00
static void
2012-03-15 01:10:16 +04:00
argument_error ( const rb_iseq_t * iseq , int miss_argc , int min_argc , int max_argc )
2010-05-04 07:50:39 +04:00
{
2012-03-15 01:10:16 +04:00
VALUE exc = rb_arg_error_new ( miss_argc , min_argc , max_argc ) ;
2010-05-04 07:50:39 +04:00
VALUE bt = rb_make_backtrace ( ) ;
VALUE err_line = 0 ;
if ( iseq ) {
2012-03-16 07:00:44 +04:00
int line_no = rb_iseq_first_lineno ( iseq ) ;
2010-05-04 07:50:39 +04:00
err_line = rb_sprintf ( " %s:%d:in `%s' " ,
2012-06-04 06:49:37 +04:00
RSTRING_PTR ( iseq - > location . path ) ,
line_no , RSTRING_PTR ( iseq - > location . label ) ) ;
2010-05-04 07:50:39 +04:00
rb_funcall ( bt , rb_intern ( " unshift " ) , 1 , err_line ) ;
}
rb_funcall ( exc , rb_intern ( " set_backtrace " ) , 1 , bt ) ;
rb_exc_raise ( exc ) ;
}
2011-12-26 18:20:09 +04:00
NORETURN ( static void unknown_keyword_error ( const rb_iseq_t * iseq , VALUE hash ) ) ;
static void
unknown_keyword_error ( const rb_iseq_t * iseq , VALUE hash )
{
2011-12-26 18:20:20 +04:00
VALUE sep = rb_usascii_str_new2 ( " , " ) , keys ;
const char * msg ;
int i ;
for ( i = 0 ; i < iseq - > arg_keywords ; i + + ) {
rb_hash_delete ( hash , ID2SYM ( iseq - > arg_keyword_table [ i ] ) ) ;
}
keys = rb_funcall ( hash , rb_intern ( " keys " ) , 0 , 0 ) ;
2012-05-23 11:13:21 +04:00
if ( ! RB_TYPE_P ( keys , T_ARRAY ) ) rb_raise ( rb_eArgError , " unknown keyword " ) ;
2012-05-24 18:36:54 +04:00
msg = RARRAY_LEN ( keys ) = = 1 ? " " : " s " ;
2011-12-26 18:20:20 +04:00
keys = rb_funcall ( keys , rb_intern ( " join " ) , 1 , sep ) ;
2012-05-24 18:36:54 +04:00
rb_raise ( rb_eArgError , " unknown keyword%s: % " PRIsVALUE , msg , keys ) ;
2011-12-26 18:20:09 +04:00
}
2012-03-15 01:10:34 +04:00
void
2012-03-15 05:39:00 +04:00
rb_error_arity ( int argc , int min , int max )
{
2012-03-15 01:10:34 +04:00
rb_exc_raise ( rb_arg_error_new ( argc , min , max ) ) ;
}
2012-10-14 23:58:59 +04:00
/* svar */
static inline NODE *
lep_svar_place ( rb_thread_t * th , VALUE * lep )
{
VALUE * svar ;
if ( lep & & th - > root_lep ! = lep ) {
svar = & lep [ - 1 ] ;
2008-06-06 18:48:07 +04:00
}
2012-10-14 23:58:59 +04:00
else {
svar = & th - > root_svar ;
}
if ( NIL_P ( * svar ) ) {
* svar = ( VALUE ) NEW_IF ( Qnil , Qnil , Qnil ) ;
}
return ( NODE * ) * svar ;
}
2008-06-06 18:48:07 +04:00
2012-10-14 23:58:59 +04:00
static VALUE
2012-12-10 10:11:16 +04:00
lep_svar_get ( rb_thread_t * th , VALUE * lep , rb_num_t key )
2007-06-24 21:19:22 +04:00
{
2012-10-14 23:58:59 +04:00
NODE * svar = lep_svar_place ( th , lep ) ;
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
switch ( key ) {
case 0 :
return svar - > u1 . value ;
case 1 :
return svar - > u2 . value ;
default : {
2012-12-10 10:11:16 +04:00
const VALUE ary = svar - > u3 . value ;
2008-06-06 18:48:07 +04:00
2012-12-10 10:11:16 +04:00
if ( NIL_P ( ary ) ) {
2012-10-14 23:58:59 +04:00
return Qnil ;
2011-12-26 18:20:09 +04:00
}
else {
2012-12-10 10:11:16 +04:00
return rb_ary_entry ( ary , key - DEFAULT_SPECIAL_VAR_COUNT ) ;
2011-12-26 18:20:09 +04:00
}
2012-10-14 23:58:59 +04:00
}
2011-12-26 18:20:09 +04:00
}
2012-10-14 23:58:59 +04:00
}
2011-12-26 18:20:09 +04:00
2012-10-14 23:58:59 +04:00
static void
2012-12-10 10:11:16 +04:00
lep_svar_set ( rb_thread_t * th , VALUE * lep , rb_num_t key , VALUE val )
2012-10-14 23:58:59 +04:00
{
NODE * svar = lep_svar_place ( th , lep ) ;
2008-05-21 19:18:15 +04:00
2012-10-14 23:58:59 +04:00
switch ( key ) {
case 0 :
svar - > u1 . value = val ;
return ;
case 1 :
svar - > u2 . value = val ;
return ;
default : {
2012-12-10 10:11:16 +04:00
VALUE ary = svar - > u3 . value ;
2007-06-24 21:19:22 +04:00
2012-12-10 10:11:16 +04:00
if ( NIL_P ( ary ) ) {
svar - > u3 . value = ary = rb_ary_new ( ) ;
2007-06-24 21:19:22 +04:00
}
2012-12-10 10:11:16 +04:00
rb_ary_store ( ary , key - DEFAULT_SPECIAL_VAR_COUNT , val ) ;
2012-10-14 23:58:59 +04:00
}
}
}
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
static inline VALUE
2012-12-10 10:11:16 +04:00
vm_getspecial ( rb_thread_t * th , VALUE * lep , rb_num_t key , rb_num_t type )
2012-10-14 23:58:59 +04:00
{
VALUE val ;
if ( type = = 0 ) {
2012-12-10 10:11:16 +04:00
val = lep_svar_get ( th , lep , key ) ;
2008-06-06 18:48:07 +04:00
}
2012-10-14 23:58:59 +04:00
else {
VALUE backref = lep_svar_get ( th , lep , 1 ) ;
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
if ( type & 0x01 ) {
switch ( type > > 1 ) {
case ' & ' :
val = rb_reg_last_match ( backref ) ;
break ;
case ' ` ' :
val = rb_reg_match_pre ( backref ) ;
break ;
case ' \' ' :
val = rb_reg_match_post ( backref ) ;
break ;
case ' + ' :
val = rb_reg_match_last ( backref ) ;
break ;
default :
rb_bug ( " unexpected back-ref " ) ;
}
2007-06-24 21:19:22 +04:00
}
2008-06-06 18:48:07 +04:00
else {
2012-10-14 23:58:59 +04:00
val = rb_reg_nth_match ( ( int ) ( type > > 1 ) , backref ) ;
2007-06-24 21:19:22 +04:00
}
2008-06-06 18:48:07 +04:00
}
2012-10-14 23:58:59 +04:00
return val ;
}
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
static NODE *
vm_get_cref0 ( const rb_iseq_t * iseq , const VALUE * ep )
{
while ( 1 ) {
if ( VM_EP_LEP_P ( ep ) ) {
if ( ! RUBY_VM_NORMAL_ISEQ_P ( iseq ) ) return NULL ;
return iseq - > cref_stack ;
}
else if ( ep [ - 1 ] ! = Qnil ) {
return ( NODE * ) ep [ - 1 ] ;
}
ep = VM_EP_PREV_EP ( ep ) ;
2008-06-06 18:48:07 +04:00
}
2012-10-14 23:58:59 +04:00
}
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
NODE *
rb_vm_get_cref ( const rb_iseq_t * iseq , const VALUE * ep )
{
NODE * cref = vm_get_cref0 ( iseq , ep ) ;
2011-12-26 18:20:09 +04:00
2012-10-14 23:58:59 +04:00
if ( cref = = 0 ) {
rb_bug ( " rb_vm_get_cref: unreachable " ) ;
}
return cref ;
}
2007-08-18 08:17:39 +04:00
2012-10-14 23:58:59 +04:00
static NODE *
vm_cref_push ( rb_thread_t * th , VALUE klass , int noex , rb_block_t * blockptr )
{
rb_control_frame_t * cfp = vm_get_ruby_level_caller_cfp ( th , th - > cfp ) ;
NODE * cref = NEW_CREF ( klass ) ;
cref - > nd_refinements = Qnil ;
cref - > nd_visi = noex ;
2007-12-09 08:56:00 +03:00
2012-10-14 23:58:59 +04:00
if ( blockptr ) {
cref - > nd_next = vm_get_cref0 ( blockptr - > iseq , blockptr - > ep ) ;
}
else if ( cfp ) {
cref - > nd_next = vm_get_cref0 ( cfp - > iseq , cfp - > ep ) ;
}
/* TODO: why cref->nd_next is 1? */
if ( cref - > nd_next & & cref - > nd_next ! = ( void * ) 1 & &
! NIL_P ( cref - > nd_next - > nd_refinements ) ) {
COPY_CREF_OMOD ( cref , cref - > nd_next ) ;
2007-06-24 21:19:22 +04:00
}
2008-06-06 18:48:07 +04:00
2012-10-14 23:58:59 +04:00
return cref ;
2007-06-24 21:19:22 +04:00
}
2012-10-14 23:58:59 +04:00
static inline VALUE
vm_get_cbase ( const rb_iseq_t * iseq , const VALUE * ep )
2007-06-24 21:19:22 +04:00
{
2012-10-14 23:58:59 +04:00
NODE * cref = rb_vm_get_cref ( iseq , ep ) ;
VALUE klass = Qundef ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-14 23:58:59 +04:00
while ( cref ) {
if ( ( klass = cref - > nd_clss ) ! = 0 ) {
break ;
2007-06-24 22:40:13 +04:00
}
2012-10-14 23:58:59 +04:00
cref = cref - > nd_next ;
2007-06-24 21:19:22 +04:00
}
2012-10-14 23:58:59 +04:00
return klass ;
}
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-14 23:58:59 +04:00
static inline VALUE
vm_get_const_base ( const rb_iseq_t * iseq , const VALUE * ep )
{
NODE * cref = rb_vm_get_cref ( iseq , ep ) ;
VALUE klass = Qundef ;
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
while ( cref ) {
if ( ! ( cref - > flags & NODE_FL_CREF_PUSHED_BY_EVAL ) & &
( klass = cref - > nd_clss ) ! = 0 ) {
break ;
2007-06-24 21:19:22 +04:00
}
2012-10-14 23:58:59 +04:00
cref = cref - > nd_next ;
}
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
return klass ;
}
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
static inline void
vm_check_if_namespace ( VALUE klass )
{
VALUE str ;
if ( ! RB_TYPE_P ( klass , T_CLASS ) & & ! RB_TYPE_P ( klass , T_MODULE ) ) {
str = rb_inspect ( klass ) ;
rb_raise ( rb_eTypeError , " %s is not a class/module " ,
StringValuePtr ( str ) ) ;
2007-06-24 21:19:22 +04:00
}
}
static inline VALUE
2012-10-14 23:58:59 +04:00
vm_get_iclass ( rb_control_frame_t * cfp , VALUE klass )
2007-06-24 21:19:22 +04:00
{
2012-12-29 16:22:01 +04:00
if ( RB_TYPE_P ( klass , T_MODULE ) & &
2012-10-14 23:58:59 +04:00
FL_TEST ( klass , RMODULE_IS_OVERLAID ) & &
2012-12-29 16:22:01 +04:00
RB_TYPE_P ( cfp - > klass , T_ICLASS ) & &
2012-10-14 23:58:59 +04:00
RBASIC ( cfp - > klass ) - > klass = = klass ) {
return cfp - > klass ;
}
else {
return klass ;
2007-06-24 21:19:22 +04:00
}
}
static inline VALUE
2012-10-14 23:58:59 +04:00
vm_get_ev_const ( rb_thread_t * th , const rb_iseq_t * iseq ,
VALUE orig_klass , ID id , int is_defined )
2007-06-24 21:19:22 +04:00
{
2012-10-14 23:58:59 +04:00
VALUE val ;
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
if ( orig_klass = = Qnil ) {
/* in current lexical scope */
const NODE * root_cref = rb_vm_get_cref ( iseq , th - > cfp - > ep ) ;
const NODE * cref ;
VALUE klass = orig_klass ;
2009-07-15 18:59:41 +04:00
2012-10-14 23:58:59 +04:00
while ( root_cref & & root_cref - > flags & NODE_FL_CREF_PUSHED_BY_EVAL ) {
root_cref = root_cref - > nd_next ;
}
cref = root_cref ;
while ( cref & & cref - > nd_next ) {
if ( cref - > flags & NODE_FL_CREF_PUSHED_BY_EVAL ) {
klass = Qnil ;
}
else {
klass = cref - > nd_clss ;
}
cref = cref - > nd_next ;
2012-06-11 07:14:59 +04:00
2012-10-14 23:58:59 +04:00
if ( ! NIL_P ( klass ) ) {
VALUE av , am = 0 ;
st_data_t data ;
search_continue :
if ( RCLASS_CONST_TBL ( klass ) & &
st_lookup ( RCLASS_CONST_TBL ( klass ) , id , & data ) ) {
val = ( ( rb_const_entry_t * ) data ) - > value ;
if ( val = = Qundef ) {
if ( am = = klass ) break ;
am = klass ;
if ( is_defined ) return 1 ;
if ( rb_autoloading_value ( klass , id , & av ) ) return av ;
rb_autoload_load ( klass , id ) ;
goto search_continue ;
}
else {
if ( is_defined ) {
return 1 ;
}
else {
return val ;
}
}
}
}
}
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
/* search self */
if ( root_cref & & ! NIL_P ( root_cref - > nd_clss ) ) {
klass = vm_get_iclass ( th - > cfp , root_cref - > nd_clss ) ;
}
else {
klass = CLASS_OF ( th - > cfp - > self ) ;
}
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
if ( is_defined ) {
return rb_const_defined ( klass , id ) ;
}
else {
return rb_const_get ( klass , id ) ;
}
}
else {
vm_check_if_namespace ( orig_klass ) ;
if ( is_defined ) {
return rb_public_const_defined_from ( orig_klass , id ) ;
}
else {
return rb_public_const_get_from ( orig_klass , id ) ;
}
2010-01-24 16:52:32 +03:00
}
2007-06-24 21:19:22 +04:00
}
static inline VALUE
2012-10-14 23:58:59 +04:00
vm_get_cvar_base ( NODE * cref , rb_control_frame_t * cfp )
2007-06-24 21:19:22 +04:00
{
2012-10-14 23:58:59 +04:00
VALUE klass ;
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
if ( ! cref ) {
rb_bug ( " vm_get_cvar_base: no cref " ) ;
}
2011-06-30 17:34:53 +04:00
2012-10-14 23:58:59 +04:00
while ( cref - > nd_next & &
( NIL_P ( cref - > nd_clss ) | | FL_TEST ( cref - > nd_clss , FL_SINGLETON ) | |
( cref - > flags & NODE_FL_CREF_PUSHED_BY_EVAL ) ) ) {
cref = cref - > nd_next ;
}
if ( ! cref - > nd_next ) {
rb_warn ( " class variable access from toplevel " ) ;
}
2011-06-30 17:34:53 +04:00
2012-10-14 23:58:59 +04:00
klass = vm_get_iclass ( cfp , cref - > nd_clss ) ;
2011-06-30 17:34:53 +04:00
2012-10-14 23:58:59 +04:00
if ( NIL_P ( klass ) ) {
rb_raise ( rb_eTypeError , " no class variables available " ) ;
}
return klass ;
2007-06-24 21:19:22 +04:00
}
2012-10-14 23:58:59 +04:00
static VALUE
vm_search_const_defined_class ( const VALUE cbase , ID id )
2009-02-22 04:43:59 +03:00
{
2012-10-14 23:58:59 +04:00
if ( rb_const_defined_at ( cbase , id ) ) return cbase ;
if ( cbase = = rb_cObject ) {
VALUE tmp = RCLASS_SUPER ( cbase ) ;
while ( tmp ) {
if ( rb_const_defined_at ( tmp , id ) ) return tmp ;
tmp = RCLASS_SUPER ( tmp ) ;
}
}
return 0 ;
2007-06-24 21:19:22 +04:00
}
2012-10-14 23:58:59 +04:00
# ifndef USE_IC_FOR_IVAR
# define USE_IC_FOR_IVAR 1
# endif
2012-10-16 21:07:23 +04:00
static inline VALUE
vm_getivar ( VALUE obj , ID id , IC ic , rb_call_info_t * ci , int is_attr )
2007-06-24 21:19:22 +04:00
{
2012-10-14 23:58:59 +04:00
# if USE_IC_FOR_IVAR
if ( RB_TYPE_P ( obj , T_OBJECT ) ) {
VALUE val = Qundef ;
VALUE klass = RBASIC ( obj ) - > klass ;
2007-06-24 21:19:22 +04:00
2012-10-16 21:07:23 +04:00
if ( LIKELY ( ( ! is_attr & & ( ic - > ic_class = = klass & & ic - > ic_vmstat = = GET_VM_STATE_VERSION ( ) ) ) | |
( is_attr & & ci - > aux . index > 0 ) ) ) {
2012-10-17 11:24:52 +04:00
long index = ! is_attr ? ic - > ic_value . index : ci - > aux . index - 1 ;
2012-10-14 23:58:59 +04:00
long len = ROBJECT_NUMIV ( obj ) ;
VALUE * ptr = ROBJECT_IVPTR ( obj ) ;
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
if ( index < len ) {
val = ptr [ index ] ;
2007-08-06 15:36:30 +04:00
}
}
else {
2012-10-14 23:58:59 +04:00
st_data_t index ;
long len = ROBJECT_NUMIV ( obj ) ;
VALUE * ptr = ROBJECT_IVPTR ( obj ) ;
struct st_table * iv_index_tbl = ROBJECT_IV_INDEX_TBL ( obj ) ;
2007-08-06 15:36:30 +04:00
2012-10-14 23:58:59 +04:00
if ( iv_index_tbl ) {
if ( st_lookup ( iv_index_tbl , id , & index ) ) {
if ( ( long ) index < len ) {
val = ptr [ index ] ;
}
2012-10-16 21:07:23 +04:00
if ( ! is_attr ) {
ic - > ic_class = klass ;
ic - > ic_value . index = index ;
ic - > ic_vmstat = GET_VM_STATE_VERSION ( ) ;
}
else { /* call_info */
2012-10-17 11:24:52 +04:00
ci - > aux . index = index + 1 ;
2012-10-16 21:07:23 +04:00
}
2012-10-14 23:58:59 +04:00
}
}
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
}
2012-10-16 21:07:23 +04:00
2012-10-14 23:58:59 +04:00
if ( UNLIKELY ( val = = Qundef ) ) {
2012-10-16 21:07:23 +04:00
if ( ! is_attr ) rb_warning ( " instance variable %s not initialized " , rb_id2name ( id ) ) ;
2012-10-14 23:58:59 +04:00
val = Qnil ;
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
}
2012-10-14 23:58:59 +04:00
return val ;
}
2012-12-12 08:39:48 +04:00
# endif /* USE_IC_FOR_IVAR */
2012-12-12 08:40:55 +04:00
if ( is_attr )
return rb_attr_get ( obj , id ) ;
2012-10-14 23:58:59 +04:00
return rb_ivar_get ( obj , id ) ;
2010-09-23 04:01:40 +04:00
}
2013-02-06 21:31:22 +04:00
static inline VALUE
2012-10-16 21:07:23 +04:00
vm_setivar ( VALUE obj , ID id , VALUE val , IC ic , rb_call_info_t * ci , int is_attr )
2010-09-23 04:01:40 +04:00
{
2012-10-14 23:58:59 +04:00
# if USE_IC_FOR_IVAR
if ( ! OBJ_UNTRUSTED ( obj ) & & rb_safe_level ( ) > = 4 ) {
rb_raise ( rb_eSecurityError , " Insecure: can't modify instance variable " ) ;
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
}
2012-10-14 23:58:59 +04:00
rb_check_frozen ( obj ) ;
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 04:20:28 +04:00
2012-10-14 23:58:59 +04:00
if ( RB_TYPE_P ( obj , T_OBJECT ) ) {
VALUE klass = RBASIC ( obj ) - > klass ;
st_data_t index ;
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 04:20:28 +04:00
2012-10-16 21:07:23 +04:00
if ( LIKELY (
( ! is_attr & & ic - > ic_class = = klass & & ic - > ic_vmstat = = GET_VM_STATE_VERSION ( ) ) | |
( is_attr & & ci - > aux . index > 0 ) ) ) {
long index = ! is_attr ? ic - > ic_value . index : ci - > aux . index - 1 ;
2012-10-14 23:58:59 +04:00
long len = ROBJECT_NUMIV ( obj ) ;
VALUE * ptr = ROBJECT_IVPTR ( obj ) ;
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 04:20:28 +04:00
2012-10-14 23:58:59 +04:00
if ( index < len ) {
ptr [ index ] = val ;
2013-02-06 21:31:22 +04:00
return val ; /* inline cache hit */
2012-10-14 23:58:59 +04:00
}
}
else {
struct st_table * iv_index_tbl = ROBJECT_IV_INDEX_TBL ( obj ) ;
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 04:20:28 +04:00
2012-10-14 23:58:59 +04:00
if ( iv_index_tbl & & st_lookup ( iv_index_tbl , ( st_data_t ) id , & index ) ) {
2012-10-16 21:07:23 +04:00
if ( ! is_attr ) {
ic - > ic_class = klass ;
ic - > ic_value . index = index ;
ic - > ic_vmstat = GET_VM_STATE_VERSION ( ) ;
}
else {
ci - > aux . index = index + 1 ;
}
2012-10-14 23:58:59 +04:00
}
/* fall through */
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 04:20:28 +04:00
}
}
2012-12-12 08:39:48 +04:00
# endif /* USE_IC_FOR_IVAR */
2013-02-06 21:31:22 +04:00
return rb_ivar_set ( obj , id , val ) ;
* common.mk: clean up
- remove blockinlining.$(OBJEXT) to built
- make ENCODING_H_INCLDUES variable (include/ruby/encoding.h)
- make VM_CORE_H_INCLUDES variable (vm_core.h)
- simplify rules.
- make depends rule to output depend status using gcc -MM.
* include/ruby/mvm.h, include/ruby/vm.h: rename mvm.h to vm.h.
* include/ruby.h: ditto.
* load.c: add inclusion explicitly.
* enumerator.c, object.c, parse.y, thread.c, vm_dump.c:
remove useless inclusion.
* eval_intern.h: cleanup inclusion.
* vm_core.h: rb_thread_t should be defined in this file.
* vm_evalbody.c, vm_exec.c: rename vm_evalbody.c to vm_exec.c.
* vm.h, vm_exec.h: rename vm.h to vm_exec.h.
* insnhelper.h, vm_insnhelper.h: rename insnhelper.h to vm_insnhelper.h.
* vm.c, vm_insnhelper.c, vm_insnhelper.h:
- rename vm_eval() to vm_exec_core().
- rename vm_eval_body() to vm_exec().
- cleanup include order.
* vm_method.c: fix comment.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19466 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-09-23 04:20:28 +04:00
}
* vm.c, insns.def, eval.c, vm_insnhelper.c: fix CREF handling.
VM value stack frame of block contains cref information.
(dfp[-1] points CREF)
* compile.c, eval_intern.h, eval_method.c, load.c, proc.c,
vm_dump.h, vm_core.h: ditto.
* include/ruby/ruby.h, gc.c: remove T_VALUES because of above
changes.
* bootstraptest/test_eval.rb, test_knownbug.rb: move solved test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16468 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2008-05-19 07:08:50 +04:00
2012-10-16 21:07:23 +04:00
static VALUE
vm_getinstancevariable ( VALUE obj , ID id , IC ic )
{
return vm_getivar ( obj , id , ic , 0 , 0 ) ;
}
static void
vm_setinstancevariable ( VALUE obj , ID id , VALUE val , IC ic )
{
vm_setivar ( obj , id , val , ic , 0 , 0 ) ;
}
2012-10-14 23:58:59 +04:00
static VALUE
vm_throw ( rb_thread_t * th , rb_control_frame_t * reg_cfp ,
rb_num_t throw_state , VALUE throwobj )
2009-12-03 21:25:57 +03:00
{
2012-10-14 23:58:59 +04:00
int state = ( int ) ( throw_state & 0xff ) ;
int flag = ( int ) ( throw_state & 0x8000 ) ;
rb_num_t level = throw_state > > 16 ;
2009-12-03 21:25:57 +03:00
2012-10-14 23:58:59 +04:00
if ( state ! = 0 ) {
VALUE * pt = 0 ;
if ( flag ! = 0 ) {
pt = ( void * ) 1 ;
2009-12-03 21:25:57 +03:00
}
2012-10-14 23:58:59 +04:00
else {
if ( state = = TAG_BREAK ) {
rb_control_frame_t * cfp = GET_CFP ( ) ;
VALUE * ep = GET_EP ( ) ;
int is_orphan = 1 ;
rb_iseq_t * base_iseq = GET_ISEQ ( ) ;
2009-12-03 21:25:57 +03:00
2012-10-14 23:58:59 +04:00
search_parent :
if ( cfp - > iseq - > type ! = ISEQ_TYPE_BLOCK ) {
if ( cfp - > iseq - > type = = ISEQ_TYPE_CLASS ) {
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( cfp ) ;
ep = cfp - > ep ;
goto search_parent ;
}
ep = VM_EP_PREV_EP ( ep ) ;
base_iseq = base_iseq - > parent_iseq ;
2009-12-03 21:25:57 +03:00
2012-10-14 23:58:59 +04:00
while ( ( VALUE * ) cfp < th - > stack + th - > stack_size ) {
if ( cfp - > ep = = ep ) {
goto search_parent ;
}
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( cfp ) ;
}
rb_bug ( " VM (throw): can't find break base. " ) ;
}
2008-04-03 14:59:44 +04:00
2012-10-14 23:58:59 +04:00
if ( VM_FRAME_TYPE ( cfp ) = = VM_FRAME_MAGIC_LAMBDA ) {
/* lambda{... break ...} */
is_orphan = 0 ;
pt = cfp - > ep ;
state = TAG_RETURN ;
}
else {
ep = VM_EP_PREV_EP ( ep ) ;
2012-08-02 15:34:19 +04:00
2012-10-14 23:58:59 +04:00
while ( ( VALUE * ) cfp < th - > stack + th - > stack_size ) {
if ( cfp - > ep = = ep ) {
VALUE epc = cfp - > pc - cfp - > iseq - > iseq_encoded ;
rb_iseq_t * iseq = cfp - > iseq ;
int i ;
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
for ( i = 0 ; i < iseq - > catch_table_size ; i + + ) {
struct iseq_catch_table_entry * entry = & iseq - > catch_table [ i ] ;
if ( entry - > type = = CATCH_TYPE_BREAK & &
entry - > start < epc & & entry - > end > = epc ) {
if ( entry - > cont = = epc ) {
goto found ;
}
else {
break ;
}
}
}
break ;
found :
pt = ep ;
is_orphan = 0 ;
break ;
}
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( cfp ) ;
}
}
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
if ( is_orphan ) {
rb_vm_localjump_error ( " break from proc-closure " , throwobj , TAG_BREAK ) ;
}
2011-03-31 13:07:42 +04:00
}
2012-10-14 23:58:59 +04:00
else if ( state = = TAG_RETRY ) {
rb_num_t i ;
pt = VM_EP_PREV_EP ( GET_EP ( ) ) ;
for ( i = 0 ; i < level ; i + + ) {
pt = GC_GUARDED_PTR_REF ( ( VALUE * ) * pt ) ;
}
2011-03-31 13:07:42 +04:00
}
2012-10-14 23:58:59 +04:00
else if ( state = = TAG_RETURN ) {
rb_control_frame_t * cfp = GET_CFP ( ) ;
VALUE * ep = GET_EP ( ) ;
VALUE * target_lep = VM_CF_LEP ( cfp ) ;
int in_class_frame = 0 ;
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
/* check orphan and get dfp */
while ( ( VALUE * ) cfp < th - > stack + th - > stack_size ) {
VALUE * lep = VM_CF_LEP ( cfp ) ;
if ( ! target_lep ) {
target_lep = lep ;
2007-06-24 21:19:22 +04:00
}
2012-10-14 23:58:59 +04:00
if ( lep = = target_lep & & cfp - > iseq - > type = = ISEQ_TYPE_CLASS ) {
in_class_frame = 1 ;
target_lep = 0 ;
}
if ( lep = = target_lep ) {
if ( VM_FRAME_TYPE ( cfp ) = = VM_FRAME_MAGIC_LAMBDA ) {
VALUE * tep = ep ;
if ( in_class_frame ) {
/* lambda {class A; ... return ...; end} */
ep = cfp - > ep ;
goto valid_return ;
}
while ( target_lep ! = tep ) {
if ( cfp - > ep = = tep ) {
/* in lambda */
ep = cfp - > ep ;
goto valid_return ;
}
tep = VM_EP_PREV_EP ( tep ) ;
}
2008-05-19 22:47:56 +04:00
}
2007-06-24 21:19:22 +04:00
}
2012-10-14 23:58:59 +04:00
if ( cfp - > ep = = target_lep & & cfp - > iseq - > type = = ISEQ_TYPE_METHOD ) {
ep = target_lep ;
goto valid_return ;
}
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( cfp ) ;
2007-06-24 21:19:22 +04:00
}
2008-05-19 22:47:56 +04:00
2012-10-14 23:58:59 +04:00
rb_vm_localjump_error ( " unexpected return " , throwobj , TAG_RETURN ) ;
2008-05-19 22:47:56 +04:00
2012-10-14 23:58:59 +04:00
valid_return :
pt = ep ;
}
else {
rb_bug ( " isns(throw): unsupport throw type " ) ;
}
2007-06-24 21:19:22 +04:00
}
2012-10-14 23:58:59 +04:00
th - > state = state ;
return ( VALUE ) NEW_THROW_OBJECT ( throwobj , ( VALUE ) pt , state ) ;
2007-06-24 21:19:22 +04:00
}
else {
2012-10-14 23:58:59 +04:00
/* continue throw */
VALUE err = throwobj ;
if ( FIXNUM_P ( err ) ) {
th - > state = FIX2INT ( err ) ;
}
else if ( SYMBOL_P ( err ) ) {
th - > state = TAG_THROW ;
}
else if ( BUILTIN_TYPE ( err ) = = T_NODE ) {
th - > state = GET_THROWOBJ_STATE ( err ) ;
2007-06-24 21:19:22 +04:00
}
else {
2012-10-14 23:58:59 +04:00
th - > state = TAG_RAISE ;
/*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/
2007-06-24 21:19:22 +04:00
}
2012-10-14 23:58:59 +04:00
return err ;
2007-06-24 21:19:22 +04:00
}
}
2012-10-14 23:58:59 +04:00
static inline void
vm_expandarray ( rb_control_frame_t * cfp , VALUE ary , rb_num_t num , int flag )
2007-06-24 21:19:22 +04:00
{
2012-10-14 23:58:59 +04:00
int is_splat = flag & 0x01 ;
rb_num_t space_size = num + is_splat ;
VALUE * base = cfp - > sp , * ptr ;
rb_num_t len ;
2008-05-19 22:47:56 +04:00
2012-10-14 23:58:59 +04:00
if ( ! RB_TYPE_P ( ary , T_ARRAY ) ) {
ary = rb_ary_to_ary ( ary ) ;
2011-09-20 13:09:00 +04:00
}
2012-10-14 23:58:59 +04:00
cfp - > sp + = space_size ;
2008-05-19 22:47:56 +04:00
2012-10-14 23:58:59 +04:00
ptr = RARRAY_PTR ( ary ) ;
len = ( rb_num_t ) RARRAY_LEN ( ary ) ;
2008-05-19 22:47:56 +04:00
2012-10-14 23:58:59 +04:00
if ( flag & 0x02 ) {
/* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */
rb_num_t i = 0 , j ;
if ( len < num ) {
for ( i = 0 ; i < num - len ; i + + ) {
* base + + = Qnil ;
}
}
for ( j = 0 ; i < num ; i + + , j + + ) {
VALUE v = ptr [ len - j - 1 ] ;
* base + + = v ;
}
if ( is_splat ) {
* base = rb_ary_new4 ( len - j , ptr ) ;
}
2007-06-24 21:19:22 +04:00
}
2012-10-14 23:58:59 +04:00
else {
/* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */
rb_num_t i ;
VALUE * bptr = & base [ space_size - 1 ] ;
2007-06-24 21:19:22 +04:00
2012-10-14 23:58:59 +04:00
for ( i = 0 ; i < num ; i + + ) {
if ( len < = i ) {
for ( ; i < num ; i + + ) {
* bptr - - = Qnil ;
}
break ;
}
* bptr - - = ptr [ i ] ;
}
if ( is_splat ) {
if ( num > len ) {
* bptr = rb_ary_new ( ) ;
}
else {
* bptr = rb_ary_new4 ( len - num , ptr + num ) ;
}
2011-09-02 09:36:49 +04:00
}
2011-09-01 12:31:24 +04:00
}
2012-10-14 23:58:59 +04:00
RB_GC_GUARD ( ary ) ;
2011-09-01 12:31:24 +04:00
}
2009-09-06 11:40:24 +04:00
2012-10-14 23:58:59 +04:00
static VALUE vm_call_general ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci ) ;
2009-09-06 11:40:24 +04:00
2012-10-14 23:58:59 +04:00
static void
vm_search_method ( rb_call_info_t * ci , VALUE recv )
2009-07-13 08:44:20 +04:00
{
2012-10-14 23:58:59 +04:00
VALUE klass = CLASS_OF ( recv ) ;
2009-07-13 08:44:20 +04:00
2012-10-14 23:58:59 +04:00
# if OPT_INLINE_METHOD_CACHE
2012-11-12 11:00:12 +04:00
if ( LIKELY ( GET_VM_STATE_VERSION ( ) = = ci - > vmstat & & klass = = ci - > klass ) ) {
2012-10-14 23:58:59 +04:00
/* cache hit! */
2009-07-13 08:44:20 +04:00
}
else {
2012-11-12 11:00:12 +04:00
ci - > me = rb_method_entry ( klass , ci - > mid , & ci - > defined_class ) ;
2012-10-14 23:58:59 +04:00
ci - > klass = klass ;
ci - > vmstat = GET_VM_STATE_VERSION ( ) ;
ci - > call = vm_call_general ;
2009-07-13 08:44:20 +04:00
}
# else
2012-11-12 11:00:12 +04:00
ci - > me = rb_method_entry ( klass , ci - > mid , & ci - > defined_class ) ;
2012-10-14 23:58:59 +04:00
ci - > call = vm_call_general ;
ci - > klass = klass ;
2009-07-13 08:44:20 +04:00
# endif
}
2012-10-14 23:58:59 +04:00
static inline int
check_cfunc ( const rb_method_entry_t * me , VALUE ( * func ) ( ) )
2009-09-06 11:40:24 +04:00
{
2012-10-14 23:58:59 +04:00
if ( me & & me - > def - > type = = VM_METHOD_TYPE_CFUNC & &
me - > def - > body . cfunc . func = = func ) {
return 1 ;
2009-09-06 11:40:24 +04:00
}
2012-10-14 23:58:59 +04:00
else {
return 0 ;
}
}
* array.c, gc.c, hash.c, object.c, string.c, struct.c,
transcode.c, variable.c, vm.c, vm_insnhelper.c, vm_method.c:
replace calls to rb_error_frozen() with rb_check_frozen(). a
patch from Run Paint Run Run at [ruby-core:32014]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29583 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2010-10-24 12:14:05 +04:00
2012-10-14 23:58:59 +04:00
static
# ifndef NO_BIG_INLINE
inline
# endif
VALUE
opt_eq_func ( VALUE recv , VALUE obj , CALL_INFO ci )
{
if ( FIXNUM_2_P ( recv , obj ) & &
BASIC_OP_UNREDEFINED_P ( BOP_EQ , FIXNUM_REDEFINED_OP_FLAG ) ) {
return ( recv = = obj ) ? Qtrue : Qfalse ;
}
else if ( FLONUM_2_P ( recv , obj ) & &
BASIC_OP_UNREDEFINED_P ( BOP_EQ , FLOAT_REDEFINED_OP_FLAG ) ) {
return ( recv = = obj ) ? Qtrue : Qfalse ;
}
else if ( ! SPECIAL_CONST_P ( recv ) & & ! SPECIAL_CONST_P ( obj ) ) {
if ( HEAP_CLASS_OF ( recv ) = = rb_cFloat & &
HEAP_CLASS_OF ( obj ) = = rb_cFloat & &
BASIC_OP_UNREDEFINED_P ( BOP_EQ , FLOAT_REDEFINED_OP_FLAG ) ) {
double a = RFLOAT_VALUE ( recv ) ;
double b = RFLOAT_VALUE ( obj ) ;
2009-09-06 11:40:24 +04:00
2012-10-14 23:58:59 +04:00
if ( isnan ( a ) | | isnan ( b ) ) {
return Qfalse ;
2009-09-06 11:40:24 +04:00
}
2012-10-14 23:58:59 +04:00
return ( a = = b ) ? Qtrue : Qfalse ;
2009-09-06 11:40:24 +04:00
}
2012-10-14 23:58:59 +04:00
else if ( HEAP_CLASS_OF ( recv ) = = rb_cString & &
HEAP_CLASS_OF ( obj ) = = rb_cString & &
BASIC_OP_UNREDEFINED_P ( BOP_EQ , STRING_REDEFINED_OP_FLAG ) ) {
return rb_str_equal ( recv , obj ) ;
}
}
2009-09-06 11:40:24 +04:00
2012-10-14 23:58:59 +04:00
{
vm_search_method ( ci , recv ) ;
if ( check_cfunc ( ci - > me , rb_obj_equal ) ) {
return recv = = obj ? Qtrue : Qfalse ;
2009-09-06 11:40:24 +04:00
}
}
2012-10-14 23:58:59 +04:00
return Qundef ;
2009-09-06 11:40:24 +04:00
}
2012-10-14 23:58:59 +04:00
static VALUE
check_match ( VALUE pattern , VALUE target , enum vm_check_match_type type )
{
switch ( type ) {
case VM_CHECKMATCH_TYPE_WHEN :
return pattern ;
case VM_CHECKMATCH_TYPE_CASE :
return rb_funcall2 ( pattern , idEqq , 1 , & target ) ;
case VM_CHECKMATCH_TYPE_RESCUE : {
if ( ! rb_obj_is_kind_of ( pattern , rb_cModule ) ) {
rb_raise ( rb_eTypeError , " class or module required for rescue clause " ) ;
}
return RTEST ( rb_funcall2 ( pattern , idEqq , 1 , & target ) ) ;
}
default :
rb_bug ( " check_match: unreachable " ) ;
}
}
2007-08-06 15:36:30 +04:00
2012-10-14 23:58:59 +04:00
# if defined(_MSC_VER) && _MSC_VER < 1300
# define CHECK_CMP_NAN(a, b) if (isnan(a) || isnan(b)) return Qfalse;
# else
# define CHECK_CMP_NAN(a, b) /* do nothing */
# endif
2007-08-06 15:36:30 +04:00
2012-10-14 23:58:59 +04:00
static inline VALUE
double_cmp_lt ( double a , double b )
{
CHECK_CMP_NAN ( a , b ) ;
return a < b ? Qtrue : Qfalse ;
}
2007-08-06 15:36:30 +04:00
2012-10-14 23:58:59 +04:00
static inline VALUE
double_cmp_le ( double a , double b )
{
CHECK_CMP_NAN ( a , b ) ;
return a < = b ? Qtrue : Qfalse ;
}
2007-08-06 15:36:30 +04:00
2012-10-14 23:58:59 +04:00
static inline VALUE
double_cmp_gt ( double a , double b )
{
CHECK_CMP_NAN ( a , b ) ;
return a > b ? Qtrue : Qfalse ;
}
2012-06-11 07:14:59 +04:00
2012-10-14 23:58:59 +04:00
static inline VALUE
double_cmp_ge ( double a , double b )
{
CHECK_CMP_NAN ( a , b ) ;
return a > = b ? Qtrue : Qfalse ;
}
2012-06-11 07:14:59 +04:00
2012-10-14 23:58:59 +04:00
static VALUE *
vm_base_ptr ( rb_control_frame_t * cfp )
{
rb_control_frame_t * prev_cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( cfp ) ;
VALUE * bp = prev_cfp - > sp + cfp - > iseq - > local_size + 1 ;
2010-05-09 22:21:39 +04:00
2012-10-14 23:58:59 +04:00
if ( cfp - > iseq - > type = = ISEQ_TYPE_METHOD ) {
/* adjust `self' */
bp + = 1 ;
}
2008-06-17 23:27:24 +04:00
2012-10-14 23:58:59 +04:00
# if VM_DEBUG_BP_CHECK
if ( bp ! = cfp - > bp_check ) {
fprintf ( stderr , " bp_check: %ld, bp: %ld \n " ,
( long ) ( cfp - > bp_check - GET_THREAD ( ) - > stack ) ,
( long ) ( bp - GET_THREAD ( ) - > stack ) ) ;
rb_bug ( " vm_base_ptr: unreachable " ) ;
}
# endif
2011-07-10 13:04:44 +04:00
2012-10-14 23:58:59 +04:00
return bp ;
}
2008-06-17 23:27:24 +04:00
2012-10-14 23:58:59 +04:00
/* method call processes with call_info */
2008-06-17 23:27:24 +04:00
2012-10-14 23:58:59 +04:00
static void
vm_caller_setup_args ( const rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci )
{
2012-11-13 12:34:43 +04:00
# define SAVE_RESTORE_CI(expr, ci) do { \
int saved_argc = ( ci ) - > argc ; rb_block_t * saved_blockptr = ( ci ) - > blockptr ; /* save */ \
expr ; \
( ci ) - > argc = saved_argc ; ( ci ) - > blockptr = saved_blockptr ; /* restore */ \
} while ( 0 )
2012-10-15 21:22:57 +04:00
if ( UNLIKELY ( ci - > flag & VM_CALL_ARGS_BLOCKARG ) ) {
2012-10-14 23:58:59 +04:00
rb_proc_t * po ;
VALUE proc ;
2007-08-06 15:36:30 +04:00
2012-10-14 23:58:59 +04:00
proc = * ( - - cfp - > sp ) ;
2007-08-06 15:36:30 +04:00
2012-10-14 23:58:59 +04:00
if ( proc ! = Qnil ) {
if ( ! rb_obj_is_proc ( proc ) ) {
2012-11-13 12:34:43 +04:00
VALUE b ;
SAVE_RESTORE_CI ( b = rb_check_convert_type ( proc , T_DATA , " Proc " , " to_proc " ) , ci ) ;
2012-10-14 23:58:59 +04:00
if ( NIL_P ( b ) | | ! rb_obj_is_proc ( b ) ) {
rb_raise ( rb_eTypeError ,
" wrong argument type %s (expected Proc) " ,
rb_obj_classname ( proc ) ) ;
}
proc = b ;
2007-08-06 15:36:30 +04:00
}
2012-10-14 23:58:59 +04:00
GetProcPtr ( proc , po ) ;
ci - > blockptr = & po - > block ;
RUBY_VM_GET_BLOCK_PTR_IN_CFP ( cfp ) - > proc = proc ;
2007-08-06 15:36:30 +04:00
}
}
2012-10-18 13:41:55 +04:00
else if ( ci - > blockiseq ! = 0 ) { /* likely */
2012-10-14 23:58:59 +04:00
ci - > blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP ( cfp ) ;
ci - > blockptr - > iseq = ci - > blockiseq ;
ci - > blockptr - > proc = 0 ;
}
2007-08-06 15:36:30 +04:00
2012-10-14 23:58:59 +04:00
/* expand top of stack? */
2012-10-15 21:22:57 +04:00
if ( UNLIKELY ( ci - > flag & VM_CALL_ARGS_SPLAT ) ) {
2012-10-14 23:58:59 +04:00
VALUE ary = * ( cfp - > sp - 1 ) ;
VALUE * ptr ;
int i ;
2012-11-13 12:34:43 +04:00
VALUE tmp ;
SAVE_RESTORE_CI ( tmp = rb_check_convert_type ( ary , T_ARRAY , " Array " , " to_a " ) , ci ) ;
2012-10-14 23:58:59 +04:00
if ( NIL_P ( tmp ) ) {
/* do nothing */
2007-08-06 15:36:30 +04:00
}
else {
2012-10-14 23:58:59 +04:00
long len = RARRAY_LEN ( tmp ) ;
ptr = RARRAY_PTR ( tmp ) ;
cfp - > sp - = 1 ;
2012-12-25 13:57:07 +04:00
CHECK_VM_STACK_OVERFLOW ( cfp , len ) ;
2012-10-14 23:58:59 +04:00
for ( i = 0 ; i < len ; i + + ) {
* cfp - > sp + + = ptr [ i ] ;
}
ci - > argc + = i - 1 ;
2007-08-06 15:36:30 +04:00
}
}
}
2012-12-30 06:06:28 +04:00
static inline int
2013-01-07 07:09:28 +04:00
vm_callee_setup_keyword_arg ( const rb_iseq_t * iseq , int argc , VALUE * orig_argv , VALUE * kwd )
2012-12-30 06:06:28 +04:00
{
2013-01-07 07:09:28 +04:00
VALUE keyword_hash ;
2012-12-30 06:06:28 +04:00
int i , j ;
2013-01-07 07:09:28 +04:00
if ( argc > 0 & &
! NIL_P ( keyword_hash = rb_check_hash_type ( orig_argv [ argc - 1 ] ) ) ) {
2012-12-30 06:06:28 +04:00
argc - - ;
keyword_hash = rb_hash_dup ( keyword_hash ) ;
if ( iseq - > arg_keyword_check ) {
for ( i = j = 0 ; i < iseq - > arg_keywords ; i + + ) {
if ( st_lookup ( RHASH_TBL ( keyword_hash ) , ID2SYM ( iseq - > arg_keyword_table [ i ] ) , 0 ) ) j + + ;
}
if ( RHASH_TBL ( keyword_hash ) - > num_entries > ( unsigned int ) j ) {
unknown_keyword_error ( iseq , keyword_hash ) ;
}
}
}
else {
keyword_hash = rb_hash_new ( ) ;
}
2013-01-07 07:09:28 +04:00
* kwd = keyword_hash ;
2012-12-30 06:06:28 +04:00
return argc ;
}
2012-10-18 10:14:39 +04:00
static inline int
2012-10-14 23:58:59 +04:00
vm_callee_setup_arg_complex ( rb_thread_t * th , rb_call_info_t * ci , const rb_iseq_t * iseq , VALUE * orig_argv )
{
const int m = iseq - > argc ;
const int opts = iseq - > arg_opts - ( iseq - > arg_opts > 0 ) ;
const int min = m + iseq - > arg_post_len ;
const int max = ( iseq - > arg_rest = = - 1 ) ? m + opts + iseq - > arg_post_len : UNLIMITED_ARGUMENTS ;
const int orig_argc = ci - > argc ;
int argc = orig_argc ;
VALUE * argv = orig_argv ;
2013-01-07 07:09:28 +04:00
VALUE keyword_hash = Qnil ;
2012-10-15 04:57:37 +04:00
rb_num_t opt_pc = 0 ;
2007-08-23 11:10:56 +04:00
2012-10-14 23:58:59 +04:00
th - > mark_stack_len = argc + iseq - > arg_size ;
2007-08-23 11:10:56 +04:00
2012-12-30 06:06:28 +04:00
/* keyword argument */
2012-10-14 23:58:59 +04:00
if ( iseq - > arg_keyword ! = - 1 ) {
2013-01-07 07:09:28 +04:00
argc = vm_callee_setup_keyword_arg ( iseq , argc , orig_argv , & keyword_hash ) ;
2012-10-14 23:58:59 +04:00
}
/* mandatory */
if ( ( argc < min ) | | ( argc > max & & max ! = UNLIMITED_ARGUMENTS ) ) {
argument_error ( iseq , argc , min , max ) ;
}
argv + = m ;
argc - = m ;
/* post arguments */
if ( iseq - > arg_post_len ) {
if ( ! ( orig_argc < iseq - > arg_post_start ) ) {
VALUE * new_argv = ALLOCA_N ( VALUE , argc ) ;
MEMCPY ( new_argv , argv , VALUE , argc ) ;
argv = new_argv ;
2007-08-23 11:10:56 +04:00
}
2012-10-14 23:58:59 +04:00
MEMCPY ( & orig_argv [ iseq - > arg_post_start ] , & argv [ argc - = iseq - > arg_post_len ] ,
VALUE , iseq - > arg_post_len ) ;
2007-08-23 11:10:56 +04:00
}
2012-10-14 23:58:59 +04:00
/* opt arguments */
if ( iseq - > arg_opts ) {
if ( argc > opts ) {
argc - = opts ;
argv + = opts ;
opt_pc = iseq - > arg_opt_table [ opts ] ; /* no opt */
2007-08-23 11:10:56 +04:00
}
2012-10-14 23:58:59 +04:00
else {
int i ;
for ( i = argc ; i < opts ; i + + ) {
orig_argv [ i + m ] = Qnil ;
2007-08-23 11:10:56 +04:00
}
2012-10-14 23:58:59 +04:00
opt_pc = iseq - > arg_opt_table [ argc ] ;
argc = 0 ;
2007-08-23 11:10:56 +04:00
}
}
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-14 23:58:59 +04:00
/* rest arguments */
if ( iseq - > arg_rest ! = - 1 ) {
orig_argv [ iseq - > arg_rest ] = rb_ary_new4 ( argc , argv ) ;
argc = 0 ;
}
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2013-01-07 07:09:28 +04:00
/* keyword argument */
if ( iseq - > arg_keyword ! = - 1 ) {
orig_argv [ iseq - > arg_keyword ] = keyword_hash ;
}
2012-10-14 23:58:59 +04:00
/* block arguments */
if ( iseq - > arg_block ! = - 1 ) {
VALUE blockval = Qnil ;
const rb_block_t * blockptr = ci - > blockptr ;
if ( blockptr ) {
/* make Proc object */
if ( blockptr - > proc = = 0 ) {
rb_proc_t * proc ;
blockval = rb_vm_make_proc ( th , blockptr , rb_cProc ) ;
GetProcPtr ( blockval , proc ) ;
ci - > blockptr = & proc - > block ;
}
else {
blockval = blockptr - > proc ;
}
}
orig_argv [ iseq - > arg_block ] = blockval ; /* Proc or nil */
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
2012-10-14 23:58:59 +04:00
th - > mark_stack_len = 0 ;
return ( int ) opt_pc ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
2012-10-14 23:58:59 +04:00
static VALUE vm_call_iseq_setup_2 ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci ) ;
2012-10-24 13:48:32 +04:00
static inline VALUE vm_call_iseq_setup_normal ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci ) ;
static inline VALUE vm_call_iseq_setup_tailcall ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci ) ;
2012-10-14 23:58:59 +04:00
2012-10-15 04:44:04 +04:00
# define VM_CALLEE_SETUP_ARG(th, ci, iseq, argv, is_lambda) \
2012-10-15 00:59:21 +04:00
if ( LIKELY ( ( iseq ) - > arg_simple & 0x01 ) ) { \
/* simple check */ \
if ( ( ci ) - > argc ! = ( iseq ) - > argc ) { \
argument_error ( ( iseq ) , ( ( ci ) - > argc ) , ( iseq ) - > argc , ( iseq ) - > argc ) ; \
} \
2012-10-16 21:07:23 +04:00
( ci ) - > aux . opt_pc = 0 ; \
2012-10-17 01:20:11 +04:00
CI_SET_FASTPATH ( ( ci ) , UNLIKELY ( ( ci ) - > flag & VM_CALL_TAILCALL ) ? vm_call_iseq_setup_tailcall : vm_call_iseq_setup_normal , ! ( is_lambda ) & & ! ( ( ci ) - > me - > flag & NOEX_PROTECTED ) ) ; \
2012-10-15 00:59:21 +04:00
} \
else { \
2012-10-16 21:07:23 +04:00
( ci ) - > aux . opt_pc = vm_callee_setup_arg_complex ( ( th ) , ( ci ) , ( iseq ) , ( argv ) ) ; \
2012-10-15 00:59:21 +04:00
}
2012-10-14 23:58:59 +04:00
static VALUE
vm_call_iseq_setup ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci )
2007-12-18 15:07:51 +03:00
{
2012-10-15 04:44:04 +04:00
VM_CALLEE_SETUP_ARG ( th , ci , ci - > me - > def - > body . iseq , cfp - > sp - ci - > argc , 0 ) ;
2012-10-14 23:58:59 +04:00
return vm_call_iseq_setup_2 ( th , cfp , ci ) ;
2007-12-18 15:07:51 +03:00
}
2012-10-14 23:58:59 +04:00
static VALUE
vm_call_iseq_setup_2 ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci )
2012-10-17 01:20:11 +04:00
{
if ( LIKELY ( ! ( ci - > flag & VM_CALL_TAILCALL ) ) ) {
return vm_call_iseq_setup_normal ( th , cfp , ci ) ;
}
else {
return vm_call_iseq_setup_tailcall ( th , cfp , ci ) ;
}
}
2012-10-18 10:14:39 +04:00
static inline VALUE
2012-10-17 01:20:11 +04:00
vm_call_iseq_setup_normal ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci )
2007-12-18 15:07:51 +03:00
{
2012-10-14 23:58:59 +04:00
int i ;
VALUE * argv = cfp - > sp - ci - > argc ;
rb_iseq_t * iseq = ci - > me - > def - > body . iseq ;
2012-10-17 01:20:11 +04:00
VALUE * sp = argv + iseq - > arg_size ;
2007-12-18 15:07:51 +03:00
2012-12-25 13:57:07 +04:00
CHECK_VM_STACK_OVERFLOW ( cfp , iseq - > stack_max ) ;
2012-10-14 23:58:59 +04:00
2012-10-17 01:20:11 +04:00
/* clear local variables */
for ( i = 0 ; i < iseq - > local_size - iseq - > arg_size ; i + + ) {
* sp + + = Qnil ;
}
2012-10-14 23:58:59 +04:00
2012-10-17 01:20:11 +04:00
vm_push_frame ( th , iseq , VM_FRAME_MAGIC_METHOD , ci - > recv , ci - > defined_class ,
VM_ENVVAL_BLOCK_PTR ( ci - > blockptr ) ,
iseq - > iseq_encoded + ci - > aux . opt_pc , sp , 0 , ci - > me ) ;
2012-10-14 23:58:59 +04:00
2012-10-17 01:20:11 +04:00
cfp - > sp = argv - 1 /* recv */ ;
return Qundef ;
}
2012-10-14 23:58:59 +04:00
2012-10-18 10:14:39 +04:00
static inline VALUE
2012-10-17 01:20:11 +04:00
vm_call_iseq_setup_tailcall ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci )
{
int i ;
VALUE * argv = cfp - > sp - ci - > argc ;
rb_iseq_t * iseq = ci - > me - > def - > body . iseq ;
VALUE * src_argv = argv ;
VALUE * sp_orig , * sp ;
VALUE finish_flag = VM_FRAME_TYPE_FINISH_P ( cfp ) ? VM_FRAME_FLAG_FINISH : 0 ;
2007-12-18 15:07:51 +03:00
2012-10-17 01:20:11 +04:00
cfp = th - > cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( th - > cfp ) ; /* pop cf */
2009-08-15 22:18:07 +04:00
2012-12-25 13:57:07 +04:00
CHECK_VM_STACK_OVERFLOW ( cfp , iseq - > stack_max ) ;
2012-10-17 01:20:11 +04:00
RUBY_VM_CHECK_INTS ( th ) ;
2012-10-14 23:58:59 +04:00
2012-10-17 01:20:11 +04:00
sp_orig = sp = cfp - > sp ;
2007-12-18 15:07:51 +03:00
2012-10-17 01:20:11 +04:00
/* push self */
sp [ 0 ] = ci - > recv ;
sp + + ;
2009-08-12 09:55:06 +04:00
2012-10-17 01:20:11 +04:00
/* copy arguments */
for ( i = 0 ; i < iseq - > arg_size ; i + + ) {
* sp + + = src_argv [ i ] ;
}
2012-08-02 15:34:19 +04:00
2012-10-17 01:20:11 +04:00
/* clear local variables */
for ( i = 0 ; i < iseq - > local_size - iseq - > arg_size ; i + + ) {
* sp + + = Qnil ;
2012-10-14 23:58:59 +04:00
}
2012-08-02 15:34:19 +04:00
2012-10-17 01:20:11 +04:00
vm_push_frame ( th , iseq , VM_FRAME_MAGIC_METHOD | finish_flag ,
ci - > recv , ci - > defined_class , VM_ENVVAL_BLOCK_PTR ( ci - > blockptr ) ,
iseq - > iseq_encoded + ci - > aux . opt_pc , sp , 0 , ci - > me ) ;
cfp - > sp = sp_orig ;
2012-10-14 23:58:59 +04:00
return Qundef ;
2012-08-02 15:34:19 +04:00
}
2012-10-19 14:38:30 +04:00
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_m2 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-08-02 15:34:19 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , rb_ary_new4 ( argc , argv ) ) ;
2012-10-19 14:38:30 +04:00
}
2012-08-02 15:34:19 +04:00
2012-10-19 14:38:30 +04:00
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_m1 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( argc , argv , recv ) ;
2012-10-19 14:38:30 +04:00
}
2012-10-14 23:58:59 +04:00
2012-10-19 14:38:30 +04:00
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_0 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_1 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_2 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_3 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_4 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_5 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_6 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] , argv [ 5 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_7 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] , argv [ 5 ] , argv [ 6 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_8 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] , argv [ 5 ] , argv [ 6 ] , argv [ 7 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_9 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] , argv [ 5 ] , argv [ 6 ] , argv [ 7 ] , argv [ 8 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_10 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] , argv [ 5 ] , argv [ 6 ] , argv [ 7 ] , argv [ 8 ] , argv [ 9 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_11 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] , argv [ 5 ] , argv [ 6 ] , argv [ 7 ] , argv [ 8 ] , argv [ 9 ] , argv [ 10 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_12 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] , argv [ 5 ] , argv [ 6 ] , argv [ 7 ] , argv [ 8 ] , argv [ 9 ] , argv [ 10 ] , argv [ 11 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_13 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] , argv [ 5 ] , argv [ 6 ] , argv [ 7 ] , argv [ 8 ] , argv [ 9 ] , argv [ 10 ] , argv [ 11 ] , argv [ 12 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_14 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] , argv [ 5 ] , argv [ 6 ] , argv [ 7 ] , argv [ 8 ] , argv [ 9 ] , argv [ 10 ] , argv [ 11 ] , argv [ 12 ] , argv [ 13 ] ) ;
2012-10-19 14:38:30 +04:00
}
static VALUE
2012-11-13 13:48:08 +04:00
call_cfunc_15 ( VALUE ( * func ) ( ANYARGS ) , VALUE recv , int argc , const VALUE * argv )
2012-10-19 14:38:30 +04:00
{
2012-11-13 13:48:08 +04:00
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] , argv [ 5 ] , argv [ 6 ] , argv [ 7 ] , argv [ 8 ] , argv [ 9 ] , argv [ 10 ] , argv [ 11 ] , argv [ 12 ] , argv [ 13 ] , argv [ 14 ] ) ;
2012-10-19 14:38:30 +04:00
}
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
# ifndef VM_PROFILE
# define VM_PROFILE 0
# endif
# if VM_PROFILE
static int vm_profile_counter [ 4 ] ;
# define VM_PROFILE_UP(x) (vm_profile_counter[x]++)
# define VM_PROFILE_ATEXIT() atexit(vm_profile_show_result)
2012-11-07 02:50:30 +04:00
static void vm_profile_show_result ( void )
{
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
fprintf ( stderr , " VM Profile results: \n " ) ;
fprintf ( stderr , " r->c call: %d \n " , vm_profile_counter [ 0 ] ) ;
fprintf ( stderr , " r->c popf: %d \n " , vm_profile_counter [ 1 ] ) ;
fprintf ( stderr , " c->c call: %d \n " , vm_profile_counter [ 2 ] ) ;
fprintf ( stderr , " r->c popf: %d \n " , vm_profile_counter [ 3 ] ) ;
2012-08-02 15:34:19 +04:00
}
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
# else
# define VM_PROFILE_UP(x)
# define VM_PROFILE_ATEXIT()
# endif
2012-08-02 15:34:19 +04:00
2012-08-08 11:52:19 +04:00
static VALUE
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
vm_call_cfunc_with_frame ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci )
2012-08-08 11:52:19 +04:00
{
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
VALUE val ;
2012-10-14 23:58:59 +04:00
const rb_method_entry_t * me = ci - > me ;
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
const rb_method_cfunc_t * cfunc = & me - > def - > body . cfunc ;
int len = cfunc - > argc ;
2012-11-13 13:48:08 +04:00
/* don't use `ci' after EXEC_EVENT_HOOK because ci can be override */
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
VALUE recv = ci - > recv ;
2012-11-13 13:48:08 +04:00
VALUE defined_class = ci - > defined_class ;
rb_block_t * blockptr = ci - > blockptr ;
int argc = ci - > argc ;
2012-10-14 23:58:59 +04:00
2012-12-01 06:13:06 +04:00
RUBY_DTRACE_CMETHOD_ENTRY_HOOK ( th , me - > klass , me - > called_id ) ;
2012-11-20 13:48:24 +04:00
EXEC_EVENT_HOOK ( th , RUBY_EVENT_C_CALL , recv , me - > called_id , me - > klass , Qundef ) ;
2012-10-14 23:58:59 +04:00
2012-11-13 13:48:08 +04:00
vm_push_frame ( th , 0 , VM_FRAME_MAGIC_CFUNC , recv , defined_class ,
VM_ENVVAL_BLOCK_PTR ( blockptr ) , 0 , th - > cfp - > sp , 1 , me ) ;
2012-10-14 23:58:59 +04:00
2012-11-13 13:48:08 +04:00
if ( len > = 0 ) rb_check_arity ( argc , len , len ) ;
2012-10-14 23:58:59 +04:00
2012-11-13 13:48:08 +04:00
reg_cfp - > sp - = argc + 1 ;
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
VM_PROFILE_UP ( 0 ) ;
2012-11-13 13:48:08 +04:00
val = ( * cfunc - > invoker ) ( cfunc - > func , recv , argc , reg_cfp - > sp + 1 ) ;
2012-10-14 23:58:59 +04:00
if ( reg_cfp ! = th - > cfp + 1 ) {
2012-10-19 14:38:30 +04:00
rb_bug ( " vm_call_cfunc - cfp consistency error " ) ;
2012-08-08 11:52:19 +04:00
}
2012-10-14 23:58:59 +04:00
vm_pop_frame ( th ) ;
2012-08-23 11:22:40 +04:00
2012-11-20 13:48:24 +04:00
EXEC_EVENT_HOOK ( th , RUBY_EVENT_C_RETURN , recv , me - > called_id , me - > klass , val ) ;
2012-12-01 06:13:06 +04:00
RUBY_DTRACE_CMETHOD_RETURN_HOOK ( th , me - > klass , me - > called_id ) ;
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
return val ;
}
# if OPT_CALL_CFUNC_WITHOUT_FRAME
static VALUE
vm_call_cfunc_latter ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci )
{
VALUE val ;
int argc = ci - > argc ;
VALUE * argv = STACK_ADDR_FROM_TOP ( argc ) ;
const rb_method_cfunc_t * cfunc = & ci - > me - > def - > body . cfunc ;
th - > passed_ci = ci ;
reg_cfp - > sp - = argc + 1 ;
ci - > aux . inc_sp = argc + 1 ;
VM_PROFILE_UP ( 0 ) ;
val = ( * cfunc - > invoker ) ( cfunc - > func , ci , argv ) ;
/* check */
if ( reg_cfp = = th - > cfp ) { /* no frame push */
if ( UNLIKELY ( th - > passed_ci ! = ci ) ) {
rb_bug ( " vm_call_cfunc_latter: passed_ci error (ci: %p, passed_ci: %p) " , ci , th - > passed_ci ) ;
}
th - > passed_ci = 0 ;
}
else {
if ( UNLIKELY ( reg_cfp ! = RUBY_VM_PREVIOUS_CONTROL_FRAME ( th - > cfp ) ) ) {
rb_bug ( " vm_call_cfunc_latter: cfp consistency error (%p, %p) " , reg_cfp , th - > cfp + 1 ) ;
}
vm_pop_frame ( th ) ;
VM_PROFILE_UP ( 1 ) ;
}
return val ;
}
static VALUE
vm_call_cfunc ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci )
{
VALUE val ;
const rb_method_entry_t * me = ci - > me ;
int len = me - > def - > body . cfunc . argc ;
VALUE recv = ci - > recv ;
if ( len > = 0 ) rb_check_arity ( ci - > argc , len , len ) ;
2012-12-01 06:13:06 +04:00
RUBY_DTRACE_CMETHOD_ENTRY_HOOK ( th , me - > klass , me - > called_id ) ;
2012-11-20 13:48:24 +04:00
EXEC_EVENT_HOOK ( th , RUBY_EVENT_C_CALL , recv , me - > called_id , me - > klass , Qnil ) ;
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
if ( ! ( ci - > me - > flag & NOEX_PROTECTED ) & &
! ( ci - > flag & VM_CALL_ARGS_SPLAT ) ) {
CI_SET_FASTPATH ( ci , vm_call_cfunc_latter , 1 ) ;
}
val = vm_call_cfunc_latter ( th , reg_cfp , ci ) ;
2012-11-20 13:48:24 +04:00
EXEC_EVENT_HOOK ( th , RUBY_EVENT_C_RETURN , recv , me - > called_id , me - > klass , val ) ;
2012-12-01 06:13:06 +04:00
RUBY_DTRACE_CMETHOD_RETURN_HOOK ( th , me - > klass , me - > called_id ) ;
2012-08-23 11:22:40 +04:00
2012-10-14 23:58:59 +04:00
return val ;
2012-08-23 11:22:40 +04:00
}
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
void
vm_call_cfunc_push_frame ( rb_thread_t * th )
{
rb_call_info_t * ci = th - > passed_ci ;
const rb_method_entry_t * me = ci - > me ;
th - > passed_ci = 0 ;
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 ;
}
}
# else /* OPT_CALL_CFUNC_WITHOUT_FRAME */
static VALUE
vm_call_cfunc ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci )
{
return vm_call_cfunc_with_frame ( th , reg_cfp , ci ) ;
}
# endif
2012-10-14 23:58:59 +04:00
static VALUE
vm_call_ivar ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci )
{
2012-10-16 21:07:23 +04:00
VALUE val = vm_getivar ( ci - > recv , ci - > me - > def - > body . attr . id , 0 , ci , 1 ) ;
2012-10-14 23:58:59 +04:00
cfp - > sp - = 1 ;
return val ;
}
static VALUE
vm_call_attrset ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci )
2012-08-23 11:22:40 +04:00
{
2013-02-06 21:31:22 +04:00
VALUE val = vm_setivar ( ci - > recv , ci - > me - > def - > body . attr . id , * ( cfp - > sp - 1 ) , 0 , ci , 1 ) ;
2012-10-14 23:58:59 +04:00
cfp - > sp - = 2 ;
2013-02-06 21:31:22 +04:00
return val ;
2012-08-23 11:22:40 +04:00
}
2012-10-18 10:14:39 +04:00
static inline VALUE
2012-10-14 23:58:59 +04:00
vm_call_bmethod_body ( rb_thread_t * th , rb_call_info_t * ci , const VALUE * argv )
2012-08-23 11:22:40 +04:00
{
2012-10-14 23:58:59 +04:00
rb_proc_t * proc ;
VALUE val ;
2012-12-01 06:13:06 +04:00
RUBY_DTRACE_METHOD_ENTRY_HOOK ( th , ci - > me - > klass , ci - > me - > called_id ) ;
2012-11-20 13:48:24 +04:00
EXEC_EVENT_HOOK ( th , RUBY_EVENT_CALL , ci - > recv , ci - > me - > called_id , ci - > me - > klass , Qnil ) ;
2012-10-14 23:58:59 +04:00
/* control block frame */
th - > passed_me = ci - > me ;
GetProcPtr ( ci - > me - > def - > body . proc , proc ) ;
val = vm_invoke_proc ( th , proc , ci - > recv , ci - > defined_class , ci - > argc , argv , ci - > blockptr ) ;
2012-11-20 13:48:24 +04:00
EXEC_EVENT_HOOK ( th , RUBY_EVENT_RETURN , ci - > recv , ci - > me - > called_id , ci - > me - > klass , val ) ;
2012-11-29 21:55:54 +04:00
RUBY_DTRACE_METHOD_RETURN_HOOK ( th , ci - > me - > klass , ci - > me - > called_id ) ;
2012-10-14 23:58:59 +04:00
return val ;
2012-08-23 11:22:40 +04:00
}
2012-10-14 23:58:59 +04:00
static VALUE
vm_call_bmethod ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci )
2012-08-23 11:22:40 +04:00
{
2012-10-14 23:58:59 +04:00
VALUE * argv = ALLOCA_N ( VALUE , ci - > argc ) ;
MEMCPY ( argv , cfp - > sp - ci - > argc , VALUE , ci - > argc ) ;
cfp - > sp + = - ci - > argc - 1 ;
return vm_call_bmethod_body ( th , ci , argv ) ;
2012-08-23 11:22:40 +04:00
}
2012-09-28 08:05:36 +04:00
2012-12-14 12:04:55 +04:00
static
# ifdef _MSC_VER
__forceinline
# else
inline
# endif
VALUE vm_call_method ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci ) ;
2012-10-14 23:58:59 +04:00
static VALUE
vm_call_opt_send ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci )
2012-09-28 08:05:36 +04:00
{
2012-10-14 23:58:59 +04:00
int i = ci - > argc - 1 ;
VALUE sym ;
rb_call_info_t ci_entry ;
2012-09-28 08:05:36 +04:00
2012-10-14 23:58:59 +04:00
if ( ci - > argc = = 0 ) {
rb_raise ( rb_eArgError , " no method name given " ) ;
2012-09-28 08:05:36 +04:00
}
2012-10-14 23:58:59 +04:00
ci_entry = * ci ; /* copy ci entry */
ci = & ci_entry ;
sym = TOPN ( i ) ;
if ( SYMBOL_P ( sym ) ) {
ci - > mid = SYM2ID ( sym ) ;
2012-09-28 08:05:36 +04:00
}
2012-10-14 23:58:59 +04:00
else if ( ! ( ci - > mid = rb_check_id ( & sym ) ) ) {
if ( rb_method_basic_definition_p ( CLASS_OF ( ci - > recv ) , idMethodMissing ) ) {
VALUE exc = make_no_method_exception ( rb_eNoMethodError , NULL , ci - > recv , rb_long2int ( ci - > argc ) , & TOPN ( i ) ) ;
rb_exc_raise ( exc ) ;
}
ci - > mid = rb_to_id ( sym ) ;
}
2012-10-17 11:12:40 +04:00
2012-10-14 23:58:59 +04:00
/* shift arguments */
if ( i > 0 ) {
MEMMOVE ( & TOPN ( i ) , & TOPN ( i - 1 ) , VALUE , i ) ;
}
2012-12-09 12:48:34 +04:00
ci - > me =
rb_method_entry_without_refinements ( CLASS_OF ( ci - > recv ) ,
ci - > mid , & ci - > defined_class ) ;
2012-10-14 23:58:59 +04:00
ci - > argc - = 1 ;
DEC_SP ( 1 ) ;
2012-09-28 08:05:36 +04:00
2012-10-17 11:12:40 +04:00
ci - > flag = VM_CALL_FCALL | VM_CALL_OPT_SEND ;
2012-10-14 23:58:59 +04:00
return vm_call_method ( th , reg_cfp , ci ) ;
2012-09-28 08:05:36 +04:00
}
2012-10-14 23:58:59 +04:00
static VALUE
vm_call_opt_call ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci )
{
rb_proc_t * proc ;
int argc = ci - > argc ;
VALUE * argv = ALLOCA_N ( VALUE , argc ) ;
GetProcPtr ( ci - > recv , proc ) ;
MEMCPY ( argv , cfp - > sp - argc , VALUE , argc ) ;
cfp - > sp - = argc + 1 ;
return rb_vm_invoke_proc ( th , proc , argc , argv , ci - > blockptr ) ;
}
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-14 23:58:59 +04:00
static VALUE
2012-10-17 11:12:40 +04:00
vm_call_method_missing ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci )
2012-10-14 23:58:59 +04:00
{
2012-10-17 11:12:40 +04:00
VALUE * argv = STACK_ADDR_FROM_TOP ( ci - > argc ) ;
rb_call_info_t ci_entry ;
2012-10-14 23:58:59 +04:00
2012-10-17 11:12:40 +04:00
ci_entry . flag = VM_CALL_FCALL | VM_CALL_OPT_SEND ;
ci_entry . argc = ci - > argc + 1 ;
ci_entry . mid = idMethodMissing ;
ci_entry . blockptr = ci - > blockptr ;
ci_entry . recv = ci - > recv ;
ci_entry . me = rb_method_entry ( CLASS_OF ( ci_entry . recv ) , idMethodMissing , & ci_entry . defined_class ) ;
2012-10-14 23:58:59 +04:00
2012-10-17 11:12:40 +04:00
/* shift arguments: m(a, b, c) #=> method_missing(:m, a, b, c) */
2012-12-25 13:57:07 +04:00
CHECK_VM_STACK_OVERFLOW ( reg_cfp , 1 ) ;
2012-10-17 11:12:40 +04:00
if ( ci - > argc > 0 ) {
MEMMOVE ( argv + 1 , argv , VALUE , ci - > argc ) ;
}
2012-10-14 23:58:59 +04:00
argv [ 0 ] = ID2SYM ( ci - > mid ) ;
2012-10-17 11:12:40 +04:00
INC_SP ( 1 ) ;
th - > method_missing_reason = ci - > aux . missing_reason ;
return vm_call_method ( th , reg_cfp , & ci_entry ) ;
2012-10-14 23:58:59 +04:00
}
2012-12-07 19:49:21 +04:00
static inline VALUE
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
find_refinement ( VALUE refinements , VALUE klass )
{
if ( NIL_P ( refinements ) ) {
return Qnil ;
}
2012-12-07 19:49:21 +04:00
return rb_hash_lookup ( refinements , klass ) ;
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
}
static int rb_method_definition_eq ( const rb_method_definition_t * d1 , const rb_method_definition_t * d2 ) ;
static VALUE vm_call_super_method ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci ) ;
2013-02-24 08:36:00 +04:00
static rb_control_frame_t *
current_method_entry ( rb_thread_t * th , rb_control_frame_t * cfp )
{
rb_control_frame_t * top_cfp = cfp ;
if ( cfp - > iseq & & cfp - > iseq - > type = = ISEQ_TYPE_BLOCK ) {
rb_iseq_t * local_iseq = cfp - > iseq - > local_iseq ;
do {
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( cfp ) ;
if ( RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P ( th , cfp ) ) {
/* TODO: orphan block */
return top_cfp ;
}
} while ( cfp - > iseq ! = local_iseq ) ;
}
return cfp ;
}
2012-12-14 12:04:55 +04:00
static
# ifdef _MSC_VER
__forceinline
# else
inline
# endif
VALUE
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
vm_call_method ( rb_thread_t * th , rb_control_frame_t * cfp , rb_call_info_t * ci )
{
2012-10-15 21:40:50 +04:00
int enable_fastpath = 1 ;
2012-11-28 17:56:29 +04:00
rb_call_info_t ci_temp ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
start_method_dispatch :
if ( ci - > me ! = 0 ) {
if ( ( ci - > me - > flag = = 0 ) ) {
normal_method_dispatch :
switch ( ci - > me - > def - > type ) {
case VM_METHOD_TYPE_ISEQ : {
2012-10-15 21:40:50 +04:00
CI_SET_FASTPATH ( ci , vm_call_iseq_setup , enable_fastpath ) ;
2012-10-14 23:58:59 +04:00
return vm_call_iseq_setup ( th , cfp , ci ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
case VM_METHOD_TYPE_NOTIMPLEMENTED :
* vm_core.h, vm_insnhelper.c, vm_eval.c (OPT_CALL_CFUNC_WITHOUT_FRAME):
add a new otpimization and its macro `OPT_CALL_CFUNC_WITHOUT_FRAME'.
This optimization makes all cfunc method calls `frameless', which
is fster than ordinal cfunc method call.
If `frame' is needed (for example, it calls another method with
`rb_funcall()'), then build a frame. In other words, this
optimization delays frame building.
However, to delay the frame building, we need additional overheads:
(1) Store the last call information.
(2) Check the delayed frame buidling before the frame is needed.
(3) Overhead to build a delayed frame.
rb_thread_t::passed_ci is storage of delayed cfunc call information.
(1) is lightweight because it is only 1 assignment to `passed_ci'.
To achieve (2), we modify GET_THREAD() to check `passed_ci' every
time. It causes 10% overhead on my envrionment.
This optimization only works for cfunc methods which do not need
their `frame'.
After evaluation on my environment, this optimization does not
effective every time. Because of this evaluation results, this
optimization is disabled at default.
* vm_insnhelper.c, vm.c: add VM_PROFILE* macros to measure behaviour
of VM internals. I will extend this feature.
* vm_method.c, method.h: change parameters of the `invoker' function.
Receive `func' pointer as the first parameter.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37293 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-23 08:22:31 +04:00
case VM_METHOD_TYPE_CFUNC :
2012-10-15 21:40:50 +04:00
CI_SET_FASTPATH ( ci , vm_call_cfunc , enable_fastpath ) ;
2012-10-17 01:49:18 +04:00
return vm_call_cfunc ( th , cfp , ci ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
case VM_METHOD_TYPE_ATTRSET : {
2012-10-15 00:59:21 +04:00
rb_check_arity ( ci - > argc , 0 , 1 ) ;
2012-10-16 21:07:23 +04:00
ci - > aux . index = 0 ;
2012-10-16 01:35:29 +04:00
CI_SET_FASTPATH ( ci , vm_call_attrset , enable_fastpath & & ! ( ci - > flag & VM_CALL_ARGS_SPLAT ) ) ;
2012-10-17 01:49:18 +04:00
return vm_call_attrset ( th , cfp , ci ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
case VM_METHOD_TYPE_IVAR : {
2012-10-15 00:59:21 +04:00
rb_check_arity ( ci - > argc , 0 , 0 ) ;
2012-10-16 21:07:23 +04:00
ci - > aux . index = 0 ;
2012-10-16 01:35:29 +04:00
CI_SET_FASTPATH ( ci , vm_call_ivar , enable_fastpath & & ! ( ci - > flag & VM_CALL_ARGS_SPLAT ) ) ;
2012-10-17 01:49:18 +04:00
return vm_call_ivar ( th , cfp , ci ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
case VM_METHOD_TYPE_MISSING : {
2012-10-17 11:12:40 +04:00
ci - > aux . missing_reason = 0 ;
CI_SET_FASTPATH ( ci , vm_call_method_missing , enable_fastpath ) ;
return vm_call_method_missing ( th , cfp , ci ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
case VM_METHOD_TYPE_BMETHOD : {
2012-10-15 21:40:50 +04:00
CI_SET_FASTPATH ( ci , vm_call_bmethod , enable_fastpath ) ;
2012-10-17 01:49:18 +04:00
return vm_call_bmethod ( th , cfp , ci ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
case VM_METHOD_TYPE_ZSUPER : {
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
VALUE klass ;
zsuper_method_dispatch :
klass = RCLASS_SUPER ( ci - > me - > klass ) ;
2012-11-28 17:56:29 +04:00
ci_temp = * ci ;
ci = & ci_temp ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
ci - > me = rb_method_entry ( klass , ci - > mid , & ci - > defined_class ) ;
if ( ci - > me ! = 0 ) {
goto normal_method_dispatch ;
}
else {
goto start_method_dispatch ;
}
}
case VM_METHOD_TYPE_OPTIMIZED : {
switch ( ci - > me - > def - > body . optimize_type ) {
2012-10-16 01:24:08 +04:00
case OPTIMIZED_METHOD_TYPE_SEND :
2012-10-15 21:40:50 +04:00
CI_SET_FASTPATH ( ci , vm_call_opt_send , enable_fastpath ) ;
2012-10-17 01:49:18 +04:00
return vm_call_opt_send ( th , cfp , ci ) ;
2012-10-16 01:24:08 +04:00
case OPTIMIZED_METHOD_TYPE_CALL :
2012-10-15 21:40:50 +04:00
CI_SET_FASTPATH ( ci , vm_call_opt_call , enable_fastpath ) ;
2012-10-17 01:49:18 +04:00
return vm_call_opt_call ( th , cfp , ci ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
default :
2012-10-16 01:24:08 +04:00
rb_bug ( " vm_call_method: unsupported optimized method type (%d) " ,
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
ci - > me - > def - > body . optimize_type ) ;
}
break ;
}
2012-10-24 00:53:35 +04:00
case VM_METHOD_TYPE_UNDEF :
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
break ;
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
case VM_METHOD_TYPE_REFINED : {
NODE * cref = rb_vm_get_cref ( cfp - > iseq , cfp - > ep ) ;
VALUE refinements = cref ? cref - > nd_refinements : Qnil ;
VALUE refinement , defined_class ;
rb_method_entry_t * me ;
refinement = find_refinement ( refinements ,
ci - > defined_class ) ;
if ( NIL_P ( refinement ) ) {
goto no_refinement_dispatch ;
}
me = rb_method_entry ( refinement , ci - > mid , & defined_class ) ;
if ( me ) {
2013-02-24 08:36:00 +04:00
if ( ci - > call = = vm_call_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 ) ) {
goto no_refinement_dispatch ;
}
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
}
ci - > me = me ;
ci - > defined_class = defined_class ;
if ( me - > def - > type ! = VM_METHOD_TYPE_REFINED ) {
goto normal_method_dispatch ;
}
}
no_refinement_dispatch :
if ( ci - > me - > def - > body . orig_me ) {
ci - > me = ci - > me - > def - > body . orig_me ;
goto normal_method_dispatch ;
}
else {
goto zsuper_method_dispatch ;
}
}
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
2012-10-24 00:53:35 +04:00
rb_bug ( " vm_call_method: unsupported method type (%d) " , ci - > me - > def - > type ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
else {
int noex_safe ;
2012-10-15 21:22:57 +04:00
if ( ! ( ci - > flag & VM_CALL_FCALL ) & & ( ci - > me - > flag & NOEX_MASK ) & NOEX_PRIVATE ) {
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
int stat = NOEX_PRIVATE ;
2012-10-15 21:22:57 +04:00
if ( ci - > flag & VM_CALL_VCALL ) {
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
stat | = NOEX_VCALL ;
}
2012-10-17 11:12:40 +04:00
ci - > aux . missing_reason = stat ;
CI_SET_FASTPATH ( ci , vm_call_method_missing , 1 ) ;
return vm_call_method_missing ( th , cfp , ci ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
2012-10-15 21:22:57 +04:00
else if ( ! ( ci - > flag & VM_CALL_OPT_SEND ) & & ( ci - > me - > flag & NOEX_MASK ) & NOEX_PROTECTED ) {
2012-10-15 21:40:50 +04:00
enable_fastpath = 0 ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
if ( ! rb_obj_is_kind_of ( cfp - > self , ci - > defined_class ) ) {
2012-10-17 11:12:40 +04:00
ci - > aux . missing_reason = NOEX_PROTECTED ;
return vm_call_method_missing ( th , cfp , ci ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
else {
goto normal_method_dispatch ;
}
}
else if ( ( noex_safe = NOEX_SAFE ( ci - > me - > flag ) ) > th - > safe_level & & ( noex_safe > 2 ) ) {
rb_raise ( rb_eSecurityError , " calling insecure method: %s " , rb_id2name ( ci - > mid ) ) ;
}
else {
goto normal_method_dispatch ;
}
}
}
else {
/* method missing */
int stat = 0 ;
2012-10-15 21:22:57 +04:00
if ( ci - > flag & VM_CALL_VCALL ) {
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
stat | = NOEX_VCALL ;
}
2012-10-15 21:22:57 +04:00
if ( ci - > flag & VM_CALL_SUPER ) {
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
stat | = NOEX_SUPER ;
}
if ( ci - > mid = = idMethodMissing ) {
rb_control_frame_t * reg_cfp = cfp ;
VALUE * argv = STACK_ADDR_FROM_TOP ( ci - > argc ) ;
rb_raise_method_missing ( th , ci - > argc , argv , ci - > recv , stat ) ;
}
else {
2012-10-17 11:12:40 +04:00
ci - > aux . missing_reason = stat ;
CI_SET_FASTPATH ( ci , vm_call_method_missing , 1 ) ;
return vm_call_method_missing ( th , cfp , ci ) ;
2012-10-14 23:58:59 +04:00
}
}
2012-10-17 01:49:18 +04:00
rb_bug ( " vm_call_method: unreachable " ) ;
2012-10-14 23:58:59 +04:00
}
static VALUE
vm_call_general ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci )
{
return vm_call_method ( th , reg_cfp , ci ) ;
}
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
static VALUE
vm_call_super_method ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci )
{
return vm_call_method ( th , reg_cfp , ci ) ;
}
2012-10-14 23:58:59 +04:00
/* super */
static inline VALUE
vm_search_normal_superclass ( VALUE klass )
{
2012-12-08 07:36:58 +04:00
if ( BUILTIN_TYPE ( klass ) = = T_ICLASS & &
FL_TEST ( RBASIC ( klass ) - > klass , RMODULE_IS_REFINEMENT ) ) {
* fix the behavior when a module is included into a refinement.
This change is a little tricky, so it might be better to prohibit
module inclusion to refinements.
* include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag
to represent that a module (iclass) is included into a refinement.
* class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT
if klass is a refinement.
* eval.c (rb_mod_refine): set the superclass of a refinement to the
refined class for super.
* eval.c (rb_using_refinement): skip the above superclass (the
refined class) when creating iclasses for refinements. Otherwise,
`using Refinement1; using Refinement2' creates iclasses:
<Refinement2> -> <RefinedClass> -> <Refinement1> -> RefinedClass,
where <Module> is an iclass for Module, so RefinedClass is
searched before Refinement1. The correct iclasses should be
<Refinement2> -> <Refinement1> -> RefinedClass.
* vm_insnhelper.c (vm_search_normal_superclass): if klass is an
iclass for a refinement, use the refinement's superclass instead
of the iclass's superclass. Otherwise, multiple refinements are
searched by super. For example, if a refinement Refinement2
includes a module M (i.e., Refinement2 -> <M> -> RefinedClass,
and if refinements iclasses are <Refinement2> -> <M>' ->
<Refinement1> -> RefinedClass, then super in <Refinement2> should
use Refinement2's superclass <M> instead of <Refinement2>'s
superclass <M>'.
* vm_insnhelper.c (vm_search_super_method): do not raise a
NotImplementError if current_defind_class is a module included
into a refinement. Because of the change of
vm_search_normal_superclass(), the receiver might not be an
instance of the module('s iclass).
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-10 20:05:45 +04:00
klass = RBASIC ( klass ) - > klass ;
2012-12-08 07:36:58 +04:00
}
* fix the behavior when a module is included into a refinement.
This change is a little tricky, so it might be better to prohibit
module inclusion to refinements.
* include/ruby/ruby.h (RMODULE_INCLUDED_INTO_REFINEMENT): new flag
to represent that a module (iclass) is included into a refinement.
* class.c (include_modules_at): set RMODULE_INCLUDED_INTO_REFINEMENT
if klass is a refinement.
* eval.c (rb_mod_refine): set the superclass of a refinement to the
refined class for super.
* eval.c (rb_using_refinement): skip the above superclass (the
refined class) when creating iclasses for refinements. Otherwise,
`using Refinement1; using Refinement2' creates iclasses:
<Refinement2> -> <RefinedClass> -> <Refinement1> -> RefinedClass,
where <Module> is an iclass for Module, so RefinedClass is
searched before Refinement1. The correct iclasses should be
<Refinement2> -> <Refinement1> -> RefinedClass.
* vm_insnhelper.c (vm_search_normal_superclass): if klass is an
iclass for a refinement, use the refinement's superclass instead
of the iclass's superclass. Otherwise, multiple refinements are
searched by super. For example, if a refinement Refinement2
includes a module M (i.e., Refinement2 -> <M> -> RefinedClass,
and if refinements iclasses are <Refinement2> -> <M>' ->
<Refinement1> -> RefinedClass, then super in <Refinement2> should
use Refinement2's superclass <M> instead of <Refinement2>'s
superclass <M>'.
* vm_insnhelper.c (vm_search_super_method): do not raise a
NotImplementError if current_defind_class is a module included
into a refinement. Because of the change of
vm_search_normal_superclass(), the receiver might not be an
instance of the module('s iclass).
* test/ruby/test_refinement.rb: related test.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38298 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-10 20:05:45 +04:00
klass = RCLASS_ORIGIN ( klass ) ;
return RCLASS_SUPER ( klass ) ;
2012-10-14 23:58:59 +04:00
}
static void
vm_super_outside ( void )
{
rb_raise ( rb_eNoMethodError , " super called outside of method " ) ;
}
static void
vm_search_superclass ( rb_control_frame_t * reg_cfp , rb_iseq_t * iseq , VALUE sigval , rb_call_info_t * ci )
{
while ( iseq & & ! iseq - > klass ) {
iseq = iseq - > parent_iseq ;
}
if ( iseq = = 0 ) {
vm_super_outside ( ) ;
}
ci - > mid = iseq - > defined_method_id ;
if ( iseq ! = iseq - > local_iseq ) {
/* defined by Module#define_method() */
rb_control_frame_t * lcfp = GET_CFP ( ) ;
if ( ! sigval ) {
/* zsuper */
rb_raise ( rb_eRuntimeError , " implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly. " ) ;
}
while ( lcfp - > iseq ! = iseq ) {
rb_thread_t * th = GET_THREAD ( ) ;
VALUE * tep = VM_EP_PREV_EP ( lcfp - > ep ) ;
while ( 1 ) {
lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( lcfp ) ;
if ( RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P ( th , lcfp ) ) {
vm_super_outside ( ) ;
}
if ( lcfp - > ep = = tep ) {
break ;
}
}
}
/* temporary measure for [Bug #2420] [Bug #3136] */
if ( ! lcfp - > me ) {
vm_super_outside ( ) ;
}
ci - > mid = lcfp - > me - > def - > original_id ;
ci - > klass = vm_search_normal_superclass ( lcfp - > klass ) ;
}
else {
ci - > klass = vm_search_normal_superclass ( reg_cfp - > klass ) ;
}
}
static void
vm_search_super_method ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci )
{
2012-12-11 13:31:26 +04:00
VALUE current_defined_class ;
2012-10-14 23:58:59 +04:00
rb_iseq_t * iseq = GET_ISEQ ( ) ;
VALUE sigval = TOPN ( ci - > orig_argc ) ;
2012-12-11 13:31:26 +04:00
current_defined_class = GET_CFP ( ) - > klass ;
if ( NIL_P ( current_defined_class ) ) {
2012-10-14 23:58:59 +04:00
vm_super_outside ( ) ;
}
2012-12-11 13:31:26 +04:00
if ( ! NIL_P ( RCLASS_REFINED_CLASS ( current_defined_class ) ) ) {
current_defined_class = RCLASS_REFINED_CLASS ( current_defined_class ) ;
2012-10-14 23:58:59 +04:00
}
2012-12-11 13:31:26 +04:00
if ( ! FL_TEST ( current_defined_class , RMODULE_INCLUDED_INTO_REFINEMENT ) & &
! rb_obj_is_kind_of ( ci - > recv , current_defined_class ) ) {
2013-01-10 11:51:35 +04:00
VALUE m = RB_TYPE_P ( current_defined_class , T_ICLASS ) ?
RBASIC ( current_defined_class ) - > klass : current_defined_class ;
rb_raise ( rb_eTypeError ,
" self has wrong type to call super in this context: "
" %s (expected %s) " ,
rb_obj_classname ( ci - > recv ) , rb_class2name ( m ) ) ;
2012-10-14 23:58:59 +04:00
}
vm_search_superclass ( GET_CFP ( ) , iseq , sigval , ci ) ;
/* TODO: use inline cache */
ci - > me = rb_method_entry ( ci - > klass , ci - > mid , & ci - > defined_class ) ;
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
ci - > call = vm_call_super_method ;
2012-10-14 23:58:59 +04:00
while ( iseq & & ! iseq - > klass ) {
iseq = iseq - > parent_iseq ;
}
if ( ci - > me & & ci - > me - > def - > type = = VM_METHOD_TYPE_ISEQ & & ci - > me - > def - > body . iseq = = iseq ) {
ci - > klass = RCLASS_SUPER ( ci - > defined_class ) ;
* revised r37993 to avoid SEGV/ILL in tests. In r37993, a method
entry with VM_METHOD_TYPE_REFINED holds only the original method
definition, so ci->me is set to a method entry allocated in the
stack, and it causes SEGV/ILL. In this commit, a method entry
with VM_METHOD_TYPE_REFINED holds the whole original method entry.
Furthermore, rb_thread_mark() is changed to mark cfp->klass to
avoid GC for iclasses created by copy_refinement_iclass().
* vm_method.c (rb_method_entry_make): add a method entry with
VM_METHOD_TYPE_REFINED to the class refined by the refinement if
the target module is a refinement. When a method entry with
VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
the same name is searched in refinements. If such a method is
found, the method is invoked. Otherwise, the original method in
the refined class (rb_method_definition_t::body.orig_me) is
invoked. This change is made to simplify the normal method lookup
and to improve the performance of normal method calls.
* vm_method.c (EXPR1, search_method, rb_method_entry),
vm_eval.c (rb_call0, rb_search_method_entry): do not use
refinements for method lookup.
* vm_insnhelper.c (vm_call_method): search methods in refinements if
ci->me is VM_METHOD_TYPE_REFINED. If the method is called by
super (i.e., ci->call == vm_call_super_method), skip the same
method entry as the current method to avoid infinite call of the
same method.
* class.c (include_modules_at): add a refined method entry for each
method defined in a module included in a refinement.
* class.c (rb_prepend_module): set an empty table to
RCLASS_M_TBL(klass) to add refined method entries, because
refinements should have priority over prepended modules.
* proc.c (mnew): use rb_method_entry_with_refinements() to get
a refined method.
* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
copy_refinement_iclass().
* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
the test because it should pass successfully.
* test/ruby/test_refinement.rb (test_redefine_refined_method): new
test for the case a refined method is redefined.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38236 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-06 17:08:41 +04:00
ci - > me = rb_method_entry ( ci - > klass , ci - > mid , & ci - > defined_class ) ;
2012-10-14 23:58:59 +04:00
}
}
/* yield */
static inline int
block_proc_is_lambda ( const VALUE procval )
{
rb_proc_t * proc ;
if ( procval ) {
GetProcPtr ( procval , proc ) ;
return proc - > is_lambda ;
}
else {
return 0 ;
}
}
static inline VALUE
vm_yield_with_cfunc ( rb_thread_t * th , const rb_block_t * block ,
VALUE self , int argc , const VALUE * argv ,
const rb_block_t * blockargptr )
{
NODE * ifunc = ( NODE * ) block - > iseq ;
VALUE val , arg , blockarg ;
int lambda = block_proc_is_lambda ( block - > proc ) ;
rb_control_frame_t * cfp ;
if ( lambda ) {
arg = rb_ary_new4 ( argc , argv ) ;
}
else if ( argc = = 0 ) {
arg = Qnil ;
}
else {
arg = argv [ 0 ] ;
}
if ( blockargptr ) {
if ( blockargptr - > proc ) {
blockarg = blockargptr - > proc ;
}
else {
blockarg = rb_vm_make_proc ( th , blockargptr , rb_cProc ) ;
}
}
else {
blockarg = Qnil ;
}
cfp = vm_push_frame ( th , ( rb_iseq_t * ) ifunc , VM_FRAME_MAGIC_IFUNC , self ,
0 , VM_ENVVAL_PREV_EP_PTR ( block - > ep ) , 0 ,
th - > cfp - > sp , 1 , 0 ) ;
if ( blockargptr ) {
VM_CF_LEP ( cfp ) [ 0 ] = VM_ENVVAL_BLOCK_PTR ( blockargptr ) ;
}
val = ( * ifunc - > nd_cfnc ) ( arg , ifunc - > nd_tval , argc , argv , blockarg ) ;
th - > cfp + + ;
return val ;
}
/*--
* @ brief on supplied all of optional , rest and post parameters .
* @ pre iseq is block style ( not lambda style )
*/
static inline int
vm_yield_setup_block_args_complex ( rb_thread_t * th , const rb_iseq_t * iseq ,
int argc , VALUE * argv )
{
rb_num_t opt_pc = 0 ;
int i ;
const int m = iseq - > argc ;
const int r = iseq - > arg_rest ;
int len = iseq - > arg_post_len ;
int start = iseq - > arg_post_start ;
int rsize = argc > m ? argc - m : 0 ; /* # of arguments which did not consumed yet */
int psize = rsize > len ? len : rsize ; /* # of post arguments */
int osize = 0 ; /* # of opt arguments */
VALUE ary ;
/* reserves arguments for post parameters */
rsize - = psize ;
if ( iseq - > arg_opts ) {
const int opts = iseq - > arg_opts - 1 ;
if ( rsize > opts ) {
osize = opts ;
opt_pc = iseq - > arg_opt_table [ opts ] ;
}
else {
osize = rsize ;
opt_pc = iseq - > arg_opt_table [ rsize ] ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
}
2012-10-14 23:58:59 +04:00
rsize - = osize ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-14 23:58:59 +04:00
if ( 0 ) {
printf ( " argc: %d \n " , argc ) ;
printf ( " len: %d \n " , len ) ;
printf ( " start: %d \n " , start ) ;
printf ( " rsize: %d \n " , rsize ) ;
}
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-14 23:58:59 +04:00
if ( r = = - 1 ) {
/* copy post argument */
MEMMOVE ( & argv [ start ] , & argv [ m + osize ] , VALUE , psize ) ;
}
else {
ary = rb_ary_new4 ( rsize , & argv [ r ] ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-14 23:58:59 +04:00
/* copy post argument */
MEMMOVE ( & argv [ start ] , & argv [ m + rsize + osize ] , VALUE , psize ) ;
argv [ r ] = ary ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
2012-10-14 23:58:59 +04:00
for ( i = psize ; i < len ; i + + ) {
argv [ start + i ] = Qnil ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
2012-10-14 23:58:59 +04:00
return ( int ) opt_pc ;
}
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-14 23:58:59 +04:00
static inline int
vm_yield_setup_block_args ( rb_thread_t * th , const rb_iseq_t * iseq ,
int orig_argc , VALUE * argv ,
const rb_block_t * blockptr )
{
int i ;
int argc = orig_argc ;
const int m = iseq - > argc ;
VALUE ary , arg0 ;
2013-01-07 07:09:28 +04:00
VALUE keyword_hash = Qnil ;
2012-10-14 23:58:59 +04:00
int opt_pc = 0 ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-14 23:58:59 +04:00
th - > mark_stack_len = argc ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-12-30 06:06:28 +04:00
/* keyword argument */
if ( iseq - > arg_keyword ! = - 1 ) {
2013-01-07 07:09:28 +04:00
argc = vm_callee_setup_keyword_arg ( iseq , argc , argv , & keyword_hash ) ;
2012-12-30 06:06:28 +04:00
}
2012-10-14 23:58:59 +04:00
/*
* yield [ 1 , 2 ]
* = > { | a | } = > a = [ 1 , 2 ]
* = > { | a , b | } = > a , b = [ 1 , 2 ]
*/
arg0 = argv [ 0 ] ;
2012-10-28 03:22:10 +04:00
if ( ! ( iseq - > arg_simple & 0x02 ) & & /* exclude {|a|} */
2012-12-28 06:50:57 +04:00
( ( m + iseq - > arg_post_len ) > 0 | | iseq - > arg_opts > 2 ) & & /* this process is meaningful */
2012-10-28 03:22:10 +04:00
argc = = 1 & & ! NIL_P ( ary = rb_check_array_type ( arg0 ) ) ) { /* rhs is only an array */
th - > mark_stack_len = argc = RARRAY_LENINT ( ary ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-12-25 13:57:07 +04:00
CHECK_VM_STACK_OVERFLOW ( th - > cfp , argc ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-28 03:22:10 +04:00
MEMCPY ( argv , RARRAY_PTR ( ary ) , VALUE , argc ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
else {
2012-10-28 03:22:10 +04:00
argv [ 0 ] = arg0 ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
2012-10-14 23:58:59 +04:00
for ( i = argc ; i < m ; i + + ) {
2012-10-28 03:22:10 +04:00
argv [ i ] = Qnil ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
2012-10-14 23:58:59 +04:00
if ( iseq - > arg_rest = = - 1 & & iseq - > arg_opts = = 0 ) {
2012-10-28 03:22:10 +04:00
const int arg_size = iseq - > arg_size ;
if ( arg_size < argc ) {
/*
* yield 1 , 2
* = > { | a | } # truncate
*/
th - > mark_stack_len = argc = arg_size ;
}
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
2012-10-14 23:58:59 +04:00
else {
2012-10-28 03:22:10 +04:00
int r = iseq - > arg_rest ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-28 03:22:10 +04:00
if ( iseq - > arg_post_len | |
iseq - > arg_opts ) { /* TODO: implement simple version for (iseq->arg_post_len==0 && iseq->arg_opts > 0) */
2012-10-14 23:58:59 +04:00
opt_pc = vm_yield_setup_block_args_complex ( th , iseq , argc , argv ) ;
2012-10-28 03:22:10 +04:00
}
else {
if ( argc < r ) {
/* yield 1
* = > { | a , b , * r | }
*/
for ( i = argc ; i < r ; i + + ) {
argv [ i ] = Qnil ;
}
argv [ r ] = rb_ary_new ( ) ;
}
else {
argv [ r ] = rb_ary_new4 ( argc - r , & argv [ r ] ) ;
}
}
th - > mark_stack_len = iseq - > arg_size ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
2013-01-07 07:09:28 +04:00
/* keyword argument */
if ( iseq - > arg_keyword ! = - 1 ) {
argv [ iseq - > arg_keyword ] = keyword_hash ;
}
2012-10-14 23:58:59 +04:00
/* {|&b|} */
if ( iseq - > arg_block ! = - 1 ) {
2012-10-28 03:22:10 +04:00
VALUE procval = Qnil ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-28 03:22:10 +04:00
if ( blockptr ) {
2012-10-14 23:58:59 +04:00
if ( blockptr - > proc = = 0 ) {
procval = rb_vm_make_proc ( th , blockptr , rb_cProc ) ;
}
else {
procval = blockptr - > proc ;
}
2012-10-28 03:22:10 +04:00
}
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
2012-10-28 03:22:10 +04:00
argv [ iseq - > arg_block ] = procval ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
2012-10-14 23:58:59 +04:00
th - > mark_stack_len = 0 ;
return opt_pc ;
}
static inline int
vm_yield_setup_args ( rb_thread_t * const th , const rb_iseq_t * iseq ,
int argc , VALUE * argv , const rb_block_t * blockptr , int lambda )
{
if ( 0 ) { /* for debug */
printf ( " argc: %d \n " , argc ) ;
printf ( " iseq argc: %d \n " , iseq - > argc ) ;
printf ( " iseq opts: %d \n " , iseq - > arg_opts ) ;
printf ( " iseq rest: %d \n " , iseq - > arg_rest ) ;
printf ( " iseq post: %d \n " , iseq - > arg_post_len ) ;
printf ( " iseq blck: %d \n " , iseq - > arg_block ) ;
printf ( " iseq smpl: %d \n " , iseq - > arg_simple ) ;
printf ( " lambda: %s \n " , lambda ? " true " : " false " ) ;
}
if ( lambda ) {
/* call as method */
rb_call_info_t ci_entry ;
ci_entry . flag = 0 ;
ci_entry . argc = argc ;
ci_entry . blockptr = ( rb_block_t * ) blockptr ;
2012-10-15 04:44:04 +04:00
VM_CALLEE_SETUP_ARG ( th , & ci_entry , iseq , argv , 1 ) ;
2012-10-16 21:07:23 +04:00
return ci_entry . aux . opt_pc ;
2012-10-14 23:58:59 +04:00
}
else {
return vm_yield_setup_block_args ( th , iseq , argc , argv , blockptr ) ;
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}
}
static VALUE
2012-10-14 23:58:59 +04:00
vm_invoke_block ( rb_thread_t * th , rb_control_frame_t * reg_cfp , rb_call_info_t * ci )
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
{
2012-10-14 23:58:59 +04:00
const rb_block_t * block = VM_CF_BLOCK_PTR ( reg_cfp ) ;
rb_iseq_t * iseq ;
VALUE type = GET_ISEQ ( ) - > local_iseq - > type ;
if ( ( type ! = ISEQ_TYPE_METHOD & & type ! = ISEQ_TYPE_CLASS ) | | block = = 0 ) {
rb_vm_localjump_error ( " no block given (yield) " , Qnil , 0 ) ;
}
iseq = block - > iseq ;
2012-10-17 00:30:17 +04:00
if ( UNLIKELY ( ci - > flag & VM_CALL_ARGS_SPLAT ) ) {
vm_caller_setup_args ( th , GET_CFP ( ) , ci ) ;
}
2012-10-14 23:58:59 +04:00
if ( BUILTIN_TYPE ( iseq ) ! = T_NODE ) {
int opt_pc ;
const int arg_size = iseq - > arg_size ;
VALUE * const rsp = GET_SP ( ) - ci - > argc ;
SET_SP ( rsp ) ;
2012-12-25 13:57:07 +04:00
CHECK_VM_STACK_OVERFLOW ( GET_CFP ( ) , iseq - > stack_max ) ;
2012-10-14 23:58:59 +04:00
opt_pc = vm_yield_setup_args ( th , iseq , ci - > argc , rsp , 0 , block_proc_is_lambda ( block - > proc ) ) ;
vm_push_frame ( th , iseq , VM_FRAME_MAGIC_BLOCK , block - > self ,
block - > klass ,
VM_ENVVAL_PREV_EP_PTR ( block - > ep ) ,
iseq - > iseq_encoded + opt_pc ,
rsp + arg_size ,
iseq - > local_size - arg_size , 0 ) ;
return Qundef ;
}
else {
VALUE val = vm_yield_with_cfunc ( th , block , block - > self , ci - > argc , STACK_ADDR_FROM_TOP ( ci - > argc ) , 0 ) ;
POPN ( ci - > argc ) ; /* TODO: should put before C/yield? */
return val ;
}
* insns.def (send, invokesuper, invokeblock, opt_*), vm_core.h:
use only a `ci' (rb_call_info_t) parameter instead of using
parameters such as `op_id', 'op_argc', `blockiseq' and flag.
These information are stored in rb_call_info_t at the compile
time.
This technique simplifies parameter passings at related
function calls (~10% speedups for simple mehtod invocation at
my machine).
`rb_call_info_t' also has new function pointer variable `call'.
This `call' variable enables to customize method (block)
invocation process for each place. However, it always call
`vm_call_general()' at this changes.
`rb_call_info_t' also has temporary variables for method
(block) invocation.
* vm_core.h, compile.c, insns.def: introduce VM_CALL_ARGS_SKIP_SETUP
VM_CALL macro. This flag indicates that this call can skip
caller_setup (block arg and splat arg).
* compile.c: catch up above changes.
* iseq.c: catch up above changes (especially for TS_CALLINFO).
* tool/instruction.rb: catch up above chagnes.
* vm_insnhelper.c, vm_insnhelper.h: ditto. Macros and functions
parameters are changed.
* vm_eval.c (vm_call0): ditto (it will be rewriten soon).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-10-14 20:59:05 +04:00
}