Project

General

Profile

Feature #10575 ยป struct_iseq-v1-r48725.patch

normalperson (Eric Wong), 12/06/2014 12:31 AM

View differences:

benchmark/bm_vm2_struct_big_aref_hi.rb
s = Struct.new(*('a'..'z').map { |x| x.to_sym })
x = s.new
i = 0
while i<6_000_000 # benchmark loop 2
i += 1
x.z # x[25]
end
benchmark/bm_vm2_struct_big_aref_lo.rb
s = Struct.new(*('a'..'z').map { |x| x.to_sym })
x = s.new
i = 0
while i<6_000_000 # benchmark loop 2
i += 1
x.k # x[10]
end
benchmark/bm_vm2_struct_big_aset.rb
s = Struct.new(*('a'..'z').map { |x| x.to_sym })
x = s.new
i = 0
while i<6_000_000 # benchmark loop 2
i += 1
x.k = i # x[10] = i
end
benchmark/bm_vm2_struct_small_aref.rb
s = Struct.new(:a, :b, :c)
x = s.new
i = 0
while i<6_000_000 # benchmark loop 2
i += 1
x.a
end
benchmark/bm_vm2_struct_small_aset.rb
s = Struct.new(:a, :b, :c)
x = s.new
i = 0
while i<6_000_000 # benchmark loop 2
i += 1
x.a = i
end
iseq.c
return iseqval;
}
rb_iseq_t *
rb_method_for_self_aref(VALUE name, VALUE arg)
{
VALUE iseqval = iseq_alloc(rb_cISeq);
rb_iseq_t *iseq;
VALUE path = rb_str_new2("<compiled>");
VALUE lineno = INT2FIX(1);
VALUE parent = 0;
VALUE misc, locals, params, exception, body, send_arg;
int flag = VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE;
GetISeqPtr(iseqval, iseq);
iseq->self = iseqval;
iseq->local_iseq = iseq;
prepare_iseq_build(iseq, rb_sym2str(name), path, path, lineno, parent,
ISEQ_TYPE_METHOD, &COMPILE_OPTION_DEFAULT);
misc = params = rb_hash_new(); /* empty */
locals = exception = rb_ary_new(); /* empty */
body = rb_ary_new();
#define S(s) ID2SYM(rb_intern(#s))
/* def name; self[arg]; end */
rb_ary_push(body, lineno);
rb_ary_push(body, rb_ary_new3(1, S(putself)));
rb_ary_push(body, rb_ary_new3(2, S(putobject), arg));
/* {:mid=>:[], :flag=>264, :blockptr=>nil, :orig_argc=>1} */
send_arg = rb_hash_new();
rb_hash_aset(send_arg, S(mid), ID2SYM(idAREF));
rb_hash_aset(send_arg, S(flag), INT2FIX(flag));
rb_hash_aset(send_arg, S(blockptr), Qnil);
rb_hash_aset(send_arg, S(orig_argc), INT2FIX(1));
/* we do not want opt_aref for struct */
rb_ary_push(body, rb_ary_new3(2, S(opt_send_without_block), send_arg));
rb_ary_push(body, rb_ary_new3(1, S(leave)));
#undef S
rb_iseq_build_from_ary(iseq, misc, locals, params, exception, body);
cleanup_iseq_build(iseq);
return iseq;
}
rb_iseq_t *
rb_method_for_self_aset(VALUE name, VALUE arg)
{
VALUE iseqval = iseq_alloc(rb_cISeq);
rb_iseq_t *iseq;
VALUE path = rb_str_new2("<compiled>");
VALUE lineno = INT2FIX(1);
VALUE parent = 0;
VALUE misc, locals, params, exception, body, send_arg;
int flag = VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE;
GetISeqPtr(iseqval, iseq);
iseq->self = iseqval;
iseq->local_iseq = iseq;
prepare_iseq_build(iseq, rb_sym2str(name), path, path, lineno, parent,
ISEQ_TYPE_METHOD, &COMPILE_OPTION_DEFAULT);
/* def name=(val); self[arg] = val; end */
#define S(s) ID2SYM(rb_intern(#s))
misc = rb_hash_new(); /* empty */
locals = rb_ary_new3(1, S(val));
params = rb_hash_new();
exception = rb_ary_new(); /* empty */
body = rb_ary_new();
rb_hash_aset(params, S(lead_num), INT2FIX(1));
rb_ary_push(body, lineno);
rb_ary_push(body, rb_ary_new3(1, S(putnil)));
rb_ary_push(body, rb_ary_new3(1, S(putself)));
rb_ary_push(body, rb_ary_new3(2, S(putobject), arg));
rb_ary_push(body, rb_ary_new3(3, S(getlocal), INT2FIX(2), INT2FIX(0)));
rb_ary_push(body, rb_ary_new3(2, S(setn), INT2FIX(3)));
/* {:mid=>:[]=, :flag=>264, :blockptr=>nil, :orig_argc=>2} */
send_arg = rb_hash_new();
rb_hash_aset(send_arg, S(mid), ID2SYM(idASET));
rb_hash_aset(send_arg, S(flag), INT2FIX(flag));
rb_hash_aset(send_arg, S(blockptr), Qnil);
rb_hash_aset(send_arg, S(orig_argc), INT2FIX(2));
/* we do not want opt_aset for struct */
rb_ary_push(body, rb_ary_new3(2, S(opt_send_without_block), send_arg));
rb_ary_push(body, rb_ary_new3(1, S(pop)));
rb_ary_push(body, rb_ary_new3(1, S(leave)));
#undef S
rb_iseq_build_from_ary(iseq, misc, locals, params, exception, body);
cleanup_iseq_build(iseq);
return iseq;
}
/*
* :nodoc:
*/
struct.c
**********************************************************************/
#include "internal.h"
#include "vm_core.h"
#include "method.h"
rb_iseq_t *rb_method_for_self_aref(VALUE name, VALUE arg);
rb_iseq_t *rb_method_for_self_aset(VALUE name, VALUE arg);
VALUE rb_cStruct;
static ID id_members;
......
UNREACHABLE;
}
static VALUE
rb_struct_ref(VALUE obj)
{
return rb_struct_getmember(obj, rb_frame_this_func());
}
static VALUE rb_struct_ref0(VALUE obj) {return RSTRUCT_GET(obj, 0);}
static VALUE rb_struct_ref1(VALUE obj) {return RSTRUCT_GET(obj, 1);}
static VALUE rb_struct_ref2(VALUE obj) {return RSTRUCT_GET(obj, 2);}
......
}
static VALUE
rb_struct_set(VALUE obj, VALUE val)
{
VALUE members, slot, fsym;
long i, len;
ID fid = rb_frame_this_func();
members = rb_struct_members(obj);
len = RARRAY_LEN(members);
rb_struct_modify(obj);
fid = rb_id_attrget(fid);
if (!fid) not_a_member(rb_frame_this_func());
fsym = ID2SYM(fid);
for (i=0; i<len; i++) {
slot = RARRAY_AREF(members, i);
if (slot == fsym) {
RSTRUCT_SET(obj, i, val);
return val;
}
}
not_a_member(fid);
UNREACHABLE;
}
static VALUE
anonymous_struct(VALUE klass)
{
VALUE nstr;
......
return rb_define_class_id_under(super, id, super);
}
static void
define_aref_method(VALUE nstr, VALUE name, VALUE off)
{
rb_iseq_t *iseq = rb_method_for_self_aref(name, off);
rb_add_method(nstr, SYM2ID(name), VM_METHOD_TYPE_ISEQ, iseq, NOEX_PUBLIC);
RB_GC_GUARD(iseq->self);
}
static void
define_aset_method(VALUE nstr, VALUE name, VALUE off)
{
rb_iseq_t *iseq = rb_method_for_self_aset(name, off);
rb_add_method(nstr, SYM2ID(name), VM_METHOD_TYPE_ISEQ, iseq, NOEX_PUBLIC);
RB_GC_GUARD(iseq->self);
}
static VALUE
setup_struct(VALUE nstr, VALUE members)
{
......
len = RARRAY_LEN(members);
for (i=0; i< len; i++) {
ID id = SYM2ID(ptr_members[i]);
VALUE off = LONG2NUM(i);
if (i < N_REF_FUNC) {
rb_define_method_id(nstr, id, ref_func[i], 0);
}
else {
rb_define_method_id(nstr, id, rb_struct_ref, 0);
define_aref_method(nstr, ptr_members[i], off);
}
rb_define_method_id(nstr, rb_id_attrset(id), rb_struct_set, 1);
define_aset_method(nstr, ID2SYM(rb_id_attrset(id)), off);
}
return nstr;
test/ruby/test_struct.rb
assert_raise(ArgumentError) { o.select(1) }
end
def test_big_struct
klass1 = @Struct.new(*('a'..'z').map(&:to_sym))
o = klass1.new
assert_nil o.z
assert_equal(:foo, o.z = :foo)
assert_equal(:foo, o.z)
assert_equal(:foo, o[25])
end
def test_equal
klass1 = @Struct.new(:a)
klass2 = @Struct.new(:a, :b)
-
    (1-1/1)