1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* vm_core.h (rb_call_info_t): add new type `rb_call_inf_t'.

This data structure contains information including inline method
  cache. After that, `struct iseq_inline_cache_entry' does not
  need to contain inline cache for method invocation.
  Other information will be added to this data structure.
* vm_core.h (rb_iseq_t): add `callinfo_entries' and `callinfo_size'
  members to `rb_iseq_t'.
* insns.def, compile.c: Use CALL_INFO instead of IC.
* tool/instruction.rb: support CALL_INFO as operand type.
* vm_insnhelper.c, vm_insnhelper.h: ditto.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37121 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ko1 2012-10-09 05:33:54 +00:00
parent 4be0c562a4
commit 7ea3edc409
7 changed files with 107 additions and 51 deletions

View file

@ -1,3 +1,20 @@
Tue Oct 9 14:28:18 2012 Koichi Sasada <ko1@atdot.net>
* vm_core.h (rb_call_info_t): add new type `rb_call_inf_t'.
This data structure contains information including inline method
cache. After that, `struct iseq_inline_cache_entry' does not
need to contain inline cache for method invocation.
Other information will be added to this data structure.
* vm_core.h (rb_iseq_t): add `callinfo_entries' and `callinfo_size'
members to `rb_iseq_t'.
* insns.def, compile.c: Use CALL_INFO instead of IC.
* tool/instruction.rb: support CALL_INFO as operand type.
* vm_insnhelper.c, vm_insnhelper.h: ditto.
Sun Oct 7 23:54:33 2012 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org> Sun Oct 7 23:54:33 2012 CHIKANAGA Tomoyuki <nagachika@ruby-lang.org>
* ext/zlib/zlib.c (zstream_run_func): don't call inflate() when * ext/zlib/zlib.c (zstream_run_func): don't call inflate() when

View file

@ -946,7 +946,7 @@ new_insn_send(rb_iseq_t *iseq, int line_no,
operands[1] = argc; operands[1] = argc;
operands[2] = block; operands[2] = block;
operands[3] = flag; operands[3] = flag;
operands[4] = INT2FIX(iseq->ic_size++); operands[4] = INT2FIX(iseq->callinfo_size++);
iobj = new_insn_core(iseq, line_no, BIN(send), 5, operands); iobj = new_insn_core(iseq, line_no, BIN(send), 5, operands);
return iobj; return iobj;
} }
@ -1398,6 +1398,8 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
line_info_table = ALLOC_N(struct iseq_line_info_entry, k); line_info_table = ALLOC_N(struct iseq_line_info_entry, k);
iseq->ic_entries = ALLOC_N(struct iseq_inline_cache_entry, iseq->ic_size); iseq->ic_entries = ALLOC_N(struct iseq_inline_cache_entry, iseq->ic_size);
MEMZERO(iseq->ic_entries, struct iseq_inline_cache_entry, iseq->ic_size); MEMZERO(iseq->ic_entries, struct iseq_inline_cache_entry, iseq->ic_size);
iseq->callinfo_entries = ALLOC_N(rb_call_info_t, iseq->callinfo_size);
MEMZERO(iseq->callinfo_entries, rb_call_info_t, iseq->callinfo_size);
list = FIRST_ELEMENT(anchor); list = FIRST_ELEMENT(anchor);
k = pos = sp = 0; k = pos = sp = 0;
@ -1495,12 +1497,21 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
int ic_index = FIX2INT(operands[j]); int ic_index = FIX2INT(operands[j]);
IC ic = &iseq->ic_entries[ic_index]; IC ic = &iseq->ic_entries[ic_index];
if (UNLIKELY(ic_index >= iseq->ic_size)) { if (UNLIKELY(ic_index >= iseq->ic_size)) {
rb_bug("iseq_set_sequence: ic_index overflow: index: %d, size: %d", rb_bug("iseq_set_sequence: ic_index overflow: index: %d, size: %d", ic_index, iseq->ic_size);
ic_index, iseq->ic_size);
} }
generated_iseq[pos + 1 + j] = (VALUE)ic; generated_iseq[pos + 1 + j] = (VALUE)ic;
break; break;
} }
case TS_CALLINFO: /* call info */
{
int ci_index = FIX2INT(operands[j]);
CALL_INFO ci = &iseq->callinfo_entries[ci_index];
if (UNLIKELY(ci_index >= iseq->callinfo_size)) {
rb_bug("iseq_set_sequence: ci_index overflow: index: %d, size: %d", ci_index, iseq->callinfo_size);
}
generated_iseq[pos + 1 + j] = (VALUE)ci;
break;
}
case TS_ID: /* ID */ case TS_ID: /* ID */
generated_iseq[pos + 1 + j] = SYM2ID(operands[j]); generated_iseq[pos + 1 + j] = SYM2ID(operands[j]);
break; break;
@ -1859,7 +1870,7 @@ insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
} }
for (i=0; i<iobj->operand_size; i++) { for (i=0; i<iobj->operand_size; i++) {
iobj->operands[i] = INT2FIX(iseq->ic_size++); iobj->operands[i] = INT2FIX(iseq->callinfo_size++);
} }
return COMPILE_OK; return COMPILE_OK;
@ -5234,9 +5245,12 @@ insn_data_to_s_detail(INSN *iobj)
(OPERAND_AT(iobj, j) & (~1)); (OPERAND_AT(iobj, j) & (~1));
rb_str_cat2(str, rb_id2name(entry->id)); rb_str_cat2(str, rb_id2name(entry->id));
} }
case TS_IC: /* method cache */ case TS_IC: /* inline cache */
rb_str_catf(str, "<ic:%d>", FIX2INT(OPERAND_AT(iobj, j))); rb_str_catf(str, "<ic:%d>", FIX2INT(OPERAND_AT(iobj, j)));
break; break;
case TS_CALLINFO: /* call info */
rb_str_catf(str, "<callinfo:%d>", FIX2INT(OPERAND_AT(iobj, j)));
break;
case TS_CDHASH: /* case/when condition cache */ case TS_CDHASH: /* case/when condition cache */
rb_str_cat2(str, "<ch>"); rb_str_cat2(str, "<ch>");
break; break;
@ -5500,9 +5514,15 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
break; break;
case TS_IC: case TS_IC:
argv[j] = op; argv[j] = op;
if (NUM2INT(op) >= iseq->ic_size) if (NUM2INT(op) >= iseq->ic_size) {
iseq->ic_size = NUM2INT(op) + 1; iseq->ic_size = NUM2INT(op) + 1;
}
break; break;
case TS_CALLINFO:
argv[j] = op;
if (NUM2INT(op) >= iseq->callinfo_size) {
iseq->callinfo_size = NUM2INT(op) + 1;
}
case TS_ID: case TS_ID:
argv[j] = rb_convert_type(op, T_SYMBOL, argv[j] = rb_convert_type(op, T_SYMBOL,
"Symbol", "to_sym"); "Symbol", "to_sym");

View file

@ -963,7 +963,7 @@ defineclass
*/ */
DEFINE_INSN DEFINE_INSN
send send
(ID op_id, rb_num_t op_argc, ISEQ blockiseq, rb_num_t op_flag, IC ic) (ID op_id, rb_num_t op_argc, ISEQ blockiseq, rb_num_t op_flag, CALL_INFO ci)
(...) (...)
(VALUE val) // inc += - (int)(op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0)); (VALUE val) // inc += - (int)(op_argc + ((op_flag & VM_CALL_ARGS_BLOCKARG_BIT) ? 1 : 0));
{ {
@ -978,7 +978,7 @@ send
/* get receiver */ /* get receiver */
recv = TOPN(num); recv = TOPN(num);
klass = CLASS_OF(recv); klass = CLASS_OF(recv);
me = vm_method_search(id, klass, ic, &defined_class); me = vm_method_search(id, klass, ci, &defined_class);
CALL_METHOD(num, blockptr, flag, id, me, recv, defined_class); CALL_METHOD(num, blockptr, flag, id, me, recv, defined_class);
} }
@ -1286,7 +1286,7 @@ opt_case_dispatch
*/ */
DEFINE_INSN DEFINE_INSN
opt_plus opt_plus
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
@ -1349,7 +1349,7 @@ opt_plus
*/ */
DEFINE_INSN DEFINE_INSN
opt_minus opt_minus
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
@ -1397,7 +1397,7 @@ opt_minus
*/ */
DEFINE_INSN DEFINE_INSN
opt_mult opt_mult
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
@ -1450,7 +1450,7 @@ opt_mult
*/ */
DEFINE_INSN DEFINE_INSN
opt_div opt_div
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
@ -1513,7 +1513,7 @@ opt_div
*/ */
DEFINE_INSN DEFINE_INSN
opt_mod opt_mod
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
@ -1577,11 +1577,11 @@ opt_mod
*/ */
DEFINE_INSN DEFINE_INSN
opt_eq opt_eq
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
val = opt_eq_func(recv, obj, ic); val = opt_eq_func(recv, obj, ci);
if (val == Qundef) { if (val == Qundef) {
/* other */ /* other */
@ -1598,16 +1598,16 @@ opt_eq
*/ */
DEFINE_INSN DEFINE_INSN
opt_neq opt_neq
(IC ic, IC ic_eq) (CALL_INFO ci, CALL_INFO ci_eq)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2); extern VALUE rb_obj_not_equal(VALUE obj1, VALUE obj2);
const rb_method_entry_t *me = vm_method_search(idNeq, CLASS_OF(recv), ic, 0); const rb_method_entry_t *me = vm_method_search(idNeq, CLASS_OF(recv), ci, 0);
val = Qundef; val = Qundef;
if (check_cfunc(me, rb_obj_not_equal)) { if (check_cfunc(me, rb_obj_not_equal)) {
val = opt_eq_func(recv, obj, ic_eq); val = opt_eq_func(recv, obj, ci_eq);
if (val != Qundef) { if (val != Qundef) {
val = RTEST(val) ? Qfalse : Qtrue; val = RTEST(val) ? Qfalse : Qtrue;
@ -1629,7 +1629,7 @@ opt_neq
*/ */
DEFINE_INSN DEFINE_INSN
opt_lt opt_lt
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
@ -1673,7 +1673,7 @@ opt_lt
*/ */
DEFINE_INSN DEFINE_INSN
opt_le opt_le
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
@ -1708,7 +1708,7 @@ opt_le
*/ */
DEFINE_INSN DEFINE_INSN
opt_gt opt_gt
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
@ -1752,7 +1752,7 @@ opt_gt
*/ */
DEFINE_INSN DEFINE_INSN
opt_ge opt_ge
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
@ -1786,7 +1786,7 @@ opt_ge
*/ */
DEFINE_INSN DEFINE_INSN
opt_ltlt opt_ltlt
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
@ -1818,7 +1818,7 @@ opt_ltlt
*/ */
DEFINE_INSN DEFINE_INSN
opt_aref opt_aref
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj) (VALUE recv, VALUE obj)
(VALUE val) (VALUE val)
{ {
@ -1848,7 +1848,7 @@ opt_aref
*/ */
DEFINE_INSN DEFINE_INSN
opt_aset opt_aset
(IC ic) (CALL_INFO ci)
(VALUE recv, VALUE obj, VALUE set) (VALUE recv, VALUE obj, VALUE set)
(VALUE val) (VALUE val)
{ {
@ -1881,7 +1881,7 @@ opt_aset
*/ */
DEFINE_INSN DEFINE_INSN
opt_length opt_length
(IC ic) (CALL_INFO ci)
(VALUE recv) (VALUE recv)
(VALUE val) (VALUE val)
{ {
@ -1916,7 +1916,7 @@ opt_length
*/ */
DEFINE_INSN DEFINE_INSN
opt_size opt_size
(IC ic) (CALL_INFO ci)
(VALUE recv) (VALUE recv)
(VALUE val) (VALUE val)
{ {
@ -1951,7 +1951,7 @@ opt_size
*/ */
DEFINE_INSN DEFINE_INSN
opt_empty_p opt_empty_p
(IC ic) (CALL_INFO ci)
(VALUE recv) (VALUE recv)
(VALUE val) (VALUE val)
{ {
@ -1989,7 +1989,7 @@ opt_empty_p
*/ */
DEFINE_INSN DEFINE_INSN
opt_succ opt_succ
(IC ic) (CALL_INFO ci)
(VALUE recv) (VALUE recv)
(VALUE val) (VALUE val)
{ {
@ -2036,12 +2036,12 @@ opt_succ
*/ */
DEFINE_INSN DEFINE_INSN
opt_not opt_not
(IC ic) (CALL_INFO ci)
(VALUE recv) (VALUE recv)
(VALUE val) (VALUE val)
{ {
extern VALUE rb_obj_not(VALUE obj); extern VALUE rb_obj_not(VALUE obj);
const rb_method_entry_t *me = vm_method_search(idNot, CLASS_OF(recv), ic, 0); const rb_method_entry_t *me = vm_method_search(idNot, CLASS_OF(recv), ci, 0);
if (check_cfunc(me, rb_obj_not)) { if (check_cfunc(me, rb_obj_not)) {
val = RTEST(recv) ? Qfalse : Qtrue; val = RTEST(recv) ? Qfalse : Qtrue;

View file

@ -706,10 +706,13 @@ class RubyVM
break break
end end
# skip make operands when body has no reference to this operand
# TODO: really needed?
re = /\b#{var}\b/n re = /\b#{var}\b/n
if re =~ insn.body or re =~ insn.sp_inc or insn.rets.any?{|t, v| re =~ v} or re =~ 'ic' if re =~ insn.body or re =~ insn.sp_inc or insn.rets.any?{|t, v| re =~ v} or re =~ 'ic' or re =~ 'ci'
ops << " #{type} #{var} = (#{type})GET_OPERAND(#{i+1});" ops << " #{type} #{var} = (#{type})GET_OPERAND(#{i+1});"
end end
n += 1 n += 1
} }
@opn = n @opn = n
@ -938,6 +941,8 @@ class RubyVM
"TS_GENTRY" "TS_GENTRY"
when /^IC/ when /^IC/
"TS_IC" "TS_IC"
when /^CALL_INFO/
"TS_CALLINFO"
when /^\.\.\./ when /^\.\.\./
"TS_VARIABLE" "TS_VARIABLE"
when /^CDHASH/ when /^CDHASH/
@ -958,7 +963,8 @@ class RubyVM
'TS_VALUE' => 'V', 'TS_VALUE' => 'V',
'TS_ID' => 'I', 'TS_ID' => 'I',
'TS_GENTRY' => 'G', 'TS_GENTRY' => 'G',
'TS_IC' => 'C', 'TS_IC' => 'K',
'TS_CALLINFO' => 'C',
'TS_CDHASH' => 'H', 'TS_CDHASH' => 'H',
'TS_ISEQ' => 'S', 'TS_ISEQ' => 'S',
'TS_VARIABLE' => '.', 'TS_VARIABLE' => '.',

View file

@ -134,14 +134,21 @@ struct iseq_inline_cache_entry {
VALUE ic_class; VALUE ic_class;
union { union {
VALUE value; VALUE value;
rb_method_entry_t *method;
long index; long index;
} ic_value; } ic_value;
union {
VALUE defined_class;
} ic_value2;
}; };
/* rb_call_info_t contains calling information including inline cache */
typedef struct rb_call_info_struct {
/* inline cache: keys */
VALUE ic_vmstat;
VALUE ic_class;
/* inline cache: values */
rb_method_entry_t *method;
VALUE defined_class;
} rb_call_info_t;
#if 1 #if 1
#define GetCoreDataFromValue(obj, type, ptr) do { \ #define GetCoreDataFromValue(obj, type, ptr) do { \
(ptr) = (type*)DATA_PTR(obj); \ (ptr) = (type*)DATA_PTR(obj); \
@ -201,6 +208,9 @@ struct rb_iseq_struct {
struct iseq_inline_cache_entry *ic_entries; struct iseq_inline_cache_entry *ic_entries;
int ic_size; int ic_size;
rb_call_info_t *callinfo_entries;
int callinfo_size;
/** /**
* argument information * argument information
* *
@ -661,6 +671,7 @@ enum vm_special_object_type {
/* inline cache */ /* inline cache */
typedef struct iseq_inline_cache_entry *IC; typedef struct iseq_inline_cache_entry *IC;
typedef rb_call_info_t *CALL_INFO;
void rb_vm_change_state(void); void rb_vm_change_state(void);

View file

@ -1430,25 +1430,27 @@ vm_setivar(VALUE obj, ID id, VALUE val, IC ic)
} }
static inline const rb_method_entry_t * static inline const rb_method_entry_t *
vm_method_search(VALUE id, VALUE klass, IC ic, VALUE *defined_class_ptr) vm_method_search(VALUE id, VALUE klass, CALL_INFO ci, VALUE *defined_class_ptr)
{ {
rb_method_entry_t *me; rb_method_entry_t *me;
#if OPT_INLINE_METHOD_CACHE #if OPT_INLINE_METHOD_CACHE
if (LIKELY(klass == ic->ic_class && if (LIKELY(klass == ci->ic_class &&
GET_VM_STATE_VERSION() == ic->ic_vmstat)) { GET_VM_STATE_VERSION() == ci->ic_vmstat)) {
me = ic->ic_value.method; me = ci->method;
if (defined_class_ptr) if (defined_class_ptr) {
*defined_class_ptr = ic->ic_value2.defined_class; *defined_class_ptr = ci->defined_class;
}
} }
else { else {
VALUE defined_class; VALUE defined_class;
me = rb_method_entry(klass, id, &defined_class); me = rb_method_entry(klass, id, &defined_class);
if (defined_class_ptr) if (defined_class_ptr) {
*defined_class_ptr = defined_class; *defined_class_ptr = defined_class;
ic->ic_class = klass; }
ic->ic_value.method = me; ci->ic_class = klass;
ic->ic_value2.defined_class = defined_class; ci->method = me;
ic->ic_vmstat = GET_VM_STATE_VERSION(); ci->defined_class = defined_class;
ci->ic_vmstat = GET_VM_STATE_VERSION();
} }
#else #else
me = rb_method_entry(klass, id, defined_class_ptr); me = rb_method_entry(klass, id, defined_class_ptr);
@ -1773,7 +1775,7 @@ static
inline inline
#endif #endif
VALUE VALUE
opt_eq_func(VALUE recv, VALUE obj, IC ic) opt_eq_func(VALUE recv, VALUE obj, CALL_INFO ci)
{ {
if (FIXNUM_2_P(recv, obj) && if (FIXNUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_EQ, FIXNUM_REDEFINED_OP_FLAG)) { BASIC_OP_UNREDEFINED_P(BOP_EQ, FIXNUM_REDEFINED_OP_FLAG)) {
@ -1803,7 +1805,7 @@ opt_eq_func(VALUE recv, VALUE obj, IC ic)
} }
{ {
const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ic, 0); const rb_method_entry_t *me = vm_method_search(idEq, CLASS_OF(recv), ci, 0);
if (check_cfunc(me, rb_obj_equal)) { if (check_cfunc(me, rb_obj_equal)) {
return recv == obj ? Qtrue : Qfalse; return recv == obj ? Qtrue : Qfalse;

View file

@ -239,7 +239,7 @@ enum vm_regan_acttype {
#define CALL_SIMPLE_METHOD(num, id, recv) do { \ #define CALL_SIMPLE_METHOD(num, id, recv) do { \
VALUE klass = CLASS_OF(recv), defined_class; \ VALUE klass = CLASS_OF(recv), defined_class; \
const rb_method_entry_t *me = vm_method_search((id), klass, ic, &defined_class); \ const rb_method_entry_t *me = vm_method_search((id), klass, ci, &defined_class); \
CALL_METHOD((num), 0, 0, (id), me, (recv), defined_class); \ CALL_METHOD((num), 0, 0, (id), me, (recv), defined_class); \
} while (0) } while (0)