From: "Masahiro Kanai (CanI)" Date: 2009-09-28T00:28:59+09:00 Subject: [ruby-dev:39385] Removing constant-able macros inside of the loop. 金井 仁弘と申します。 ループ内で定数化されうるマクロを、ループの外に出すことによって、 一部メソッドの高速化を図りました。 revision 24444での修正と同様の発想です。 今回の修正は、Array, String, Structに対して行いました。 いずれも、R{Array, String, Struct}_{LEN, PTR}を持っており、 特定の場合において、ループ内で定数化可能です。 ただ、[ruby-dev:24254]等で挙げられているように、 ループ中に、元の{Array, String, Struct}に破壊的変更が加わった場合は、 SEGVしてしまうので、その点は考慮しました。 ベンチマーク結果は、以下の通りです。 $ ./ruby -v ruby 1.9.2dev (2009-09-23 trunk 25052) [i686-linux] a : revision 25052 b : working copy -------------------------------------------------------------------------------- a b % String#* 2.06 1.85 111.35 String#split 2.25 2.13 105.63 String#start_with? 1.93 1.79 107.82 String#end_with? 2.9 2.86 101.4 Array#*   2.17 2.1 103.33 Array#shuffle! 7.76 7.62 101.84 Array#sample 1.52 1.49 102.01 Struct#[] 2.61 2.59 100.77 Struct#[]= 1.37 1.36 100.74 Struct#inspect 3.61 3.57 101.12 Struct#== 3.46 2.11 163.98 Struct#eql? 1.65 1.62 101.85 Struct#hash 1.32 1.31 100.76 -------------------------------------------------------------------------------- 全体で約8%、最高は、Struct#==で、約63%の高速化となります。 詳細は、自分が書いたblogエントリにもあります。 自分の検証では、Struct#{==, eql?, inspect, hash}のループ中に、 ruby上でのメソッドの再定義によって、元のStructに破壊的変更を 加える方法は見つかりませんでした。 しかし、仮に元のStructに破壊的変更が加えられる場合は、 SEGVの原因となりえます。 ・ruby上で、元のStructに破壊的変更を加えることは可能でしょうか? 上記1点も含め、よろしくお願いいたします。 なお、このパッチは、revision 24547でのパッチと同様に、 セキュリティ&プログラミングキャンプ2009の成果物です。 --- array.c (revision 25052) +++ array.c (working copy) @@ -2708,8 +2708,8 @@ rb_ary_concat(VALUE x, VALUE y) static VALUE rb_ary_times(VALUE ary, VALUE times) { - VALUE ary2, tmp; - long i, len; + VALUE ary2, tmp, *ptr, *ptr2; + long i, t, len; tmp = rb_check_string_type(times); if (!NIL_P(tmp)) { @@ -2732,8 +2732,11 @@ rb_ary_times(VALUE ary, VALUE times) ary2 = ary_new(rb_obj_class(ary), len); ARY_SET_LEN(ary2, len); - for (i=0; i= 0) { regs = RMATCH_REGS(rb_backref_get()); if (start == end && BEG(0) == END(0)) { - if (!RSTRING_PTR(str)) { + if (!ptr) { rb_ary_push(result, rb_str_new("", 0)); break; } else if (last_null == 1) { rb_ary_push(result, rb_str_subseq(str, beg, - rb_enc_fast_mbclen(RSTRING_PTR(str)+beg, - RSTRING_END(str), + rb_enc_fast_mbclen(ptr+beg, + ptr+len, enc))); beg = start; } else { - if (RSTRING_PTR(str)+start == RSTRING_END(str)) + if (ptr+start == ptr+len) start++; else - start += rb_enc_fast_mbclen(RSTRING_PTR(str)+start,RSTRING_END(str),enc); + start += rb_enc_fast_mbclen(ptr+start,ptr+len,enc); last_null = 1; continue; } @@ -7048,13 +7053,15 @@ static VALUE rb_str_start_with(int argc, VALUE *argv, VALUE str) { int i; + char *ptr = RSTRING_PTR(str); + long len = RSTRING_LEN(str); for (i=0; i struct @@ -498,7 +507,8 @@ inspect_struct(VALUE s, VALUE dummy, int recur) { VALUE cname = rb_class_name(rb_obj_class(s)); VALUE members, str = rb_str_new2("#"); OBJ_INFECT(str, s); @@ -588,14 +601,16 @@ rb_struct_init_copy(VALUE copy, VALUE s) static VALUE rb_struct_aref_id(VALUE s, ID id) { - VALUE members; + VALUE *ptr, members, *ptr_members; long i, len; + ptr = RSTRUCT_PTR(s); members = rb_struct_members(s); + ptr_members = RARRAY_PTR(members); len = RARRAY_LEN(members); for (i=0; i