Feature #10575 ยป struct_iseq-v1-r48725.patch
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)
|
||
-
|