Skip to content

Commit

Permalink
a quick implementation for #define_method (not yet 100% complete)
Browse files Browse the repository at this point in the history
  • Loading branch information
lrz committed Jun 15, 2009
1 parent b49db08 commit 208a965
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 53 deletions.
3 changes: 1 addition & 2 deletions class.c
Original file line number Diff line number Diff line change
Expand Up @@ -940,8 +940,7 @@ rb_objc_add_method(VALUE klass, const char *name, void *imp, const int arity,
assert(name[strlen(name) - 1] != ':');
}

NODE *node = NEW_CFUNC(imp, arity);
NODE *body = NEW_FBODY(NEW_METHOD(node, klass, noex), 0);
NODE *body = rb_vm_cfunc_node_from_imp((Class)klass, arity, (IMP)imp, noex);
rb_objc_retain(body);

rb_vm_define_method((Class)klass, name_to_sel(name, arity), (IMP)imp,
Expand Down
38 changes: 38 additions & 0 deletions compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ RoxorCompiler::RoxorCompiler(const char *_fname)
masgnGetSplatFunc = NULL;
newStringFunc = NULL;
yieldFunc = NULL;
blockEvalFunc = NULL;
gvarSetFunc = NULL;
gvarGetFunc = NULL;
cvarSetFunc = NULL;
Expand Down Expand Up @@ -5351,6 +5352,43 @@ RoxorCompiler::compile_objc_stub(Function *ruby_func, const char *types)
return f;
}

Function *
RoxorCompiler::compile_block_caller(rb_vm_block_t *block)
{
// VALUE foo(VALUE rcv, SEL sel, int argc, VALUE *argv)
// {
// return rb_vm_block_eval2(block, rcv, argc, argv);
// }
Function *f = cast<Function>(module->getOrInsertFunction("",
RubyObjTy, RubyObjTy, PtrTy, Type::Int32Ty, RubyObjPtrTy,
NULL));
Function::arg_iterator arg = f->arg_begin();
Value *rcv = arg++;
arg++; // sel
Value *argc = arg++;
Value *argv = arg++;

bb = BasicBlock::Create("EntryBlock", f);

if (blockEvalFunc == NULL) {
blockEvalFunc = cast<Function>(module->getOrInsertFunction(
"rb_vm_block_eval2",
RubyObjTy, PtrTy, RubyObjTy, Type::Int32Ty, RubyObjPtrTy,
NULL));
}
std::vector<Value *> params;
params.push_back(compile_const_pointer(block));
params.push_back(rcv);
params.push_back(argc);
params.push_back(argv);

Value *retval = compile_protected_call(blockEvalFunc, params);

ReturnInst::Create(retval, bb);

return f;
}

Function *
RoxorCompiler::compile_to_rval_convertor(const char *type)
{
Expand Down
2 changes: 2 additions & 0 deletions compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class RoxorCompiler {
Function *compile_to_rval_convertor(const char *type);
Function *compile_to_ocval_convertor(const char *type);
Function *compile_objc_stub(Function *ruby_func, const char *types);
Function *compile_block_caller(rb_vm_block_t *block);

const Type *convert_type(const char *type);

Expand Down Expand Up @@ -131,6 +132,7 @@ class RoxorCompiler {
Function *masgnGetSplatFunc;
Function *newStringFunc;
Function *yieldFunc;
Function *blockEvalFunc;
Function *gvarSetFunc;
Function *gvarGetFunc;
Function *cvarSetFunc;
Expand Down
50 changes: 18 additions & 32 deletions proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,16 @@ rb_proc_alloc_with_block(VALUE klass, rb_vm_block_t *proc)
return obj;
}

VALUE
rb_obj_is_proc(VALUE proc)
static inline bool
rb_obj_is_proc(VALUE obj)
{
if (TYPE(proc) == T_DATA) {
// TODO check if it's really a rb_cProc
return Qtrue;
}
return Qfalse;
return CLASS_OF(obj) == rb_cProc;
}

static inline bool
rb_obj_is_method(VALUE obj)
{
return CLASS_OF(obj) == rb_cMethod;
}

static VALUE
Expand Down Expand Up @@ -944,11 +946,8 @@ rb_mod_public_instance_method(VALUE mod, SEL sel, VALUE vid)
static VALUE
rb_mod_define_method(VALUE mod, SEL sel, int argc, VALUE *argv)
{
#if 0 // TODO
ID id;
VALUE body;
NODE *node;
int noex = NOEX_PUBLIC;

if (argc == 1) {
id = rb_to_id(argv[0]);
Expand All @@ -967,7 +966,11 @@ rb_mod_define_method(VALUE mod, SEL sel, int argc, VALUE *argv)
rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
}

if (true/*RDATA(body)->dmark == (RUBY_DATA_FUNC) bm_mark*/) {
SEL method_sel = sel_registerName(rb_id2name(id));
if (rb_obj_is_method(body)) {
// TODO
abort();
#if 0
struct METHOD *method = (struct METHOD *)DATA_PTR(body);
VALUE rclass = method->rclass;
if (rclass != mod) {
Expand All @@ -982,32 +985,15 @@ rb_mod_define_method(VALUE mod, SEL sel, int argc, VALUE *argv)
}
}
node = method->body;
}
#if 0 // TODO
else if (rb_obj_is_proc(body)) {
rb_proc_t *proc;
body = proc_dup(body, 0);
GetProcPtr(body, proc);
if (BUILTIN_TYPE(proc->block.iseq) != T_NODE) {
proc->block.iseq->defined_method_id = id;
proc->block.iseq->klass = mod;
proc->is_lambda = Qtrue;
proc->is_from_method = Qtrue;
}
node = NEW_BMETHOD(body);
}
#endif
}
else {
/* type error */
rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)");
rb_vm_block_t *proc;
GetProcPtr(body, proc);
rb_vm_define_method3((Class)mod, method_sel, proc);
}

/* TODO: visibility */

rb_add_method(mod, id, node, noex);
return body;
#endif
return Qnil;
}

static VALUE
Expand Down
58 changes: 41 additions & 17 deletions vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ RoxorVM::should_invalidate_inline_op(SEL sel, Class klass)
abort();
}

void
rb_vm_method_node_t *
RoxorVM::add_method(Class klass, SEL sel, IMP imp, IMP ruby_imp,
const rb_vm_arity_t &arity, int flags, const char *types)
{
Expand Down Expand Up @@ -608,6 +608,8 @@ RoxorVM::add_method(Class klass, SEL sel, IMP imp, IMP ruby_imp,
}
}
}

return node;
}

void
Expand Down Expand Up @@ -1343,15 +1345,16 @@ rb_vm_prepare_method(Class klass, SEL sel, Function *func, NODE *node)
}
}

static void __rb_vm_define_method(Class klass, SEL sel, IMP imp,
const rb_vm_arity_t &arity, int flags, bool direct);
static void __rb_vm_define_method(Class klass, SEL sel, IMP objc_imp,
IMP ruby_imp, const rb_vm_arity_t &arity, int flags, bool direct);

extern "C"
void
rb_vm_prepare_method2(Class klass, SEL sel, IMP imp, rb_vm_arity_t arity,
int flags)
{
__rb_vm_define_method(klass, sel, imp, arity, flags, false);
// TODO: create objc_imp
__rb_vm_define_method(klass, sel, imp, imp, arity, flags, false);
}

#define VISI(x) ((x)&NOEX_MASK)
Expand Down Expand Up @@ -1616,26 +1619,23 @@ rb_vm_define_attr(Class klass, const char *name, bool read, bool write,
}

static void
__rb_vm_define_method(Class klass, SEL sel, IMP imp,
__rb_vm_define_method(Class klass, SEL sel, IMP objc_imp, IMP ruby_imp,
const rb_vm_arity_t &arity, int flags, bool direct)
{
assert(klass != NULL);

const char *sel_name = sel_getName(sel);
const bool genuine_selector = sel_name[strlen(sel_name) - 1] == ':';

int oc_arity = genuine_selector ? arity.real : 0;
bool redefined = direct;
rb_vm_method_node_t *node = GET_VM()->method_node_get(imp);
IMP ruby_imp = node == NULL ? imp : node->ruby_imp;

define_method:
Method method = class_getInstanceMethod(klass, sel);

char types[100];
resolve_method_type(types, sizeof types, klass, method, sel, oc_arity);

GET_VM()->add_method(klass, sel, imp, ruby_imp, arity, flags, types);
GET_VM()->add_method(klass, sel, objc_imp, ruby_imp, arity, flags, types);

if (!redefined) {
if (!genuine_selector && arity.max != arity.min) {
Expand Down Expand Up @@ -1666,7 +1666,8 @@ rb_vm_define_method(Class klass, SEL sel, IMP imp, NODE *node, bool direct)
{
assert(node != NULL);

__rb_vm_define_method(klass, sel, imp, rb_vm_node_arity(node),
// TODO: create objc_imp
__rb_vm_define_method(klass, sel, imp, imp, rb_vm_node_arity(node),
rb_vm_node_flags(node), direct);
}

Expand All @@ -1677,8 +1678,23 @@ rb_vm_define_method2(Class klass, SEL sel, rb_vm_method_node_t *node,
{
assert(node != NULL);

__rb_vm_define_method(klass, sel, node->objc_imp, node->arity,
node->flags, direct);
__rb_vm_define_method(klass, sel, node->objc_imp, node->ruby_imp,
node->arity, node->flags, direct);
}

extern "C"
void
rb_vm_define_method3(Class klass, SEL sel, rb_vm_block_t *block)
{
assert(block != NULL);

Function *func = RoxorCompiler::shared->compile_block_caller(block);
IMP imp = GET_VM()->compile(func);
NODE *body = rb_vm_cfunc_node_from_imp(klass, -1, imp, 0);
rb_objc_retain(body);
rb_objc_retain(block);

rb_vm_define_method(klass, sel, imp, body, false);
}

extern "C"
Expand Down Expand Up @@ -3133,7 +3149,7 @@ rb_vm_create_block_from_method(rb_vm_method_t *method)
}

static inline VALUE
rb_vm_block_eval0(rb_vm_block_t *b, int argc, const VALUE *argv)
rb_vm_block_eval0(rb_vm_block_t *b, VALUE self, int argc, const VALUE *argv)
{
if (b->node != NULL) {
if (nd_type(b->node) == NODE_IFUNC) {
Expand Down Expand Up @@ -3205,7 +3221,7 @@ rb_vm_block_eval0(rb_vm_block_t *b, int argc, const VALUE *argv)
m->sel, argc, argv);
}
else {
v = __rb_vm_bcall(b->self, (VALUE)b->dvars, b, b->imp, b->arity,
v = __rb_vm_bcall(self, (VALUE)b->dvars, b, b->imp, b->arity,
argc, argv);
}
}
Expand All @@ -3222,7 +3238,15 @@ extern "C"
VALUE
rb_vm_block_eval(rb_vm_block_t *b, int argc, const VALUE *argv)
{
return rb_vm_block_eval0(b, argc, argv);
return rb_vm_block_eval0(b, b->self, argc, argv);
}

extern "C"
VALUE
rb_vm_block_eval2(rb_vm_block_t *b, VALUE self, int argc, const VALUE *argv)
{
// TODO check given arity and raise exception
return rb_vm_block_eval0(b, self, argc, argv);
}

static inline VALUE
Expand All @@ -3237,7 +3261,7 @@ rb_vm_yield0(int argc, const VALUE *argv)

VALUE retval = Qnil;
try {
retval = rb_vm_block_eval0(b, argc, argv);
retval = rb_vm_block_eval0(b, b->self, argc, argv);
}
catch (...) {
GET_VM()->add_current_block(b);
Expand Down Expand Up @@ -3270,7 +3294,7 @@ rb_vm_yield_under(VALUE klass, VALUE self, int argc, const VALUE *argv)

VALUE retval = Qnil;
try {
retval = rb_vm_block_eval0(b, argc, argv);
retval = rb_vm_block_eval0(b, b->self, argc, argv);
}
catch (...) {
b->self = old_self;
Expand Down
13 changes: 11 additions & 2 deletions vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,13 @@ rb_vm_method_node_noex(rb_vm_method_node_t *node)
return 0;
}

static inline NODE *
rb_vm_cfunc_node_from_imp(Class klass, int arity, IMP imp, int noex)
{
NODE *node = NEW_CFUNC(imp, arity);
return NEW_FBODY(NEW_METHOD(node, klass, noex), 0);
}

VALUE rb_vm_run(const char *fname, NODE *node, rb_vm_binding_t *binding,
bool try_interpreter);
VALUE rb_vm_run_under(VALUE klass, VALUE self, const char *fname, NODE *node,
Expand All @@ -217,6 +224,7 @@ void rb_vm_define_method(Class klass, SEL sel, IMP imp, NODE *node,
bool direct);
void rb_vm_define_method2(Class klass, SEL sel, rb_vm_method_node_t *node,
bool direct);
void rb_vm_define_method3(Class klass, SEL sel, rb_vm_block_t *node);
void rb_vm_define_attr(Class klass, const char *name, bool read, bool write,
int noex);
void rb_vm_undef_method(Class klass, const char *name, bool must_exist);
Expand Down Expand Up @@ -582,8 +590,9 @@ class RoxorVM {

struct mcache *method_cache_get(SEL sel, bool super);
rb_vm_method_node_t *method_node_get(IMP imp);
void add_method(Class klass, SEL sel, IMP imp, IMP ruby_imp,
const rb_vm_arity_t &arity, int flags, const char *types);
rb_vm_method_node_t *add_method(Class klass, SEL sel, IMP imp,
IMP ruby_imp, const rb_vm_arity_t &arity, int flags,
const char *types);

GlobalVariable *redefined_op_gvar(SEL sel, bool create);
bool should_invalidate_inline_op(SEL sel, Class klass);
Expand Down

0 comments on commit 208a965

Please sign in to comment.