summaryrefslogtreecommitdiff
path: root/compile.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-10-22 06:30:12 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-10-22 06:30:12 +0000
commita356fe1c3550892902103f66928426ac8279e072 (patch)
treebee931e36267315487d45d5776ae8f4a568feddf /compile.c
parent5a599dde0c43b62ff32c8a0c36a05a758a309818 (diff)
Safe navigation operator
* compile.c (iseq_peephole_optimize): peephole optimization for branchnil jumps. * compile.c (iseq_compile_each): generate save navigation operator code. * insns.def (branchnil): new opcode to pop the tos and branch if it is nil. * parse.y (NEW_QCALL, call_op, parser_yylex): parse token '.?'. [Feature #11537] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52214 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'compile.c')
-rw-r--r--compile.c53
1 files changed, 50 insertions, 3 deletions
diff --git a/compile.c b/compile.c
index 2527977..b28861e 100644
--- a/compile.c
+++ b/compile.c
@@ -1942,6 +1942,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
}
if (iobj->insn_id == BIN(branchif) ||
+ iobj->insn_id == BIN(branchnil) ||
iobj->insn_id == BIN(branchunless)) {
/*
* if L1
@@ -1955,6 +1956,31 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
if (nobj->insn_id == BIN(jump)) {
OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
}
+
+ if (nobj->insn_id == BIN(dup)) {
+ /*
+ * dup
+ * if L1
+ * ...
+ * L1:
+ * dup
+ * if L2
+ * =>
+ * dup
+ * if L2
+ * ...
+ * L1:
+ * dup
+ * if L2
+ */
+ INSN *pobj = (INSN *)iobj->link.prev;
+ nobj = (INSN *)nobj->link.next;
+ /* basic blocks, with no labels in the middle */
+ if ((pobj && pobj->insn_id == BIN(dup)) &&
+ (nobj && nobj->insn_id == iobj->insn_id)) {
+ OPERAND_AT(iobj, 0) = OPERAND_AT(nobj, 0);
+ }
+ }
}
if (do_tailcallopt && iobj->insn_id == BIN(leave)) {
@@ -4319,6 +4345,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
VALUE asgnflag;
LABEL *lfin = NEW_LABEL(line);
LABEL *lcfin = NEW_LABEL(line);
+ LABEL *lskip = 0;
/*
class C; attr_accessor :c; end
r = C.new
@@ -4362,6 +4389,11 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
*/
asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
+ if (node->nd_next->nd_aid) {
+ lskip = NEW_LABEL(line);
+ ADD_INSN(ret, line, dup);
+ ADD_INSNL(ret, line, branchnil, lskip);
+ }
ADD_INSN(ret, line, dup);
ADD_SEND(ret, line, vid, INT2FIX(0));
@@ -4385,6 +4417,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
ADD_LABEL(ret, lfin);
ADD_INSN(ret, line, pop);
+ if (lskip) {
+ ADD_LABEL(ret, lskip);
+ }
if (poped) {
/* we can apply more optimize */
ADD_INSN(ret, line, pop);
@@ -4392,14 +4427,16 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
}
else {
COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value);
- ADD_SEND(ret, line, node->nd_next->nd_mid,
- INT2FIX(1));
+ ADD_SEND(ret, line, atype, INT2FIX(1));
if (!poped) {
ADD_INSN(ret, line, swap);
ADD_INSN1(ret, line, topn, INT2FIX(1));
}
ADD_SEND_WITH_FLAG(ret, line, aid, INT2FIX(1), INT2FIX(asgnflag));
ADD_INSN(ret, line, pop);
+ if (lskip) {
+ ADD_LABEL(ret, lskip);
+ }
}
break;
}
@@ -4548,6 +4585,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
}
break;
}
+ case NODE_QCALL:
case NODE_FCALL:
case NODE_VCALL:{ /* VCALL: variable or call */
/*
@@ -4557,6 +4595,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
*/
DECL_ANCHOR(recv);
DECL_ANCHOR(args);
+ LABEL *lskip = 0;
ID mid = node->nd_mid;
VALUE argc;
unsigned int flag = 0;
@@ -4631,8 +4670,13 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
}
#endif
/* receiver */
- if (type == NODE_CALL) {
+ if (type == NODE_CALL || type == NODE_QCALL) {
COMPILE(recv, "recv", node->nd_recv);
+ if (type == NODE_QCALL) {
+ lskip = NEW_LABEL(line);
+ ADD_INSN(recv, line, dup);
+ ADD_INSNL(recv, line, branchnil, lskip);
+ }
}
else if (type == NODE_FCALL || type == NODE_VCALL) {
ADD_CALL_RECEIVER(recv, line);
@@ -4662,6 +4706,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
ADD_SEND_R(ret, line, mid, argc, parent_block, INT2FIX(flag), keywords);
+ if (lskip) {
+ ADD_LABEL(ret, lskip);
+ }
if (poped) {
ADD_INSN(ret, line, pop);
}