8000 * vm_core.h: split rb_call_info_t into several structs. · documenting-ruby/ruby@d5ec9ec · GitHub
[go: up one dir, main page]

Skip to content

Commit d5ec9ec

Browse files
committed
* vm_core.h: split rb_call_info_t into several structs.
* rb_call_info (ci) has compiled fixed information. * if ci->flag & VM_CALL_KWARG, then rb_call_info is also rb_call_info_with_kwarg. This technique reduce one word for major rb_call_info data. * rb_calling_info has temporary data (argc, blockptr, recv). for each method dispatch. This data is allocated only on machine stack. * rb_call_cache is for inline method cache. Before this patch, only rb_call_info_t data is passed. After this patch, above three structs are passed. This patch improves: * data locarity (rb_call_info is now read-only data). * reduce memory consumption (rb_call_info_with_kwarg, rb_calling_info). * compile.c: use above data. * insns.def: ditto. * iseq.c: ditto. * vm_args.c: ditto. * vm_eval.c: ditto. * vm_insnhelper.c: ditto. * vm_insnhelper.h: ditto. * iseq.h: add iseq_compile_data::ci_index and iseq_compile_data::ci_kw_indx. * tool/instruction.rb: introduce TS_CALLCACHE operand type. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51903 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
1 parent 19499aa commit d5ec9ec

File tree

12 files changed

+681
-522
lines changed

12 files changed

+681
-522
lines changed

ChangeLog

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,42 @@
1+
Sun Sep 20 02:46:34 2015 Koichi Sasada <ko1@atdot.net>
2+
3+
* vm_core.h: split rb_call_info_t into several structs.
4+
* rb_call_info (ci) has compiled fixed information.
5+
* if ci->flag & VM_CALL_KWARG, then rb_call_info is
6+
also rb_call_info_with_kwarg. This technique reduce one word
7+
for major rb_call_info data.
8+
* rb_calling_info has temporary data (argc, blockptr, recv).
9+
for each method dispatch. This data is allocated only on
10+
machine stack.
11+
* rb_call_cache is for inline method cache.
12+
13+
Before this patch, only rb_call_info_t data is passed.
14+
After this patch, above three structs are passed.
15+
16+
This patch improves:
17+
* data locarity (rb_call_info is now read-only data).
18+
* reduce memory consumption (rb_call_info_with_kwarg,
19+
rb_calling_info).
20+
21+
* compile.c: use above data.
22+
23+
* insns.def: ditto.
24+
25+
* iseq.c: ditto.
26+
27+
* vm_args.c: ditto.
28+
29+
* vm_eval.c: ditto.
30+
31+
* vm_insnhelper.c: ditto.
32+
33+
* vm_insnhelper.h: ditto.
34+
35+
* iseq.h: add iseq_compile_data::ci_index and
36+
iseq_compile_data::ci_kw_indx.
37+
38+
* tool/instruction.rb: introduce TS_CALLCACHE operand type.
39+
140
Sun Sep 20 02:18:10 2015 Tanaka Akira <akr@fsij.org>
241

342
* test/lib/envutil.rb: mkfifo command based File.mkfifo method

compile.c

Lines changed: 82 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -944,45 +944,42 @@ new_insn_body(rb_iseq_t *iseq, int line_no, enum ruby_vminsn_type insn_id, int a
944944
return new_insn_core(iseq, line_no, insn_id, argc, operands);
945945
}
946946

947-
static rb_call_info_t *
948-
new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, rb_call_info_kw_arg_t *kw_arg, int has_blockiseq)
947+
static struct rb_call_info *
948+
new_callinfo(rb_iseq_t *iseq, ID mid, int argc, unsigned int flag, struct rb_call_info_kw_arg *kw_arg, int has_blockiseq)
949949
{
950-
rb_call_info_t *ci = (rb_call_info_t *)compile_data_alloc(iseq, sizeof(rb_call_info_t));
950+
size_t size = kw_arg != NULL ? sizeof(struct rb_call_info_with_kwarg) : sizeof(struct rb_call_info);
951+
struct rb_call_info *ci = (struct rb_call_info *)compile_data_alloc(iseq, size);
952+
struct rb_call_info_with_kwarg *ci_kw = (struct rb_call_info_with_kwarg *)ci;
951953

952954
ci->mid = mid;
953955
ci->flag = flag;
954956
ci->orig_argc = argc;
955-
ci->argc = argc;
956-
ci->kw_arg = kw_arg;
957957

958958
if (kw_arg) {
959-
ci->argc += kw_arg->keyword_len;
959+
ci->flag |= VM_CALL_KWARG;
960+
ci_kw->kw_arg = kw_arg;
960961
ci->orig_argc += kw_arg->keyword_len;
962+
iseq->body->ci_kw_size++;
963+
}
964+
else {
965+
iseq->body->ci_size++;
961966
}
962967

963968
if (!(ci->flag & (VM_CALL_ARGS_SPLAT | VM_CALL_ARGS_BLOCKARG)) &&
964-
ci->kw_arg == NULL && !has_blockiseq) {
969+
kw_arg == NULL && !has_blockiseq) {
965970
ci->flag |= VM_CALL_ARGS_SIMPLE;
966971
}
967-
968-
ci->method_state = 0;
969-
ci->class_serial = 0;
970-
ci->blockptr = 0;
971-
ci->recv = Qundef;
972-
ci->call = 0; /* TODO: should set default function? */
973-
974-
ci->aux.index = iseq->body->callinfo_size++;
975-
976972
return ci;
977973
}
978974

979975
static INSN *
980-
new_insn_send(rb_iseq_t *iseq, int line_no, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, rb_call_info_kw_arg_t *keywords)
976+
new_insn_send(rb_iseq_t *iseq, int line_no, ID id, VALUE argc, const rb_iseq_t *blockiseq, VALUE flag, struct rb_call_info_kw_arg *keywords)
981977
{
982-
VALUE *operands = (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * 2);
978+
VALUE *operands = (VALUE *)compile_data_alloc(iseq, sizeof(VALUE) * 3);
983979
operands[0] = (VALUE)new_callinfo(iseq, id, FIX2INT(argc), FIX2INT(flag), keywords, blockiseq != NULL);
984-
operands[1] = (VALUE)blockiseq;
985-
return new_insn_core(iseq, line_no, BIN(send), 2, operands);
980+
operands[1] = Qfalse; /* cache */
981+
operands[2] = (VALUE)blockiseq;
982+
return new_insn_core(iseq, line_no, BIN(send), 3, operands);
986983
}
987984

988985
static rb_iseq_t *
@@ -1497,8 +1494,11 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
14971494
generated_iseq = ALLOC_N(VALUE, code_index);
14981495
line_info_table = ALLOC_N(struct iseq_line_info_entry, insn_num);
14991496
iseq->body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, iseq->body->is_size);
1500-
iseq->body->callinfo_entries = ALLOC_N(rb_call_info_t, iseq->body->callinfo_size);
1501-
/* MEMZERO(iseq->body->callinfo_entries, rb_call_info_t, iseq->body->callinfo_size); */
1497+
iseq->body->ci_entries = (struct rb_call_info *)ruby_xmalloc(sizeof(struct rb_call_info) * iseq->body->ci_size +
1498+
sizeof(struct rb_call_info_with_kwarg) * iseq->body->ci_kw_size);
1499+
iseq->body->cc_entries = ZALLOC_N(struct rb_call_cache, iseq->body->ci_size + iseq->body->ci_kw_size);
1500+
1501+
iseq->compile_data->ci_index = iseq->compile_data->ci_kw_index = 0;
15021502

15031503
list = FIRST_ELEMENT(anchor);
15041504
line_info_index = code_index = sp = 0;
@@ -1599,16 +1599,31 @@ iseq_set_sequence(rb_iseq_t *iseq, LINK_ANCHOR *anchor)
15991599
}
16001600
case TS_CALLINFO: /* call info */
16011601
{
1602-
rb_call_info_t *base_ci = (rb_call_info_t *)operands[j];
1603-
rb_call_info_t *ci = &iseq->body->callinfo_entries[base_ci->aux.index];
1604-
*ci = *base_ci;
1605-
1606-
if (UNLIKELY(base_ci->aux.index >= iseq->body->callinfo_size)) {
1607-
rb_bug("iseq_set_sequence: ci_index overflow: index: %d, size: %d", base_ci->argc, iseq->body->callinfo_size);
1602+
struct rb_call_info *base_ci = (struct rb_call_info *)operands[j];
1603+
struct rb_call_info *ci;
1604+
1605+
if (base_ci->flag & VM_CALL_KWARG) {
1606+
struct rb_call_info_with_kwarg *ci_kw_entries = (struct rb_call_info_with_kwarg *)&iseq->body->ci_entries[iseq->body->ci_size];
1607+
struct rb_call_info_with_kwarg *ci_kw = &ci_kw_entries[iseq->compile_data->ci_kw_index++];
1608+
*ci_kw = *((struct rb_call_info_with_kwarg *)base_ci);
1609+
ci = (struct rb_call_info *)ci_kw;
1610+
assert(iseq->compile_data->ci_kw_index <= iseq->body->ci_kw_size);
1611+
}
1612+
else {
1613+
ci = &iseq->body->ci_entries[iseq->compile_data->ci_index++];
1614+
*ci = *base_ci;
1615+
assert(iseq->compile_data->ci_index <= iseq->body->ci_size);
16081616
}
1617+
16091618
generated_iseq[code_index + 1 + j] = (VALUE)ci;
16101619
break;
16111620
}
1621+
case TS_CALLCACHE:
1622+
{
1623+
struct rb_call_cache *cc = &iseq->body->cc_entries[iseq->compile_data->ci_index + iseq->compile_data->ci_kw_index - 1];
1624+
generated_iseq[code_index + 1 + j] = (VALUE)cc;
1625+
break;
1626+
}
16121627
case TS_ID: /* ID */
16131628
generated_iseq[code_index + 1 + j] = SYM2ID(operands[j]);
16141629
break;
@@ -1948,7 +1963,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
19481963
enum ruby_vminsn_type previ = piobj->insn_id;
19491964

19501965
if (previ == BIN(send) || previ == BIN(opt_send_without_block) || previ == BIN(invokesuper)) {
1951-
rb_call_info_t *ci = (rb_call_info_t *)piobj->operands[0];
1966+
struct rb_call_info *ci = (struct rb_call_info *)piobj->operands[0];
19521967
rb_iseq_t *blockiseq = (rb_iseq_t *)piobj->operands[1];
19531968
if (blockiseq == 0) {
19541969
ci->flag |= VM_CALL_TAILCALL;
@@ -1966,9 +1981,12 @@ insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
19661981

19671982
if (insn_id == BIN(opt_neq)) {
19681983
VALUE *old_operands = iobj->operands;
1984+
iobj->operand_size = 4;
19691985
iobj->operands = (VALUE *)compile_data_alloc(iseq, iobj->operand_size * sizeof(VALUE));
19701986
iobj->operands[0] = old_operands[0];
1971-
iobj->operands[1] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
1987+
iobj->operands[1] = Qfalse; /* CALL_CACHE */
1988+
iobj->operands[2] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
1989+
iobj->operands[3] = Qfalse; /* CALL_CACHE */
19721990
}
19731991

19741992
return COMPILE_OK;
@@ -1978,8 +1996,8 @@ static int
19781996
iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
19791997
{
19801998
if (iobj->insn_id == BIN(send)) {
1981-
rb_call_info_t *ci = (rb_call_info_t *)OPERAND_AT(iobj, 0);
1982-
const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
1999+
struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(iobj, 0);
2000+
const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 2);
19832001

19842002
#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
19852003
if (ci->flag & VM_CALL_ARGS_SIMPLE) {
@@ -2020,7 +2038,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
20202038

20212039
if ((ci->flag & VM_CALL_ARGS_BLOCKARG) == 0 && blockiseq == NULL) {
20222040
iobj->insn_id = BIN(opt_send_without_block);
2023-
iobj->operand_size = 1;
2041+
iobj->operand_size = insn_len(iobj->insn_id) - 1;
20242042
}
20252043
}
20262044
#undef SP_INSN
@@ -2402,7 +2420,7 @@ compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * cond,
24022420
}
24032421

24042422
static int
2405-
compile_array_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE * const root_node, rb_call_info_kw_arg_t ** const kw_arg_ptr)
2423+
compile_array_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE * const root_node, struct rb_call_info_kw_arg ** const kw_arg_ptr)
24062424
{
24072425
if (kw_arg_ptr == NULL) return FALSE;
24082426

@@ -2427,7 +2445,7 @@ compile_array_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE * const
24272445
node = root_node->nd_head;
24282446
{
24292447
int len = (int)node->nd_alen / 2;
2430-
rb_call_info_kw_arg_t *kw_arg = (rb_call_info_kw_arg_t *)ruby_xmalloc(sizeof(rb_call_info_kw_arg_t) + sizeof(VALUE) * (len - 1));
2448+
struct rb_call_info_kw_arg *kw_arg = (struct rb_call_info_kw_arg *)ruby_xmalloc(sizeof(struct rb_call_info_kw_arg) + sizeof(VALUE) * (len - 1));
24312449
VALUE *keywords = kw_arg->keywords;
24322450
int i = 0;
24332451
kw_arg->keyword_len = len;
@@ -2455,7 +2473,7 @@ enum compile_array_type_t {
24552473

24562474
static int
24572475
compile_array_(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE* node_root,
2458-
enum compile_array_type_t type, rb_call_info_kw_arg_t **keywords_ptr, int poped)
2476+
enum compile_array_type_t type, struct rb_call_info_kw_arg **keywords_ptr, int poped)
24592477
{
24602478
NODE *node = node_root;
24612479
int line = (int)nd_line(node);
@@ -2680,15 +2698,15 @@ compile_massign_lhs(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *node)
26802698
switch (nd_type(node)) {
26812699
case NODE_ATTRASGN: {
26822700
INSN *iobj;
2683-
rb_call_info_t *ci;
2701+
struct rb_call_info *ci;
26842702
VALUE dupidx;
26852703

26862704
COMPILE_POPED(ret, "masgn lhs (NODE_ATTRASGN)", node);
26872705

26882706
POP_ELEMENT(ret); /* pop pop insn */
26892707
iobj = (INSN *)POP_ELEMENT(ret); /* pop send insn */
2690-
ci = (rb_call_info_t *)iobj->operands[0];
2691-
ci->orig_argc += 1; ci->argc = ci->orig_argc;
2708+
ci = (struct rb_call_info *)iobj->operands[0];
2709+
ci->orig_argc += 1;
26922710
dupidx = INT2FIX(ci->orig_argc);
26932711

26942712
ADD_INSN1(ret, nd_line(node), topn, dupidx);
@@ -3228,7 +3246,7 @@ add_ensure_iseq(LINK_ANCHOR *ret, rb_iseq_t *iseq, int is_return)
32283246
}
32293247

32303248
static VALUE
3231-
setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, unsigned int *flag, rb_call_info_kw_arg_t **keywords)
3249+
setup_args(rb_iseq_t *iseq, LINK_ANCHOR *args, NODE *argn, unsigned int *flag, struct rb_call_info_kw_arg **keywords)
32323250
{
32333251
VALUE argc = INT2FIX(0);
32343252
int nsplat = 0;
@@ -4504,8 +4522,10 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
45044522
VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
45054523
node->nd_args->nd_head->nd_lit = str;
45064524
COMPILE(ret, "recv", node->nd_recv);
4507-
ADD_INSN2(ret, line, opt_aref_with,
4508-
new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE), str);
4525+
ADD_INSN3(ret, line, opt_aref_with,
4526+
new_callinfo(iseq, idAREF, 1, 0, NULL, FALSE),
4527+
Qnil, /* CALL_CACHE */
4528+
str);
45094529
if (poped) {
45104530
ADD_INSN(ret, line, pop);
45114531
}
@@ -4523,7 +4543,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
45234543
ID mid = node->nd_mid;
45244544
VALUE argc;
45254545
unsigned int flag = 0;
4526-
rb_call_info_kw_arg_t *keywords = NULL;
4546+
struct rb_call_info_kw_arg *keywords = NULL;
45274547
const rb_iseq_t *parent_block = iseq->compile_data->current_block;
45284548
iseq->compile_data->current_block = NULL;
45294549

@@ -4635,7 +4655,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
46354655
DECL_ANCHOR(args);
46364656
int argc;
46374657
unsigned int flag = 0;
4638-
rb_call_info_kw_arg_t *keywords = NULL;
4658+
struct rb_call_info_kw_arg *keywords = NULL;
46394659
const rb_iseq_t *parent_block = iseq->compile_data->current_block;
46404660

46414661
INIT_ANCHOR(args);
@@ -4742,8 +4762,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
47424762
/* dummy receiver */
47434763
ADD_INSN1(ret, line, putobject, nd_type(node) == NODE_ZSUPER ? Qfalse : Qtrue);
47444764
ADD_SEQ(ret, args);
4745-
ADD_INSN2(ret, line, invokesuper,
4765+
ADD_INSN3(ret, line, invokesuper,
47464766
new_callinfo(iseq, 0, argc, flag | VM_CALL_SUPER | VM_CALL_FCALL, keywords, parent_block != NULL),
4767+
Qnil, /* CALL_CACHE */
47474768
parent_block);
47484769

47494770
if (poped) {
@@ -4839,7 +4860,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
48394860
DECL_ANCHOR(args);
48404861
VALUE argc;
48414862
unsigned int flag = 0;
4842-
rb_call_info_kw_arg_t *keywords = NULL;
4863+
struct rb_call_info_kw_arg *keywords = NULL;
48434864

48444865
INIT_ANCHOR(args);
48454866
if (iseq->body->type == ISEQ_TYPE_TOP) {
@@ -4982,7 +5003,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
49825003
else {
49835004
ADD_SEQ(ret, recv);
49845005
ADD_SEQ(ret, val);
4985-
ADD_INSN1(ret, line, opt_regexpmatch2, new_callinfo(iseq, idEqTilde, 1, 0, NULL, FALSE));
5006+
ADD_INSN2(ret, line, opt_regexpmatch2, new_callinfo(iseq, idEqTilde, 1, 0, NULL, FALSE), Qnil);
49865007
}
49875008
}
49885009
else {
@@ -5516,8 +5537,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
55165537
ADD_INSN(ret, line, swap);
55175538
ADD_INSN1(ret, line, topn, INT2FIX(1));
55185539
}
5519-
ADD_INSN2(ret, line, opt_aset_with,
5520-
new_callinfo(iseq, idASET, 2, 0, NULL, FALSE), str);
5540+
ADD_INSN3(ret, line, opt_aset_with,
5541+
new_callinfo(iseq, idASET, 2, 0, NULL, FALSE),
5542+
Qnil/* CALL_CACHE */, str);
55215543
ADD_INSN(ret, line, pop);
55225544
break;
55235545
}
@@ -5687,13 +5709,17 @@ insn_data_to_s_detail(INSN *iobj)
56875709
break;
56885710
case TS_CALLINFO: /* call info */
56895711
{
5690-
rb_call_info_t *ci = (rb_call_info_t *)OPERAND_AT(iobj, j);
5712+
struct rb_call_info *ci = (struct rb_call_info *)OPERAND_AT(iobj, j);
56915713
rb_str_cat2(str, "<callinfo:");
5692-
if (ci->mid)
5693-
rb_str_catf(str, "%"PRIsVALUE, rb_id2str(ci->mid));
5714+
if (ci->mid) rb_str_catf(str, "%"PRIsVALUE, rb_id2str(ci->mid));
56945715
rb_str_catf(str, ", %d>", ci->orig_argc);
56955716
break;
56965717
}
5718+
case TS_CALLCACHE: /* call cache */
5719+
{
5720+
rb_str_catf(str, "<call cache>");
5721+
break;
5722+
}
56975723
case TS_CDHASH: /* case/when condition cache */
56985724
rb_str_cat2(str, "<ch>");
56995725
break;
@@ -5911,7 +5937,7 @@ iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
59115937
ID mid = 0;
59125938
int orig_argc = 0;
59135939
unsigned int flag = 0;
5914-
rb_call_info_kw_arg_t *kw_arg = 0;
5940+
struct rb_call_info_kw_arg *kw_arg = 0;
59155941

59165942
if (!NIL_P(op)) {
59175943
VALUE vmid = rb_hash_aref(op, ID2SYM(rb_intern("mid")));
@@ -6030,6 +6056,9 @@ iseq_build_from_ary_body(rb_iseq_t *iseq, LINK_ANCHOR *anchor,
60306056
case TS_CALLINFO:
60316057
argv[j] = iseq_build_callinfo_from_hash(iseq, op);
60326058
break;
6059+
case TS_CALLCACHE:
6060+
argv[j] = Qfalse;
6061+
break;
60336062
case TS_ID:
60346063
argv[j] = rb_convert_type(op, T_SYMBOL,
60356064
"Symbol", "to_sym");

0 commit comments

Comments
 (0)
0