mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* method.h, vm_core.h: add rb_method_entry_t. Remove nodes around
method management. This change affect some VM control stack structure. * vm.c, vm_insnhelper.c, vm_method.c, vm_eval.c: ditto. and make some refactoring. * insns.def, class.c, eval.c, proc.c, vm_dump.c : ditto. * vm_core.h, compile.c (iseq_specialized_instruction): remove VM_CALL_SEND_BIT. use another optimization tech for Kernel#send. * node.h: remove unused node types. * ext/objspace/objspace.c (count_nodes): ditto. * gc.c: add mark/free functions for method entry. * include/ruby/intern.h: remove decl of rb_define_notimplement_method_id(). nobody can use it because noex is not opend. * iseq.c (iseq_mark): fix to check ic_method is available. * iseq.c (rb_iseq_disasm): fix to use rb_method_get_iseq(). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@24128 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
d3cbda6e8d
commit
c330876d7c
19 changed files with 886 additions and 789 deletions
27
ChangeLog
27
ChangeLog
|
@ -1,3 +1,30 @@
|
|||
Wed Jul 15 23:46:55 2009 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* method.h, vm_core.h: add rb_method_entry_t. Remove nodes around
|
||||
method management. This change affect some VM control stack structure.
|
||||
|
||||
* vm.c, vm_insnhelper.c, vm_method.c, vm_eval.c: ditto. and make some
|
||||
refactoring.
|
||||
|
||||
* insns.def, class.c, eval.c, proc.c, vm_dump.c : ditto.
|
||||
|
||||
* vm_core.h, compile.c (iseq_specialized_instruction): remove
|
||||
VM_CALL_SEND_BIT. use another optimization tech for Kernel#send.
|
||||
|
||||
* node.h: remove unused node types.
|
||||
|
||||
* ext/objspace/objspace.c (count_nodes): ditto.
|
||||
|
||||
* gc.c: add mark/free functions for method entry.
|
||||
|
||||
* include/ruby/intern.h: remove decl of
|
||||
rb_define_notimplement_method_id(). nobody can use it
|
||||
because noex is not opend.
|
||||
|
||||
* iseq.c (iseq_mark): fix to check ic_method is available.
|
||||
|
||||
* iseq.c (rb_iseq_disasm): fix to use rb_method_get_iseq().
|
||||
|
||||
Wed Jul 15 23:45:11 2009 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* dir.c (push_glob): fix GC problem.
|
||||
|
|
65
class.c
65
class.c
|
@ -25,7 +25,8 @@
|
|||
|
||||
#include "ruby/ruby.h"
|
||||
#include "ruby/st.h"
|
||||
#include "node.h"
|
||||
#include "method.h"
|
||||
#include "vm_core.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern st_table *rb_class_tbl;
|
||||
|
@ -123,28 +124,19 @@ struct clone_method_data {
|
|||
VALUE rb_iseq_clone(VALUE iseqval, VALUE newcbase);
|
||||
|
||||
static int
|
||||
clone_method(ID mid, NODE *body, struct clone_method_data *data)
|
||||
clone_method(ID mid, const rb_method_entry_t *me, struct clone_method_data *data)
|
||||
{
|
||||
if (body == 0) {
|
||||
st_insert(data->tbl, mid, 0);
|
||||
}
|
||||
else {
|
||||
NODE *fbody = body->nd_body->nd_body;
|
||||
|
||||
if (nd_type(fbody) == RUBY_VM_METHOD_NODE) {
|
||||
fbody = NEW_NODE(RUBY_VM_METHOD_NODE, 0,
|
||||
rb_iseq_clone((VALUE)fbody->nd_body, data->klass),
|
||||
0);
|
||||
}
|
||||
st_insert(data->tbl, mid,
|
||||
(st_data_t)
|
||||
NEW_NODE_LONGLIFE(
|
||||
NODE_FBODY,
|
||||
0,
|
||||
NEW_NODE_LONGLIFE(NODE_METHOD,
|
||||
rb_gc_write_barrier(data->klass), /* TODO */
|
||||
rb_gc_write_barrier((VALUE)fbody),
|
||||
body->nd_body->nd_noex), 0));
|
||||
switch (me->type) {
|
||||
case VM_METHOD_TYPE_ISEQ: {
|
||||
VALUE newiseqval = rb_iseq_clone(me->body.iseq->self, data->klass);
|
||||
rb_iseq_t *iseq;
|
||||
GetISeqPtr(newiseqval, iseq);
|
||||
rb_add_method(data->klass, mid, VM_METHOD_TYPE_ISEQ, iseq, me->flag);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rb_add_method_me(data->klass, mid, me, me->flag);
|
||||
break;
|
||||
}
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
@ -674,7 +666,7 @@ ins_methods_pub_i(ID name, long type, VALUE ary)
|
|||
}
|
||||
|
||||
static int
|
||||
method_entry(ID key, NODE *body, st_table *list)
|
||||
method_entry(ID key, const rb_method_entry_t *me, st_table *list)
|
||||
{
|
||||
long type;
|
||||
|
||||
|
@ -683,11 +675,11 @@ method_entry(ID key, NODE *body, st_table *list)
|
|||
}
|
||||
|
||||
if (!st_lookup(list, key, 0)) {
|
||||
if (body ==0 || !body->nd_body->nd_body) {
|
||||
if (!me || me->type == VM_METHOD_TYPE_UNDEF) {
|
||||
type = -1; /* none */
|
||||
}
|
||||
else {
|
||||
type = VISI(body->nd_body->nd_noex);
|
||||
type = VISI(me->flag);
|
||||
}
|
||||
st_add_direct(list, key, type);
|
||||
}
|
||||
|
@ -874,44 +866,33 @@ rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj)
|
|||
}
|
||||
|
||||
void
|
||||
rb_define_method_id(VALUE klass, ID name, VALUE (*func)(ANYARGS), int argc)
|
||||
rb_define_method_id(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc)
|
||||
{
|
||||
if (func == rb_f_notimplement)
|
||||
rb_define_notimplement_method_id(klass, name, NOEX_PUBLIC);
|
||||
else
|
||||
rb_add_method(klass, name, NEW_NODE_LONGLIFE(NODE_CFUNC, func, argc, 0), NOEX_PUBLIC);
|
||||
rb_add_method_cfunc(klass, mid, func, argc, NOEX_PUBLIC);
|
||||
}
|
||||
|
||||
void
|
||||
rb_define_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc)
|
||||
{
|
||||
rb_define_method_id(klass, rb_intern(name), func, argc);
|
||||
rb_add_method_cfunc(klass, rb_intern(name), func, argc, NOEX_PUBLIC);
|
||||
}
|
||||
|
||||
void
|
||||
rb_define_protected_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc)
|
||||
{
|
||||
ID id = rb_intern(name);
|
||||
if (func == rb_f_notimplement)
|
||||
rb_define_notimplement_method_id(klass, id, NOEX_PROTECTED);
|
||||
else
|
||||
rb_add_method(klass, id, NEW_NODE_LONGLIFE(NODE_CFUNC, func, argc, 0), NOEX_PROTECTED);
|
||||
rb_add_method_cfunc(klass, rb_intern(name), func, argc, NOEX_PROTECTED);
|
||||
}
|
||||
|
||||
void
|
||||
rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(ANYARGS), int argc)
|
||||
{
|
||||
ID id = rb_intern(name);
|
||||
if (func == rb_f_notimplement)
|
||||
rb_define_notimplement_method_id(klass, id, NOEX_PRIVATE);
|
||||
else
|
||||
rb_add_method(klass, id, NEW_NODE_LONGLIFE(NODE_CFUNC, func, argc, 0), NOEX_PRIVATE);
|
||||
rb_add_method_cfunc(klass, rb_intern(name), func, argc, NOEX_PRIVATE);
|
||||
}
|
||||
|
||||
void
|
||||
rb_undef_method(VALUE klass, const char *name)
|
||||
{
|
||||
rb_add_method(klass, rb_intern(name), 0, NOEX_UNDEF);
|
||||
rb_add_method(klass, rb_intern(name), VM_METHOD_TYPE_UNDEF, 0, NOEX_UNDEF);
|
||||
}
|
||||
|
||||
#define SPECIAL_SINGLETON(x,c) do {\
|
||||
|
|
|
@ -1855,12 +1855,6 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > 0) {
|
||||
if (mid == idSend || mid == id__send__ ) {
|
||||
OPERAND_AT(iobj, 3) |= INT2FIX(VM_CALL_SEND_BIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
return COMPILE_OK;
|
||||
}
|
||||
|
|
2
eval.c
2
eval.c
|
@ -684,7 +684,7 @@ frame_func_id(rb_control_frame_t *cfp)
|
|||
{
|
||||
rb_iseq_t *iseq = cfp->iseq;
|
||||
if (!iseq) {
|
||||
return cfp->method_id;
|
||||
return cfp->me->original_id;
|
||||
}
|
||||
while (iseq) {
|
||||
if (RUBY_VM_IFUNC_P(iseq)) {
|
||||
|
|
|
@ -350,9 +350,6 @@ count_nodes(int argc, VALUE *argv, VALUE os)
|
|||
VALUE node;
|
||||
switch (i) {
|
||||
#define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); break;
|
||||
COUNT_NODE(NODE_METHOD);
|
||||
COUNT_NODE(NODE_FBODY);
|
||||
COUNT_NODE(NODE_CFUNC);
|
||||
COUNT_NODE(NODE_SCOPE);
|
||||
COUNT_NODE(NODE_BLOCK);
|
||||
COUNT_NODE(NODE_IF);
|
||||
|
@ -441,7 +438,6 @@ count_nodes(int argc, VALUE *argv, VALUE os)
|
|||
COUNT_NODE(NODE_DOT3);
|
||||
COUNT_NODE(NODE_FLIP2);
|
||||
COUNT_NODE(NODE_FLIP3);
|
||||
COUNT_NODE(NODE_ATTRSET);
|
||||
COUNT_NODE(NODE_SELF);
|
||||
COUNT_NODE(NODE_NIL);
|
||||
COUNT_NODE(NODE_TRUE);
|
||||
|
|
72
gc.c
72
gc.c
|
@ -1435,12 +1435,6 @@ mark_tbl(rb_objspace_t *objspace, st_table *tbl, int lev)
|
|||
st_foreach(tbl, mark_entry, (st_data_t)&arg);
|
||||
}
|
||||
|
||||
void
|
||||
rb_mark_tbl(st_table *tbl)
|
||||
{
|
||||
mark_tbl(&rb_objspace, tbl, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
mark_key(VALUE key, VALUE value, st_data_t data)
|
||||
{
|
||||
|
@ -1490,6 +1484,64 @@ rb_mark_hash(st_table *tbl)
|
|||
mark_hash(&rb_objspace, tbl, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
mark_method_entry(rb_objspace_t *objspace, const rb_method_entry_t *me, int lev)
|
||||
{
|
||||
gc_mark(objspace, me->klass, lev);
|
||||
switch (me->type) {
|
||||
case VM_METHOD_TYPE_ISEQ:
|
||||
gc_mark(objspace, me->body.iseq->self, lev);
|
||||
break;
|
||||
case VM_METHOD_TYPE_BMETHOD:
|
||||
gc_mark(objspace, me->body.proc, lev);
|
||||
break;
|
||||
default:
|
||||
break; /* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_gc_mark_method_entry(const rb_method_entry_t *me)
|
||||
{
|
||||
mark_method_entry(&rb_objspace, me, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
mark_method_entry_i(ID key, const rb_method_entry_t *me, st_data_t data)
|
||||
{
|
||||
struct mark_tbl_arg *arg = (void*)data;
|
||||
mark_method_entry(arg->objspace, me, arg->lev);
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
mark_m_tbl(rb_objspace_t *objspace, st_table *tbl, int lev) {
|
||||
struct mark_tbl_arg arg;
|
||||
if (!tbl) return;
|
||||
arg.objspace = objspace;
|
||||
arg.lev = lev;
|
||||
st_foreach(tbl, mark_method_entry_i, (st_data_t)&arg);
|
||||
}
|
||||
|
||||
static int
|
||||
free_method_entry_i(ID key, rb_method_entry_t *me, st_data_t data)
|
||||
{
|
||||
xfree(me);
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
free_m_table(st_table *tbl)
|
||||
{
|
||||
st_foreach(tbl, free_method_entry_i, 0);
|
||||
}
|
||||
|
||||
void
|
||||
rb_mark_tbl(st_table *tbl)
|
||||
{
|
||||
mark_tbl(&rb_objspace, tbl, 0);
|
||||
}
|
||||
|
||||
void
|
||||
rb_gc_mark_maybe(VALUE obj)
|
||||
{
|
||||
|
@ -1591,7 +1643,6 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
|
|||
ptr = (VALUE)obj->as.node.u3.node;
|
||||
goto again;
|
||||
|
||||
case NODE_METHOD: /* 1,2 */
|
||||
case NODE_WHILE:
|
||||
case NODE_UNTIL:
|
||||
case NODE_AND:
|
||||
|
@ -1612,7 +1663,6 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
|
|||
case NODE_ARGSCAT:
|
||||
gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
|
||||
/* fall through */
|
||||
case NODE_FBODY: /* 2 */
|
||||
case NODE_GASGN:
|
||||
case NODE_LASGN:
|
||||
case NODE_DASGN:
|
||||
|
@ -1653,7 +1703,6 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
|
|||
|
||||
case NODE_ZARRAY: /* - */
|
||||
case NODE_ZSUPER:
|
||||
case NODE_CFUNC:
|
||||
case NODE_VCALL:
|
||||
case NODE_GVAR:
|
||||
case NODE_LVAR:
|
||||
|
@ -1669,7 +1718,6 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
|
|||
case NODE_TRUE:
|
||||
case NODE_FALSE:
|
||||
case NODE_ERRINFO:
|
||||
case NODE_ATTRSET:
|
||||
case NODE_BLOCK_ARG:
|
||||
break;
|
||||
case NODE_ALLOCA:
|
||||
|
@ -1698,7 +1746,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
|
|||
case T_ICLASS:
|
||||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
mark_tbl(objspace, RCLASS_M_TBL(obj), lev);
|
||||
mark_m_tbl(objspace, RCLASS_M_TBL(obj), lev);
|
||||
mark_tbl(objspace, RCLASS_IV_TBL(obj), lev);
|
||||
ptr = RCLASS_SUPER(obj);
|
||||
goto again;
|
||||
|
@ -2072,7 +2120,7 @@ obj_free(rb_objspace_t *objspace, VALUE obj)
|
|||
case T_MODULE:
|
||||
case T_CLASS:
|
||||
rb_clear_cache_by_class((VALUE)obj);
|
||||
st_free_table(RCLASS_M_TBL(obj));
|
||||
free_m_table(RCLASS_M_TBL(obj));
|
||||
if (RCLASS_IV_TBL(obj)) {
|
||||
st_free_table(RCLASS_IV_TBL(obj));
|
||||
}
|
||||
|
|
|
@ -275,7 +275,6 @@ int rb_method_basic_definition_p(VALUE, ID);
|
|||
VALUE rb_eval_cmd(VALUE, VALUE, int);
|
||||
int rb_obj_respond_to(VALUE, ID, int);
|
||||
int rb_respond_to(VALUE, ID);
|
||||
void rb_define_notimplement_method_id(VALUE mod, ID id, int noex);
|
||||
VALUE rb_f_notimplement(int argc, VALUE *argv, VALUE obj);
|
||||
void rb_interrupt(void);
|
||||
VALUE rb_apply(VALUE, ID, VALUE);
|
||||
|
|
36
insns.def
36
insns.def
|
@ -785,11 +785,11 @@ defined
|
|||
break;
|
||||
case DEFINED_METHOD:{
|
||||
VALUE klass = CLASS_OF(v);
|
||||
NODE *method = (NODE *) rb_method_node(klass, SYM2ID(obj));
|
||||
const rb_method_entry_t *me = rb_method_entry(klass, SYM2ID(obj));
|
||||
|
||||
if (method) {
|
||||
if (!(method->nd_noex & NOEX_PRIVATE)) {
|
||||
if (!((method->nd_noex & NOEX_PROTECTED) &&
|
||||
if (me) {
|
||||
if (!(me->flag & NOEX_PRIVATE)) {
|
||||
if (!((me->flag & NOEX_PROTECTED) &&
|
||||
!rb_obj_is_kind_of(GET_SELF(),
|
||||
rb_class_real(klass)))) {
|
||||
expr_type = "method";
|
||||
|
@ -979,7 +979,7 @@ send
|
|||
(...)
|
||||
(VALUE val) // inc += - (int)(op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
|
||||
{
|
||||
NODE *mn;
|
||||
const rb_method_entry_t *me;
|
||||
VALUE recv, klass;
|
||||
rb_block_t *blockptr = 0;
|
||||
rb_num_t num = caller_setup_args(th, GET_CFP(), op_flag, (int)op_argc,
|
||||
|
@ -990,14 +990,8 @@ send
|
|||
/* get receiver */
|
||||
recv = (flag & VM_CALL_FCALL_BIT) ? GET_SELF() : TOPN(num);
|
||||
klass = CLASS_OF(recv);
|
||||
mn = vm_method_search(id, klass, ic);
|
||||
|
||||
/* send/funcall optimization */
|
||||
if (flag & VM_CALL_SEND_BIT) {
|
||||
vm_send_optimize(GET_CFP(), &mn, &flag, &num, &id, klass);
|
||||
}
|
||||
|
||||
CALL_METHOD(num, blockptr, flag, id, mn, recv);
|
||||
me = vm_method_search(id, klass, ic);
|
||||
CALL_METHOD(num, blockptr, flag, id, me, recv);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1017,15 +1011,15 @@ invokesuper
|
|||
rb_num_t num = caller_setup_args(th, GET_CFP(), op_flag,
|
||||
(int)op_argc, blockiseq, &blockptr);
|
||||
VALUE recv, klass;
|
||||
NODE *mn;
|
||||
ID id;
|
||||
const VALUE flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
|
||||
VALUE flag = VM_CALL_SUPER_BIT | VM_CALL_FCALL_BIT;
|
||||
const rb_method_entry_t *me;
|
||||
|
||||
recv = GET_SELF();
|
||||
vm_search_superclass(GET_CFP(), GET_ISEQ(), recv, TOPN(num), &id, &klass);
|
||||
mn = rb_method_node(klass, id);
|
||||
me = rb_method_entry(klass, id);
|
||||
|
||||
CALL_METHOD(num, blockptr, flag, id, mn, recv);
|
||||
CALL_METHOD(num, blockptr, flag, id, me, recv);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1629,10 +1623,10 @@ opt_neq
|
|||
(VALUE val)
|
||||
{
|
||||
extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
|
||||
NODE *mn = vm_method_search(idNeq, CLASS_OF(recv), ic1);
|
||||
const rb_method_entry_t *me = vm_method_search(idNeq, CLASS_OF(recv), ic1);
|
||||
val = Qundef;
|
||||
|
||||
if (check_cfunc(mn, rb_obj_not_equal)) {
|
||||
if (check_cfunc(me, rb_obj_not_equal)) {
|
||||
val = opt_eq_func(recv, obj, ic2);
|
||||
|
||||
if (val != Qundef) {
|
||||
|
@ -1997,9 +1991,9 @@ opt_not
|
|||
(VALUE val)
|
||||
{
|
||||
extern VALUE rb_obj_not(VALUE obj);
|
||||
NODE *mn = vm_method_search(idNot, CLASS_OF(recv), ic);
|
||||
const rb_method_entry_t *me = vm_method_search(idNot, CLASS_OF(recv), ic);
|
||||
|
||||
if (check_cfunc(mn, rb_obj_not)) {
|
||||
if (check_cfunc(me, rb_obj_not)) {
|
||||
val = RTEST(recv) ? Qfalse : Qtrue;
|
||||
}
|
||||
else {
|
||||
|
|
14
iseq.c
14
iseq.c
|
@ -107,6 +107,9 @@ iseq_mark(void *ptr)
|
|||
for (i=0; i<iseq->ic_size; i++) {
|
||||
RUBY_MARK_UNLESS_NULL(iseq->ic_entries[i].ic_class);
|
||||
RUBY_MARK_UNLESS_NULL(iseq->ic_entries[i].ic_value);
|
||||
if (iseq->ic_entries[i].ic_method) {
|
||||
rb_gc_mark_method_entry(iseq->ic_entries[i].ic_method);
|
||||
}
|
||||
}
|
||||
|
||||
if (iseq->compile_data != 0) {
|
||||
|
@ -1002,17 +1005,14 @@ rb_iseq_disasm(VALUE self)
|
|||
static VALUE
|
||||
iseq_s_disasm(VALUE klass, VALUE body)
|
||||
{
|
||||
extern NODE *rb_method_body(VALUE body);
|
||||
NODE *node;
|
||||
VALUE ret = Qnil;
|
||||
rb_iseq_t *iseq;
|
||||
extern rb_iseq_t *rb_method_get_iseq(VALUE body);
|
||||
|
||||
rb_secure(1);
|
||||
|
||||
if ((node = rb_method_body(body)) != 0) {
|
||||
if (nd_type(node) == RUBY_VM_METHOD_NODE) {
|
||||
VALUE iseqval = (VALUE)node->nd_body;
|
||||
ret = rb_iseq_disasm(iseqval);
|
||||
}
|
||||
if ((iseq = rb_method_get_iseq(body)) != 0) {
|
||||
ret = rb_iseq_disasm(iseq->self);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
78
method.h
Normal file
78
method.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/**********************************************************************
|
||||
|
||||
method.h -
|
||||
|
||||
$Author: ko1 $
|
||||
created at: Wed Jul 15 20:02:33 2009
|
||||
|
||||
Copyright (C) 2009 Koichi Sasada
|
||||
|
||||
**********************************************************************/
|
||||
#ifndef METHOD_H
|
||||
#define METHOD_H
|
||||
|
||||
typedef enum {
|
||||
NOEX_PUBLIC = 0x00,
|
||||
NOEX_NOSUPER = 0x01,
|
||||
NOEX_PRIVATE = 0x02,
|
||||
NOEX_PROTECTED = 0x04,
|
||||
NOEX_MASK = 0x06,
|
||||
NOEX_BASIC = 0x08,
|
||||
NOEX_UNDEF = NOEX_NOSUPER,
|
||||
NOEX_MODFUNC = 0x12,
|
||||
NOEX_SUPER = 0x20,
|
||||
NOEX_VCALL = 0x40,
|
||||
} rb_method_flag_t;
|
||||
|
||||
#define NOEX_SAFE(n) ((int)((n) >> 8) & 0x0F)
|
||||
#define NOEX_WITH(n, s) ((s << 8) | (n) | (ruby_running ? 0 : NOEX_BASIC))
|
||||
#define NOEX_WITH_SAFE(n) NOEX_WITH(n, rb_safe_level())
|
||||
|
||||
/* method data type */
|
||||
|
||||
typedef enum {
|
||||
VM_METHOD_TYPE_ISEQ,
|
||||
VM_METHOD_TYPE_CFUNC,
|
||||
VM_METHOD_TYPE_ATTRSET,
|
||||
VM_METHOD_TYPE_IVAR,
|
||||
VM_METHOD_TYPE_BMETHOD,
|
||||
VM_METHOD_TYPE_ZSUPER,
|
||||
VM_METHOD_TYPE_UNDEF,
|
||||
VM_METHOD_TYPE_NOTIMPLEMENTED,
|
||||
VM_METHOD_TYPE_OPTIMIZED, /* Kernel#send, Proc#call, etc */
|
||||
} rb_method_type_t;
|
||||
|
||||
typedef struct rb_method_cfunc_struct {
|
||||
VALUE (*func)(ANYARGS);
|
||||
int argc;
|
||||
} rb_method_cfunc_t;
|
||||
|
||||
typedef struct rb_iseq_struct rb_iseq_t;
|
||||
|
||||
typedef struct rb_method_entry_struct {
|
||||
rb_method_flag_t flag;
|
||||
rb_method_type_t type; /* method type */
|
||||
ID called_id;
|
||||
ID original_id;
|
||||
VALUE klass; /* should be mark */
|
||||
union {
|
||||
rb_iseq_t *iseq; /* should be mark */
|
||||
rb_method_cfunc_t cfunc;
|
||||
ID attr_id;
|
||||
VALUE proc;
|
||||
enum method_optimized_type {
|
||||
OPTIMIZED_METHOD_TYPE_SEND,
|
||||
OPTIMIZED_METHOD_TYPE_CALL,
|
||||
} optimize_type;
|
||||
} body;
|
||||
int alias_count;
|
||||
} rb_method_entry_t;
|
||||
|
||||
void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
|
||||
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex);
|
||||
void rb_add_method_me(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_flag_t noex);
|
||||
rb_method_entry_t *rb_method_entry(VALUE klass, ID id);
|
||||
int rb_method_entry_arity(const rb_method_entry_t *me);
|
||||
void rb_gc_mark_method_entry(const rb_method_entry_t *me);
|
||||
|
||||
#endif /* METHOD_H */
|
47
node.h
47
node.h
|
@ -20,12 +20,6 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
enum node_type {
|
||||
NODE_METHOD,
|
||||
#define NODE_METHOD NODE_METHOD
|
||||
NODE_FBODY,
|
||||
#define NODE_FBODY NODE_FBODY
|
||||
NODE_CFUNC,
|
||||
#define NODE_CFUNC NODE_CFUNC
|
||||
NODE_SCOPE,
|
||||
#define NODE_SCOPE NODE_SCOPE
|
||||
NODE_BLOCK,
|
||||
|
@ -202,8 +196,6 @@ enum node_type {
|
|||
#define NODE_FLIP2 NODE_FLIP2
|
||||
NODE_FLIP3,
|
||||
#define NODE_FLIP3 NODE_FLIP3
|
||||
NODE_ATTRSET,
|
||||
#define NODE_ATTRSET NODE_ATTRSET
|
||||
NODE_SELF,
|
||||
#define NODE_SELF NODE_SELF
|
||||
NODE_NIL,
|
||||
|
@ -356,11 +348,8 @@ typedef struct RNode {
|
|||
#define NEW_NODE(t,a0,a1,a2) rb_node_newnode((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2))
|
||||
#define NEW_NODE_LONGLIFE(t,a0,a1,a2) rb_node_newnode_longlife((t),(VALUE)(a0),(VALUE)(a1),(VALUE)(a2))
|
||||
|
||||
#define NEW_METHOD(n,x,v) NEW_NODE(NODE_METHOD,x,n,v)
|
||||
#define NEW_FBODY(n,i) NEW_NODE(NODE_FBODY,i,n,0)
|
||||
#define NEW_DEFN(i,a,d,p) NEW_NODE(NODE_DEFN,0,i,NEW_SCOPE(a,d))
|
||||
#define NEW_DEFS(r,i,a,d) NEW_NODE(NODE_DEFS,r,i,NEW_SCOPE(a,d))
|
||||
#define NEW_CFUNC(f,c) NEW_NODE(NODE_CFUNC,f,c,0)
|
||||
#define NEW_IFUNC(f,c) NEW_NODE(NODE_IFUNC,f,c,0)
|
||||
#define NEW_SCOPE(a,b) NEW_NODE(NODE_SCOPE,local_tbl(),b,a)
|
||||
#define NEW_BLOCK(a) NEW_NODE(NODE_BLOCK,a,0,0)
|
||||
|
@ -446,7 +435,6 @@ typedef struct RNode {
|
|||
#define NEW_COLON3(i) NEW_NODE(NODE_COLON3,0,i,0)
|
||||
#define NEW_DOT2(b,e) NEW_NODE(NODE_DOT2,b,e,0)
|
||||
#define NEW_DOT3(b,e) NEW_NODE(NODE_DOT3,b,e,0)
|
||||
#define NEW_ATTRSET(a) NEW_NODE(NODE_ATTRSET,a,0,0)
|
||||
#define NEW_SELF() NEW_NODE(NODE_SELF,0,0,0)
|
||||
#define NEW_NIL() NEW_NODE(NODE_NIL,0,0,0)
|
||||
#define NEW_TRUE() NEW_NODE(NODE_TRUE,0,0,0)
|
||||
|
@ -460,30 +448,6 @@ typedef struct RNode {
|
|||
#define NEW_PRELUDE(p,b) NEW_NODE(NODE_PRELUDE,p,b,0)
|
||||
#define NEW_OPTBLOCK(a) NEW_NODE(NODE_OPTBLOCK,a,0,0)
|
||||
|
||||
#define NOEX_PUBLIC 0x00
|
||||
#define NOEX_NOSUPER 0x01
|
||||
#define NOEX_PRIVATE 0x02
|
||||
#define NOEX_PROTECTED 0x04
|
||||
#define NOEX_MASK 0x06 /* 0110 */
|
||||
#define NOEX_BASIC 0x08
|
||||
|
||||
#define NOEX_UNDEF NOEX_NOSUPER
|
||||
|
||||
#define NOEX_MODFUNC 0x12
|
||||
#define NOEX_SUPER 0x20
|
||||
#define NOEX_VCALL 0x40
|
||||
|
||||
#define NOEX_SAFE(n) ((int)((n) >> 8) & 0x0F)
|
||||
#define NOEX_WITH(n, s) ((s << 8) | (n) | (ruby_running ? 0 : NOEX_BASIC))
|
||||
#define NOEX_WITH_SAFE(n) NOEX_WITH(n, rb_safe_level())
|
||||
|
||||
#define CALL_PUBLIC 0
|
||||
#define CALL_FCALL 1
|
||||
#define CALL_VCALL 2
|
||||
#define CALL_SUPER 3
|
||||
|
||||
#define RUBY_VM_METHOD_NODE NODE_METHOD
|
||||
|
||||
VALUE rb_parser_new(void);
|
||||
VALUE rb_parser_end_seen_p(VALUE);
|
||||
VALUE rb_parser_encoding(VALUE);
|
||||
|
@ -496,20 +460,9 @@ NODE *rb_compile_cstr(const char*, const char*, int, int);
|
|||
NODE *rb_compile_string(const char*, VALUE, int);
|
||||
NODE *rb_compile_file(const char*, VALUE, int);
|
||||
|
||||
void rb_add_method(VALUE, ID, NODE *, int);
|
||||
NODE *rb_node_newnode(enum node_type,VALUE,VALUE,VALUE);
|
||||
NODE *rb_node_newnode_longlife(enum node_type,VALUE,VALUE,VALUE);
|
||||
|
||||
NODE* rb_method_node(VALUE klass, ID id);
|
||||
int rb_node_arity(NODE* node);
|
||||
|
||||
int rb_notimplement_body_p(NODE*);
|
||||
|
||||
struct global_entry *rb_global_entry(ID);
|
||||
VALUE rb_gvar_get(struct global_entry *);
|
||||
VALUE rb_gvar_set(struct global_entry *, VALUE);
|
||||
VALUE rb_gvar_defined(struct global_entry *);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#if 0
|
||||
{ /* satisfy cc-mode */
|
||||
|
|
210
proc.c
210
proc.c
|
@ -13,11 +13,10 @@
|
|||
#include "gc.h"
|
||||
|
||||
struct METHOD {
|
||||
VALUE oclass; /* class that holds the method */
|
||||
VALUE rclass; /* class of the receiver */
|
||||
VALUE recv;
|
||||
ID id, oid;
|
||||
NODE *body;
|
||||
VALUE rclass;
|
||||
ID id;
|
||||
rb_method_entry_t *me;
|
||||
};
|
||||
|
||||
VALUE rb_cUnboundMethod;
|
||||
|
@ -30,7 +29,7 @@ VALUE rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc);
|
|||
static VALUE bmcall(VALUE, VALUE);
|
||||
static int method_arity(VALUE);
|
||||
static int rb_obj_is_method(VALUE m);
|
||||
static rb_iseq_t *get_method_iseq(VALUE method);
|
||||
rb_iseq_t *rb_method_get_iseq(VALUE method);
|
||||
|
||||
/* Proc */
|
||||
|
||||
|
@ -657,7 +656,7 @@ get_proc_iseq(VALUE self, int *is_proc)
|
|||
iseq = 0;
|
||||
if (nd_type(node) == NODE_IFUNC && node->nd_cfnc == bmcall) {
|
||||
/* method(:foo).to_proc */
|
||||
iseq = get_method_iseq(node->nd_tval);
|
||||
iseq = rb_method_get_iseq(node->nd_tval);
|
||||
if (is_proc) *is_proc = 0;
|
||||
}
|
||||
}
|
||||
|
@ -843,9 +842,8 @@ bm_mark(void *ptr)
|
|||
{
|
||||
struct METHOD *data = ptr;
|
||||
rb_gc_mark(data->rclass);
|
||||
rb_gc_mark(data->oclass);
|
||||
rb_gc_mark(data->recv);
|
||||
rb_gc_mark((VALUE)data->body);
|
||||
rb_gc_mark_method_entry(data->me);
|
||||
}
|
||||
|
||||
static size_t
|
||||
|
@ -867,59 +865,47 @@ rb_obj_is_method(VALUE m)
|
|||
return rb_typeddata_is_kind_of(m, &method_data_type);
|
||||
}
|
||||
|
||||
NODE *
|
||||
rb_method_body(VALUE method)
|
||||
{
|
||||
if (rb_obj_is_method(method)) {
|
||||
struct METHOD *data = DATA_PTR(method);
|
||||
return data->body;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
NODE *rb_get_method_body(VALUE klass, ID id, ID *idp);
|
||||
|
||||
static VALUE
|
||||
mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
||||
{
|
||||
VALUE method;
|
||||
NODE *body;
|
||||
struct METHOD *data;
|
||||
VALUE rclass = klass;
|
||||
ID oid = id;
|
||||
ID rid = id;
|
||||
struct METHOD *data;
|
||||
rb_method_entry_t *me;
|
||||
|
||||
again:
|
||||
if ((body = rb_get_method_body(klass, id, 0)) == 0) {
|
||||
rb_print_undef(rclass, oid, 0);
|
||||
me = rb_method_entry(klass, id);
|
||||
if (!me) {
|
||||
rb_print_undef(klass, id, 0);
|
||||
}
|
||||
if (scope && (body->nd_noex & NOEX_MASK) != NOEX_PUBLIC) {
|
||||
rb_print_undef(rclass, oid, (int)(body->nd_noex & NOEX_MASK));
|
||||
if (scope && (me->flag & NOEX_MASK) != NOEX_PUBLIC) {
|
||||
rb_print_undef(rclass, me->original_id, (int)(me->flag & NOEX_MASK));
|
||||
}
|
||||
|
||||
klass = body->nd_clss;
|
||||
body = body->nd_body;
|
||||
|
||||
if (nd_type(body) == NODE_ZSUPER) {
|
||||
klass = RCLASS_SUPER(klass);
|
||||
if (me->type == VM_METHOD_TYPE_ZSUPER) {
|
||||
klass = RCLASS_SUPER(me->klass);
|
||||
id = me->original_id;
|
||||
goto again;
|
||||
}
|
||||
|
||||
klass = me->klass;
|
||||
|
||||
while (rclass != klass &&
|
||||
(FL_TEST(rclass, FL_SINGLETON) || TYPE(rclass) == T_ICLASS)) {
|
||||
rclass = RCLASS_SUPER(rclass);
|
||||
}
|
||||
if (TYPE(klass) == T_ICLASS)
|
||||
klass = RBASIC(klass)->klass;
|
||||
method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data);
|
||||
data->oclass = klass;
|
||||
data->recv = obj;
|
||||
|
||||
data->id = id;
|
||||
data->body = body;
|
||||
if (TYPE(klass) == T_ICLASS) {
|
||||
klass = RBASIC(klass)->klass;
|
||||
}
|
||||
|
||||
method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data);
|
||||
|
||||
data->recv = obj;
|
||||
data->rclass = rclass;
|
||||
data->oid = oid;
|
||||
data->id = rid;
|
||||
data->me = me;
|
||||
|
||||
OBJ_INFECT(method, klass);
|
||||
|
||||
return method;
|
||||
|
@ -958,11 +944,11 @@ mnew(VALUE klass, VALUE obj, ID id, VALUE mclass, int scope)
|
|||
* object and contain the same body.
|
||||
*/
|
||||
|
||||
|
||||
static VALUE
|
||||
method_eq(VALUE method, VALUE other)
|
||||
{
|
||||
struct METHOD *m1, *m2;
|
||||
extern int rb_method_entry_eq(rb_method_entry_t *m1, rb_method_entry_t *m2);
|
||||
|
||||
if (!rb_obj_is_method(other))
|
||||
return Qfalse;
|
||||
|
@ -973,9 +959,11 @@ method_eq(VALUE method, VALUE other)
|
|||
m1 = (struct METHOD *)DATA_PTR(method);
|
||||
m2 = (struct METHOD *)DATA_PTR(other);
|
||||
|
||||
if (m1->oclass != m2->oclass || m1->rclass != m2->rclass ||
|
||||
m1->recv != m2->recv || m1->body != m2->body)
|
||||
if (!rb_method_entry_eq(m1->me, m2->me) ||
|
||||
m1->rclass != m2->rclass ||
|
||||
m1->recv != m2->recv) {
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
return Qtrue;
|
||||
}
|
||||
|
@ -994,10 +982,9 @@ method_hash(VALUE method)
|
|||
long hash;
|
||||
|
||||
TypedData_Get_Struct(method, struct METHOD, &method_data_type, m);
|
||||
hash = (long)m->oclass;
|
||||
hash ^= (long)m->rclass;
|
||||
hash = (long)m->rclass;
|
||||
hash ^= (long)m->recv;
|
||||
hash ^= (long)m->body;
|
||||
hash ^= (long)m->me;
|
||||
|
||||
return INT2FIX(hash);
|
||||
}
|
||||
|
@ -1018,14 +1005,12 @@ method_unbind(VALUE obj)
|
|||
struct METHOD *orig, *data;
|
||||
|
||||
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, orig);
|
||||
method =
|
||||
TypedData_Make_Struct(rb_cUnboundMethod, struct METHOD, &method_data_type, data);
|
||||
data->oclass = orig->oclass;
|
||||
method = TypedData_Make_Struct(rb_cUnboundMethod, struct METHOD,
|
||||
&method_data_type, data);
|
||||
data->recv = Qundef;
|
||||
data->id = orig->id;
|
||||
data->body = orig->body;
|
||||
data->me = orig->me;
|
||||
data->rclass = orig->rclass;
|
||||
data->oid = orig->oid;
|
||||
OBJ_INFECT(method, obj);
|
||||
|
||||
return method;
|
||||
|
@ -1076,7 +1061,7 @@ method_owner(VALUE obj)
|
|||
struct METHOD *data;
|
||||
|
||||
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
|
||||
return data->oclass;
|
||||
return data->me->klass;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1205,7 +1190,6 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
|
|||
{
|
||||
ID id;
|
||||
VALUE body;
|
||||
NODE *node;
|
||||
int noex = NOEX_PUBLIC;
|
||||
|
||||
if (argc == 1) {
|
||||
|
@ -1239,7 +1223,7 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
|
|||
rb_class2name(rclass));
|
||||
}
|
||||
}
|
||||
node = method->body;
|
||||
rb_add_method_me(mod, id, method->me, noex);
|
||||
}
|
||||
else if (rb_obj_is_proc(body)) {
|
||||
rb_proc_t *proc;
|
||||
|
@ -1251,16 +1235,13 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod)
|
|||
proc->is_lambda = Qtrue;
|
||||
proc->is_from_method = Qtrue;
|
||||
}
|
||||
node = NEW_BMETHOD(body);
|
||||
rb_add_method(mod, id, VM_METHOD_TYPE_BMETHOD, (void *)body, noex);
|
||||
}
|
||||
else {
|
||||
/* type error */
|
||||
rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)");
|
||||
}
|
||||
|
||||
/* TODO: visibility */
|
||||
|
||||
rb_add_method(mod, id, node, noex);
|
||||
return body;
|
||||
}
|
||||
|
||||
|
@ -1351,12 +1332,11 @@ rb_method_call(int argc, VALUE *argv, VALUE method)
|
|||
}
|
||||
if ((state = EXEC_TAG()) == 0) {
|
||||
rb_thread_t *th = GET_THREAD();
|
||||
VALUE rb_vm_call(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid,
|
||||
int argc, const VALUE *argv, const NODE *body, int nosuper);
|
||||
VALUE rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||||
const rb_method_entry_t *me);
|
||||
|
||||
PASS_PASSED_BLOCK_TH(th);
|
||||
result = rb_vm_call(th, data->oclass, data->recv, data->id, data->oid,
|
||||
argc, argv, data->body, 0);
|
||||
result = rb_vm_call(th, data->recv, data->id, argc, argv, data->me);
|
||||
}
|
||||
POP_TAG();
|
||||
if (safe >= 0)
|
||||
|
@ -1483,34 +1463,32 @@ umethod_bind(VALUE method, VALUE recv)
|
|||
}
|
||||
|
||||
int
|
||||
rb_node_arity(NODE* body)
|
||||
rb_method_entry_arity(const rb_method_entry_t *me)
|
||||
{
|
||||
switch (nd_type(body)) {
|
||||
case NODE_CFUNC:
|
||||
if (body->nd_argc < 0)
|
||||
switch (me->type) {
|
||||
case VM_METHOD_TYPE_CFUNC:
|
||||
if (me->body.cfunc.argc < 0)
|
||||
return -1;
|
||||
return check_argc(body->nd_argc);
|
||||
case NODE_ZSUPER:
|
||||
return check_argc(me->body.cfunc.argc);
|
||||
case VM_METHOD_TYPE_ZSUPER:
|
||||
return -1;
|
||||
case NODE_ATTRSET:
|
||||
case VM_METHOD_TYPE_ATTRSET:
|
||||
return 1;
|
||||
case NODE_IVAR:
|
||||
case VM_METHOD_TYPE_IVAR:
|
||||
return 0;
|
||||
case NODE_BMETHOD:
|
||||
return rb_proc_arity(body->nd_cval);
|
||||
case RUBY_VM_METHOD_NODE:
|
||||
{
|
||||
rb_iseq_t *iseq;
|
||||
GetISeqPtr((VALUE)body->nd_body, iseq);
|
||||
if (iseq->arg_rest == -1 && iseq->arg_opts == 0) {
|
||||
return iseq->argc;
|
||||
}
|
||||
else {
|
||||
return -(iseq->argc + 1 + iseq->arg_post_len);
|
||||
}
|
||||
}
|
||||
case VM_METHOD_TYPE_BMETHOD:
|
||||
return rb_proc_arity(me->body.proc);
|
||||
case VM_METHOD_TYPE_ISEQ: {
|
||||
rb_iseq_t *iseq = me->body.iseq;
|
||||
if (iseq->arg_rest == -1 && iseq->arg_opts == 0) {
|
||||
return iseq->argc;
|
||||
}
|
||||
else {
|
||||
return -(iseq->argc + 1 + iseq->arg_post_len);
|
||||
}
|
||||
}
|
||||
default:
|
||||
rb_raise(rb_eArgError, "invalid node 0x%x", nd_type(body));
|
||||
rb_bug("rb_method_entry_arity: invalid method entry type (%d)", me->type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1560,14 +1538,14 @@ method_arity(VALUE method)
|
|||
struct METHOD *data;
|
||||
|
||||
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
|
||||
return rb_node_arity(data->body);
|
||||
return rb_method_entry_arity(data->me);
|
||||
}
|
||||
|
||||
int
|
||||
rb_mod_method_arity(VALUE mod, ID id)
|
||||
{
|
||||
NODE *node = rb_method_node(mod, id);
|
||||
return rb_node_arity(node);
|
||||
rb_method_entry_t *me = rb_method_entry(mod, id);
|
||||
return rb_method_entry_arity(me);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1576,25 +1554,23 @@ rb_obj_method_arity(VALUE obj, ID id)
|
|||
return rb_mod_method_arity(CLASS_OF(obj), id);
|
||||
}
|
||||
|
||||
static rb_iseq_t *
|
||||
get_method_iseq(VALUE method)
|
||||
rb_iseq_t *
|
||||
rb_method_get_iseq(VALUE method)
|
||||
{
|
||||
struct METHOD *data;
|
||||
NODE *body;
|
||||
rb_iseq_t *iseq;
|
||||
rb_method_entry_t *me;
|
||||
|
||||
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
|
||||
body = data->body;
|
||||
switch (nd_type(body)) {
|
||||
case NODE_BMETHOD:
|
||||
return get_proc_iseq(body->nd_cval, 0);
|
||||
case RUBY_VM_METHOD_NODE:
|
||||
GetISeqPtr((VALUE)body->nd_body, iseq);
|
||||
if (RUBY_VM_NORMAL_ISEQ_P(iseq)) break;
|
||||
me = data->me;
|
||||
|
||||
switch (me->type) {
|
||||
case VM_METHOD_TYPE_BMETHOD:
|
||||
return get_proc_iseq(me->body.proc, 0);
|
||||
case VM_METHOD_TYPE_ISEQ:
|
||||
return me->body.iseq;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return iseq;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1608,7 +1584,7 @@ get_method_iseq(VALUE method)
|
|||
VALUE
|
||||
rb_method_location(VALUE method)
|
||||
{
|
||||
return iseq_location(get_method_iseq(method));
|
||||
return iseq_location(rb_method_get_iseq(method));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1621,7 +1597,7 @@ rb_method_location(VALUE method)
|
|||
static VALUE
|
||||
rb_method_parameters(VALUE method)
|
||||
{
|
||||
rb_iseq_t *iseq = get_method_iseq(method);
|
||||
rb_iseq_t *iseq = rb_method_get_iseq(method);
|
||||
if (!iseq) {
|
||||
return unnamed_parameters(method_arity(method));
|
||||
}
|
||||
|
@ -1652,11 +1628,11 @@ method_inspect(VALUE method)
|
|||
rb_str_buf_cat2(str, s);
|
||||
rb_str_buf_cat2(str, ": ");
|
||||
|
||||
if (FL_TEST(data->oclass, FL_SINGLETON)) {
|
||||
VALUE v = rb_iv_get(data->oclass, "__attached__");
|
||||
if (FL_TEST(data->me->klass, FL_SINGLETON)) {
|
||||
VALUE v = rb_iv_get(data->me->klass, "__attached__");
|
||||
|
||||
if (data->recv == Qundef) {
|
||||
rb_str_buf_append(str, rb_inspect(data->oclass));
|
||||
rb_str_buf_append(str, rb_inspect(data->me->klass));
|
||||
}
|
||||
else if (data->recv == v) {
|
||||
rb_str_buf_append(str, rb_inspect(v));
|
||||
|
@ -1672,15 +1648,15 @@ method_inspect(VALUE method)
|
|||
}
|
||||
else {
|
||||
rb_str_buf_cat2(str, rb_class2name(data->rclass));
|
||||
if (data->rclass != data->oclass) {
|
||||
if (data->rclass != data->me->klass) {
|
||||
rb_str_buf_cat2(str, "(");
|
||||
rb_str_buf_cat2(str, rb_class2name(data->oclass));
|
||||
rb_str_buf_cat2(str, rb_class2name(data->me->klass));
|
||||
rb_str_buf_cat2(str, ")");
|
||||
}
|
||||
}
|
||||
rb_str_buf_cat2(str, sharp);
|
||||
rb_str_append(str, rb_id2str(data->oid));
|
||||
if (rb_notimplement_body_p(data->body)) {
|
||||
rb_str_append(str, rb_id2str(data->me->original_id));
|
||||
if (data->me->type == VM_METHOD_TYPE_NOTIMPLEMENTED) {
|
||||
rb_str_buf_cat2(str, " (not-implemented)");
|
||||
}
|
||||
rb_str_buf_cat2(str, ">");
|
||||
|
@ -1949,10 +1925,22 @@ Init_Proc(void)
|
|||
rb_cProc = rb_define_class("Proc", rb_cObject);
|
||||
rb_undef_alloc_func(rb_cProc);
|
||||
rb_define_singleton_method(rb_cProc, "new", rb_proc_s_new, -1);
|
||||
|
||||
#if 0 /* incomplete. */
|
||||
rb_add_method(rb_cProc, rb_intern("call"), VM_METHOD_TYPE_OPTIMIZED,
|
||||
(void *)OPTIMIZED_METHOD_TYPE_CALL, 0);
|
||||
rb_add_method(rb_cProc, rb_intern("[]"), VM_METHOD_TYPE_OPTIMIZED,
|
||||
(void *)OPTIMIZED_METHOD_TYPE_CALL, 0);
|
||||
rb_add_method(rb_cProc, rb_intern("==="), VM_METHOD_TYPE_OPTIMIZED,
|
||||
(void *)OPTIMIZED_METHOD_TYPE_CALL, 0);
|
||||
rb_add_method(rb_cProc, rb_intern("yield"), VM_METHOD_TYPE_OPTIMIZED,
|
||||
(void *)OPTIMIZED_METHOD_TYPE_CALL, 0);
|
||||
#else
|
||||
rb_define_method(rb_cProc, "call", proc_call, -1);
|
||||
rb_define_method(rb_cProc, "[]", proc_call, -1);
|
||||
rb_define_method(rb_cProc, "===", proc_call, -1);
|
||||
rb_define_method(rb_cProc, "yield", proc_call, -1);
|
||||
#endif
|
||||
rb_define_method(rb_cProc, "to_proc", proc_to_proc, 0);
|
||||
rb_define_method(rb_cProc, "arity", proc_arity, 0);
|
||||
rb_define_method(rb_cProc, "clone", proc_clone, 0);
|
||||
|
|
37
vm.c
37
vm.c
|
@ -575,7 +575,7 @@ vm_yield(rb_thread_t *th, int argc, const VALUE *argv)
|
|||
|
||||
VALUE
|
||||
rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self,
|
||||
int argc, const VALUE *argv, rb_block_t * blockptr)
|
||||
int argc, const VALUE *argv, const rb_block_t * blockptr)
|
||||
{
|
||||
VALUE val = Qundef;
|
||||
int state;
|
||||
|
@ -734,7 +734,7 @@ vm_backtrace_each(rb_thread_t *th, int lev, rb_backtrace_iter_func *iter, void *
|
|||
}
|
||||
}
|
||||
else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
|
||||
if ((*iter)(arg, file, line_no, rb_id2name(cfp->method_id))) break;
|
||||
if ((*iter)(arg, file, line_no, rb_id2name(cfp->me->original_id))) break;
|
||||
}
|
||||
cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp);
|
||||
}
|
||||
|
@ -929,22 +929,23 @@ rb_iter_break(void)
|
|||
static st_table *vm_opt_method_table = 0;
|
||||
|
||||
static void
|
||||
rb_vm_check_redefinition_opt_method(const NODE *node)
|
||||
rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me)
|
||||
{
|
||||
VALUE bop;
|
||||
|
||||
if (st_lookup(vm_opt_method_table, (st_data_t)node, &bop)) {
|
||||
ruby_vm_redefined_flag[bop] = 1;
|
||||
if (me->type == VM_METHOD_TYPE_CFUNC) {
|
||||
if (st_lookup(vm_opt_method_table, (st_data_t)me, &bop)) {
|
||||
ruby_vm_redefined_flag[bop] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_opt_method(VALUE klass, ID mid, VALUE bop)
|
||||
{
|
||||
NODE *node;
|
||||
if (st_lookup(RCLASS_M_TBL(klass), mid, (void *)&node) &&
|
||||
nd_type(node->nd_body->nd_body) == NODE_CFUNC) {
|
||||
st_insert(vm_opt_method_table, (st_data_t)node, (st_data_t)bop);
|
||||
rb_method_entry_t *me;
|
||||
if (st_lookup(RCLASS_M_TBL(klass), mid, (void *)&me) &&
|
||||
me->type == VM_METHOD_TYPE_CFUNC) {
|
||||
st_insert(vm_opt_method_table, (st_data_t)me, (st_data_t)bop);
|
||||
}
|
||||
else {
|
||||
rb_bug("undefined optimized method: %s", rb_id2name(mid));
|
||||
|
@ -1323,8 +1324,8 @@ rb_thread_method_id_and_class(rb_thread_t *th,
|
|||
rb_control_frame_t *cfp = th->cfp;
|
||||
rb_iseq_t *iseq = cfp->iseq;
|
||||
if (!iseq) {
|
||||
if (idp) *idp = cfp->method_id;
|
||||
if (klassp) *klassp = cfp->method_class;
|
||||
if (idp) *idp = cfp->me->original_id;
|
||||
if (klassp) *klassp = cfp->me->klass;
|
||||
return 1;
|
||||
}
|
||||
while (iseq) {
|
||||
|
@ -1367,10 +1368,10 @@ rb_thread_current_status(const rb_thread_t *th)
|
|||
file, line_no, RSTRING_PTR(iseq->name));
|
||||
}
|
||||
}
|
||||
else if (cfp->method_id) {
|
||||
else if (cfp->me->original_id) {
|
||||
str = rb_sprintf("`%s#%s' (cfunc)",
|
||||
RSTRING_PTR(rb_class_name(cfp->method_class)),
|
||||
rb_id2name(cfp->method_id));
|
||||
RSTRING_PTR(rb_class_name(cfp->me->klass)),
|
||||
rb_id2name(cfp->me->original_id));
|
||||
}
|
||||
|
||||
return str;
|
||||
|
@ -1739,7 +1740,6 @@ static void
|
|||
vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
|
||||
rb_num_t is_singleton, NODE *cref)
|
||||
{
|
||||
NODE *newbody;
|
||||
VALUE klass = cref->nd_clss;
|
||||
int noex = (int)cref->nd_visi;
|
||||
rb_iseq_t *miseq;
|
||||
|
@ -1768,11 +1768,10 @@ vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval,
|
|||
COPY_CREF(miseq->cref_stack, cref);
|
||||
miseq->klass = klass;
|
||||
miseq->defined_method_id = id;
|
||||
newbody = NEW_NODE_LONGLIFE(RUBY_VM_METHOD_NODE, 0, rb_gc_write_barrier(miseq->self), 0);
|
||||
rb_add_method(klass, id, newbody, noex);
|
||||
rb_add_method(klass, id, VM_METHOD_TYPE_ISEQ, miseq, noex);
|
||||
|
||||
if (!is_singleton && noex == NOEX_MODFUNC) {
|
||||
rb_add_method(rb_singleton_class(klass), id, newbody, NOEX_PUBLIC);
|
||||
rb_add_method(rb_singleton_class(klass), id, VM_METHOD_TYPE_ISEQ, miseq, NOEX_PUBLIC);
|
||||
}
|
||||
INC_VM_STATE_VERSION();
|
||||
}
|
||||
|
|
39
vm_core.h
39
vm_core.h
|
@ -21,6 +21,7 @@
|
|||
#include "debug.h"
|
||||
#include "vm_opts.h"
|
||||
#include "id.h"
|
||||
#include "method.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "thread_win32.h"
|
||||
|
@ -92,6 +93,8 @@
|
|||
|
||||
typedef unsigned long rb_num_t;
|
||||
|
||||
/* iseq data type */
|
||||
|
||||
struct iseq_compile_data_ensure_node_stack;
|
||||
|
||||
typedef struct rb_compile_option_struct {
|
||||
|
@ -109,12 +112,8 @@ typedef struct rb_compile_option_struct {
|
|||
struct iseq_inline_cache_entry {
|
||||
long ic_vmstat;
|
||||
VALUE ic_class;
|
||||
union {
|
||||
NODE *method;
|
||||
VALUE value;
|
||||
} value;
|
||||
#define ic_value value.value
|
||||
#define ic_method value.method
|
||||
VALUE ic_value;
|
||||
rb_method_entry_t *ic_method;
|
||||
#define ic_index ic_vmstat
|
||||
};
|
||||
|
||||
|
@ -234,8 +233,6 @@ enum ruby_special_exceptions {
|
|||
ruby_special_error_count
|
||||
};
|
||||
|
||||
typedef struct rb_iseq_struct rb_iseq_t;
|
||||
|
||||
#define GetVMPtr(obj, ptr) \
|
||||
GetCoreDataFromValue(obj, rb_vm_t, ptr)
|
||||
|
||||
|
@ -296,8 +293,7 @@ typedef struct {
|
|||
VALUE *dfp; /* cfp[7] / block[2] */
|
||||
rb_iseq_t *block_iseq; /* cfp[8] / block[3] */
|
||||
VALUE proc; /* cfp[9] / block[4] */
|
||||
ID method_id; /* cfp[10] saved in special case */
|
||||
VALUE method_class; /* cfp[11] saved in special case */
|
||||
const rb_method_entry_t *me;/* cfp[10] */
|
||||
} rb_control_frame_t;
|
||||
|
||||
typedef struct rb_block_struct {
|
||||
|
@ -359,7 +355,7 @@ typedef struct rb_thread_struct
|
|||
int state;
|
||||
|
||||
/* for rb_iterate */
|
||||
rb_block_t *passed_block;
|
||||
const rb_block_t *passed_block;
|
||||
|
||||
/* for load(true) */
|
||||
VALUE top_self;
|
||||
|
@ -464,11 +460,6 @@ RUBY_EXTERN VALUE rb_mRubyVMFrozenCore;
|
|||
/* each thread has this size stack : 128KB */
|
||||
#define RUBY_VM_THREAD_STACK_SIZE (128 * 1024)
|
||||
|
||||
struct global_entry {
|
||||
struct global_variable *var;
|
||||
ID id;
|
||||
};
|
||||
|
||||
#define GetProcPtr(obj, ptr) \
|
||||
GetCoreDataFromValue(obj, rb_proc_t, ptr)
|
||||
|
||||
|
@ -500,6 +491,15 @@ typedef struct {
|
|||
VALUE env;
|
||||
} rb_binding_t;
|
||||
|
||||
struct global_entry {
|
||||
struct global_variable *var;
|
||||
ID id;
|
||||
};
|
||||
|
||||
struct global_entry *rb_global_entry(ID);
|
||||
VALUE rb_gvar_get(struct global_entry *);
|
||||
VALUE rb_gvar_set(struct global_entry *, VALUE);
|
||||
VALUE rb_gvar_defined(struct global_entry *);
|
||||
|
||||
/* used by compile time and send insn */
|
||||
#define VM_CALL_ARGS_SPLAT_BIT (0x01 << 1)
|
||||
|
@ -509,7 +509,6 @@ typedef struct {
|
|||
#define VM_CALL_TAILCALL_BIT (0x01 << 5)
|
||||
#define VM_CALL_TAILRECURSION_BIT (0x01 << 6)
|
||||
#define VM_CALL_SUPER_BIT (0x01 << 7)
|
||||
#define VM_CALL_SEND_BIT (0x01 << 8)
|
||||
|
||||
#define VM_SPECIAL_OBJECT_VMCORE 0x01
|
||||
#define VM_SPECIAL_OBJECT_CBASE 0x02
|
||||
|
@ -532,11 +531,9 @@ typedef struct {
|
|||
/* other frame flag */
|
||||
#define VM_FRAME_FLAG_PASSED 0x0100
|
||||
|
||||
|
||||
#define RUBYVM_CFUNC_FRAME_P(cfp) \
|
||||
(VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC)
|
||||
|
||||
|
||||
/* inline cache */
|
||||
typedef struct iseq_inline_cache_entry *IC;
|
||||
|
||||
|
@ -584,9 +581,7 @@ extern void rb_vmdebug_stack_dump_raw(rb_thread_t *, rb_control_frame_t *);
|
|||
#define SDR2(cfp) rb_vmdebug_stack_dump_raw(GET_THREAD(), (cfp))
|
||||
void rb_vm_bugreport(void);
|
||||
|
||||
|
||||
/* functions about thread/vm execution */
|
||||
|
||||
VALUE rb_iseq_eval(VALUE iseqval);
|
||||
VALUE rb_iseq_eval_main(VALUE iseqval);
|
||||
void rb_enable_interrupt(void);
|
||||
|
@ -594,7 +589,7 @@ void rb_disable_interrupt(void);
|
|||
int rb_thread_method_id_and_class(rb_thread_t *th, ID *idp, VALUE *klassp);
|
||||
|
||||
VALUE rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, VALUE self,
|
||||
int argc, const VALUE *argv, rb_block_t *blockptr);
|
||||
int argc, const VALUE *argv, const rb_block_t *blockptr);
|
||||
VALUE rb_vm_make_proc(rb_thread_t *th, const rb_block_t *block, VALUE klass);
|
||||
VALUE rb_vm_make_env_object(rb_thread_t *th, rb_control_frame_t *cfp);
|
||||
|
||||
|
|
|
@ -112,9 +112,9 @@ control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp)
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (cfp->method_id) {
|
||||
iseq_name = rb_id2name(cfp->method_id);
|
||||
snprintf(posbuf, MAX_POSBUF, ":%s", rb_id2name(cfp->method_id));
|
||||
else if (cfp->me) {
|
||||
iseq_name = rb_id2name(cfp->me->original_id);
|
||||
snprintf(posbuf, MAX_POSBUF, ":%s", rb_id2name(cfp->me->original_id));
|
||||
line = -1;
|
||||
}
|
||||
|
||||
|
@ -253,7 +253,7 @@ vm_stack_dump_each(rb_thread_t *th, rb_control_frame_t *cfp)
|
|||
|
||||
if (iseq == 0) {
|
||||
if (RUBYVM_CFUNC_FRAME_P(cfp)) {
|
||||
name = rb_id2name(cfp->method_id);
|
||||
name = rb_id2name(cfp->me->original_id);
|
||||
}
|
||||
else {
|
||||
name = "?";
|
||||
|
|
252
vm_eval.c
252
vm_eval.c
|
@ -21,141 +21,153 @@ static NODE *vm_cref_push(rb_thread_t *th, VALUE klass, int noex);
|
|||
static VALUE vm_exec(rb_thread_t *th);
|
||||
static void vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref);
|
||||
static int vm_collect_local_variables_in_heap(rb_thread_t *th, VALUE *dfp, VALUE ary);
|
||||
static VALUE send_internal(int argc, const VALUE *argv, VALUE recv, int scope);
|
||||
|
||||
typedef enum call_type {
|
||||
CALL_PUBLIC,
|
||||
CALL_FCALL,
|
||||
CALL_VCALL,
|
||||
} call_type;
|
||||
|
||||
static inline VALUE
|
||||
vm_call0(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid,
|
||||
int argc, const VALUE *argv, const NODE *body, int nosuper)
|
||||
vm_call0(rb_thread_t* th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||||
const rb_method_entry_t *me)
|
||||
{
|
||||
VALUE val;
|
||||
rb_block_t *blockptr = 0;
|
||||
|
||||
if (0) printf("id: %s, nd: %s, argc: %d, passed: %p\n",
|
||||
rb_id2name(id), ruby_node_name(nd_type(body)),
|
||||
argc, (void *)th->passed_block);
|
||||
VALUE klass = me->klass;
|
||||
const rb_block_t *blockptr = 0;
|
||||
|
||||
if (th->passed_block) {
|
||||
blockptr = th->passed_block;
|
||||
th->passed_block = 0;
|
||||
}
|
||||
|
||||
again:
|
||||
switch (nd_type(body)) {
|
||||
case RUBY_VM_METHOD_NODE:{
|
||||
rb_control_frame_t *reg_cfp;
|
||||
VALUE iseqval = (VALUE)body->nd_body;
|
||||
int i;
|
||||
switch (me->type) {
|
||||
case VM_METHOD_TYPE_ISEQ: {
|
||||
rb_control_frame_t *reg_cfp;
|
||||
int i;
|
||||
|
||||
rb_vm_set_finish_env(th);
|
||||
reg_cfp = th->cfp;
|
||||
rb_vm_set_finish_env(th);
|
||||
reg_cfp = th->cfp;
|
||||
|
||||
CHECK_STACK_OVERFLOW(reg_cfp, argc + 1);
|
||||
CHECK_STACK_OVERFLOW(reg_cfp, argc + 1);
|
||||
|
||||
*reg_cfp->sp++ = recv;
|
||||
for (i = 0; i < argc; i++) {
|
||||
*reg_cfp->sp++ = argv[i];
|
||||
}
|
||||
*reg_cfp->sp++ = recv;
|
||||
for (i = 0; i < argc; i++) {
|
||||
*reg_cfp->sp++ = argv[i];
|
||||
}
|
||||
|
||||
vm_setup_method(th, reg_cfp, argc, blockptr, 0, iseqval, recv);
|
||||
val = vm_exec(th);
|
||||
break;
|
||||
vm_setup_method(th, reg_cfp, recv, argc, blockptr, 0 /* flag */, me);
|
||||
val = vm_exec(th);
|
||||
break;
|
||||
}
|
||||
case NODE_CFUNC: {
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass);
|
||||
{
|
||||
rb_control_frame_t *reg_cfp = th->cfp;
|
||||
rb_control_frame_t *cfp =
|
||||
case VM_METHOD_TYPE_CFUNC: {
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass);
|
||||
{
|
||||
rb_control_frame_t *reg_cfp = th->cfp;
|
||||
rb_control_frame_t *cfp =
|
||||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
|
||||
recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1);
|
||||
|
||||
cfp->method_id = oid;
|
||||
cfp->method_class = klass;
|
||||
cfp->me = me;
|
||||
val = call_cfunc(me->body.cfunc.func, recv, me->body.cfunc.argc, argc, argv);
|
||||
|
||||
val = call_cfunc(body->nd_cfnc, recv, (int)body->nd_argc, argc, argv);
|
||||
|
||||
if (reg_cfp != th->cfp + 1) {
|
||||
SDR2(reg_cfp);
|
||||
SDR2(th->cfp-5);
|
||||
rb_bug("cfp consistency error - call0");
|
||||
th->cfp = reg_cfp;
|
||||
if (reg_cfp != th->cfp + 1) {
|
||||
rb_bug("cfp consistency error - call0");
|
||||
}
|
||||
vm_pop_frame(th);
|
||||
}
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass);
|
||||
break;
|
||||
}
|
||||
case VM_METHOD_TYPE_ATTRSET: {
|
||||
if (argc != 1) {
|
||||
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
|
||||
}
|
||||
val = rb_ivar_set(recv, me->body.attr_id, argv[0]);
|
||||
break;
|
||||
}
|
||||
case VM_METHOD_TYPE_IVAR: {
|
||||
if (argc != 0) {
|
||||
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
|
||||
}
|
||||
val = rb_attr_get(recv, me->body.attr_id);
|
||||
break;
|
||||
}
|
||||
case VM_METHOD_TYPE_BMETHOD: {
|
||||
val = vm_call_bmethod(th, recv, argc, argv, blockptr, me);
|
||||
break;
|
||||
}
|
||||
case VM_METHOD_TYPE_ZSUPER: {
|
||||
klass = RCLASS_SUPER(klass);
|
||||
if (!klass || !(me = rb_method_entry(klass, id))) {
|
||||
return method_missing(recv, id, argc, argv, 0);
|
||||
}
|
||||
RUBY_VM_CHECK_INTS();
|
||||
goto again;
|
||||
}
|
||||
case VM_METHOD_TYPE_OPTIMIZED: {
|
||||
switch (me->body.optimize_type) {
|
||||
case OPTIMIZED_METHOD_TYPE_SEND:
|
||||
val = send_internal(argc, argv, recv, NOEX_NOSUPER | NOEX_PRIVATE);
|
||||
break;
|
||||
case OPTIMIZED_METHOD_TYPE_CALL: {
|
||||
rb_proc_t *proc;
|
||||
GetProcPtr(recv, proc);
|
||||
val = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, blockptr);
|
||||
break;
|
||||
}
|
||||
vm_pop_frame(th);
|
||||
}
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass);
|
||||
break;
|
||||
}
|
||||
case NODE_ATTRSET:{
|
||||
if (argc != 1) {
|
||||
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
|
||||
}
|
||||
val = rb_ivar_set(recv, body->nd_vid, argv[0]);
|
||||
break;
|
||||
}
|
||||
case NODE_IVAR: {
|
||||
if (argc != 0) {
|
||||
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)",
|
||||
argc);
|
||||
}
|
||||
val = rb_attr_get(recv, body->nd_vid);
|
||||
break;
|
||||
}
|
||||
case NODE_BMETHOD:{
|
||||
val = vm_call_bmethod(th, oid, body->nd_cval,
|
||||
recv, klass, argc, (VALUE *)argv, blockptr);
|
||||
break;
|
||||
}
|
||||
case NODE_ZSUPER:{
|
||||
klass = RCLASS_SUPER(klass);
|
||||
if (!klass || !(body = rb_method_node(klass, id))) {
|
||||
return method_missing(recv, id, argc, argv, 0);
|
||||
}
|
||||
RUBY_VM_CHECK_INTS();
|
||||
nosuper = CALL_SUPER;
|
||||
body = body->nd_body;
|
||||
goto again;
|
||||
default:
|
||||
rb_bug("vm_call0: unsupported optimized method type (%d)", me->body.optimize_type);
|
||||
val = Qundef;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
rb_bug("unsupported: vm_call0(%s)", ruby_node_name(nd_type(body)));
|
||||
rb_bug("vm_call0: unsupported method type (%d)", me->type);
|
||||
val = Qundef;
|
||||
}
|
||||
RUBY_VM_CHECK_INTS();
|
||||
return val;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_vm_call(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id, ID oid,
|
||||
int argc, const VALUE *argv, const NODE *body, int nosuper)
|
||||
rb_vm_call(rb_thread_t *th, VALUE recv, VALUE id, int argc, const VALUE *argv,
|
||||
const rb_method_entry_t *me)
|
||||
{
|
||||
return vm_call0(th, klass, recv, id, oid, argc, argv, body, nosuper);
|
||||
return vm_call0(th, recv, id, argc, argv, me);
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
vm_call_super(rb_thread_t * const th, const int argc, const VALUE * const argv)
|
||||
vm_call_super(rb_thread_t *th, int argc, const VALUE *argv)
|
||||
{
|
||||
VALUE recv = th->cfp->self;
|
||||
VALUE klass;
|
||||
ID id;
|
||||
NODE *body;
|
||||
rb_method_entry_t *me;
|
||||
rb_control_frame_t *cfp = th->cfp;
|
||||
|
||||
if (!cfp->iseq) {
|
||||
klass = cfp->method_class;
|
||||
klass = cfp->me->klass;
|
||||
klass = RCLASS_SUPER(klass);
|
||||
|
||||
if (klass == 0) {
|
||||
klass = vm_search_normal_superclass(cfp->method_class, recv);
|
||||
klass = vm_search_normal_superclass(cfp->me->klass, recv);
|
||||
}
|
||||
|
||||
id = cfp->method_id;
|
||||
id = cfp->me->original_id;
|
||||
}
|
||||
else {
|
||||
rb_bug("vm_call_super: should not be reached");
|
||||
}
|
||||
|
||||
body = rb_method_node(klass, id); /* this returns NODE_METHOD */
|
||||
if (!body) {
|
||||
me = rb_method_entry(klass, id);
|
||||
if (!me) {
|
||||
return method_missing(recv, id, argc, argv, 0);
|
||||
}
|
||||
|
||||
return vm_call0(th, klass, recv, id, (ID)body->nd_file,
|
||||
argc, argv, body->nd_body, CALL_SUPER);
|
||||
return vm_call0(th, recv, id, argc, argv, me);
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
@ -177,14 +189,15 @@ stack_check(void)
|
|||
}
|
||||
|
||||
static inline VALUE
|
||||
rb_call0(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv,
|
||||
int scope, VALUE self)
|
||||
rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
|
||||
call_type scope, VALUE self)
|
||||
{
|
||||
NODE *body, *method;
|
||||
int noex;
|
||||
ID id = mid;
|
||||
VALUE klass = CLASS_OF(recv);
|
||||
rb_method_entry_t *me;
|
||||
struct cache_entry *ent;
|
||||
rb_thread_t *th = GET_THREAD();
|
||||
ID oid;
|
||||
int noex;
|
||||
|
||||
if (!klass) {
|
||||
const char *adj = "terminated";
|
||||
|
@ -194,40 +207,41 @@ rb_call0(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv,
|
|||
"method `%s' called on %s object (%p)",
|
||||
rb_id2name(mid), adj, (void *)recv);
|
||||
}
|
||||
|
||||
/* is it in the method cache? */
|
||||
ent = cache + EXPR1(klass, mid);
|
||||
|
||||
if (ent->mid == mid && ent->klass == klass) {
|
||||
if (!ent->method)
|
||||
return method_missing(recv, mid, argc, argv,
|
||||
scope == 2 ? NOEX_VCALL : 0);
|
||||
id = ent->mid0;
|
||||
noex = (int)ent->method->nd_noex;
|
||||
klass = ent->method->nd_clss;
|
||||
body = ent->method->nd_body;
|
||||
if (!ent->me) {
|
||||
return method_missing(recv, mid, argc, argv,
|
||||
scope == CALL_VCALL ? NOEX_VCALL : 0);
|
||||
}
|
||||
me = ent->me;
|
||||
klass = me->klass;
|
||||
}
|
||||
else if ((method = rb_get_method_body(klass, id, &id)) != 0) {
|
||||
noex = (int)method->nd_noex;
|
||||
klass = method->nd_clss;
|
||||
body = method->nd_body;
|
||||
else if ((me = rb_method_entry(klass, mid)) != 0) {
|
||||
klass = me->klass;
|
||||
}
|
||||
else {
|
||||
if (scope == 3) {
|
||||
return method_missing(recv, mid, argc, argv, NOEX_SUPER);
|
||||
}
|
||||
return method_missing(recv, mid, argc, argv,
|
||||
scope == 2 ? NOEX_VCALL : 0);
|
||||
scope == CALL_VCALL ? NOEX_VCALL : 0);
|
||||
}
|
||||
|
||||
if (mid != idMethodMissing) {
|
||||
oid = me->original_id;
|
||||
noex = me->flag;
|
||||
|
||||
if (oid != idMethodMissing) {
|
||||
/* receiver specified form for private method */
|
||||
if (UNLIKELY(noex)) {
|
||||
if (((noex & NOEX_MASK) & NOEX_PRIVATE) && scope == 0) {
|
||||
if (((noex & NOEX_MASK) & NOEX_PRIVATE) && scope == CALL_PUBLIC) {
|
||||
return method_missing(recv, mid, argc, argv, NOEX_PRIVATE);
|
||||
}
|
||||
|
||||
/* self must be kind of a specified form for protected method */
|
||||
if (((noex & NOEX_MASK) & NOEX_PROTECTED) && scope == 0) {
|
||||
if (((noex & NOEX_MASK) & NOEX_PROTECTED) && scope == CALL_PUBLIC) {
|
||||
VALUE defined_class = klass;
|
||||
|
||||
if (TYPE(defined_class) == T_ICLASS) {
|
||||
|
@ -249,13 +263,13 @@ rb_call0(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv,
|
|||
}
|
||||
|
||||
stack_check();
|
||||
return vm_call0(th, klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER);
|
||||
return vm_call0(th, recv, mid, argc, argv, me);
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
rb_call(VALUE klass, VALUE recv, ID mid, int argc, const VALUE *argv, int scope)
|
||||
rb_call(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope)
|
||||
{
|
||||
return rb_call0(klass, recv, mid, argc, argv, scope, Qundef);
|
||||
return rb_call0(recv, mid, argc, argv, scope, Qundef);
|
||||
}
|
||||
|
||||
NORETURN(static void raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv,
|
||||
|
@ -404,7 +418,7 @@ rb_apply(VALUE recv, ID mid, VALUE args)
|
|||
argc = RARRAY_LENINT(args);
|
||||
argv = ALLOCA_N(VALUE, argc);
|
||||
MEMCPY(argv, RARRAY_PTR(args), VALUE, argc);
|
||||
return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALL_FCALL);
|
||||
return rb_call(recv, mid, argc, argv, CALL_FCALL);
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
@ -427,23 +441,23 @@ rb_funcall(VALUE recv, ID mid, int n, ...)
|
|||
else {
|
||||
argv = 0;
|
||||
}
|
||||
return rb_call(CLASS_OF(recv), recv, mid, n, argv, CALL_FCALL);
|
||||
return rb_call(recv, mid, n, argv, CALL_FCALL);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_funcall2(VALUE recv, ID mid, int argc, const VALUE *argv)
|
||||
{
|
||||
return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALL_FCALL);
|
||||
return rb_call(recv, mid, argc, argv, CALL_FCALL);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_funcall3(VALUE recv, ID mid, int argc, const VALUE *argv)
|
||||
{
|
||||
return rb_call(CLASS_OF(recv), recv, mid, argc, argv, CALL_PUBLIC);
|
||||
return rb_call(recv, mid, argc, argv, CALL_PUBLIC);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
send_internal(int argc, VALUE *argv, VALUE recv, int scope)
|
||||
send_internal(int argc, const VALUE *argv, VALUE recv, int scope)
|
||||
{
|
||||
VALUE vid;
|
||||
VALUE self = RUBY_VM_PREVIOUS_CONTROL_FRAME(GET_THREAD()->cfp)->self;
|
||||
|
@ -456,7 +470,7 @@ send_internal(int argc, VALUE *argv, VALUE recv, int scope)
|
|||
vid = *argv++; argc--;
|
||||
PASS_PASSED_BLOCK_TH(th);
|
||||
|
||||
return rb_call0(CLASS_OF(recv), recv, rb_to_id(vid), argc, argv, scope, self);
|
||||
return rb_call0(recv, rb_to_id(vid), argc, argv, scope, self);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -667,8 +681,7 @@ iterate_method(VALUE obj)
|
|||
const struct iter_method_arg * arg =
|
||||
(struct iter_method_arg *) obj;
|
||||
|
||||
return rb_call(CLASS_OF(arg->obj), arg->obj, arg->mid,
|
||||
arg->argc, arg->argv, CALL_FCALL);
|
||||
return rb_call(arg->obj, arg->mid, arg->argc, arg->argv, CALL_FCALL);
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
@ -687,7 +700,7 @@ rb_block_call(VALUE obj, ID mid, int argc, VALUE * argv,
|
|||
VALUE
|
||||
rb_each(VALUE obj)
|
||||
{
|
||||
return rb_call(CLASS_OF(obj), obj, idEach, 0, 0, CALL_FCALL);
|
||||
return rb_call(obj, idEach, 0, 0, CALL_FCALL);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
@ -1486,8 +1499,15 @@ Init_vm_eval(void)
|
|||
rb_define_method(rb_cBasicObject, "instance_exec", rb_obj_instance_exec, -1);
|
||||
rb_define_private_method(rb_cBasicObject, "method_missing", rb_method_missing, -1);
|
||||
|
||||
#if 1
|
||||
rb_add_method(rb_cBasicObject, rb_intern("__send__"),
|
||||
VM_METHOD_TYPE_OPTIMIZED, (void *)OPTIMIZED_METHOD_TYPE_SEND, 0);
|
||||
rb_add_method(rb_mKernel, rb_intern("send"),
|
||||
VM_METHOD_TYPE_OPTIMIZED, (void *)OPTIMIZED_METHOD_TYPE_SEND, 0);
|
||||
#else
|
||||
rb_define_method(rb_cBasicObject, "__send__", rb_f_send, -1);
|
||||
rb_define_method(rb_mKernel, "send", rb_f_send, -1);
|
||||
#endif
|
||||
rb_define_method(rb_mKernel, "public_send", rb_f_public_send, -1);
|
||||
|
||||
rb_define_method(rb_cModule, "module_exec", rb_mod_module_exec, -1);
|
||||
|
|
236
vm_insnhelper.c
236
vm_insnhelper.c
|
@ -350,21 +350,24 @@ call_cfunc(VALUE (*func)(), VALUE recv,
|
|||
break;
|
||||
default:
|
||||
rb_raise(rb_eArgError, "too many arguments(%d)", len);
|
||||
break;
|
||||
return Qundef; /* not reached */
|
||||
}
|
||||
return Qnil; /* not reached */
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
||||
int num, ID id, ID oid, VALUE recv, VALUE klass,
|
||||
VALUE flag, const NODE *mn, const rb_block_t *blockptr)
|
||||
int num, VALUE recv, const rb_block_t *blockptr, VALUE flag,
|
||||
const rb_method_entry_t *me)
|
||||
{
|
||||
VALUE val = 0;
|
||||
int state = 0;
|
||||
VALUE klass = me->klass;
|
||||
ID id = me->original_id;
|
||||
|
||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass);
|
||||
|
||||
TH_PUSH_TAG(th);
|
||||
// TODO: fix me. separate event
|
||||
if (th->event_flags & RUBY_EVENT_C_RETURN) {
|
||||
state = TH_EXEC_TAG();
|
||||
}
|
||||
|
@ -376,12 +379,10 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
|||
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
|
||||
recv, (VALUE) blockptr, 0, reg_cfp->sp, 0, 1);
|
||||
|
||||
cfp->method_id = oid;
|
||||
cfp->method_class = klass;
|
||||
|
||||
cfp->me = me;
|
||||
reg_cfp->sp -= num + 1;
|
||||
|
||||
val = call_cfunc(mn->nd_cfnc, recv, (int)mn->nd_argc, num, reg_cfp->sp + 1);
|
||||
val = call_cfunc(me->body.cfunc.func, recv, (int)me->body.cfunc.argc, num, reg_cfp->sp + 1);
|
||||
|
||||
if (reg_cfp != th->cfp + 1) {
|
||||
rb_bug("cfp consistency error - send");
|
||||
|
@ -397,25 +398,24 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp,
|
|||
}
|
||||
|
||||
static inline VALUE
|
||||
vm_call_bmethod(rb_thread_t *th, ID id, VALUE procval, VALUE recv,
|
||||
VALUE klass, int argc, VALUE *argv, rb_block_t *blockptr)
|
||||
vm_call_bmethod(rb_thread_t *th, VALUE recv, int argc, const VALUE *argv,
|
||||
const rb_block_t *blockptr, const rb_method_entry_t *me)
|
||||
{
|
||||
rb_control_frame_t *cfp = th->cfp;
|
||||
rb_proc_t *proc;
|
||||
VALUE val;
|
||||
|
||||
/* control block frame */
|
||||
(cfp-2)->method_id = id;
|
||||
(cfp-2)->method_class = klass;
|
||||
(cfp-2)->me = me;
|
||||
|
||||
GetProcPtr(procval, proc);
|
||||
GetProcPtr(me->body.proc, proc);
|
||||
val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
vm_method_missing_args(rb_thread_t *th, VALUE *argv,
|
||||
int num, rb_block_t *blockptr, int opt)
|
||||
int num, const rb_block_t *blockptr, int opt)
|
||||
{
|
||||
rb_control_frame_t * const reg_cfp = th->cfp;
|
||||
MEMCPY(argv, STACK_ADDR_FROM_TOP(num + 1), VALUE, num + 1);
|
||||
|
@ -426,7 +426,7 @@ vm_method_missing_args(rb_thread_t *th, VALUE *argv,
|
|||
|
||||
static inline VALUE
|
||||
vm_method_missing(rb_thread_t *th, ID id, VALUE recv,
|
||||
int num, rb_block_t *blockptr, int opt)
|
||||
int num, const rb_block_t *blockptr, int opt)
|
||||
{
|
||||
VALUE *argv = ALLOCA_N(VALUE, num + 1);
|
||||
vm_method_missing_args(th, argv, num, blockptr, opt);
|
||||
|
@ -435,16 +435,14 @@ vm_method_missing(rb_thread_t *th, ID id, VALUE recv,
|
|||
}
|
||||
|
||||
static inline void
|
||||
vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||
const int argc, const rb_block_t *blockptr, const VALUE flag,
|
||||
const VALUE iseqval, const VALUE recv)
|
||||
vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||
VALUE recv, int argc, const rb_block_t *blockptr, VALUE flag,
|
||||
const rb_method_entry_t *me)
|
||||
{
|
||||
rb_iseq_t *iseq;
|
||||
int opt_pc, i;
|
||||
VALUE *sp, *rsp = cfp->sp - argc;
|
||||
rb_iseq_t *iseq = me->body.iseq;
|
||||
|
||||
/* TODO: eliminate it */
|
||||
GetISeqPtr(iseqval, iseq);
|
||||
VM_CALLEE_SETUP_ARG(opt_pc, th, iseq, argc, rsp, &blockptr);
|
||||
|
||||
/* stack overflow check */
|
||||
|
@ -491,69 +489,105 @@ vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
|||
}
|
||||
|
||||
static inline VALUE
|
||||
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)
|
||||
vm_call_method(rb_thread_t *th, rb_control_frame_t *cfp,
|
||||
int num, const rb_block_t *blockptr, VALUE flag,
|
||||
ID id, const rb_method_entry_t *me, VALUE recv)
|
||||
{
|
||||
VALUE val;
|
||||
|
||||
start_method_dispatch:
|
||||
|
||||
if (mn != 0) {
|
||||
if ((mn->nd_noex == 0)) {
|
||||
/* dispatch method */
|
||||
NODE *node;
|
||||
|
||||
if (me != 0) {
|
||||
if ((me->flag == 0)) {
|
||||
normal_method_dispatch:
|
||||
|
||||
node = mn->nd_body;
|
||||
|
||||
switch (nd_type(node)) {
|
||||
case RUBY_VM_METHOD_NODE:{
|
||||
vm_setup_method(th, cfp, num, blockptr, flag, (VALUE)node->nd_body, recv);
|
||||
switch (me->type) {
|
||||
case VM_METHOD_TYPE_ISEQ:{
|
||||
vm_setup_method(th, cfp, recv, num, blockptr, flag, me);
|
||||
return Qundef;
|
||||
}
|
||||
case NODE_CFUNC:{
|
||||
val = vm_call_cfunc(th, cfp, num, id, (ID)mn->nd_file, recv, mn->nd_clss, flag, node, blockptr);
|
||||
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
||||
case VM_METHOD_TYPE_CFUNC:{
|
||||
val = vm_call_cfunc(th, cfp, num, recv, blockptr, flag, me);
|
||||
break;
|
||||
}
|
||||
case NODE_ATTRSET:{
|
||||
val = rb_ivar_set(recv, node->nd_vid, *(cfp->sp - 1));
|
||||
case VM_METHOD_TYPE_ATTRSET:{
|
||||
if (num != 1) {
|
||||
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", num);
|
||||
}
|
||||
val = rb_ivar_set(recv, me->body.attr_id, *(cfp->sp - 1));
|
||||
cfp->sp -= 2;
|
||||
break;
|
||||
}
|
||||
case NODE_IVAR:{
|
||||
case VM_METHOD_TYPE_IVAR:{
|
||||
if (num != 0) {
|
||||
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)",
|
||||
num);
|
||||
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", num);
|
||||
}
|
||||
val = rb_attr_get(recv, node->nd_vid);
|
||||
val = rb_attr_get(recv, me->body.attr_id);
|
||||
cfp->sp -= 1;
|
||||
break;
|
||||
}
|
||||
case NODE_BMETHOD:{
|
||||
case VM_METHOD_TYPE_BMETHOD:{
|
||||
VALUE *argv = ALLOCA_N(VALUE, num);
|
||||
MEMCPY(argv, cfp->sp - num, VALUE, num);
|
||||
cfp->sp += - num - 1;
|
||||
val = vm_call_bmethod(th, (ID)mn->nd_file, node->nd_cval, recv, mn->nd_clss, num, argv, blockptr);
|
||||
val = vm_call_bmethod(th, recv, num, argv, blockptr, me);
|
||||
break;
|
||||
}
|
||||
case NODE_ZSUPER:{
|
||||
VALUE klass;
|
||||
klass = RCLASS_SUPER(mn->nd_clss);
|
||||
mn = rb_method_node(klass, id);
|
||||
case VM_METHOD_TYPE_ZSUPER:{
|
||||
VALUE klass = RCLASS_SUPER(me->klass);
|
||||
me = rb_method_entry(klass, id);
|
||||
|
||||
if (mn != 0) {
|
||||
if (me != 0) {
|
||||
goto normal_method_dispatch;
|
||||
}
|
||||
else {
|
||||
goto start_method_dispatch;
|
||||
}
|
||||
}
|
||||
case VM_METHOD_TYPE_OPTIMIZED:{
|
||||
switch (me->body.optimize_type) {
|
||||
case OPTIMIZED_METHOD_TYPE_SEND: {
|
||||
rb_control_frame_t *reg_cfp = cfp;
|
||||
rb_num_t i = num - 1;
|
||||
VALUE sym;
|
||||
|
||||
if (num == 0) {
|
||||
rb_raise(rb_eArgError, "no method name given");
|
||||
}
|
||||
|
||||
sym = TOPN(i);
|
||||
id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym);
|
||||
/* shift arguments */
|
||||
if (i > 0) {
|
||||
MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i);
|
||||
}
|
||||
me = rb_method_entry(CLASS_OF(recv), id);
|
||||
num -= 1;
|
||||
DEC_SP(1);
|
||||
flag |= VM_CALL_FCALL_BIT;
|
||||
|
||||
goto start_method_dispatch;
|
||||
}
|
||||
break;
|
||||
case OPTIMIZED_METHOD_TYPE_CALL: {
|
||||
rb_proc_t *proc;
|
||||
int argc = num;
|
||||
VALUE *argv = ALLOCA_N(VALUE, num);
|
||||
GetProcPtr(recv, proc);
|
||||
MEMCPY(argv, cfp->sp - num, VALUE, num);
|
||||
cfp->sp -= num + 1;
|
||||
|
||||
val = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, blockptr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rb_bug("eval_invoke_method: unsupported optimized method type (%d)",
|
||||
me->body.optimize_type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:{
|
||||
printf("node: %s\n", ruby_node_name(nd_type(node)));
|
||||
rb_bug("eval_invoke_method: unreachable");
|
||||
/* unreachable */
|
||||
rb_bug("eval_invoke_method: unsupported method type (%d)", me->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -562,7 +596,7 @@ vm_call_method(rb_thread_t * const th, rb_control_frame_t * const cfp,
|
|||
int noex_safe;
|
||||
|
||||
if (!(flag & VM_CALL_FCALL_BIT) &&
|
||||
(mn->nd_noex & NOEX_MASK) & NOEX_PRIVATE) {
|
||||
(me->flag & NOEX_MASK) & NOEX_PRIVATE) {
|
||||
int stat = NOEX_PRIVATE;
|
||||
|
||||
if (flag & VM_CALL_VCALL_BIT) {
|
||||
|
@ -570,9 +604,8 @@ vm_call_method(rb_thread_t * const th, rb_control_frame_t * const cfp,
|
|||
}
|
||||
val = vm_method_missing(th, id, recv, num, blockptr, stat);
|
||||
}
|
||||
else if (((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) &&
|
||||
!(flag & VM_CALL_SEND_BIT)) {
|
||||
VALUE defined_class = mn->nd_clss;
|
||||
else if ((me->flag & NOEX_MASK) & NOEX_PROTECTED) {
|
||||
VALUE defined_class = me->klass;
|
||||
|
||||
if (TYPE(defined_class) == T_ICLASS) {
|
||||
defined_class = RBASIC(defined_class)->klass;
|
||||
|
@ -585,7 +618,7 @@ vm_call_method(rb_thread_t * const th, rb_control_frame_t * const cfp,
|
|||
goto normal_method_dispatch;
|
||||
}
|
||||
}
|
||||
else if ((noex_safe = NOEX_SAFE(mn->nd_noex)) > th->safe_level &&
|
||||
else if ((noex_safe = NOEX_SAFE(me->flag)) > th->safe_level &&
|
||||
(noex_safe > 2)) {
|
||||
rb_raise(rb_eSecurityError, "calling insecure method: %s", rb_id2name(id));
|
||||
}
|
||||
|
@ -617,33 +650,6 @@ vm_call_method(rb_thread_t * const th, rb_control_frame_t * const cfp,
|
|||
return val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (node->nd_cfnc == rb_f_send) {
|
||||
rb_num_t i = *num - 1;
|
||||
VALUE sym = TOPN(i);
|
||||
*id = SYMBOL_P(sym) ? SYM2ID(sym) : rb_to_id(sym);
|
||||
|
||||
/* shift arguments */
|
||||
if (i > 0) {
|
||||
MEMMOVE(&TOPN(i), &TOPN(i-1), VALUE, i);
|
||||
}
|
||||
|
||||
*mn = rb_method_node(klass, *id);
|
||||
*num -= 1;
|
||||
DEC_SP(1);
|
||||
*flag |= VM_CALL_FCALL_BIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* yield */
|
||||
|
||||
static inline int
|
||||
|
@ -707,8 +713,8 @@ vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,
|
|||
* @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)
|
||||
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;
|
||||
|
@ -765,8 +771,8 @@ vm_yield_setup_block_args_complex(rb_thread_t *th, const rb_iseq_t * iseq,
|
|||
|
||||
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 orig_argc, VALUE *argv,
|
||||
const rb_block_t *blockptr)
|
||||
{
|
||||
int i;
|
||||
int argc = orig_argc;
|
||||
|
@ -839,7 +845,12 @@ vm_yield_setup_block_args(rb_thread_t *th, const rb_iseq_t * iseq,
|
|||
VALUE procval = Qnil;
|
||||
|
||||
if (blockptr) {
|
||||
procval = blockptr->proc;
|
||||
if (blockptr->proc == 0) {
|
||||
procval = rb_vm_make_proc(th, blockptr, rb_cProc);
|
||||
}
|
||||
else {
|
||||
procval = blockptr->proc;
|
||||
}
|
||||
}
|
||||
|
||||
argv[iseq->arg_block] = procval;
|
||||
|
@ -879,7 +890,7 @@ vm_yield_setup_args(rb_thread_t * const th, const rb_iseq_t *iseq,
|
|||
static VALUE
|
||||
vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_num_t num, rb_num_t flag)
|
||||
{
|
||||
rb_block_t * const block = GET_BLOCK_PTR();
|
||||
const rb_block_t *block = GET_BLOCK_PTR();
|
||||
rb_iseq_t *iseq;
|
||||
int argc = (int)num;
|
||||
|
||||
|
@ -1218,28 +1229,25 @@ vm_getivar(VALUE obj, ID id, IC ic)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline NODE *
|
||||
static inline const rb_method_entry_t *
|
||||
vm_method_search(VALUE id, VALUE klass, IC ic)
|
||||
{
|
||||
NODE *mn;
|
||||
|
||||
rb_method_entry_t *me;
|
||||
#if OPT_INLINE_METHOD_CACHE
|
||||
{
|
||||
if (LIKELY(klass == ic->ic_class) &&
|
||||
LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) {
|
||||
mn = ic->ic_method;
|
||||
}
|
||||
else {
|
||||
mn = rb_method_node(klass, id);
|
||||
ic->ic_class = klass;
|
||||
ic->ic_method = mn;
|
||||
ic->ic_vmstat = GET_VM_STATE_VERSION();
|
||||
}
|
||||
if (LIKELY(klass == ic->ic_class) &&
|
||||
LIKELY(GET_VM_STATE_VERSION() == ic->ic_vmstat)) {
|
||||
me = ic->ic_method;
|
||||
}
|
||||
else {
|
||||
me = rb_method_entry(klass, id);
|
||||
ic->ic_class = klass;
|
||||
ic->ic_method = me;
|
||||
ic->ic_vmstat = GET_VM_STATE_VERSION();
|
||||
}
|
||||
#else
|
||||
mn = rb_method_node(klass, id);
|
||||
me = rb_method_entry(klass, id);
|
||||
#endif
|
||||
return mn;
|
||||
return me;
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
|
@ -1300,8 +1308,8 @@ vm_search_superclass(rb_control_frame_t *reg_cfp, rb_iseq_t *ip,
|
|||
}
|
||||
}
|
||||
|
||||
id = lcfp->method_id;
|
||||
klass = vm_search_normal_superclass(lcfp->method_class, recv);
|
||||
id = lcfp->me->original_id;
|
||||
klass = vm_search_normal_superclass(lcfp->me->klass, recv);
|
||||
}
|
||||
else {
|
||||
klass = vm_search_normal_superclass(ip->klass, recv);
|
||||
|
@ -1520,10 +1528,10 @@ vm_expandarray(rb_control_frame_t *cfp, VALUE ary, rb_num_t num, int flag)
|
|||
}
|
||||
|
||||
static inline int
|
||||
check_cfunc(const NODE *mn, VALUE (*func)())
|
||||
check_cfunc(const rb_method_entry_t *me, VALUE (*func)())
|
||||
{
|
||||
if (mn && nd_type(mn->nd_body) == NODE_CFUNC &&
|
||||
mn->nd_body->nd_cfnc == func) {
|
||||
if (me && me->type == VM_METHOD_TYPE_CFUNC &&
|
||||
me->body.cfunc.func == func) {
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
|
@ -1572,10 +1580,10 @@ opt_eq_func(VALUE recv, VALUE obj, IC ic)
|
|||
val = rb_str_equal(recv, obj);
|
||||
}
|
||||
else {
|
||||
NODE *mn = vm_method_search(idEq, CLASS_OF(recv), ic);
|
||||
const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ic);
|
||||
extern VALUE rb_obj_equal(VALUE obj1, VALUE obj2);
|
||||
|
||||
if (check_cfunc(mn, rb_obj_equal)) {
|
||||
if (check_cfunc(me, rb_obj_equal)) {
|
||||
return recv == obj ? Qtrue : Qfalse;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -159,8 +159,8 @@ extern VALUE ruby_vm_const_missing_count;
|
|||
c1->nd_next = (NODE *)rb_gc_write_barrier((VALUE)__tmp_c2->nd_next);\
|
||||
} while (0)
|
||||
|
||||
#define CALL_METHOD(num, blockptr, flag, id, mn, recv) do { \
|
||||
VALUE v = vm_call_method(th, GET_CFP(), num, blockptr, flag, id, mn, recv); \
|
||||
#define CALL_METHOD(num, blockptr, flag, id, me, recv) do { \
|
||||
VALUE v = vm_call_method(th, GET_CFP(), num, blockptr, flag, id, me, recv); \
|
||||
if (v == Qundef) { \
|
||||
RESTORE_REGS(); \
|
||||
NEXT_INSN(); \
|
||||
|
@ -189,7 +189,7 @@ extern VALUE ruby_vm_const_missing_count;
|
|||
|
||||
#define CALL_SIMPLE_METHOD(num, id, recv) do { \
|
||||
VALUE klass = CLASS_OF(recv); \
|
||||
CALL_METHOD(num, 0, 0, id, rb_method_node(klass, id), recv); \
|
||||
CALL_METHOD(num, 0, 0, id, rb_method_entry(klass, id), recv); \
|
||||
} while (0)
|
||||
|
||||
#endif /* RUBY_INSNHELPER_H */
|
||||
|
|
535
vm_method.c
535
vm_method.c
|
@ -6,7 +6,7 @@
|
|||
#define CACHE_MASK 0x7ff
|
||||
#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
|
||||
|
||||
static void rb_vm_check_redefinition_opt_method(const NODE *node);
|
||||
static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me);
|
||||
|
||||
static ID object_id;
|
||||
static ID removed, singleton_removed, undefined, singleton_undefined;
|
||||
|
@ -14,18 +14,14 @@ static ID added, singleton_added;
|
|||
|
||||
struct cache_entry { /* method hash table. */
|
||||
ID mid; /* method's id */
|
||||
ID mid0; /* method's original id */
|
||||
VALUE klass; /* receiver's class */
|
||||
VALUE oklass; /* original's class */
|
||||
NODE *method;
|
||||
rb_method_entry_t *me;
|
||||
};
|
||||
|
||||
static struct cache_entry cache[CACHE_SIZE];
|
||||
#define ruby_running (GET_VM()->running)
|
||||
/* int ruby_running = 0; */
|
||||
|
||||
static NODE *notimplement_body = 0;
|
||||
|
||||
void
|
||||
rb_clear_cache(void)
|
||||
{
|
||||
|
@ -38,7 +34,7 @@ rb_clear_cache(void)
|
|||
ent = cache;
|
||||
end = ent + CACHE_SIZE;
|
||||
while (ent < end) {
|
||||
ent->mid = 0;
|
||||
ent->me = ent->mid = 0;
|
||||
ent++;
|
||||
}
|
||||
}
|
||||
|
@ -55,8 +51,8 @@ rb_clear_cache_for_undef(VALUE klass, ID id)
|
|||
ent = cache;
|
||||
end = ent + CACHE_SIZE;
|
||||
while (ent < end) {
|
||||
if (ent->oklass == klass && ent->mid == id) {
|
||||
ent->mid = 0;
|
||||
if ((ent->me && ent->me->klass == klass) && ent->mid == id) {
|
||||
ent->me = ent->mid = 0;
|
||||
}
|
||||
ent++;
|
||||
}
|
||||
|
@ -75,7 +71,7 @@ rb_clear_cache_by_id(ID id)
|
|||
end = ent + CACHE_SIZE;
|
||||
while (ent < end) {
|
||||
if (ent->mid == id) {
|
||||
ent->mid = 0;
|
||||
ent->me = ent->mid = 0;
|
||||
}
|
||||
ent++;
|
||||
}
|
||||
|
@ -93,17 +89,43 @@ rb_clear_cache_by_class(VALUE klass)
|
|||
ent = cache;
|
||||
end = ent + CACHE_SIZE;
|
||||
while (ent < end) {
|
||||
if (ent->klass == klass || ent->oklass == klass) {
|
||||
ent->mid = 0;
|
||||
if (ent->klass == klass || (ent->me && ent->me->klass == klass)) {
|
||||
ent->me = ent->mid = 0;
|
||||
}
|
||||
ent++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_add_method(VALUE klass, ID mid, NODE * node, int noex)
|
||||
VALUE rb_f_notimplement(int argc, VALUE *argv, VALUE obj)
|
||||
{
|
||||
NODE *body;
|
||||
rb_notimplement();
|
||||
}
|
||||
|
||||
static void rb_define_notimplement_method_id(VALUE mod, ID id, rb_method_flag_t noex)
|
||||
{
|
||||
rb_add_method(mod, id, VM_METHOD_TYPE_NOTIMPLEMENTED, 0, noex);
|
||||
}
|
||||
|
||||
void
|
||||
rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex)
|
||||
{
|
||||
if (func != rb_f_notimplement) {
|
||||
rb_method_cfunc_t opt = {
|
||||
func, argc,
|
||||
};
|
||||
rb_add_method(klass, mid, VM_METHOD_TYPE_CFUNC, &opt, noex);
|
||||
}
|
||||
else {
|
||||
rb_define_notimplement_method_id(klass, mid, noex);
|
||||
}
|
||||
}
|
||||
|
||||
rb_method_entry_t *
|
||||
rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex)
|
||||
{
|
||||
rb_method_entry_t *me;
|
||||
st_table *mtbl;
|
||||
st_data_t data;
|
||||
|
||||
if (NIL_P(klass)) {
|
||||
klass = rb_cObject;
|
||||
|
@ -113,15 +135,16 @@ rb_add_method(VALUE klass, ID mid, NODE * node, int noex)
|
|||
rb_raise(rb_eSecurityError, "Insecure: can't define method");
|
||||
}
|
||||
if (!FL_TEST(klass, FL_SINGLETON) &&
|
||||
node && nd_type(node) != NODE_ZSUPER &&
|
||||
type != VM_METHOD_TYPE_NOTIMPLEMENTED &&
|
||||
type != VM_METHOD_TYPE_ZSUPER &&
|
||||
(mid == rb_intern("initialize") || mid == rb_intern("initialize_copy"))) {
|
||||
noex = NOEX_PRIVATE | noex;
|
||||
}
|
||||
else if (FL_TEST(klass, FL_SINGLETON) && node
|
||||
&& nd_type(node) == NODE_CFUNC && mid == rb_intern("allocate")) {
|
||||
rb_warn
|
||||
("defining %s.allocate is deprecated; use rb_define_alloc_func()",
|
||||
rb_class2name(rb_iv_get(klass, "__attached__")));
|
||||
else if (FL_TEST(klass, FL_SINGLETON) &&
|
||||
type == VM_METHOD_TYPE_CFUNC &&
|
||||
mid == rb_intern("allocate")) {
|
||||
rb_warn("defining %s.allocate is deprecated; use rb_define_alloc_func()",
|
||||
rb_class2name(rb_iv_get(klass, "__attached__")));
|
||||
mid = ID_ALLOCATOR;
|
||||
}
|
||||
if (OBJ_FROZEN(klass)) {
|
||||
|
@ -129,189 +152,178 @@ rb_add_method(VALUE klass, ID mid, NODE * node, int noex)
|
|||
}
|
||||
rb_clear_cache_by_id(mid);
|
||||
|
||||
/*
|
||||
* NODE_METHOD (NEW_METHOD(body, klass, vis)):
|
||||
* nd_file : original id // RBASIC()->klass (TODO: dirty hack)
|
||||
* nd_body : method body // (2) // mark
|
||||
* nd_clss : klass // (1) // mark
|
||||
* nd_noex : visibility // (3)
|
||||
*
|
||||
* NODE_FBODY (NEW_FBODY(method, alias)):
|
||||
* nd_body : method (NODE_METHOD) // (2) // mark
|
||||
* nd_oid : original id // (1)
|
||||
* nd_cnt : alias count // (3)
|
||||
*/
|
||||
if (node) {
|
||||
NODE *method = NEW_NODE_LONGLIFE(NODE_METHOD,
|
||||
rb_gc_write_barrier(klass),
|
||||
rb_gc_write_barrier((VALUE)node),
|
||||
NOEX_WITH_SAFE(noex));
|
||||
method->nd_file = (void *)mid;
|
||||
body = NEW_NODE_LONGLIFE(NODE_FBODY, mid, method, 0);
|
||||
}
|
||||
else {
|
||||
body = 0;
|
||||
me = ALLOC(rb_method_entry_t);
|
||||
me->type = type;
|
||||
me->original_id = me->called_id = mid;
|
||||
me->klass = klass;
|
||||
me->flag = NOEX_WITH_SAFE(noex);
|
||||
me->alias_count = 0;
|
||||
|
||||
switch (type) {
|
||||
case VM_METHOD_TYPE_ISEQ:
|
||||
me->body.iseq = (rb_iseq_t *)opts;
|
||||
break;
|
||||
case VM_METHOD_TYPE_CFUNC:
|
||||
me->body.cfunc = *(rb_method_cfunc_t *)opts;
|
||||
break;
|
||||
case VM_METHOD_TYPE_ATTRSET:
|
||||
case VM_METHOD_TYPE_IVAR:
|
||||
me->body.attr_id = (ID)opts;
|
||||
break;
|
||||
case VM_METHOD_TYPE_BMETHOD:
|
||||
me->body.proc = (VALUE)opts;
|
||||
break;
|
||||
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
||||
me->body.cfunc.func = rb_f_notimplement;
|
||||
me->body.cfunc.argc = -1;
|
||||
break;
|
||||
case VM_METHOD_TYPE_OPTIMIZED:
|
||||
me->body.optimize_type = (enum method_optimized_type)opts;
|
||||
break;
|
||||
case VM_METHOD_TYPE_ZSUPER:
|
||||
case VM_METHOD_TYPE_UNDEF:
|
||||
break;
|
||||
default:
|
||||
rb_bug("rb_add_method: unsupported method type (%d)\n", type);
|
||||
}
|
||||
|
||||
{
|
||||
/* check re-definition */
|
||||
st_data_t data;
|
||||
NODE *old_node;
|
||||
mtbl = RCLASS_M_TBL(klass);
|
||||
|
||||
if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) {
|
||||
old_node = (NODE *)data;
|
||||
if (old_node) {
|
||||
if (nd_type(old_node->nd_body->nd_body) == NODE_CFUNC) {
|
||||
rb_vm_check_redefinition_opt_method(old_node);
|
||||
}
|
||||
if (RTEST(ruby_verbose) && node && old_node->nd_cnt == 0 && old_node->nd_body) {
|
||||
rb_warning("method redefined; discarding old %s", rb_id2name(mid));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (klass == rb_cObject && node && mid == idInitialize) {
|
||||
rb_warn("redefining Object#initialize may cause infinite loop");
|
||||
/* check re-definition */
|
||||
if (st_lookup(mtbl, mid, &data)) {
|
||||
rb_method_entry_t *old_me = (rb_method_entry_t *)data;
|
||||
rb_vm_check_redefinition_opt_method(old_me);
|
||||
|
||||
if (RTEST(ruby_verbose) &&
|
||||
old_me->alias_count == 0 &&
|
||||
old_me->type != VM_METHOD_TYPE_UNDEF) {
|
||||
rb_warning("method redefined; discarding old %s", rb_id2name(mid));
|
||||
}
|
||||
|
||||
if (mid == object_id || mid == id__send__) {
|
||||
if (node && nd_type(node) == RUBY_VM_METHOD_NODE) {
|
||||
rb_warn("redefining `%s' may cause serious problems",
|
||||
rb_id2name(mid));
|
||||
}
|
||||
// TODO: free old_me
|
||||
}
|
||||
|
||||
/* check mid */
|
||||
if (klass == rb_cObject && mid == idInitialize) {
|
||||
rb_warn("redefining Object#initialize may cause infinite loop");
|
||||
}
|
||||
/* check mid */
|
||||
if (mid == object_id || mid == id__send__) {
|
||||
if (type == VM_METHOD_TYPE_ISEQ) {
|
||||
rb_warn("redefining `%s' may cause serious problems", rb_id2name(mid));
|
||||
}
|
||||
}
|
||||
|
||||
st_insert(RCLASS_M_TBL(klass), mid, (st_data_t) body);
|
||||
st_insert(mtbl, mid, (st_data_t) me);
|
||||
|
||||
if (node && mid != ID_ALLOCATOR && ruby_running) {
|
||||
if (mid != ID_ALLOCATOR && ruby_running) {
|
||||
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||
rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1,
|
||||
ID2SYM(mid));
|
||||
rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1, ID2SYM(mid));
|
||||
}
|
||||
else {
|
||||
rb_funcall(klass, added, 1, ID2SYM(mid));
|
||||
}
|
||||
}
|
||||
|
||||
return me;
|
||||
}
|
||||
|
||||
void
|
||||
rb_define_alloc_func(VALUE klass, VALUE (*func)(VALUE))
|
||||
{
|
||||
Check_Type(klass, T_CLASS);
|
||||
rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR,
|
||||
NEW_NODE_LONGLIFE(NODE_CFUNC, func, 0, 0),
|
||||
NOEX_PRIVATE);
|
||||
rb_add_method_cfunc(rb_singleton_class(klass), ID_ALLOCATOR,
|
||||
func, 0, NOEX_PRIVATE);
|
||||
}
|
||||
|
||||
void
|
||||
rb_undef_alloc_func(VALUE klass)
|
||||
{
|
||||
Check_Type(klass, T_CLASS);
|
||||
rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR, 0, NOEX_UNDEF);
|
||||
rb_add_method(rb_singleton_class(klass), ID_ALLOCATOR, VM_METHOD_TYPE_UNDEF, 0, NOEX_UNDEF);
|
||||
}
|
||||
|
||||
rb_alloc_func_t
|
||||
rb_get_alloc_func(VALUE klass)
|
||||
{
|
||||
NODE *n;
|
||||
rb_method_entry_t *me;
|
||||
Check_Type(klass, T_CLASS);
|
||||
n = rb_method_node(CLASS_OF(klass), ID_ALLOCATOR);
|
||||
if (!n) return 0;
|
||||
if (nd_type(n) != NODE_METHOD) return 0;
|
||||
n = n->nd_body;
|
||||
if (nd_type(n) != NODE_CFUNC) return 0;
|
||||
return (rb_alloc_func_t)n->nd_cfnc;
|
||||
me = rb_method_entry(CLASS_OF(klass), ID_ALLOCATOR);
|
||||
|
||||
if (me && me->type == VM_METHOD_TYPE_CFUNC) {
|
||||
return (rb_alloc_func_t)me->body.cfunc.func;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static NODE *
|
||||
search_method(VALUE klass, ID id, VALUE *klassp)
|
||||
static rb_method_entry_t*
|
||||
search_method(VALUE klass, ID id)
|
||||
{
|
||||
st_data_t body;
|
||||
|
||||
if (!klass) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!st_lookup(RCLASS_M_TBL(klass), id, &body)) {
|
||||
klass = RCLASS_SUPER(klass);
|
||||
if (!klass)
|
||||
if (!klass) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (klassp) {
|
||||
*klassp = klass;
|
||||
}
|
||||
|
||||
return (NODE *)body;
|
||||
return (rb_method_entry_t *)body;
|
||||
}
|
||||
|
||||
/*
|
||||
* search method body (NODE_METHOD)
|
||||
* with : klass and id
|
||||
* without : method cache
|
||||
* search method entry without method cache.
|
||||
*
|
||||
* if you need method node with method cache, use
|
||||
* rb_method_node()
|
||||
* if you need method entry with method cache, use
|
||||
* rb_method_entry()
|
||||
*/
|
||||
NODE *
|
||||
rb_get_method_body(VALUE klass, ID id, ID *idp)
|
||||
rb_method_entry_t *
|
||||
rb_get_method_entry(VALUE klass, ID id)
|
||||
{
|
||||
NODE *volatile fbody, *body;
|
||||
NODE *method;
|
||||
|
||||
if ((fbody = search_method(klass, id, 0)) == 0 || !fbody->nd_body) {
|
||||
/* store empty info in cache */
|
||||
struct cache_entry *ent;
|
||||
ent = cache + EXPR1(klass, id);
|
||||
ent->klass = klass;
|
||||
ent->mid = ent->mid0 = id;
|
||||
ent->method = 0;
|
||||
ent->oklass = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
method = fbody->nd_body;
|
||||
rb_method_entry_t *me = search_method(klass, id);
|
||||
|
||||
if (ruby_running) {
|
||||
/* store in cache */
|
||||
struct cache_entry *ent;
|
||||
ent = cache + EXPR1(klass, id);
|
||||
ent->klass = klass;
|
||||
ent->mid = id;
|
||||
ent->mid0 = fbody->nd_oid;
|
||||
ent->method = body = method;
|
||||
ent->oklass = method->nd_clss;
|
||||
}
|
||||
else {
|
||||
body = method;
|
||||
|
||||
if (!me || me->type == VM_METHOD_TYPE_UNDEF) {
|
||||
ent->mid = id;
|
||||
ent->me = 0;
|
||||
me = 0;
|
||||
}
|
||||
else {
|
||||
ent->mid = id;
|
||||
ent->me = me;
|
||||
}
|
||||
}
|
||||
|
||||
if (idp) {
|
||||
*idp = fbody->nd_oid;
|
||||
}
|
||||
|
||||
return body;
|
||||
return me;
|
||||
}
|
||||
|
||||
NODE *
|
||||
rb_method_node(VALUE klass, ID id)
|
||||
rb_method_entry_t *
|
||||
rb_method_entry(VALUE klass, ID id)
|
||||
{
|
||||
struct cache_entry *ent;
|
||||
|
||||
ent = cache + EXPR1(klass, id);
|
||||
if (ent->mid == id && ent->klass == klass) {
|
||||
if (ent->method) return ent->method;
|
||||
return 0;
|
||||
return ent->me;
|
||||
}
|
||||
|
||||
return rb_get_method_body(klass, id, 0);
|
||||
return rb_get_method_entry(klass, id);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_method(VALUE klass, ID mid)
|
||||
{
|
||||
st_data_t data;
|
||||
NODE *body = 0;
|
||||
rb_method_entry_t *me = 0;
|
||||
|
||||
if (klass == rb_cObject) {
|
||||
rb_secure(4);
|
||||
|
@ -324,26 +336,26 @@ remove_method(VALUE klass, ID mid)
|
|||
if (mid == object_id || mid == id__send__ || mid == idInitialize) {
|
||||
rb_warn("removing `%s' may cause serious problems", rb_id2name(mid));
|
||||
}
|
||||
|
||||
if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) {
|
||||
body = (NODE *)data;
|
||||
if (!body || !body->nd_body) body = 0;
|
||||
me = (rb_method_entry_t *)data;
|
||||
if (!me || me->type == VM_METHOD_TYPE_UNDEF) {
|
||||
me = 0;
|
||||
}
|
||||
else {
|
||||
st_delete(RCLASS_M_TBL(klass), &mid, &data);
|
||||
}
|
||||
}
|
||||
if (!body) {
|
||||
if (!me) {
|
||||
rb_name_error(mid, "method `%s' not defined in %s",
|
||||
rb_id2name(mid), rb_class2name(klass));
|
||||
}
|
||||
|
||||
if (nd_type(body->nd_body->nd_body) == NODE_CFUNC) {
|
||||
rb_vm_check_redefinition_opt_method(body);
|
||||
}
|
||||
|
||||
rb_vm_check_redefinition_opt_method(me);
|
||||
rb_clear_cache_for_undef(klass, mid);
|
||||
|
||||
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||
rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1,
|
||||
ID2SYM(mid));
|
||||
rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1, ID2SYM(mid));
|
||||
}
|
||||
else {
|
||||
rb_funcall(klass, removed, 1, ID2SYM(mid));
|
||||
|
@ -393,49 +405,45 @@ rb_enable_super(VALUE klass, const char *name)
|
|||
static void
|
||||
rb_export_method(VALUE klass, ID name, ID noex)
|
||||
{
|
||||
NODE *fbody;
|
||||
VALUE origin;
|
||||
rb_method_entry_t *me;
|
||||
|
||||
if (klass == rb_cObject) {
|
||||
rb_secure(4);
|
||||
}
|
||||
fbody = search_method(klass, name, &origin);
|
||||
if (!fbody && TYPE(klass) == T_MODULE) {
|
||||
fbody = search_method(rb_cObject, name, &origin);
|
||||
|
||||
me = search_method(klass, name);
|
||||
if (!me && TYPE(klass) == T_MODULE) {
|
||||
me = search_method(rb_cObject, name);
|
||||
}
|
||||
if (!fbody || !fbody->nd_body) {
|
||||
|
||||
if (!me || me->type == VM_METHOD_TYPE_UNDEF) {
|
||||
rb_print_undef(klass, name, 0);
|
||||
}
|
||||
if (fbody->nd_body->nd_noex != noex) {
|
||||
if (nd_type(fbody->nd_body->nd_body) == NODE_CFUNC) {
|
||||
rb_vm_check_redefinition_opt_method(fbody);
|
||||
}
|
||||
if (klass == origin) {
|
||||
fbody->nd_body->nd_noex = noex;
|
||||
|
||||
if (me->flag != noex) {
|
||||
rb_vm_check_redefinition_opt_method(me);
|
||||
|
||||
if (klass == me->klass) {
|
||||
me->flag = noex;
|
||||
}
|
||||
else {
|
||||
rb_add_method(klass, name, NEW_ZSUPER(), noex);
|
||||
rb_add_method(klass, name, VM_METHOD_TYPE_ZSUPER, 0, noex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
rb_notimplement_body_p(NODE *method)
|
||||
{
|
||||
return method == notimplement_body ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
int
|
||||
rb_method_boundp(VALUE klass, ID id, int ex)
|
||||
{
|
||||
NODE *method;
|
||||
rb_method_entry_t *me = rb_method_entry(klass, id);
|
||||
|
||||
if ((method = rb_method_node(klass, id)) != 0) {
|
||||
if (ex && (method->nd_noex & NOEX_PRIVATE)) {
|
||||
if (me != 0) {
|
||||
if (ex && (me->flag & NOEX_PRIVATE)) {
|
||||
return Qfalse;
|
||||
}
|
||||
if (rb_notimplement_body_p(method->nd_body))
|
||||
if (me->type == VM_METHOD_TYPE_NOTIMPLEMENTED) {
|
||||
return Qfalse;
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
return Qfalse;
|
||||
|
@ -447,7 +455,7 @@ rb_attr(VALUE klass, ID id, int read, int write, int ex)
|
|||
const char *name;
|
||||
ID attriv;
|
||||
VALUE aname;
|
||||
int noex;
|
||||
rb_method_flag_t noex;
|
||||
|
||||
if (!ex) {
|
||||
noex = NOEX_PUBLIC;
|
||||
|
@ -478,32 +486,32 @@ rb_attr(VALUE klass, ID id, int read, int write, int ex)
|
|||
rb_enc_copy(aname, rb_id2str(id));
|
||||
attriv = rb_intern_str(aname);
|
||||
if (read) {
|
||||
rb_add_method(klass, id, NEW_IVAR(attriv), noex);
|
||||
rb_add_method(klass, id, VM_METHOD_TYPE_IVAR, (void *)attriv, noex);
|
||||
}
|
||||
if (write) {
|
||||
rb_add_method(klass, rb_id_attrset(id), NEW_ATTRSET(attriv), noex);
|
||||
rb_add_method(klass, rb_id_attrset(id), VM_METHOD_TYPE_ATTRSET, (void *)attriv, noex);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_undef(VALUE klass, ID id)
|
||||
{
|
||||
VALUE origin;
|
||||
NODE *body;
|
||||
rb_method_entry_t *me;
|
||||
|
||||
if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) {
|
||||
rb_secure(4);
|
||||
}
|
||||
if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
|
||||
rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'",
|
||||
rb_id2name(id));
|
||||
rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'", rb_id2name(id));
|
||||
}
|
||||
rb_frozen_class_p(klass);
|
||||
if (id == object_id || id == id__send__ || id == idInitialize) {
|
||||
rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
|
||||
}
|
||||
body = search_method(klass, id, &origin);
|
||||
if (!body || !body->nd_body) {
|
||||
|
||||
me = search_method(klass, id);
|
||||
|
||||
if (!me || me->type == VM_METHOD_TYPE_UNDEF) {
|
||||
const char *s0 = " class";
|
||||
VALUE c = klass;
|
||||
|
||||
|
@ -524,11 +532,10 @@ rb_undef(VALUE klass, ID id)
|
|||
rb_id2name(id), s0, rb_class2name(c));
|
||||
}
|
||||
|
||||
rb_add_method(klass, id, 0, NOEX_PUBLIC);
|
||||
rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);
|
||||
|
||||
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||
rb_funcall(rb_iv_get(klass, "__attached__"),
|
||||
singleton_undefined, 1, ID2SYM(id));
|
||||
rb_funcall(rb_iv_get(klass, "__attached__"), singleton_undefined, 1, ID2SYM(id));
|
||||
}
|
||||
else {
|
||||
rb_funcall(klass, undefined, 1, ID2SYM(id));
|
||||
|
@ -622,6 +629,18 @@ rb_mod_method_defined(VALUE mod, VALUE mid)
|
|||
|
||||
#define VISI_CHECK(x,f) (((x)&NOEX_MASK) == (f))
|
||||
|
||||
static VALUE
|
||||
check_definition(VALUE mod, VALUE mid, rb_method_flag_t noex)
|
||||
{
|
||||
const rb_method_entry_t *me;
|
||||
me = rb_method_entry(mod, mid);
|
||||
if (me) {
|
||||
if (VISI_CHECK(me->flag, noex))
|
||||
return Qtrue;
|
||||
}
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* mod.public_method_defined?(symbol) => true or false
|
||||
|
@ -651,15 +670,7 @@ rb_mod_method_defined(VALUE mod, VALUE mid)
|
|||
static VALUE
|
||||
rb_mod_public_method_defined(VALUE mod, VALUE mid)
|
||||
{
|
||||
ID id = rb_to_id(mid);
|
||||
NODE *method;
|
||||
|
||||
method = rb_method_node(mod, id);
|
||||
if (method) {
|
||||
if (VISI_CHECK(method->nd_noex, NOEX_PUBLIC))
|
||||
return Qtrue;
|
||||
}
|
||||
return Qfalse;
|
||||
return check_definition(mod, rb_to_id(mid), NOEX_PUBLIC);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -691,15 +702,7 @@ rb_mod_public_method_defined(VALUE mod, VALUE mid)
|
|||
static VALUE
|
||||
rb_mod_private_method_defined(VALUE mod, VALUE mid)
|
||||
{
|
||||
ID id = rb_to_id(mid);
|
||||
NODE *method;
|
||||
|
||||
method = rb_method_node(mod, id);
|
||||
if (method) {
|
||||
if (VISI_CHECK(method->nd_noex, NOEX_PRIVATE))
|
||||
return Qtrue;
|
||||
}
|
||||
return Qfalse;
|
||||
return check_definition(mod, rb_to_id(mid), NOEX_PRIVATE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -731,70 +734,100 @@ rb_mod_private_method_defined(VALUE mod, VALUE mid)
|
|||
static VALUE
|
||||
rb_mod_protected_method_defined(VALUE mod, VALUE mid)
|
||||
{
|
||||
ID id = rb_to_id(mid);
|
||||
NODE *method;
|
||||
return check_definition(mod, rb_to_id(mid), NOEX_PROTECTED);
|
||||
}
|
||||
|
||||
method = rb_method_node(mod, id);
|
||||
if (method) {
|
||||
if (VISI_CHECK(method->nd_noex, NOEX_PROTECTED))
|
||||
return Qtrue;
|
||||
static void *
|
||||
me_opts(const rb_method_entry_t *me)
|
||||
{
|
||||
switch (me->type) {
|
||||
case VM_METHOD_TYPE_ISEQ:
|
||||
return me->body.iseq;
|
||||
case VM_METHOD_TYPE_CFUNC:
|
||||
return (void *)&me->body.cfunc;
|
||||
case VM_METHOD_TYPE_ATTRSET:
|
||||
case VM_METHOD_TYPE_IVAR:
|
||||
return (void *)me->body.attr_id;
|
||||
case VM_METHOD_TYPE_BMETHOD:
|
||||
return (void *)me->body.proc;
|
||||
case VM_METHOD_TYPE_ZSUPER:
|
||||
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
||||
case VM_METHOD_TYPE_UNDEF:
|
||||
return 0;
|
||||
default:
|
||||
rb_bug("rb_add_method: unsupported method type (%d)\n", me->type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_add_method_me(VALUE klass, ID mid, const rb_method_entry_t *me, rb_method_flag_t noex)
|
||||
{
|
||||
rb_add_method(klass, mid, me->type, me_opts(me), noex);
|
||||
}
|
||||
|
||||
int
|
||||
rb_method_entry_eq(const rb_method_entry_t *m1, const rb_method_entry_t *m2)
|
||||
{
|
||||
if (m1->type != m2->type) {
|
||||
return 0;
|
||||
}
|
||||
switch (m1->type) {
|
||||
case VM_METHOD_TYPE_ISEQ:
|
||||
return m1->body.iseq == m2->body.iseq;
|
||||
case VM_METHOD_TYPE_CFUNC:
|
||||
return
|
||||
m1->body.cfunc.func == m2->body.cfunc.func &&
|
||||
m1->body.cfunc.argc == m2->body.cfunc.argc;
|
||||
case VM_METHOD_TYPE_ATTRSET:
|
||||
case VM_METHOD_TYPE_IVAR:
|
||||
return m1->body.attr_id == m2->body.attr_id;
|
||||
case VM_METHOD_TYPE_BMETHOD:
|
||||
return m1->body.proc == m2->body.proc;
|
||||
case VM_METHOD_TYPE_ZSUPER:
|
||||
case VM_METHOD_TYPE_NOTIMPLEMENTED:
|
||||
case VM_METHOD_TYPE_UNDEF:
|
||||
return 1;
|
||||
default:
|
||||
rb_bug("rb_add_method: unsupported method type (%d)\n", m1->type);
|
||||
return 0;
|
||||
}
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
void
|
||||
rb_alias(VALUE klass, ID name, ID def)
|
||||
{
|
||||
NODE *orig_fbody, *node, *method;
|
||||
rb_method_entry_t *orig_me, *me;
|
||||
VALUE singleton = 0;
|
||||
st_data_t data;
|
||||
|
||||
rb_frozen_class_p(klass);
|
||||
if (klass == rb_cObject) {
|
||||
rb_secure(4);
|
||||
}
|
||||
orig_fbody = search_method(klass, def, 0);
|
||||
if (!orig_fbody || !orig_fbody->nd_body) {
|
||||
|
||||
orig_me = search_method(klass, def);
|
||||
|
||||
if (!orig_me || orig_me->type == VM_METHOD_TYPE_UNDEF) {
|
||||
if (TYPE(klass) == T_MODULE) {
|
||||
orig_fbody = search_method(rb_cObject, def, 0);
|
||||
orig_me = search_method(rb_cObject, def);
|
||||
|
||||
if (!orig_me || !orig_me->type == VM_METHOD_TYPE_UNDEF) {
|
||||
rb_print_undef(klass, def, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!orig_fbody || !orig_fbody->nd_body) {
|
||||
rb_print_undef(klass, def, 0);
|
||||
}
|
||||
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||
singleton = rb_iv_get(klass, "__attached__");
|
||||
}
|
||||
|
||||
orig_fbody->nd_cnt++;
|
||||
|
||||
if (st_lookup(RCLASS_M_TBL(klass), name, &data)) {
|
||||
node = (NODE *)data;
|
||||
if (node) {
|
||||
if (RTEST(ruby_verbose) && node->nd_cnt == 0 && node->nd_body) {
|
||||
rb_warning("discarding old %s", rb_id2name(name));
|
||||
}
|
||||
if (nd_type(node->nd_body->nd_body) == NODE_CFUNC) {
|
||||
rb_vm_check_redefinition_opt_method(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
st_insert(RCLASS_M_TBL(klass), name,
|
||||
(st_data_t) NEW_NODE_LONGLIFE(
|
||||
NODE_FBODY,
|
||||
def,
|
||||
method = NEW_NODE_LONGLIFE(NODE_METHOD,
|
||||
rb_gc_write_barrier((VALUE)orig_fbody->nd_body->nd_clss),
|
||||
rb_gc_write_barrier((VALUE)orig_fbody->nd_body->nd_body),
|
||||
NOEX_WITH_SAFE(orig_fbody->nd_body->nd_noex)),
|
||||
0));
|
||||
method->nd_file = (void *)def;
|
||||
|
||||
rb_clear_cache_by_id(name);
|
||||
orig_me->alias_count++;
|
||||
me = rb_add_method(klass, name, orig_me->type, me_opts(orig_me), orig_me->flag);
|
||||
me->original_id = def;
|
||||
|
||||
if (!ruby_running) return;
|
||||
|
||||
rb_clear_cache_by_id(name);
|
||||
|
||||
if (singleton) {
|
||||
rb_funcall(singleton, singleton_added, 1, ID2SYM(name));
|
||||
}
|
||||
|
@ -832,18 +865,6 @@ rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname)
|
|||
return mod;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_f_notimplement(int argc, VALUE *argv, VALUE obj)
|
||||
{
|
||||
rb_notimplement();
|
||||
}
|
||||
|
||||
void
|
||||
rb_define_notimplement_method_id(VALUE mod, ID id, int noex)
|
||||
{
|
||||
rb_add_method(mod, id, notimplement_body, noex);
|
||||
}
|
||||
|
||||
static void
|
||||
secure_visibility(VALUE self)
|
||||
{
|
||||
|
@ -1042,7 +1063,7 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
|
|||
{
|
||||
int i;
|
||||
ID id;
|
||||
NODE *fbody;
|
||||
const rb_method_entry_t *me;
|
||||
|
||||
if (TYPE(module) != T_MODULE) {
|
||||
rb_raise(rb_eTypeError, "module_function must be called for modules");
|
||||
|
@ -1061,22 +1082,21 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
|
|||
|
||||
id = rb_to_id(argv[i]);
|
||||
for (;;) {
|
||||
fbody = search_method(m, id, &m);
|
||||
if (fbody == 0) {
|
||||
fbody = search_method(rb_cObject, id, &m);
|
||||
me = search_method(m, id);
|
||||
if (me == 0) {
|
||||
me = search_method(rb_cObject, id);
|
||||
}
|
||||
if (fbody == 0 || fbody->nd_body == 0) {
|
||||
if (me == 0 || me->type == VM_METHOD_TYPE_UNDEF) {
|
||||
rb_print_undef(module, id, 0);
|
||||
}
|
||||
if (nd_type(fbody->nd_body->nd_body) != NODE_ZSUPER) {
|
||||
break; /* normal case: need not to follow 'super' link */
|
||||
if (me->type != VM_METHOD_TYPE_ZSUPER) {
|
||||
break; /* normal case: need not to follow 'super' link */
|
||||
}
|
||||
m = RCLASS_SUPER(m);
|
||||
if (!m)
|
||||
break;
|
||||
}
|
||||
rb_add_method(rb_singleton_class(module), id, fbody->nd_body->nd_body,
|
||||
NOEX_PUBLIC);
|
||||
rb_add_method_me(rb_singleton_class(module), id, me, NOEX_PUBLIC);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
|
@ -1084,8 +1104,8 @@ rb_mod_modfunc(int argc, VALUE *argv, VALUE module)
|
|||
int
|
||||
rb_method_basic_definition_p(VALUE klass, ID id)
|
||||
{
|
||||
NODE *node = rb_method_node(klass, id);
|
||||
if (node && (node->nd_noex & NOEX_BASIC))
|
||||
const rb_method_entry_t *me = rb_method_entry(klass, id);
|
||||
if (me && (me->flag & NOEX_BASIC))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1174,8 +1194,5 @@ Init_eval_method(void)
|
|||
singleton_removed = rb_intern("singleton_method_removed");
|
||||
undefined = rb_intern("method_undefined");
|
||||
singleton_undefined = rb_intern("singleton_method_undefined");
|
||||
|
||||
notimplement_body = NEW_CFUNC(rb_f_notimplement, -1);
|
||||
rb_gc_register_mark_object((VALUE)notimplement_body);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue