Project

General

Profile

Feature #10423 ยป opt_str_lit-v4.patch

normalperson (Eric Wong), 10/24/2014 03:25 AM

View differences:

benchmark/bm_vm2_array_delete_lit.rb
1
ary = []
2
i = 0
3
while i<6_000_000 # while loop 2
4
  i += 1
5
  ary.delete("foo")
6
end
benchmark/bm_vm2_array_include_lit.rb
1
ary = []
2
i = 0
3
while i<6_000_000 # while loop 2
4
  i += 1
5
  ary.include?("foo")
6
end
benchmark/bm_vm2_hash_aref_lit.rb
1
h = { "foo" => nil }
2
i = 0
3
while i<6_000_000 # while loop 2
4
  i += 1
5
  h["foo"]
6
end
benchmark/bm_vm2_hash_aset_lit.rb
1
h = {}
2
i = 0
3
while i<6_000_000 # while loop 2
4
  i += 1
5
  h["foo"] = nil
6
end
benchmark/bm_vm2_hash_delete_lit.rb
1
h = {}
2
i = 0
3
while i<6_000_000 # while loop 2
4
  i += 1
5
  h.delete("foo")
6
end
benchmark/bm_vm2_set_include_lit.rb
1
require 'set'
2
set = Set.new
3
i = 0
4
while i<6_000_000 # while loop 2
5
  i += 1
6
  set.include?("foo")
7
end
benchmark/bm_vm2_str_delete.rb
1
str = ''
2
i = 0
3
while i<6_000_000 # while loop 2
4
  i += 1
5
  str.delete("foo")
6
end
benchmark/bm_vm2_str_eq1.rb
1
i = 0
2
foo = "literal"
3
while i<6_000_000 # benchmark loop 2
4
  i += 1
5
  foo == "literal"
6
end
benchmark/bm_vm2_str_eq2.rb
1
i = 0
2
foo = "literal"
3
while i<6_000_000 # benchmark loop 2
4
  i += 1
5
  "literal" == foo
6
end
benchmark/bm_vm2_str_eqq1.rb
1
i = 0
2
foo = "literal"
3
while i<6_000_000 # benchmark loop 2
4
  i += 1
5
  foo === "literal"
6
end
benchmark/bm_vm2_str_eqq2.rb
1
i = 0
2
foo = "literal"
3
while i<6_000_000 # benchmark loop 2
4
  i += 1
5
  "literal" === foo
6
end
benchmark/bm_vm2_str_fmt.rb
1
i = 0
2
while i<6_000_000 # benchmark loop 2
3
  i += 1
4
  "%d" % i
5
end
benchmark/bm_vm2_str_gsub_bang_lit.rb
1
i = 0
2
str = ""
3
while i<6_000_000 # benchmark loop 2
4
  i += 1
5
  str.gsub!("nomatch", "")
6
end
benchmark/bm_vm2_str_gsub_bang_re.rb
1
i = 0
2
str = ""
3
while i<6_000_000 # benchmark loop 2
4
  i += 1
5
  str.gsub!(/a/, "")
6
end
benchmark/bm_vm2_str_gsub_re.rb
1
i = 0
2
str = ""
3
while i<6_000_000 # benchmark loop 2
4
  i += 1
5
  str.gsub(/a/, "")
6
end
benchmark/bm_vm2_str_plus1.rb
1
i = 0
2
foo = "a"
3
while i<6_000_000 # benchmark loop 2
4
  i += 1
5
  foo + "b"
6
end
benchmark/bm_vm2_str_plus2.rb
1
i = 0
2
foo = "a"
3
while i<6_000_000 # benchmark loop 2
4
  i += 1
5
  "b" + foo
6
end
benchmark/bm_vm2_str_tr_bang.rb
1
i = 0
2
str = "a"
3
while i<6_000_000 # benchmark loop 2
4
  i += 1
5
  str.tr!("a", "A")
6
  str.tr!("A", "a")
7
end
benchmark/bm_vm2_strcat.rb
1
i = 0
2
str = ""
3
while i<6_000_000 # benchmark loop 2
4
  i += 1
5
  str << "const"
6
  str.clear
7
end
common.mk
640 640
VM_CORE_H_INCLUDES = {$(VPATH)}vm_core.h {$(VPATH)}thread_$(THREAD_MODEL).h \
641 641
		     {$(VPATH)}node.h {$(VPATH)}method.h {$(VPATH)}ruby_atomic.h \
642 642
	             {$(VPATH)}vm_debug.h {$(VPATH)}id.h {$(VPATH)}thread_native.h \
643
	             $(CCAN_LIST_INCLUDES)
643
	             $(CCAN_LIST_INCLUDES) {$(VPATH)}opt_method.h
644 644

  
645 645
###
646 646

  
......
827 827
  $(VM_CORE_H_INCLUDES) {$(VPATH)}vm_method.c {$(VPATH)}vm_eval.c \
828 828
  {$(VPATH)}vm_insnhelper.c {$(VPATH)}vm_insnhelper.h {$(VPATH)}vm_exec.c \
829 829
  {$(VPATH)}vm_exec.h {$(VPATH)}insns.def {$(VPATH)}vmtc.inc \
830
  {$(VPATH)}vm.inc {$(VPATH)}insns.inc \
830
  {$(VPATH)}vm.inc {$(VPATH)}insns.inc {$(VPATH)}opt_method.inc \
831 831
  {$(VPATH)}internal.h {$(VPATH)}vm.h {$(VPATH)}constant.h \
832 832
  $(PROBES_H_INCLUDES) {$(VPATH)}probes_helper.h {$(VPATH)}vm_opts.h
833 833
vm_dump.$(OBJEXT): {$(VPATH)}vm_dump.c $(RUBY_H_INCLUDES) \
......
939 939

  
940 940
insns: $(INSNS)
941 941

  
942
opt_method.h: $(srcdir)/tool/generic_erb.rb \
943
		$(srcdir)/template/opt_method.h.tmpl \
944
		$(srcdir)/defs/opt_method.def
945
	$(ECHO) generating $@
946
	$(Q) $(BASERUBY) $(srcdir)/tool/generic_erb.rb --output=$@ \
947
		$(srcdir)/template/opt_method.h.tmpl
948

  
949
opt_method.inc: $(srcdir)/tool/generic_erb.rb \
950
		$(srcdir)/template/opt_method.inc.tmpl \
951
		$(srcdir)/defs/opt_method.def
952
	$(ECHO) generating $@
953
	$(Q) $(BASERUBY) $(srcdir)/tool/generic_erb.rb --output=$@ \
954
		$(srcdir)/template/opt_method.inc.tmpl
955

  
942 956
id.h: $(srcdir)/tool/generic_erb.rb $(srcdir)/template/id.h.tmpl $(srcdir)/defs/id.def
943 957
	$(ECHO) generating $@
944 958
	$(Q) $(BASERUBY) $(srcdir)/tool/generic_erb.rb --output=$@ \
compile.c
1703 1703
    return 0;
1704 1704
}
1705 1705

  
1706
#define new_recvinfo_for_recv(iseq,str,mid,klass) \
1707
    new_recvinfo_for_recv_(iseq,str,OM_##mid##__##klass)
1708
static VALUE
1709
new_recvinfo_for_recv_(rb_iseq_t *iseq, VALUE str,
1710
			enum ruby_optimized_method om)
1711
{
1712
    VALUE ri = rb_ary_new_from_args(2, str, INT2FIX(om));
1713

  
1714
    hide_obj(ri);
1715
    iseq_add_mark_object(iseq, ri);
1716

  
1717
    return ri;
1718
}
1719

  
1720
#define new_recvinfo_for_arg(iseq,str,mid,klass,off) \
1721
    new_recvinfo_for_arg_((iseq),(str),(OM_##mid##__##klass),\
1722
                          (OM_TMASK_##klass),(off))
1723
static VALUE
1724
new_recvinfo_for_arg_(rb_iseq_t *iseq, VALUE str,
1725
		enum ruby_optimized_method om,
1726
		VALUE tmask, int recv_off)
1727
{
1728
    VALUE ri = rb_ary_new_from_args(4, str, INT2FIX(om),
1729
				    tmask, INT2FIX(recv_off));
1730

  
1731
    hide_obj(ri);
1732
    iseq_add_mark_object(iseq, ri);
1733

  
1734
    return ri;
1735
}
1736

  
1737
/* optimize allocation for: obj.method("literal string") */
1738
static void
1739
opt_str_lit_1(rb_iseq_t *iseq, VALUE str, rb_call_info_t *ci, INSN *list)
1740
{
1741
    enum ruby_optimized_method om;
1742
    VALUE tmask;
1743
    VALUE ri;
1744
    int data_p = 0;
1745

  
1746
    switch (ci->mid) {
1747
#define C(mid,klass) \
1748
  case mid: \
1749
    om = OM_##mid##__##klass; \
1750
    tmask = OM_TMASK_##klass; \
1751
    break
1752
      C(idAREF, Hash);
1753
      C(idEq, String);
1754
      C(idNeq, String);
1755
      C(idLTLT, String);
1756
      C(idPLUS, String);
1757
      C(idEqq, String);
1758
      C(idDelete, Array_Hash_String);
1759
      C(idIncludeP, Array_Hash_String);
1760
      C(idMemberP, Hash);
1761
      C(idHas_keyP, Hash);
1762
      C(idKeyP, Hash);
1763
      C(idFetch, Hash); /* TODO: hash.fetch("lit") { ... } block */
1764
      C(idPack, Array);
1765
      C(idUnpack, String);
1766
      C(idSplit, String); /* TODO: str.split("lit", num) */
1767
      C(idJoin, Array);
1768
      C(idCount, String);
1769
      C(idChomp, String);
1770
      C(idChomp_bang, String);
1771
      C(idSqueeze, String);
1772
      C(idSqueeze_bang, String);
1773
      C(idDelete_bang, String);
1774
      C(idEncode, String);
1775
      C(idEncode_bang, String);
1776
      C(idForce_encoding, String);
1777
      C(idIndex, String); /* TODO: str.index("lit", num) */
1778
      C(idRindex, String);
1779
      C(idMatch, String);
1780
      C(idCasecmp, String);
1781
      C(idStart_withP, String);
1782
      C(idEnd_withP, String);
1783
      C(idPartition, String);
1784
      C(idRpartition, String);
1785
#undef C
1786
#define C(mid,klass) \
1787
  case mid: \
1788
    om = OM_##mid##__##klass; \
1789
    tmask = OM_TMASK_##klass; \
1790
    data_p = 1; \
1791
    break
1792
      /* opt_str_lit_data oddities, maybe this is not worth supporting */
1793
      C(idStrftime, Time);
1794
#undef C
1795
      default: return;
1796
    }
1797

  
1798
    list->insn_id = data_p ? BIN(opt_str_lit_data) : BIN(opt_str_lit_tmask);
1799
    ri = new_recvinfo_for_arg_(iseq, str, om, tmask, 0);
1800
    list->operands[0] = ri;
1801
}
1802

  
1803
/*
1804
 * optimize common string calls which take one or two string literals:
1805
 *   obj.method("lit 1", "lit 2")
1806
 *   obj.method(any, "lit 2") # any may be regexp
1807
 */
1808
static void
1809
opt_str_lit_2(rb_iseq_t *iseq, VALUE str, rb_call_info_t *ci, INSN *list)
1810
{
1811
    INSN *piobj;
1812
    enum ruby_optimized_method om;
1813
    VALUE ri;
1814

  
1815
    switch (ci->mid) {
1816
#define C(mid) case mid: om = OM_##mid##__String; break
1817
      C(idSub);
1818
      C(idSub_bang);
1819
      C(idGsub);
1820
      C(idGsub_bang);
1821
      C(idTr);
1822
      C(idTr_bang);
1823
      C(idTr_s);
1824
      C(idTr_s_bang);
1825
      C(idInsert); /* String#insert(num, "lit") */
1826

  
1827
      /* String#encode("dst", "src") */
1828
      C(idEncode);
1829
      C(idEncode_bang);
1830
#undef C
1831
      default: return;
1832
    }
1833

  
1834
    /*
1835
     * previous arg may be a string literal, too:
1836
     *   foo.gsub!("from", "to")
1837
     *   foo.tr!("from", "to")
1838
     *   ..
1839
     */
1840
    piobj = (INSN *)get_prev_insn(list);
1841
    if (piobj && piobj->insn_id == BIN(putstring)) {
1842
	VALUE pstr = piobj->operands[0];
1843
	VALUE pri = new_recvinfo_for_arg_(iseq, pstr, om, OM_TMASK_String, 0);
1844
	piobj->operands[0] = pri;
1845
	piobj->insn_id = BIN(opt_str_lit_tmask);
1846
    }
1847

  
1848
    list->insn_id = BIN(opt_str_lit_tmask);
1849
    ri = new_recvinfo_for_arg_(iseq, str, om, OM_TMASK_String, 1);
1850
    list->operands[0] = ri;
1851
}
1852

  
1706 1853
static int
1707 1854
iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
1708 1855
{
......
1819 1966
	    }
1820 1967
	}
1821 1968
    }
1969

  
1970
    /* string literal optimizations */
1971
    if (iobj->insn_id == BIN(putstring)) {
1972
	INSN *niobj = (INSN *)get_next_insn((INSN *)list);
1973

  
1974
	if (niobj && niobj->insn_id == BIN(send)) {
1975
	    rb_call_info_t *ci = (rb_call_info_t *)niobj->operands[0];
1976

  
1977
	    if (!ci->blockiseq && !(ci->flag & ~VM_CALL_ARGS_SKIP_SETUP)) {
1978
		VALUE ri = Qfalse;
1979
		VALUE str = iobj->operands[0];
1980

  
1981
		switch (ci->orig_argc) {
1982
		  case 0:
1983
		    /*
1984
		     * optimize:
1985
		     * "literal".freeze
1986
		     * "literal".size
1987
		     * "literal".length
1988
		     */
1989
		    switch (ci->mid) {
1990
		      case idFreeze:
1991
			ri = new_recvinfo_for_recv(iseq, str, idFreeze, String);
1992
			break;
1993
		      case idSize:
1994
			ri = new_recvinfo_for_recv(iseq, str, idSize, String);
1995
			break;
1996
		      case idLength:
1997
			ri = new_recvinfo_for_recv(iseq, str, idLength, String);
1998
			break;
1999
		    }
2000
		    if (ri != Qfalse) {
2001
			iobj->insn_id = BIN(opt_str_lit_recv);
2002
			iobj->operands[0] = ri;
2003
		    }
2004
		    break;
2005
		  case 1:
2006
		    opt_str_lit_1(iseq, str, ci, (INSN *)list);
2007
		    break;
2008
		  case 2:
2009
		    opt_str_lit_2(iseq, str, ci, (INSN *)list);
2010
		    break;
2011
		}
2012
	    }
2013
	}
2014
    }
2015

  
1822 2016
    return COMPILE_OK;
1823 2017
}
1824 2018

  
......
3096 3290
    return Qnil;
3097 3291
}
3098 3292

  
3293
static enum ruby_optimized_method
3294
opt_str_lit_recv_om(ID mid)
3295
{
3296
    switch (mid) {
3297
      case idEq: return OM_idEq__String;
3298
      case idNeq: return OM_idNeq__String;
3299
      case idPLUS: return OM_idPLUS__String;
3300
      case idMULT: return OM_idMULT__String;
3301
      case idMOD: return OM_idMOD__String;
3302
      case idEqq: return OM_idEqq__String;
3303
    }
3304
    return OM_LAST_;
3305
}
3306

  
3099 3307
/**
3100 3308
  compile each node
3101 3309

  
......
4238 4446
	break;
4239 4447
      }
4240 4448
      case NODE_CALL:
4241
	/* optimization shortcut
4242
	 *   "literal".freeze -> opt_str_freeze("literal")
4243
	 */
4244
	if (node->nd_recv && nd_type(node->nd_recv) == NODE_STR &&
4245
	    node->nd_mid == idFreeze && node->nd_args == NULL)
4246
	{
4247
	    VALUE str = rb_fstring(node->nd_recv->nd_lit);
4248
	    iseq_add_mark_object(iseq, str);
4249
	    ADD_INSN1(ret, line, opt_str_freeze, str);
4250
	    if (poped) {
4251
		ADD_INSN(ret, line, pop);
4252
	    }
4253
	    break;
4254
	}
4255
	/* optimization shortcut
4256
	 *   obj["literal"] -> opt_aref_with(obj, "literal")
4257
	 */
4258
	if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
4259
	    nd_type(node->nd_args) == NODE_ARRAY && node->nd_args->nd_alen == 1 &&
4260
	    nd_type(node->nd_args->nd_head) == NODE_STR)
4261
	{
4262
	    VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
4263
	    node->nd_args->nd_head->nd_lit = str;
4264
	    COMPILE(ret, "recv", node->nd_recv);
4265
	    ADD_INSN2(ret, line, opt_aref_with,
4266
		      new_callinfo(iseq, idAREF, 1, 0, 0), str);
4267
	    if (poped) {
4268
		ADD_INSN(ret, line, pop);
4269
	    }
4270
	    break;
4271
	}
4272 4449
      case NODE_FCALL:
4273 4450
      case NODE_VCALL:{		/* VCALL: variable or call */
4274 4451
	/*
......
4352 4529
#endif
4353 4530
	/* receiver */
4354 4531
	if (type == NODE_CALL) {
4355
	    COMPILE(recv, "recv", node->nd_recv);
4532
	    enum ruby_optimized_method om;
4533
	    /*
4534
	     * optimize:
4535
	     *   "string literal".method(...)
4536
	     *   "yoda" == other -> opt_str_lit("yoda").send(:==, other)
4537
	     *   "yoda" != other -> opt_str_lit("yoda").send(:!=, other)
4538
	     *   "str" + other -> opt_str_lit("str").send(:+, other)
4539
	     *   "str" * other -> opt_str_lit("str").send(:*, other)
4540
	     *   "fmt" % args -> opt_str_lit("str").send(:%, other)
4541
	     *   ...
4542
	     */
4543
	    if (iseq->compile_data->option->peephole_optimization &&
4544
		((om = opt_str_lit_recv_om(mid)) != OM_LAST_) &&
4545
		!private_recv_p(node) &&
4546
		node->nd_recv && nd_type(node->nd_recv) == NODE_STR &&
4547
		node->nd_args && nd_type(node->nd_args) == NODE_ARRAY &&
4548
		node->nd_args->nd_alen == 1)
4549
	    {
4550
		VALUE yoda = rb_fstring(node->nd_recv->nd_lit);
4551
		VALUE recv_info = new_recvinfo_for_recv_(iseq, yoda, om);
4552

  
4553
		node->nd_recv->nd_lit = yoda;
4554
		ADD_INSN1(recv, line, opt_str_lit_recv, recv_info);
4555
	    } else {
4556
		COMPILE(recv, "recv", node->nd_recv);
4557
	    }
4356 4558
	}
4357 4559
	else if (type == NODE_FCALL || type == NODE_VCALL) {
4358 4560
	    ADD_CALL_RECEIVER(recv, line);
......
5241 5443
	int asgnflag;
5242 5444

  
5243 5445
	/* optimization shortcut
5244
	 *   obj["literal"] = value -> opt_aset_with(obj, "literal", value)
5446
	 *   obj["literal"] = val -> send(obj, :[]=, opt_str_lit("lit"), val)
5447
	 * TODO: ideally this should be done inside iseq_peephole_optimize,
5448
	 * but that would require a lot of scanning as the `val' (2nd arg)
5449
	 * is of variable distance between the :putstring and :send insns
5245 5450
	 */
5246
	if (node->nd_mid == idASET && !private_recv_p(node) && node->nd_args &&
5451
	if (iseq->compile_data->option->peephole_optimization &&
5452
	    node->nd_mid == idASET && !private_recv_p(node) && node->nd_args &&
5247 5453
	    nd_type(node->nd_args) == NODE_ARRAY && node->nd_args->nd_alen == 2 &&
5248 5454
	    nd_type(node->nd_args->nd_head) == NODE_STR)
5249 5455
	{
5250 5456
	    VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
5457
	    VALUE recv_info = new_recvinfo_for_arg(iseq, str, idASET, Hash, 0);
5458

  
5251 5459
	    node->nd_args->nd_head->nd_lit = str;
5252
	    iseq_add_mark_object(iseq, str);
5460
	    if (!poped) {
5461
		ADD_INSN(ret, line, putnil);
5462
	    }
5253 5463
	    COMPILE(ret, "recv", node->nd_recv);
5464
	    ADD_INSN1(ret, line, opt_str_lit_tmask, recv_info);
5254 5465
	    COMPILE(ret, "value", node->nd_args->nd_next->nd_head);
5255 5466
	    if (!poped) {
5256
		ADD_INSN(ret, line, swap);
5257
		ADD_INSN1(ret, line, topn, INT2FIX(1));
5467
		ADD_INSN1(ret, line, setn, INT2FIX(3));
5258 5468
	    }
5259
	    ADD_INSN2(ret, line, opt_aset_with,
5260
		      new_callinfo(iseq, idASET, 2, 0, 0), str);
5469
	    flag = VM_CALL_ARGS_SKIP_SETUP;
5470
	    ADD_SEND_R(ret, line, node->nd_mid, 2, 0, INT2FIX(flag));
5261 5471
	    ADD_INSN(ret, line, pop);
5262 5472
	    break;
5263 5473
	}
......
5906 6116
{
5907 6117
    return GET_THREAD()->parse_in_eval < 0;
5908 6118
}
6119

  
6120
/*
6121
 * Live bytecode patch:
6122
 *   - opt_str_lit(recv_info)
6123
 *   + putstring(str) # str is recv_info[0]
6124
 *
6125
 * If allocation optimization fails at this call site once, assume it
6126
 * will fail in the future.  This prevents performance regressions for
6127
 * things like #include? calls which may be used with unoptimized
6128
 * classes (Set,*DBM and many others) as well as optimized core classes
6129
 * (Array/Hash/String).  Call sites which only use optimized core
6130
 * classes will never get here.
6131
 */
6132
void
6133
rb_undo_opt_str_lit(rb_control_frame_t *cfp)
6134
{
6135
    VALUE *insn = cfp->pc - insn_len(BIN(opt_str_lit_tmask));
6136

  
6137
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
6138
    const void * const *table = rb_vm_get_insns_address_table();
6139

  
6140
    assert(((VALUE)table[BIN(opt_str_lit_tmask)] == insn[0] ||
6141
            (VALUE)table[BIN(opt_str_lit_data)] == insn[0] ||
6142
            (VALUE)table[BIN(opt_str_lit_recv)] == insn[0]) &&
6143
	    "mismatch");
6144
    insn[0] = (VALUE)table[BIN(putstring)];
6145
#else
6146
    assert(((VALUE)BIN(opt_str_lit_tmask) == insn[0] ||
6147
            (VALUE)BIN(opt_str_lit_data) == insn[0] ||
6148
            (VALUE)BIN(opt_str_lit_recv) == insn[0]) &&
6149
	    "mismatch");
6150
    insn[0] = (VALUE)BIN(putstring);
6151
#endif
6152
    assert(insn_len(BIN(putstring)) == insn_len(BIN(opt_str_lit_tmask)));
6153
    assert(insn_len(BIN(putstring)) == insn_len(BIN(opt_str_lit_data)));
6154
    assert(insn_len(BIN(putstring)) == insn_len(BIN(opt_str_lit_recv)));
6155

  
6156
    assert(T_ARRAY == BUILTIN_TYPE(insn[1]));
6157

  
6158
    /* n.b.: recv_info remains marked */
6159
    insn[1] = RARRAY_AREF(insn[1], 0); /* recv_info[0] == str */
6160
}
defs/id.def
57 57
  core#hash_merge_ary
58 58
  core#hash_merge_ptr
59 59
  core#hash_merge_kwd
60
  gsub
61
  gsub!
62
  sub
63
  sub!
64
  tr
65
  tr!
66
  tr_s
67
  tr_s!
68
  delete
69
  delete!
70
  include?
71
  member?
72
  has_key?
73
  key?
74
  fetch
75
  count
76
  chomp
77
  chomp!
78
  squeeze
79
  squeeze!
80
  strftime
81
  pack
82
  unpack
83
  split
84
  join
85
  encode
86
  encode!
87
  force_encoding
88
  index
89
  rindex
90
  match
91
  casecmp
92
  insert
93
  start_with?
94
  end_with?
95
  partition
96
  rpartition
60 97
]
61 98

  
62 99
class KeywordError < RuntimeError
......
83 120
    token = "_#{token.gsub(/\W+/, '_')}"
84 121
  else
85 122
    token = token.sub(/\?/, 'P').sub(/\A[a-z]/) {$&.upcase}
123
    token.sub!(/!\z/, "_bang")
86 124
    token.sub!(/\A\$/, "_G_")
87 125
    token.sub!(/\A@@/, "_C_")
88 126
    token.sub!(/\A@/, "_I_")
defs/opt_method.def
1
# byte align the bitmap for now, maybe some arches do better with long or int
2
# we may also use a larger size (in the unlikely case) we need more than
3
# 7 optimized classes per mid.   Currently this caps us to 256 optimized
4
# (mid, klass) combinations (tested with OM_SHIFT=4, giving us 64K)
5
OM_SHIFT = 3
6
OM_ALIGN = 1 << OM_SHIFT
7
OM_ALIGN_MASK = ~(OM_ALIGN - 1)
8
OPT_METHODS = [
9
  %w(idPLUS Fixnum Float String Array),
10
  %w(idMINUS Fixnum Float),
11
  %w(idMULT Fixnum Float String),
12
  %w(idDIV Fixnum Float),
13
  %w(idMOD Fixnum Float String),
14
  %w(idEq Fixnum Float String),
15
  %w(idNeq Fixnum Float String),
16
  # id, mask classes
17
  [ 'idEqq', %w(Bignum Fixnum Float Symbol), *%w(String) ],
18
  %w(idLT Fixnum Float),
19
  %w(idLE Fixnum Float),
20
  %w(idGT Fixnum Float),
21
  %w(idGE Fixnum Float),
22
  %w(idLTLT Array String),
23
  %w(idAREF Array Hash),
24
  %w(idASET Array Hash),
25
  %w(idLength Array Hash String),
26
  %w(idSize Array Hash String),
27
  %w(idEmptyP Array Hash String),
28
  %w(idSucc Fixnum String Time),
29
  %w(idEqTilde Regexp String),
30
  %w(idFreeze String),
31
  %w(idGsub String),
32
  %w(idGsub_bang String),
33
  %w(idSub String),
34
  %w(idSub_bang String),
35
  %w(idTr String),
36
  %w(idTr_bang String),
37
  %w(idTr_s String),
38
  %w(idTr_s_bang String),
39
  [ "idDelete", %w(Array Hash String) ],
40
  [ "idIncludeP", %w(Array Hash String) ],
41
  %w(idMemberP Hash),
42
  %w(idHas_keyP Hash),
43
  %w(idKeyP Hash),
44
  %w(idFetch Hash),
45
  %w(idStrftime Time),
46
  %w(idUnpack String),
47
  %w(idPack Array),
48
  %w(idSplit String),
49
  %w(idJoin Array),
50
  %w(idCount String),
51
  %w(idChomp String),
52
  %w(idChomp_bang String),
53
  %w(idSqueeze String),
54
  %w(idSqueeze_bang String),
55
  %w(idDelete_bang String),
56
  %w(idEncode String),
57
  %w(idEncode_bang String),
58
  %w(idForce_encoding String),
59
  %w(idIndex String),
60
  %w(idRindex String),
61
  %w(idMatch String),
62
  %w(idCasecmp String),
63
  %w(idInsert String),
64
  %w(idStart_withP String),
65
  %w(idEnd_withP String),
66
  %w(idPartition String),
67
  %w(idRpartition String),
68
]
69

  
70
# for checking optimized classes,
71
# speeds up method definitions of non-core classes
72
def opt_classes
73
  rv = {}
74
  OPT_METHODS.each do |(_, *classes)|
75
    classes.flatten.each { |c| rv[c] = true }
76
  end
77
  rv
78
end
79

  
80
def om(mid, klass)
81
  if Array === klass
82
    "OM_#{mid}__#{klass.join('_')}"
83
  else
84
    "OM_#{mid}__#{klass}"
85
  end
86
end
87

  
88
IS_T_DATA = {
89
  "Time" => true
90
}
insns.def
357 357
}
358 358

  
359 359
/**
360
  @c optimize
361
  @e put string val. string may be created depending on recv_info conditions
362
 */
363
DEFINE_INSN
364
opt_str_lit_tmask
365
(VALUE recv_info)
366
()
367
(VALUE val)
368
{
369
    /*
370
     * recv_info:
371
     * 0 - str
372
     * 1 - optimized method flag (OM_*)
373
     * 2 - tmask (optimized receiver classes)
374
     * 3 - stack offset (Fixint),
375
     *     -1 stack offset means receiver is the frozen string literal itself
376
     */
377
    const VALUE *ri = RARRAY_CONST_PTR(recv_info);
378
    enum ruby_optimized_method om = FIX2UINT(ri[1]);
379
    int tmask = FIX2INT(ri[2]);
380
    int n = FIX2INT(ri[3]);
381
    VALUE recv;
382

  
383
    val = ri[0]; /* hopefully, this is the only val assignment we need */
384
    recv = n < 0 ? val : TOPN(n);
385

  
386
    if (!SPECIAL_CONST_P(recv)) {
387
	enum ruby_value_type btype = BUILTIN_TYPE(recv);
388
	int rmask = 1 << btype;
389

  
390
	if ((rmask & tmask) &&
391
		(rb_opt_method_class(btype) == RBASIC_CLASS(recv))) {
392
	    if (rb_opt_method_is_mask(om)) {
393
		if (rb_basic_mask_unredefined_p(om)) {
394
		    goto out_tmask; /* fast path */
395
		}
396
	    }
... This diff was truncated because it exceeds the maximum size that can be displayed.