#include "method_data.h" #include #ifndef HAVE_RUBINIUS #ruby < #elif defined(REALLY_HAVE_RUBY_NODE_H) /* YARV */ #include #elif defined(RUBY_VM) /* YARV without node.h */ #include "minimal_node.h" #else /* something else */ #error "Need node.h" #endif #ifdef HAVE_ENV_H /* pre-YARV */ #include #endif #ifdef RUBY_VM /* YARV */ struct rb_thread_struct { VALUE self; void *vm; VALUE *stack; unsigned long stack_size; VALUE *cfp; /* ... */ }; typedef struct rb_thread_struct rb_thread_t; #define CFP_DATA_MEMO_NODE_AND_PC cfp[0] #define CFP_METHOD_CLASS cfp[11] /* On YARV, we store the method data on the stack. We don't have to pop * it off the stack, because the stack pointer will be reset to the * previous frame's stack pointer when the function returns. */ static void fix_frame() { do { extern rb_thread_t * ruby_current_thread; VALUE * cfp = ruby_current_thread->cfp; CFP_DATA_MEMO_NODE_AND_PC = RBASIC(CFP_METHOD_CLASS)->klass; if(rb_type(CFP_DATA_MEMO_NODE_AND_PC) != T_NODE) { /* This can happen for module functions that are created after * the stub function */ rb_raise( rb_eRuntimeError, "Cannot find method data for module function"); } else { CFP_METHOD_CLASS = RCLASS_SUPER(CFP_METHOD_CLASS); } } while(0); } #define FIX_FRAME() \ fix_frame() static NODE * data_memo_node() { extern rb_thread_t * ruby_current_thread; VALUE * cfp = ruby_current_thread->cfp; return (NODE *)CFP_DATA_MEMO_NODE_AND_PC; } #else /* pre-YARV */ /* Okay to not pop this temporary frame, since it will be popped by the * caller */ #define FIX_FRAME() \ struct FRAME _frame = *ruby_frame; \ _frame.last_class = RCLASS(ruby_frame->last_class)->super; \ _frame.prev = ruby_frame; \ ruby_frame = &_frame; \ static NODE * data_memo_node() { return (NODE *)(RBASIC(ruby_frame->prev->last_class)->klass); } #endif typedef VALUE (*Method_Func)(ANYARGS); static Method_Func actual_cfunc() { return data_memo_node()->nd_cfnc; } static VALUE data_wrapper_m1(int argc, VALUE * argv, VALUE self) { VALUE result; FIX_FRAME(); result = (*actual_cfunc())(argc, argv, self); return result; } static VALUE data_wrapper_0(VALUE self) { VALUE result; FIX_FRAME(); result = (*actual_cfunc())(self); return result; } #ruby <prev->last_class->rval. * * On YARV, the current frame is not duplicated; rather, the method data * is placed on the stack and is referenced by one of the unused members * of the control frame (the program counter): * * ruby_current_thread->cfp * |- pc - NODE_MEMO * | |- (u1) cfnc - actual C function to call * | |- (u2) rval - stored data * | +- (u3) 0 * |- method_class - klass * +- ... * */ void define_method_with_data( VALUE klass, ID id, VALUE (*cfunc)(ANYARGS), int arity, VALUE data) { /* TODO: origin should have #to_s and #inspect methods defined */ #ifdef HAVE_RB_CLASS_BOOT VALUE origin = rb_class_boot(klass); #else VALUE origin = rb_class_new(klass); #endif NODE * node; VALUE (*data_wrapper)(ANYARGS); switch(arity) { #ruby <klass = (VALUE)NEW_NODE(NODE_MEMO, cfunc, data, 0); #ifdef RUBY_VM /* YARV */ node = NEW_FBODY( NEW_METHOD( NEW_CFUNC(data_wrapper, arity), origin, NOEX_PUBLIC), id); st_insert(RCLASS_M_TBL(klass), id, (st_data_t)node); #else /* pre-YARV */ node = NEW_FBODY( NEW_CFUNC(data_wrapper, arity), id, origin); rb_add_method(klass, id, node, NOEX_PUBLIC); #endif } VALUE get_method_data() { return data_memo_node()->nd_rval; } #else /* HAVE_RUBINIUS */ void define_method_with_data( VALUE klass, ID id, VALUE (*cfunc)(ANYARGS), int arity, VALUE data) { rb_raise(rb_eNotImpError, "Not implemented: define_method_with_data"); } VALUE get_method_data() { rb_raise(rb_eNotImpError, "Not implemented: get_method_data"); } #endif

AltStyle によって変換されたページ (->オリジナル) /