2007-06-24 13:19:22 -04:00
/**********************************************************************
2007-12-20 04:29:46 -05:00
insnhelper . c - instruction helper functions .
2007-06-24 13:19:22 -04:00
$ Author $
Copyright ( C ) 2007 Koichi Sasada
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* finish iseq array */
# include "insns.inc"
2008-01-17 12:06:51 -05:00
# include <math.h>
2007-06-24 13:19:22 -04:00
/* control stack frame */
2007-08-06 07:36:30 -04:00
# ifndef INLINE
# define INLINE inline
# endif
2007-06-24 13:19:22 -04:00
static inline rb_control_frame_t *
2008-05-19 14:47:56 -04:00
vm_push_frame ( rb_thread_t * const th , const rb_iseq_t * const iseq ,
const VALUE type , const VALUE self , const VALUE specval ,
const VALUE * const pc , VALUE * sp , VALUE * lfp ,
int const local_size )
2007-06-24 13:19:22 -04:00
{
2008-05-21 11:18:15 -04:00
rb_control_frame_t * const cfp = th - > cfp = th - > cfp - 1 ;
2007-06-24 13:19:22 -04:00
int i ;
* 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-18 23:08:50 -04:00
/* setup vm value stack */
2007-06-24 13:19:22 -04:00
/* nil initialize */
for ( i = 0 ; i < local_size ; i + + ) {
* sp = Qnil ;
sp + + ;
}
/* set special val */
* sp = GC_GUARDED_PTR ( specval ) ;
if ( lfp = = 0 ) {
lfp = sp ;
}
* 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-18 23:08:50 -04:00
/* setup vm control frame stack */
2008-05-19 14:47:56 -04:00
cfp - > pc = ( VALUE * ) pc ;
2007-06-24 13:19:22 -04:00
cfp - > sp = sp + 1 ;
cfp - > bp = sp + 1 ;
2008-05-19 14:47:56 -04:00
cfp - > iseq = ( rb_iseq_t * ) iseq ;
2007-11-08 20:29:24 -05:00
cfp - > flag = type ;
2007-06-24 13:19:22 -04:00
cfp - > self = self ;
cfp - > lfp = lfp ;
2008-05-21 11:18:15 -04:00
cfp - > dfp = sp ;
2007-06-24 13:19:22 -04:00
cfp - > proc = 0 ;
# define COLLECT_PROFILE 0
# if COLLECT_PROFILE
cfp - > prof_time_self = clock ( ) ;
cfp - > prof_time_chld = 0 ;
# endif
2007-08-12 15:12:55 -04:00
if ( VMDEBUG = = 2 ) {
SDR ( ) ;
}
2007-06-24 13:19:22 -04:00
return cfp ;
}
static inline void
2008-05-19 14:47:56 -04:00
vm_pop_frame ( rb_thread_t * const th )
2007-06-24 13:19:22 -04:00
{
# if COLLECT_PROFILE
rb_control_frame_t * cfp = th - > cfp ;
if ( RUBY_VM_NORMAL_ISEQ_P ( cfp - > iseq ) ) {
VALUE current_time = clock ( ) ;
rb_control_frame_t * cfp = th - > cfp ;
cfp - > prof_time_self = current_time - cfp - > prof_time_self ;
( cfp + 1 ) - > prof_time_chld + = cfp - > prof_time_self ;
cfp - > iseq - > profile . count + + ;
cfp - > iseq - > profile . time_cumu = cfp - > prof_time_self ;
cfp - > iseq - > profile . time_self = cfp - > prof_time_self - cfp - > prof_time_chld ;
}
else if ( 0 /* c method? */ ) {
}
# endif
th - > cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( th - > cfp ) ;
2007-08-12 15:12:55 -04:00
if ( VMDEBUG = = 2 ) {
SDR ( ) ;
}
2007-06-24 13:19:22 -04:00
}
/* method dispatch */
2008-05-21 11:18:15 -04:00
static inline int
vm_callee_setup_arg ( rb_thread_t * const th , const rb_iseq_t * const iseq ,
const int orig_argc , VALUE * const orig_argv ,
rb_block_t * * const block )
2007-06-24 13:19:22 -04:00
{
const int m = iseq - > argc ;
2007-08-18 00:17:39 -04:00
if ( LIKELY ( iseq - > arg_simple & 0x01 ) ) {
2007-06-24 13:19:22 -04:00
/* simple check */
2008-05-21 11:18:15 -04:00
if ( orig_argc ! = m ) {
2007-06-24 13:19:22 -04:00
rb_raise ( rb_eArgError , " wrong number of arguments (%d for %d) " ,
2008-05-21 11:18:15 -04:00
orig_argc , m ) ;
2007-06-24 13:19:22 -04:00
}
return 0 ;
}
else {
2008-05-21 11:18:15 -04:00
int argc = orig_argc ;
VALUE * argv = orig_argv ;
2007-06-24 13:19:22 -04:00
int opt_pc = 0 ;
2008-05-21 11:18:15 -04:00
2007-12-18 08:14:32 -05:00
th - > mark_stack_len = argc + iseq - > arg_size ;
2007-06-24 13:19:22 -04:00
/* mandatory */
if ( argc < ( m + iseq - > arg_post_len ) ) { /* check with post arg */
rb_raise ( rb_eArgError , " wrong number of arguments (%d for %d) " ,
argc , m + iseq - > arg_post_len ) ;
}
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 ;
}
2008-05-21 11:18:15 -04:00
MEMCPY ( & orig_argv [ iseq - > arg_post_start ] , & argv [ argc - = iseq - > arg_post_len ] ,
2007-08-18 01:35:03 -04:00
VALUE , iseq - > arg_post_len ) ;
2007-06-24 13:19:22 -04:00
}
/* opt arguments */
if ( iseq - > arg_opts ) {
const int opts = iseq - > arg_opts - 1 /* no opt */ ;
if ( iseq - > arg_rest = = - 1 & & argc > opts ) {
2007-12-02 01:20:23 -05:00
rb_raise ( rb_eArgError , " wrong number of arguments (%d for %d) " ,
orig_argc , m + opts + iseq - > arg_post_len ) ;
2007-06-24 13:19:22 -04:00
}
if ( argc > opts ) {
argc - = opts ;
argv + = opts ;
2007-07-01 14:16:02 -04:00
opt_pc = iseq - > arg_opt_table [ opts ] ; /* no opt */
2007-06-24 13:19:22 -04:00
}
else {
2007-12-09 00:56:00 -05:00
int i ;
for ( i = argc ; i < opts ; i + + ) {
2008-05-21 11:18:15 -04:00
orig_argv [ i + m ] = Qnil ;
2007-12-09 00:56:00 -05:00
}
2007-07-01 14:16:02 -04:00
opt_pc = iseq - > arg_opt_table [ argc ] ;
2007-06-24 13:19:22 -04:00
argc = 0 ;
}
}
/* rest arguments */
if ( iseq - > arg_rest ! = - 1 ) {
2008-05-21 11:18:15 -04:00
orig_argv [ iseq - > arg_rest ] = rb_ary_new4 ( argc , argv ) ;
2007-08-18 00:17:39 -04:00
argc = 0 ;
2007-06-24 13:19:22 -04:00
}
/* block arguments */
2007-06-25 12:05:17 -04:00
if ( block & & iseq - > arg_block ! = - 1 ) {
2007-06-24 13:19:22 -04:00
VALUE blockval = Qnil ;
rb_block_t * const blockptr = * block ;
2007-08-18 00:17:39 -04:00
if ( argc ! = 0 ) {
rb_raise ( rb_eArgError , " wrong number of arguments (%d for %d) " ,
orig_argc , m + iseq - > arg_post_len ) ;
}
2007-06-24 13:19:22 -04:00
if ( blockptr ) {
/* make Proc object */
if ( blockptr - > proc = = 0 ) {
rb_proc_t * proc ;
blockval = vm_make_proc ( th , th - > cfp , blockptr ) ;
GetProcPtr ( blockval , proc ) ;
* block = & proc - > block ;
}
else {
blockval = blockptr - > proc ;
}
}
2008-05-21 11:18:15 -04:00
orig_argv [ iseq - > arg_block ] = blockval ; /* Proc or nil */
2007-06-24 13:19:22 -04:00
}
2007-12-09 00:56:00 -05:00
2007-08-18 23:35:39 -04:00
th - > mark_stack_len = 0 ;
2007-06-24 13:19:22 -04:00
return opt_pc ;
}
}
static inline int
2008-05-21 11:18:15 -04:00
caller_setup_args ( const rb_thread_t * const th ,
rb_control_frame_t * const cfp , const VALUE flag , int argc ,
rb_iseq_t * const blockiseq , rb_block_t * * const block )
2007-06-24 13:19:22 -04:00
{
rb_block_t * blockptr = 0 ;
2007-06-25 12:05:17 -04:00
if ( block ) {
2007-06-24 14:40:13 -04:00
if ( flag & VM_CALL_ARGS_BLOCKARG_BIT ) {
rb_proc_t * po ;
VALUE proc ;
2007-06-24 13:19:22 -04:00
2007-06-24 14:40:13 -04:00
proc = * ( - - cfp - > sp ) ;
2007-06-24 13:19:22 -04:00
2007-06-24 14:40:13 -04:00
if ( proc ! = Qnil ) {
2007-06-24 13:19:22 -04:00
if ( ! rb_obj_is_proc ( proc ) ) {
2007-07-03 15:59:59 -04:00
VALUE b = rb_check_convert_type ( proc , T_DATA , " Proc " , " to_proc " ) ;
if ( NIL_P ( b ) ) {
2007-06-24 14:40:13 -04:00
rb_raise ( rb_eTypeError ,
" wrong argument type %s (expected Proc) " ,
rb_obj_classname ( proc ) ) ;
}
2007-07-03 15:59:59 -04:00
proc = b ;
2007-06-24 13:19:22 -04:00
}
2007-06-24 14:40:13 -04:00
GetProcPtr ( proc , po ) ;
blockptr = & po - > block ;
RUBY_VM_GET_BLOCK_PTR_IN_CFP ( cfp ) - > proc = proc ;
* block = blockptr ;
2007-06-24 13:19:22 -04:00
}
2007-06-24 14:40:13 -04:00
}
else if ( blockiseq ) {
blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP ( cfp ) ;
blockptr - > iseq = blockiseq ;
blockptr - > proc = 0 ;
2007-06-24 13:19:22 -04:00
* block = blockptr ;
}
}
/* expand top of stack? */
if ( flag & VM_CALL_ARGS_SPLAT_BIT ) {
VALUE ary = * ( cfp - > sp - 1 ) ;
VALUE * ptr ;
int i ;
2007-12-01 00:20:06 -05:00
VALUE tmp = rb_check_convert_type ( ary , T_ARRAY , " Array " , " to_a " ) ;
2007-06-24 13:19:22 -04:00
if ( NIL_P ( tmp ) ) {
/* do nothing */
}
else {
int len = RARRAY_LEN ( tmp ) ;
ptr = RARRAY_PTR ( tmp ) ;
cfp - > sp - = 1 ;
CHECK_STACK_OVERFLOW ( cfp , len ) ;
for ( i = 0 ; i < len ; i + + ) {
* cfp - > sp + + = ptr [ i ] ;
}
argc + = i - 1 ;
}
}
return argc ;
}
static inline VALUE
2008-05-21 11:18:15 -04:00
call_cfunc ( VALUE ( * const func ) ( ) , const VALUE recv ,
const int len , const int argc , const VALUE * const argv )
2007-06-24 13:19:22 -04:00
{
/* printf("len: %d, argc: %d\n", len, argc); */
if ( len > = 0 & & argc ! = len ) {
rb_raise ( rb_eArgError , " wrong number of arguments(%d for %d) " ,
argc , len ) ;
}
switch ( len ) {
case - 2 :
return ( * func ) ( recv , rb_ary_new4 ( argc , argv ) ) ;
break ;
case - 1 :
return ( * func ) ( argc , argv , recv ) ;
break ;
case 0 :
return ( * func ) ( recv ) ;
break ;
case 1 :
return ( * func ) ( recv , argv [ 0 ] ) ;
break ;
case 2 :
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] ) ;
break ;
case 3 :
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] ) ;
break ;
case 4 :
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] ) ;
break ;
case 5 :
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] ) ;
break ;
case 6 :
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] ,
argv [ 5 ] ) ;
break ;
case 7 :
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] ,
argv [ 5 ] , argv [ 6 ] ) ;
break ;
case 8 :
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] ,
argv [ 5 ] , argv [ 6 ] , argv [ 7 ] ) ;
break ;
case 9 :
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] ,
argv [ 5 ] , argv [ 6 ] , argv [ 7 ] , argv [ 8 ] ) ;
break ;
case 10 :
return ( * func ) ( recv , argv [ 0 ] , argv [ 1 ] , argv [ 2 ] , argv [ 3 ] , argv [ 4 ] ,
argv [ 5 ] , argv [ 6 ] , argv [ 7 ] , argv [ 8 ] , argv [ 9 ] ) ;
break ;
case 11 :
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 ] ) ;
break ;
case 12 :
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 ] ) ;
break ;
case 13 :
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 ] ) ;
break ;
case 14 :
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 ] ) ;
break ;
case 15 :
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 ] ) ;
break ;
default :
rb_raise ( rb_eArgError , " too many arguments(%d) " , len ) ;
break ;
}
return Qnil ; /* not reached */
}
static inline VALUE
2008-05-21 11:18:15 -04:00
vm_call_cfunc ( rb_thread_t * const th , rb_control_frame_t * const reg_cfp ,
const int num , const ID id , const VALUE recv , const VALUE klass ,
const VALUE flag , const NODE * const mn , const rb_block_t * const blockptr )
2007-06-24 13:19:22 -04:00
{
VALUE val ;
EXEC_EVENT_HOOK ( th , RUBY_EVENT_C_CALL , recv , id , klass ) ;
{
rb_control_frame_t * cfp =
2007-11-09 08:04:22 -05:00
vm_push_frame ( th , 0 , FRAME_MAGIC_CFUNC | ( flag < < FRAME_MAGIC_MASK_BITS ) ,
2007-11-08 20:29:24 -05:00
recv , ( VALUE ) blockptr , 0 , reg_cfp - > sp , 0 , 1 ) ;
2007-06-24 13:19:22 -04:00
cfp - > method_id = id ;
2007-11-21 20:17:52 -05:00
cfp - > method_class = klass ;
2007-06-24 13:19:22 -04:00
reg_cfp - > sp - = num + 1 ;
val = call_cfunc ( mn - > nd_cfnc , recv , mn - > nd_argc , num , reg_cfp - > sp + 1 ) ;
if ( reg_cfp ! = th - > cfp + 1 ) {
rb_bug ( " cfp consistency error - send " ) ;
}
vm_pop_frame ( th ) ;
}
EXEC_EVENT_HOOK ( th , RUBY_EVENT_C_RETURN , recv , id , klass ) ;
return val ;
}
2008-05-21 11:18:15 -04:00
static inline int
vm_cfunc_flags ( const rb_control_frame_t * const cfp )
2007-11-08 20:29:24 -05:00
{
if ( RUBYVM_CFUNC_FRAME_P ( cfp ) )
2007-11-09 08:04:22 -05:00
return cfp - > flag > > FRAME_MAGIC_MASK_BITS ;
2007-11-08 20:29:24 -05:00
return 0 ;
}
2007-06-24 13:19:22 -04:00
static inline VALUE
2008-05-21 11:18:15 -04:00
vm_call_bmethod ( rb_thread_t * const th , const ID id , const VALUE procval ,
const VALUE recv , const VALUE klass , const int argc , VALUE * argv ,
rb_block_t * const blockptr )
2007-06-24 13:19:22 -04:00
{
rb_control_frame_t * cfp = th - > cfp ;
rb_proc_t * proc ;
VALUE val ;
/* control block frame */
( cfp - 2 ) - > method_id = id ;
2007-11-21 20:17:52 -05:00
( cfp - 2 ) - > method_class = klass ;
2007-06-24 13:19:22 -04:00
GetProcPtr ( procval , proc ) ;
2007-12-20 02:07:35 -05:00
val = vm_invoke_proc ( th , proc , recv , argc , argv , blockptr ) ;
2007-06-24 13:19:22 -04:00
return val ;
}
static inline VALUE
2008-05-21 11:18:15 -04:00
vm_method_missing ( rb_thread_t * const th , const ID id , const VALUE recv ,
const int num , rb_block_t * const blockptr , const int opt )
2007-06-24 13:19:22 -04:00
{
2008-05-21 11:18:15 -04:00
rb_control_frame_t * const reg_cfp = th - > cfp ;
2007-06-24 13:19:22 -04:00
VALUE * argv = STACK_ADDR_FROM_TOP ( num + 1 ) ;
VALUE val ;
argv [ 0 ] = ID2SYM ( id ) ;
th - > method_missing_reason = opt ;
th - > passed_block = blockptr ;
val = rb_funcall2 ( recv , idMethodMissing , num + 1 , argv ) ;
POPN ( num + 1 ) ;
return val ;
}
static inline void
2008-05-21 11:18:15 -04:00
vm_setup_method ( rb_thread_t * const th , rb_control_frame_t * const cfp ,
const int argc , rb_block_t * blockptr , const VALUE flag ,
const VALUE iseqval , const VALUE recv , const VALUE klass )
2007-06-24 13:19:22 -04:00
{
rb_iseq_t * iseq ;
int opt_pc , i ;
2007-12-09 00:56:00 -05:00
VALUE * sp , * rsp = cfp - > sp - argc ;
2007-06-24 13:19:22 -04:00
/* TODO: eliminate it */
GetISeqPtr ( iseqval , iseq ) ;
opt_pc = vm_callee_setup_arg ( th , iseq , argc , rsp , & blockptr ) ;
/* stack overflow check */
2007-12-18 08:14:32 -05:00
CHECK_STACK_OVERFLOW ( cfp , iseq - > stack_max ) ;
sp = rsp + iseq - > arg_size ;
2007-06-24 13:19:22 -04:00
2007-08-25 17:05:20 -04:00
if ( LIKELY ( ! ( flag & VM_CALL_TAILCALL_BIT ) ) ) {
if ( 0 ) printf ( " local_size: %d, arg_size: %d \n " ,
iseq - > local_size , iseq - > arg_size ) ;
2007-06-24 13:19:22 -04:00
/* clear local variables */
for ( i = 0 ; i < iseq - > local_size - iseq - > arg_size ; i + + ) {
* sp + + = Qnil ;
}
vm_push_frame ( th , iseq ,
FRAME_MAGIC_METHOD , recv , ( VALUE ) blockptr ,
iseq - > iseq_encoded + opt_pc , sp , 0 , 0 ) ;
2007-08-25 17:05:20 -04:00
cfp - > sp = rsp - 1 /* recv */ ;
2007-06-24 13:19:22 -04:00
}
else {
2007-08-25 17:05:20 -04:00
VALUE * p_rsp ;
2008-05-21 11:18:15 -04:00
th - > cfp + + ; /* pop cf */
2007-08-25 17:05:20 -04:00
p_rsp = th - > cfp - > sp ;
/* copy arguments */
for ( i = 0 ; i < ( sp - rsp ) ; i + + ) {
p_rsp [ i ] = rsp [ i ] ;
}
sp - = rsp - p_rsp ;
2007-06-24 13:19:22 -04:00
/* clear local variables */
for ( i = 0 ; i < iseq - > local_size - iseq - > arg_size ; i + + ) {
* sp + + = Qnil ;
}
vm_push_frame ( th , iseq ,
FRAME_MAGIC_METHOD , recv , ( VALUE ) blockptr ,
iseq - > iseq_encoded + opt_pc , sp , 0 , 0 ) ;
}
}
static inline VALUE
2008-05-21 11:18:15 -04:00
vm_call_method ( rb_thread_t * const th , rb_control_frame_t * const cfp ,
const int num , rb_block_t * const blockptr , const VALUE flag ,
const ID id , const NODE * mn , const VALUE recv , VALUE klass )
2007-06-24 13:19:22 -04:00
{
VALUE val ;
start_method_dispatch :
2008-05-21 11:18:15 -04:00
if ( mn ! = 0 ) {
2007-08-25 16:56:51 -04:00
if ( ( mn - > nd_noex = = 0 ) ) {
/* dispatch method */
NODE * node ;
normal_method_dispatch :
node = mn - > nd_body ;
switch ( nd_type ( node ) ) {
case RUBY_VM_METHOD_NODE : {
2008-01-17 11:48:18 -05:00
vm_setup_method ( th , cfp , num , blockptr , flag , ( VALUE ) node - > nd_body , recv , klass ) ;
return Qundef ;
2007-08-25 16:56:51 -04:00
}
case NODE_CFUNC : {
2008-01-17 11:48:18 -05:00
val = vm_call_cfunc ( th , cfp , num , id , recv , mn - > nd_clss , flag , node , blockptr ) ;
break ;
2007-08-25 16:56:51 -04:00
}
case NODE_ATTRSET : {
2008-01-17 11:48:18 -05:00
val = rb_ivar_set ( recv , node - > nd_vid , * ( cfp - > sp - 1 ) ) ;
cfp - > sp - = 2 ;
break ;
2007-08-25 16:56:51 -04:00
}
case NODE_IVAR : {
2008-01-17 11:48:18 -05:00
if ( num ! = 0 ) {
rb_raise ( rb_eArgError , " wrong number of arguments (%d for 0) " ,
num ) ;
}
val = rb_attr_get ( recv , node - > nd_vid ) ;
cfp - > sp - = 1 ;
break ;
2007-08-25 16:56:51 -04:00
}
case NODE_BMETHOD : {
2008-01-17 11:48:18 -05:00
VALUE * argv = cfp - > sp - num ;
val = vm_call_bmethod ( th , id , node - > nd_cval , recv , klass , num , argv , blockptr ) ;
cfp - > sp + = - num - 1 ;
break ;
2007-08-25 16:56:51 -04:00
}
case NODE_ZSUPER : {
2008-01-17 11:48:18 -05:00
klass = RCLASS_SUPER ( mn - > nd_clss ) ;
mn = rb_method_node ( klass , id ) ;
if ( mn ! = 0 ) {
goto normal_method_dispatch ;
}
else {
goto start_method_dispatch ;
}
2007-08-25 16:56:51 -04:00
}
default : {
2008-01-17 11:48:18 -05:00
printf ( " node: %s \n " , ruby_node_name ( nd_type ( node ) ) ) ;
rb_bug ( " eval_invoke_method: unreachable " ) ;
/* unreachable */
break ;
2007-08-25 16:56:51 -04:00
}
2007-08-17 08:25:47 -04:00
}
2007-06-24 13:19:22 -04:00
}
2007-08-25 16:56:51 -04:00
else {
int noex_safe ;
if ( ! ( flag & VM_CALL_FCALL_BIT ) & &
( mn - > nd_noex & NOEX_MASK ) & NOEX_PRIVATE ) {
int stat = NOEX_PRIVATE ;
2007-06-24 13:19:22 -04:00
2007-08-25 16:56:51 -04:00
if ( flag & VM_CALL_VCALL_BIT ) {
stat | = NOEX_VCALL ;
}
val = vm_method_missing ( th , id , recv , num , blockptr , stat ) ;
2007-08-17 08:25:47 -04:00
}
2007-09-28 10:17:28 -04:00
else if ( ( ( mn - > nd_noex & NOEX_MASK ) & NOEX_PROTECTED ) & &
2007-11-08 20:43:57 -05:00
! ( flag & VM_CALL_SEND_BIT ) ) {
2007-08-25 16:56:51 -04:00
VALUE defined_class = mn - > nd_clss ;
if ( TYPE ( defined_class ) = = T_ICLASS ) {
defined_class = RBASIC ( defined_class ) - > klass ;
}
2007-06-24 13:19:22 -04:00
2007-08-25 16:56:51 -04:00
if ( ! rb_obj_is_kind_of ( cfp - > self , rb_class_real ( defined_class ) ) ) {
val = vm_method_missing ( th , id , recv , num , blockptr , NOEX_PROTECTED ) ;
}
else {
goto normal_method_dispatch ;
}
}
else if ( ( noex_safe = NOEX_SAFE ( mn - > nd_noex ) ) > th - > safe_level & &
( noex_safe > 2 ) ) {
rb_raise ( rb_eSecurityError , " calling insecure method: %s " , rb_id2name ( id ) ) ;
2007-08-17 08:25:47 -04:00
}
else {
goto normal_method_dispatch ;
}
}
2007-06-24 13:19:22 -04:00
}
else {
2007-08-25 16:56:51 -04:00
/* method missing */
if ( id = = idMethodMissing ) {
rb_bug ( " method missing " ) ;
}
else {
int stat = 0 ;
if ( flag & VM_CALL_VCALL_BIT ) {
stat | = NOEX_VCALL ;
2007-08-18 01:11:49 -04:00
}
2007-08-25 16:56:51 -04:00
if ( flag & VM_CALL_SUPER_BIT ) {
stat | = NOEX_SUPER ;
2007-08-18 01:11:49 -04:00
}
2007-08-25 16:56:51 -04:00
val = vm_method_missing ( th , id , recv , num , blockptr , stat ) ;
2007-06-24 13:19:22 -04:00
}
}
RUBY_VM_CHECK_INTS ( ) ;
return val ;
}
2007-08-06 07:36:30 -04:00
static inline void
2008-05-21 11:18:15 -04:00
vm_send_optimize ( rb_control_frame_t * const reg_cfp , NODE * * const mn ,
rb_num_t * const flag , rb_num_t * const num ,
ID * const id , const VALUE klass )
2007-08-06 07:36:30 -04:00
{
if ( * mn & & nd_type ( ( * mn ) - > nd_body ) = = NODE_CFUNC ) {
NODE * node = ( * mn ) - > nd_body ;
extern VALUE rb_f_send ( int argc , VALUE * argv , VALUE recv ) ;
2007-11-04 15:36:20 -05:00
if ( node - > nd_cfnc = = rb_f_send ) {
2007-08-18 01:35:03 -04:00
int i = * num - 1 ;
VALUE sym = TOPN ( i ) ;
2007-08-06 07:36:30 -04:00
* id = SYMBOL_P ( sym ) ? SYM2ID ( sym ) : rb_to_id ( sym ) ;
/* shift arguments */
2007-08-18 01:35:03 -04:00
if ( i > 0 ) {
2007-08-18 02:52:51 -04:00
MEMMOVE ( & TOPN ( i ) , & TOPN ( i - 1 ) , VALUE , i ) ;
2007-08-06 07:36:30 -04:00
}
* mn = rb_method_node ( klass , * id ) ;
* num - = 1 ;
DEC_SP ( 1 ) ;
* flag | = VM_CALL_FCALL_BIT ;
}
}
}
2007-06-24 22:44:20 -04:00
/* yield */
2007-06-25 15:06:00 -04:00
static inline int
2008-05-21 11:18:15 -04:00
block_proc_is_lambda ( const VALUE procval )
2007-06-25 15:06:00 -04:00
{
rb_proc_t * proc ;
if ( procval ) {
GetProcPtr ( procval , proc ) ;
return proc - > is_lambda ;
}
else {
return 0 ;
}
}
2007-06-24 22:44:20 -04:00
static inline VALUE
2008-05-21 11:18:15 -04:00
vm_yield_with_cfunc ( rb_thread_t * const th , rb_block_t * const block ,
const VALUE self , const int argc , const VALUE * const argv )
2007-06-24 22:44:20 -04:00
{
NODE * ifunc = ( NODE * ) block - > iseq ;
VALUE val ;
VALUE arg ;
2007-06-25 15:06:00 -04:00
int lambda = block_proc_is_lambda ( block - > proc ) ;
2007-06-24 22:44:20 -04:00
2007-06-25 15:06:00 -04:00
if ( lambda ) {
2007-06-24 22:44:20 -04:00
arg = rb_ary_new4 ( argc , argv ) ;
}
2007-12-19 01:37:41 -05:00
else if ( argc = = 0 ) {
arg = Qnil ;
}
2007-06-24 22:44:20 -04:00
else {
2007-12-19 01:37:41 -05:00
arg = argv [ 0 ] ;
2007-06-24 22:44:20 -04:00
}
vm_push_frame ( th , 0 , FRAME_MAGIC_IFUNC ,
self , ( VALUE ) block - > dfp ,
0 , th - > cfp - > sp , block - > lfp , 1 ) ;
2007-12-19 01:37:41 -05:00
val = ( * ifunc - > nd_cfnc ) ( arg , ifunc - > nd_tval , argc , argv ) ;
2007-06-24 22:44:20 -04:00
th - > cfp + + ;
return val ;
}
static inline int
2008-05-21 11:18:15 -04:00
vm_yield_setup_args ( rb_thread_t * const th , const rb_iseq_t * const iseq ,
const int orig_argc , VALUE * const argv ,
rb_block_t * blockptr , const int lambda )
2007-06-24 22:44:20 -04:00
{
if ( 0 ) { /* for debug */
2008-05-21 11:18:15 -04:00
printf ( " argc: %d \n " , orig_argc ) ;
2007-06-24 22:44:20 -04:00
printf ( " iseq argc: %d \n " , iseq - > argc ) ;
2007-06-25 12:05:17 -04:00
printf ( " iseq opts: %d \n " , iseq - > arg_opts ) ;
2007-06-24 22:44:20 -04:00
printf ( " iseq rest: %d \n " , iseq - > arg_rest ) ;
2007-06-25 12:05:17 -04:00
printf ( " iseq post: %d \n " , iseq - > arg_post_len ) ;
2007-06-24 22:44:20 -04:00
printf ( " iseq blck: %d \n " , iseq - > arg_block ) ;
2007-06-25 12:05:17 -04:00
printf ( " iseq smpl: %d \n " , iseq - > arg_simple ) ;
2007-06-24 22:44:20 -04:00
printf ( " lambda: %s \n " , lambda ? " true " : " false " ) ;
}
2007-06-25 12:05:17 -04:00
if ( lambda ) {
/* call as method */
2008-05-21 11:18:15 -04:00
return vm_callee_setup_arg ( th , iseq , orig_argc , argv , & blockptr ) ;
2007-07-07 03:16:05 -04:00
}
2007-06-25 12:05:17 -04:00
else {
int i ;
2008-05-21 11:18:15 -04:00
int argc = orig_argc ;
2007-06-25 12:05:17 -04:00
const int m = iseq - > argc ;
2007-06-24 22:44:20 -04:00
2007-06-25 12:05:17 -04:00
th - > mark_stack_len = argc ;
2007-06-24 22:44:20 -04:00
2007-06-25 12:05:17 -04:00
/*
* yield [ 1 , 2 ]
* = > { | a | } = > a = [ 1 , 2 ]
* = > { | a , b | } = > a , b = [ 1 , 2 ]
*/
2007-08-17 22:48:13 -04:00
if ( ! ( iseq - > arg_simple & 0x02 ) & &
( m + iseq - > arg_post_len ) > 0 & &
argc = = 1 & & TYPE ( argv [ 0 ] ) = = T_ARRAY ) {
2007-06-25 12:05:17 -04:00
VALUE ary = argv [ 0 ] ;
th - > mark_stack_len = argc = RARRAY_LEN ( ary ) ;
CHECK_STACK_OVERFLOW ( th - > cfp , argc ) ;
2007-08-18 01:35:03 -04:00
MEMCPY ( argv , RARRAY_PTR ( ary ) , VALUE , argc ) ;
2007-06-24 22:44:20 -04:00
}
2007-06-25 12:05:17 -04:00
for ( i = argc ; i < m ; i + + ) {
argv [ i ] = Qnil ;
}
if ( iseq - > arg_rest = = - 1 ) {
if ( m < argc ) {
/*
* yield 1 , 2
* = > { | a | } # truncate
*/
th - > mark_stack_len = argc = m ;
2007-06-24 22:44:20 -04:00
}
}
2007-06-25 12:05:17 -04:00
else {
int r = iseq - > arg_rest ;
2007-06-24 22:44:20 -04:00
2007-06-25 12:05:17 -04:00
if ( iseq - > arg_post_len ) {
int len = iseq - > arg_post_len ;
int start = iseq - > arg_post_start ;
2007-08-18 02:45:37 -04:00
int rsize = argc > m ? argc - m : 0 ;
2007-06-25 12:05:17 -04:00
int psize = rsize ;
VALUE ary ;
if ( psize > len ) psize = len ;
2007-08-18 01:35:03 -04:00
ary = rb_ary_new4 ( rsize - psize , & argv [ r ] ) ;
2007-06-25 12:05:17 -04:00
if ( 0 ) {
printf ( " argc: %d \n " , argc ) ;
printf ( " len: %d \n " , len ) ;
printf ( " start: %d \n " , start ) ;
printf ( " rsize: %d \n " , rsize ) ;
}
/* copy post argument */
2007-08-18 01:35:03 -04:00
MEMMOVE ( & argv [ start ] , & argv [ r + rsize - psize ] , VALUE , psize ) ;
2007-06-25 12:05:17 -04:00
2007-08-18 01:35:03 -04:00
for ( i = psize ; i < len ; i + + ) {
2007-06-25 12:05:17 -04:00
argv [ start + i ] = Qnil ;
}
argv [ r ] = ary ;
2007-06-24 22:44:20 -04:00
}
else {
2007-06-25 12:05:17 -04:00
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 ] ) ;
2007-06-24 22:44:20 -04:00
}
}
2007-06-25 12:05:17 -04:00
th - > mark_stack_len = iseq - > arg_size ;
2007-06-24 22:44:20 -04:00
}
2007-06-25 12:05:17 -04:00
/* {|&b|} */
if ( iseq - > arg_block ! = - 1 ) {
2007-07-07 02:34:40 -04:00
VALUE procval = Qnil ;
2007-06-25 12:05:17 -04:00
2007-07-07 02:34:40 -04:00
if ( blockptr ) {
procval = blockptr - > proc ;
2007-06-25 12:05:17 -04:00
}
2007-06-24 22:44:20 -04:00
2007-07-07 02:34:40 -04:00
argv [ iseq - > arg_block ] = procval ;
2007-06-24 22:44:20 -04:00
}
2007-06-25 12:05:17 -04:00
th - > mark_stack_len = 0 ;
return 0 ;
2007-06-24 22:44:20 -04:00
}
}
2007-08-06 07:36:30 -04:00
static VALUE
2008-05-21 11:18:15 -04:00
vm_invoke_block ( rb_thread_t * const th , rb_control_frame_t * const reg_cfp ,
const rb_num_t num , const rb_num_t flag )
2007-08-06 07:36:30 -04:00
{
2008-05-21 11:18:15 -04:00
rb_block_t * const block = GET_BLOCK_PTR ( ) ;
2007-08-06 07:36:30 -04:00
rb_iseq_t * iseq ;
int argc = num ;
if ( GET_ISEQ ( ) - > local_iseq - > type ! = ISEQ_TYPE_METHOD | | block = = 0 ) {
vm_localjump_error ( " no block given (yield) " , Qnil , 0 ) ;
}
iseq = block - > iseq ;
2007-11-28 02:31:10 -05:00
argc = caller_setup_args ( th , GET_CFP ( ) , flag , argc , 0 , 0 ) ;
2007-08-06 07:36:30 -04:00
if ( BUILTIN_TYPE ( iseq ) ! = T_NODE ) {
int opt_pc ;
2007-12-18 08:14:32 -05:00
const int arg_size = iseq - > arg_size ;
2008-05-21 11:18:15 -04:00
VALUE * const rsp = GET_SP ( ) - argc ;
2007-12-18 08:14:32 -05:00
SET_SP ( rsp ) ;
2007-08-06 07:36:30 -04:00
CHECK_STACK_OVERFLOW ( GET_CFP ( ) , iseq - > stack_max ) ;
2007-12-18 08:14:32 -05:00
opt_pc = vm_yield_setup_args ( th , iseq , argc , rsp , 0 ,
2007-08-06 07:36:30 -04:00
block_proc_is_lambda ( block - > proc ) ) ;
vm_push_frame ( th , iseq ,
FRAME_MAGIC_BLOCK , block - > self , ( VALUE ) block - > dfp ,
2007-12-18 08:14:32 -05:00
iseq - > iseq_encoded + opt_pc , rsp + arg_size , block - > lfp ,
iseq - > local_size - arg_size ) ;
2007-08-06 07:36:30 -04:00
return Qundef ;
}
else {
2008-05-21 11:18:15 -04:00
VALUE val = vm_yield_with_cfunc ( th , block , block - > self , argc , STACK_ADDR_FROM_TOP ( argc ) ) ;
2007-11-28 02:31:10 -05:00
POPN ( argc ) ; /* TODO: should put before C/yield? */
2007-08-06 07:36:30 -04:00
return val ;
}
}
* 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-18 23:08:50 -04:00
/* svar */
2007-06-24 13: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-18 23:08:50 -04:00
static inline NODE *
2008-05-21 11:18:15 -04:00
lfp_svar_place ( rb_thread_t * const th , VALUE * const lfp )
2007-06-24 13: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-18 23:08:50 -04:00
NODE * svar ;
2007-06-24 13:19:22 -04:00
if ( th - > local_lfp ! = lfp ) {
* 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-18 23:08:50 -04:00
svar = ( NODE * ) lfp [ - 1 ] ;
2007-07-10 04:04:52 -04:00
if ( ( VALUE ) svar = = 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-18 23:08:50 -04:00
svar = NEW_IF ( Qnil , Qnil , Qnil ) ;
2007-07-10 04:04:52 -04:00
lfp [ - 1 ] = ( VALUE ) svar ;
2007-06-24 13:19:22 -04:00
}
}
else {
* 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-18 23:08:50 -04:00
svar = ( NODE * ) th - > local_svar ;
2007-07-10 04:04:52 -04:00
if ( ( VALUE ) svar = = 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-18 23:08:50 -04:00
svar = NEW_IF ( Qnil , Qnil , Qnil ) ;
2007-07-10 04:04:52 -04:00
th - > local_svar = ( VALUE ) svar ;
2007-06-24 13:19:22 -04:00
}
}
2007-07-10 04:04:52 -04:00
return svar ;
}
static VALUE
2008-05-21 11:18:15 -04:00
lfp_svar_get ( rb_thread_t * const th , VALUE * const lfp , const VALUE key )
2007-07-10 04:04:52 -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-18 23:08:50 -04:00
NODE * svar = lfp_svar_place ( th , lfp ) ;
2007-07-10 04:04:52 -04:00
switch ( key ) {
2007-06-24 13:19:22 -04:00
case 0 :
* 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-18 23:08:50 -04:00
return svar - > u1 . value ;
2007-06-24 13:19:22 -04:00
case 1 :
* 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-18 23:08:50 -04:00
return svar - > u2 . value ;
2007-07-10 04:04:52 -04:00
default : {
2008-05-21 11:18:15 -04:00
const VALUE hash = svar - > u3 . value ;
2007-07-10 04:04:52 -04:00
2007-08-18 01:11:49 -04:00
if ( hash = = Qnil ) {
return Qnil ;
}
else {
return rb_hash_lookup ( hash , key ) ;
}
2007-07-10 04:04:52 -04:00
}
}
}
static void
2008-05-21 11:18:15 -04:00
lfp_svar_set ( rb_thread_t * const th , VALUE * const lfp ,
const VALUE key , const VALUE val )
2007-07-10 04:04:52 -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-18 23:08:50 -04:00
NODE * svar = lfp_svar_place ( th , lfp ) ;
2007-07-10 04:04:52 -04:00
switch ( key ) {
case 0 :
* 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-18 23:08:50 -04:00
svar - > u1 . value = val ;
2007-07-10 04:04:52 -04:00
return ;
case 1 :
* 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-18 23:08:50 -04:00
svar - > u2 . value = val ;
2007-07-10 06:22:30 -04:00
return ;
2007-07-10 04:04:52 -04:00
default : {
* 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-18 23:08:50 -04:00
VALUE hash = svar - > u3 . value ;
2007-07-10 04:04:52 -04:00
2007-08-18 01:11:49 -04:00
if ( hash = = 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-18 23:08:50 -04:00
svar - > u3 . value = hash = rb_hash_new ( ) ;
2007-08-18 01:11:49 -04:00
}
rb_hash_aset ( hash , key , val ) ;
2007-06-24 13:19:22 -04:00
}
}
}
2007-08-06 07:36:30 -04:00
static inline VALUE
2008-05-21 11:18:15 -04:00
vm_getspecial ( rb_thread_t * const th , VALUE * const lfp ,
const VALUE key , const rb_num_t type )
2007-08-06 07:36:30 -04:00
{
VALUE val ;
if ( type = = 0 ) {
2008-05-21 11:18:15 -04:00
VALUE k = key ;
if ( FIXNUM_P ( key ) ) {
k = FIX2INT ( key ) ;
}
val = lfp_svar_get ( th , lfp , k ) ;
2007-08-06 07:36:30 -04:00
}
else {
VALUE backref = lfp_svar_get ( th , lfp , 1 ) ;
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 " ) ;
}
}
else {
val = rb_reg_nth_match ( type > > 1 , backref ) ;
}
}
return val ;
}
* 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-18 23:08:50 -04:00
static NODE *
2008-05-21 11:18:15 -04:00
vm_get_cref ( const rb_iseq_t * const iseq ,
const VALUE * const lfp , const VALUE * dfp )
* 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-18 23:08:50 -04:00
{
NODE * cref = 0 ;
while ( 1 ) {
if ( lfp = = dfp ) {
cref = iseq - > cref_stack ;
break ;
}
else if ( dfp [ - 1 ] ! = Qnil ) {
cref = ( NODE * ) dfp [ - 1 ] ;
break ;
}
dfp = GET_PREV_DFP ( dfp ) ;
}
if ( cref = = 0 ) {
rb_bug ( " vm_get_cref: unreachable " ) ;
}
return cref ;
}
2008-04-03 06:59:44 -04:00
static inline void
2008-05-21 11:18:15 -04:00
vm_check_if_namespace ( const VALUE klass )
2008-04-03 06:59:44 -04:00
{
switch ( TYPE ( klass ) ) {
case T_CLASS :
case T_MODULE :
break ;
default :
rb_raise ( rb_eTypeError , " %s is not a class/module " ,
2008-05-04 22:27:29 -04:00
RSTRING_PTR ( rb_inspect ( klass ) ) ) ;
2008-04-03 06:59:44 -04:00
}
}
2007-06-24 13:19:22 -04:00
static inline VALUE
2008-05-21 11:18:15 -04:00
vm_get_ev_const ( rb_thread_t * const th , const rb_iseq_t * const iseq ,
const VALUE orig_klass , const ID id , const int is_defined )
2007-06-24 13:19:22 -04:00
{
VALUE val ;
2008-05-21 11:18:15 -04:00
if ( orig_klass = = Qnil ) {
2007-06-24 13:19:22 -04:00
/* in current lexical scope */
2008-05-21 11:18:15 -04:00
const NODE * const root_cref = vm_get_cref ( iseq , th - > cfp - > lfp , th - > cfp - > dfp ) ;
const NODE * cref = root_cref ;
VALUE klass = orig_klass ;
2007-06-24 13:19:22 -04:00
while ( cref & & cref - > nd_next ) {
klass = cref - > nd_clss ;
cref = cref - > nd_next ;
2008-05-19 14:47:56 -04:00
if ( ! NIL_P ( klass ) ) {
search_continue :
if ( RCLASS_IV_TBL ( klass ) & &
st_lookup ( RCLASS_IV_TBL ( klass ) , id , & val ) ) {
if ( val = = Qundef ) {
rb_autoload_load ( klass , id ) ;
goto search_continue ;
2007-06-24 13:19:22 -04:00
}
else {
2008-05-19 14:47:56 -04:00
if ( is_defined ) {
return 1 ;
}
else {
return val ;
}
2007-06-24 13:19:22 -04:00
}
}
}
}
2008-05-19 14:47:56 -04:00
/* search self */
2007-06-24 13:19:22 -04:00
klass = root_cref - > nd_clss ;
2008-05-19 14:47:56 -04:00
if ( NIL_P ( klass ) ) {
klass = CLASS_OF ( th - > cfp - > self ) ;
}
2007-06-24 13:19:22 -04:00
if ( is_defined ) {
return rb_const_defined ( klass , id ) ;
}
else {
return rb_const_get ( klass , id ) ;
}
}
else {
2008-05-21 11:18:15 -04:00
vm_check_if_namespace ( orig_klass ) ;
2007-06-24 13:19:22 -04:00
if ( is_defined ) {
2008-05-21 11:18:15 -04:00
return rb_const_defined_from ( orig_klass , id ) ;
2007-06-24 13:19:22 -04:00
}
else {
2008-05-21 11:18:15 -04:00
return rb_const_get_from ( orig_klass , id ) ;
2007-06-24 13:19:22 -04:00
}
}
}
static inline VALUE
* 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-18 23:08:50 -04:00
vm_get_cvar_base ( NODE * cref )
2007-06-24 13:19:22 -04:00
{
2008-05-19 14:47:56 -04:00
VALUE klass ;
while ( cref & & cref - > nd_next & & ( NIL_P ( cref - > nd_clss ) | | FL_TEST ( cref - > nd_clss , FL_SINGLETON ) ) ) {
cref = cref - > nd_next ;
2007-06-24 13:19:22 -04:00
if ( ! cref - > nd_next ) {
rb_warn ( " class variable access from toplevel " ) ;
}
}
2008-05-19 14:47:56 -04:00
klass = cref - > nd_clss ;
2007-06-24 13:19:22 -04:00
if ( NIL_P ( klass ) ) {
rb_raise ( rb_eTypeError , " no class variables available " ) ;
}
return klass ;
}
static inline void
2008-05-21 11:18:15 -04:00
vm_define_method ( rb_thread_t * const th , const VALUE obj , const ID id ,
rb_iseq_t * const miseq , const rb_num_t is_singleton ,
NODE * const cref )
2007-06-24 13:19:22 -04:00
{
NODE * newbody ;
VALUE klass = cref - > nd_clss ;
* 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-18 23:08:50 -04:00
int noex = cref - > nd_visi ;
2007-06-24 13:19:22 -04:00
2008-05-19 14:47:56 -04:00
if ( NIL_P ( klass ) ) {
rb_raise ( rb_eTypeError , " no class/module to add method " ) ;
}
2007-06-24 13:19:22 -04:00
if ( is_singleton ) {
if ( FIXNUM_P ( obj ) | | SYMBOL_P ( obj ) ) {
rb_raise ( rb_eTypeError ,
" can't define singleton method \" %s \" for %s " ,
rb_id2name ( id ) , rb_obj_classname ( obj ) ) ;
}
if ( OBJ_FROZEN ( obj ) ) {
rb_error_frozen ( " object " ) ;
}
klass = rb_singleton_class ( obj ) ;
noex = NOEX_PUBLIC ;
}
/* dup */
COPY_CREF ( miseq - > cref_stack , cref ) ;
miseq - > klass = klass ;
miseq - > defined_method_id = id ;
newbody = NEW_NODE ( RUBY_VM_METHOD_NODE , 0 , miseq - > self , 0 ) ;
rb_add_method ( klass , id , newbody , noex ) ;
if ( ! is_singleton & & noex = = NOEX_MODFUNC ) {
rb_add_method ( rb_singleton_class ( klass ) , id , newbody , NOEX_PUBLIC ) ;
}
INC_VM_STATE_VERSION ( ) ;
}
static inline NODE *
2008-05-21 11:18:15 -04:00
vm_method_search ( const VALUE id , const VALUE klass , const IC ic )
2007-06-24 13:19:22 -04:00
{
NODE * mn ;
# if OPT_INLINE_METHOD_CACHE
{
2007-11-21 20:17:52 -05:00
if ( LIKELY ( klass = = ic - > ic_class ) & &
2007-06-24 13:19:22 -04:00
LIKELY ( GET_VM_STATE_VERSION ( ) = = ic - > ic_vmstat ) ) {
mn = ic - > ic_method ;
}
else {
mn = rb_method_node ( klass , id ) ;
2007-11-21 20:17:52 -05:00
ic - > ic_class = klass ;
2007-06-24 13:19:22 -04:00
ic - > ic_method = mn ;
ic - > ic_vmstat = GET_VM_STATE_VERSION ( ) ;
}
}
# else
mn = rb_method_node ( klass , id ) ;
# endif
return mn ;
}
2007-08-06 07:36:30 -04:00
static inline VALUE
2008-05-21 11:18:15 -04:00
vm_search_normal_superclass ( VALUE klass , const VALUE recv )
2007-06-24 22:44:20 -04:00
{
if ( BUILTIN_TYPE ( klass ) = = T_CLASS ) {
2007-09-28 02:21:46 -04:00
klass = RCLASS_SUPER ( klass ) ;
2007-06-24 22:44:20 -04:00
}
else if ( BUILTIN_TYPE ( klass ) = = T_MODULE ) {
VALUE k = CLASS_OF ( recv ) ;
while ( k ) {
if ( BUILTIN_TYPE ( k ) = = T_ICLASS & & RBASIC ( k ) - > klass = = klass ) {
2007-09-28 02:21:46 -04:00
klass = RCLASS_SUPER ( k ) ;
2007-06-24 22:44:20 -04:00
break ;
}
2007-09-28 02:21:46 -04:00
k = RCLASS_SUPER ( k ) ;
2007-06-24 22:44:20 -04:00
}
}
return klass ;
}
2007-08-06 07:36:30 -04:00
static void
2008-05-21 11:18:15 -04:00
vm_search_superclass ( rb_control_frame_t * const reg_cfp , rb_iseq_t * ip ,
const VALUE recv , const VALUE sigval ,
ID * const idp , VALUE * const klassp )
2007-08-06 07:36:30 -04:00
{
ID id ;
VALUE klass ;
while ( ip & & ! ip - > klass ) {
ip = ip - > parent_iseq ;
}
if ( ip = = 0 ) {
rb_raise ( rb_eNoMethodError , " super called outside of method " ) ;
}
id = ip - > defined_method_id ;
if ( ip ! = ip - > local_iseq ) {
/* defined by Module#define_method() */
rb_control_frame_t * lcfp = GET_CFP ( ) ;
while ( lcfp - > iseq ! = ip ) {
VALUE * tdfp = GET_PREV_DFP ( lcfp - > dfp ) ;
while ( 1 ) {
lcfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( lcfp ) ;
if ( lcfp - > dfp = = tdfp ) {
break ;
}
}
}
id = lcfp - > method_id ;
2007-11-21 20:17:52 -05:00
klass = vm_search_normal_superclass ( lcfp - > method_class , recv ) ;
2007-08-06 07:36:30 -04:00
if ( sigval = = Qfalse ) {
/* zsuper */
rb_raise ( rb_eRuntimeError , " implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly. " ) ;
}
}
else {
2007-11-21 20:17:52 -05:00
klass = vm_search_normal_superclass ( ip - > klass , recv ) ;
2007-08-06 07:36:30 -04:00
}
* idp = id ;
* klassp = klass ;
}
static VALUE
2008-05-21 11:18:15 -04:00
vm_throw ( rb_thread_t * const th , rb_control_frame_t * const reg_cfp ,
const rb_num_t throw_state , const VALUE throwobj )
2007-08-06 07:36:30 -04:00
{
rb_num_t state = throw_state & 0xff ;
rb_num_t flag = throw_state & 0x8000 ;
rb_num_t level = throw_state > > 16 ;
if ( state ! = 0 ) {
2008-05-22 00:28:13 -04:00
VALUE * pt = 0 ;
2007-08-06 07:36:30 -04:00
int i ;
if ( flag ! = 0 ) {
if ( throw_state & 0x4000 ) {
pt = ( void * ) 1 ;
}
else {
pt = 0 ;
}
}
else {
if ( state = = TAG_BREAK ) {
rb_control_frame_t * cfp = GET_CFP ( ) ;
VALUE * dfp = GET_DFP ( ) ;
int is_orphan = 1 ;
rb_iseq_t * base_iseq = GET_ISEQ ( ) ;
search_parent :
if ( cfp - > iseq - > type ! = ISEQ_TYPE_BLOCK ) {
dfp = GC_GUARDED_PTR_REF ( ( VALUE * ) * dfp ) ;
base_iseq = base_iseq - > parent_iseq ;
while ( ( VALUE * ) cfp < th - > stack + th - > stack_size ) {
if ( cfp - > dfp = = dfp ) {
goto search_parent ;
}
cfp + + ;
}
rb_bug ( " VM (throw): can't find break base. " ) ;
}
if ( VM_FRAME_TYPE ( cfp ) = = FRAME_MAGIC_LAMBDA ) {
/* lambda{... break ...} */
is_orphan = 0 ;
pt = dfp ;
}
else {
dfp = GC_GUARDED_PTR_REF ( ( VALUE * ) * dfp ) ;
while ( ( VALUE * ) cfp < th - > stack + th - > stack_size ) {
if ( cfp - > dfp = = dfp ) {
VALUE epc = epc = cfp - > pc - cfp - > iseq - > iseq_encoded ;
rb_iseq_t * iseq = cfp - > iseq ;
int i ;
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 = dfp ;
is_orphan = 0 ;
break ;
}
cfp + + ;
}
}
if ( is_orphan ) {
vm_localjump_error ( " break from proc-closure " , throwobj , TAG_BREAK ) ;
}
}
else if ( state = = TAG_RETRY ) {
pt = GC_GUARDED_PTR_REF ( ( VALUE * ) * GET_DFP ( ) ) ;
for ( i = 0 ; i < level ; i + + ) {
pt = GC_GUARDED_PTR_REF ( ( VALUE * ) * pt ) ;
}
}
else if ( state = = TAG_RETURN ) {
rb_control_frame_t * cfp = GET_CFP ( ) ;
VALUE * dfp = GET_DFP ( ) ;
int is_orphan = 1 ;
/**
* check orphan :
*/
while ( ( VALUE * ) cfp < th - > stack + th - > stack_size ) {
if ( GET_DFP ( ) = = dfp ) {
if ( VM_FRAME_TYPE ( cfp ) = = FRAME_MAGIC_LAMBDA ) {
/* in lambda */
is_orphan = 0 ;
break ;
}
}
if ( GET_LFP ( ) = = cfp - > lfp & &
cfp - > iseq - > type = = ISEQ_TYPE_METHOD ) {
is_orphan = 0 ;
break ;
}
2007-09-26 06:29:00 -04:00
cfp + + ;
2007-08-06 07:36:30 -04:00
}
if ( is_orphan ) {
vm_localjump_error ( " unexpected return " , throwobj , TAG_RETURN ) ;
}
pt = GET_LFP ( ) ;
}
else {
rb_bug ( " isns(throw): unsupport throw type " ) ;
}
}
th - > state = state ;
return ( VALUE ) NEW_THROW_OBJECT ( throwobj , ( VALUE ) pt , state ) ;
}
else {
/* 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 ) ;
}
else {
2007-08-17 22:48:13 -04:00
th - > state = TAG_RAISE ;
2007-08-23 03:59:42 -04:00
/*th->state = FIX2INT(rb_ivar_get(err, idThrowState));*/
2007-08-06 07:36:30 -04:00
}
return err ;
}
}
2007-08-23 03:10:56 -04:00
static inline void
2008-05-21 11:18:15 -04:00
vm_expandarray ( rb_control_frame_t * const cfp , VALUE ary ,
const int num , const int flag )
2007-08-23 03:10:56 -04:00
{
int is_splat = flag & 0x01 ;
int space_size = num + is_splat ;
VALUE * base = cfp - > sp , * ptr ;
2007-09-14 03:26:07 -04:00
volatile VALUE tmp_ary ;
2007-08-23 03:10:56 -04:00
int len ;
if ( TYPE ( ary ) ! = T_ARRAY ) {
ary = rb_ary_to_ary ( ary ) ;
}
2007-09-14 03:26:07 -04:00
2007-12-19 20:03:15 -05:00
cfp - > sp + = space_size ;
2007-09-14 03:26:07 -04:00
tmp_ary = ary ;
2007-08-23 03:10:56 -04:00
ptr = RARRAY_PTR ( ary ) ;
len = RARRAY_LEN ( ary ) ;
if ( flag & 0x02 ) {
/* post: ..., nil ,ary[-1], ..., ary[0..-num] # top */
int 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 ) ;
}
}
else {
/* normal: ary[num..-1], ary[num-2], ary[num-3], ..., ary[0] # top */
int i ;
VALUE * bptr = & base [ space_size - 1 ] ;
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 ) ;
}
}
}
}
2007-12-18 07:07:51 -05:00
static inline int
2008-05-21 11:18:15 -04:00
check_cfunc ( const NODE * const mn , const void * const func )
2007-12-18 07:07:51 -05:00
{
if ( mn & & nd_type ( mn - > nd_body ) = = NODE_CFUNC & &
mn - > nd_body - > nd_cfnc = = func ) {
return 1 ;
}
else {
return 0 ;
}
}
2008-05-21 11:18:15 -04:00
static inline VALUE
opt_eq_func ( const VALUE recv , const VALUE obj , const IC ic )
2007-12-18 07:07:51 -05:00
{
VALUE val = Qundef ;
if ( FIXNUM_2_P ( recv , obj ) & &
BASIC_OP_UNREDEFINED_P ( BOP_EQ ) ) {
2008-05-21 11:18:15 -04:00
if ( recv = = obj ) {
2007-12-18 07:07:51 -05:00
val = Qtrue ;
}
else {
val = 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 ) ) {
double a = RFLOAT_VALUE ( recv ) ;
double b = RFLOAT_VALUE ( obj ) ;
if ( isnan ( a ) | | isnan ( b ) ) {
val = Qfalse ;
}
else if ( a = = b ) {
val = Qtrue ;
}
else {
val = Qfalse ;
}
}
else if ( HEAP_CLASS_OF ( recv ) = = rb_cString & &
HEAP_CLASS_OF ( obj ) = = rb_cString & &
BASIC_OP_UNREDEFINED_P ( BOP_EQ ) ) {
val = rb_str_equal ( recv , obj ) ;
}
else {
NODE * mn = vm_method_search ( idEq , CLASS_OF ( recv ) , ic ) ;
extern VALUE rb_obj_equal ( VALUE obj1 , VALUE obj2 ) ;
if ( check_cfunc ( mn , rb_obj_equal ) ) {
return recv = = obj ? Qtrue : Qfalse ;
}
}
}
return val ;
}