Project

General

Profile

Feature #10423 ยป opt_str_lit-v5.patch

normalperson (Eric Wong), 11/02/2014 10:07 PM

View differences:

.gitignore
74 74
/newdate.rb
75 75
/newline.c
76 76
/newver.rb
77
/opt_method.h
77 78
/parse.c
78 79
/parse.h
79 80
/patches
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
642 642
VM_CORE_H_INCLUDES = {$(VPATH)}vm_core.h {$(VPATH)}thread_$(THREAD_MODEL).h \
643 643
		     {$(VPATH)}node.h {$(VPATH)}method.h {$(VPATH)}ruby_atomic.h \
644 644
	             {$(VPATH)}vm_debug.h {$(VPATH)}id.h {$(VPATH)}thread_native.h \
645
	             $(CCAN_LIST_INCLUDES)
645
	             $(CCAN_LIST_INCLUDES) {$(VPATH)}opt_method.h
646 646

  
647 647
###
648 648

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

  
942 942
insns: $(INSNS)
943 943

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

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

  
944 958
id.h: $(srcdir)/tool/generic_erb.rb $(srcdir)/template/id.h.tmpl $(srcdir)/defs/id.def
945 959
	$(ECHO) generating $@
946 960
	$(Q) $(BASERUBY) $(srcdir)/tool/generic_erb.rb --output=$@ \
compile.c
1744 1744
    return 0;
1745 1745
}
1746 1746

  
1747
#define new_recvinfo_for_recv(iseq,str,mid,klass) \
1748
    new_recvinfo_for_recv_(iseq,str,OM_##mid##__##klass)
1749
static VALUE
1750
new_recvinfo_for_recv_(rb_iseq_t *iseq, VALUE str,
1751
			enum ruby_optimized_method om)
1752
{
1753
    VALUE ri = rb_ary_new_from_args(2, str, INT2FIX(om));
1754

  
1755
    hide_obj(ri);
1756
    iseq_add_mark_object(iseq, ri);
1757

  
1758
    return ri;
1759
}
1760

  
1761
#define new_recvinfo_for_arg(iseq,str,mid,klass,off) \
1762
    new_recvinfo_for_arg_((iseq),(str),(OM_##mid##__##klass),\
1763
                          (OM_TMASK_##klass),(off))
1764
static VALUE
1765
new_recvinfo_for_arg_(rb_iseq_t *iseq, VALUE str,
1766
		enum ruby_optimized_method om,
1767
		VALUE tmask, int recv_off)
1768
{
1769
    VALUE ri = rb_ary_new_from_args(4, str, INT2FIX(om),
1770
				    tmask, INT2FIX(recv_off));
1771

  
1772
    hide_obj(ri);
1773
    iseq_add_mark_object(iseq, ri);
1774

  
1775
    return ri;
1776
}
1777

  
1778
/* optimize allocation for: obj.method("literal string") */
1779
static void
1780
opt_str_lit_1(rb_iseq_t *iseq, VALUE str, rb_call_info_t *ci, INSN *list)
1781
{
1782
    enum ruby_optimized_method om;
1783
    VALUE tmask;
1784
    VALUE ri;
1785
    int data_p = 0;
1786

  
1787
    switch (ci->mid) {
1788
#define C(mid,klass) \
1789
  case mid: \
1790
    om = OM_##mid##__##klass; \
1791
    tmask = OM_TMASK_##klass; \
1792
    break
1793
      C(idAREF, Hash);
1794
      C(idEq, String);
1795
      C(idNeq, String);
1796
      C(idLTLT, String);
1797
      C(idPLUS, String);
1798
      C(idEqq, String);
1799
      C(idDelete, Array_Hash_String);
1800
      C(idIncludeP, Array_Hash_String);
1801
      C(idMemberP, Hash);
1802
      C(idHas_keyP, Hash);
1803
      C(idKeyP, Hash);
1804
      C(idFetch, Hash); /* TODO: hash.fetch("lit") { ... } block */
1805
      C(idPack, Array);
1806
      C(idUnpack, String);
1807
      C(idSplit, String); /* TODO: str.split("lit", num) */
1808
      C(idJoin, Array);
1809
      C(idCount, String);
1810
      C(idChomp, String);
1811
      C(idChomp_bang, String);
1812
      C(idSqueeze, String);
1813
      C(idSqueeze_bang, String);
1814
      C(idDelete_bang, String);
1815
      C(idEncode, String);
1816
      C(idEncode_bang, String);
1817
      C(idForce_encoding, String);
1818
      C(idIndex, String); /* TODO: str.index("lit", num) */
1819
      C(idRindex, String);
1820
      C(idMatch, String);
1821
      C(idCasecmp, String);
1822
      C(idStart_withP, String);
1823
      C(idEnd_withP, String);
1824
      C(idPartition, String);
1825
      C(idRpartition, String);
1826
#undef C
1827
#define C(mid,klass) \
1828
  case mid: \
1829
    om = OM_##mid##__##klass; \
1830
    tmask = OM_TMASK_##klass; \
1831
    data_p = 1; \
1832
    break
1833
      /* opt_str_lit_data oddities, maybe this is not worth supporting */
1834
      C(idStrftime, Time);
1835
#undef C
1836
      default: return;
1837
    }
1838

  
1839
    list->insn_id = data_p ? BIN(opt_str_lit_data) : BIN(opt_str_lit_tmask);
1840
    ri = new_recvinfo_for_arg_(iseq, str, om, tmask, 0);
1841
    list->operands[0] = ri;
1842
}
1843

  
1844
/*
1845
 * optimize common string calls which take one or two string literals:
1846
 *   obj.method("lit 1", "lit 2")
1847
 *   obj.method(any, "lit 2") # any may be regexp
1848
 */
1849
static void
1850
opt_str_lit_2(rb_iseq_t *iseq, VALUE str, rb_call_info_t *ci, INSN *list)
1851
{
1852
    INSN *piobj;
1853
    enum ruby_optimized_method om;
1854
    VALUE ri;
1855

  
1856
    switch (ci->mid) {
1857
#define C(mid) case mid: om = OM_##mid##__String; break
1858
      C(idSub);
1859
      C(idSub_bang);
1860
      C(idGsub);
1861
      C(idGsub_bang);
1862
      C(idTr);
1863
      C(idTr_bang);
1864
      C(idTr_s);
1865
      C(idTr_s_bang);
1866
      C(idInsert); /* String#insert(num, "lit") */
1867

  
1868
      /* String#encode("dst", "src") */
1869
      C(idEncode);
1870
      C(idEncode_bang);
1871
#undef C
1872
      default: return;
1873
    }
1874

  
1875
    /*
1876
     * previous arg may be a string literal, too:
1877
     *   foo.gsub!("from", "to")
1878
     *   foo.tr!("from", "to")
1879
     *   ..
1880
     */
1881
    piobj = (INSN *)get_prev_insn(list);
1882
    if (piobj && piobj->insn_id == BIN(putstring)) {
1883
	VALUE pstr = piobj->operands[0];
1884
	VALUE pri = new_recvinfo_for_arg_(iseq, pstr, om, OM_TMASK_String, 0);
1885
	piobj->operands[0] = pri;
1886
	piobj->insn_id = BIN(opt_str_lit_tmask);
1887
    }
1888

  
1889
    list->insn_id = BIN(opt_str_lit_tmask);
1890
    ri = new_recvinfo_for_arg_(iseq, str, om, OM_TMASK_String, 1);
1891
    list->operands[0] = ri;
1892
}
1893

  
1747 1894
static int
1748 1895
iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
1749 1896
{
......
1860 2007
	    }
1861 2008
	}
1862 2009
    }
2010

  
2011
    /* string literal optimizations */
2012
    if (iobj->insn_id == BIN(putstring)) {
2013
	INSN *niobj = (INSN *)get_next_insn((INSN *)list);
2014

  
2015
	if (niobj && niobj->insn_id == BIN(send)) {
2016
	    rb_call_info_t *ci = (rb_call_info_t *)niobj->operands[0];
2017

  
2018
	    if (!ci->blockiseq && !(ci->flag & ~VM_CALL_ARGS_SIMPLE)) {
2019
		VALUE ri = Qfalse;
2020
		VALUE str = iobj->operands[0];
2021

  
2022
		switch (ci->orig_argc) {
2023
		  case 0:
2024
		    /*
2025
		     * optimize:
2026
		     * "literal".freeze
2027
		     * "literal".size
2028
		     * "literal".length
2029
		     */
2030
		    switch (ci->mid) {
2031
		      case idFreeze:
2032
			ri = new_recvinfo_for_recv(iseq, str, idFreeze, String);
2033
			break;
2034
		      case idSize:
2035
			ri = new_recvinfo_for_recv(iseq, str, idSize, String);
2036
			break;
2037
		      case idLength:
2038
			ri = new_recvinfo_for_recv(iseq, str, idLength, String);
2039
			break;
2040
		    }
2041
		    if (ri != Qfalse) {
2042
			iobj->insn_id = BIN(opt_str_lit_recv);
2043
			iobj->operands[0] = ri;
2044
		    }
2045
		    break;
2046
		  case 1:
2047
		    opt_str_lit_1(iseq, str, ci, (INSN *)list);
2048
		    break;
2049
		  case 2:
2050
		    opt_str_lit_2(iseq, str, ci, (INSN *)list);
2051
		    break;
2052
		}
2053
	    }
2054
	}
2055
    }
2056

  
1863 2057
    return COMPILE_OK;
1864 2058
}
1865 2059

  
......
3186 3380
    return Qnil;
3187 3381
}
3188 3382

  
3383
static enum ruby_optimized_method
3384
opt_str_lit_recv_om(ID mid)
3385
{
3386
    switch (mid) {
3387
      case idEq: return OM_idEq__String;
3388
      case idNeq: return OM_idNeq__String;
3389
      case idPLUS: return OM_idPLUS__String;
3390
      case idMULT: return OM_idMULT__String;
3391
      case idMOD: return OM_idMOD__String;
3392
      case idEqq: return OM_idEqq__String;
3393
    }
3394
    return OM_LAST_;
3395
}
3396

  
3189 3397
/**
3190 3398
  compile each node
3191 3399

  
......
4320 4528
	break;
4321 4529
      }
4322 4530
      case NODE_CALL:
4323
	/* optimization shortcut
4324
	 *   "literal".freeze -> opt_str_freeze("literal")
4325
	 */
4326
	if (node->nd_recv && nd_type(node->nd_recv) == NODE_STR &&
4327
	    node->nd_mid == idFreeze && node->nd_args == NULL)
4328
	{
4329
	    VALUE str = rb_fstring(node->nd_recv->nd_lit);
4330
	    iseq_add_mark_object(iseq, str);
4331
	    ADD_INSN1(ret, line, opt_str_freeze, str);
4332
	    if (poped) {
4333
		ADD_INSN(ret, line, pop);
4334
	    }
4335
	    break;
4336
	}
4337
	/* optimization shortcut
4338
	 *   obj["literal"] -> opt_aref_with(obj, "literal")
4339
	 */
4340
	if (node->nd_mid == idAREF && !private_recv_p(node) && node->nd_args &&
4341
	    nd_type(node->nd_args) == NODE_ARRAY && node->nd_args->nd_alen == 1 &&
4342
	    nd_type(node->nd_args->nd_head) == NODE_STR)
4343
	{
4344
	    VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
4345
	    node->nd_args->nd_head->nd_lit = str;
4346
	    COMPILE(ret, "recv", node->nd_recv);
4347
	    ADD_INSN2(ret, line, opt_aref_with,
4348
		      new_callinfo(iseq, idAREF, 1, 0, 0, NULL), str);
4349
	    if (poped) {
4350
		ADD_INSN(ret, line, pop);
4351
	    }
4352
	    break;
4353
	}
4354 4531
      case NODE_FCALL:
4355 4532
      case NODE_VCALL:{		/* VCALL: variable or call */
4356 4533
	/*
......
4435 4612
#endif
4436 4613
	/* receiver */
4437 4614
	if (type == NODE_CALL) {
4438
	    COMPILE(recv, "recv", node->nd_recv);
4615
	    enum ruby_optimized_method om;
4616
	    /*
4617
	     * optimize:
4618
	     *   "string literal".method(...)
4619
	     *   "yoda" == other -> opt_str_lit("yoda").send(:==, other)
4620
	     *   "yoda" != other -> opt_str_lit("yoda").send(:!=, other)
4621
	     *   "str" + other -> opt_str_lit("str").send(:+, other)
4622
	     *   "str" * other -> opt_str_lit("str").send(:*, other)
4623
	     *   "fmt" % args -> opt_str_lit("str").send(:%, other)
4624
	     *   ...
4625
	     */
4626
	    if (iseq->compile_data->option->peephole_optimization &&
4627
		((om = opt_str_lit_recv_om(mid)) != OM_LAST_) &&
4628
		!private_recv_p(node) &&
4629
		node->nd_recv && nd_type(node->nd_recv) == NODE_STR &&
4630
		node->nd_args && nd_type(node->nd_args) == NODE_ARRAY &&
4631
		node->nd_args->nd_alen == 1)
4632
	    {
4633
		VALUE yoda = rb_fstring(node->nd_recv->nd_lit);
4634
		VALUE recv_info = new_recvinfo_for_recv_(iseq, yoda, om);
4635

  
4636
		node->nd_recv->nd_lit = yoda;
4637
		ADD_INSN1(recv, line, opt_str_lit_recv, recv_info);
4638
	    } else {
4639
		COMPILE(recv, "recv", node->nd_recv);
4640
	    }
4439 4641
	}
4440 4642
	else if (type == NODE_FCALL || type == NODE_VCALL) {
4441 4643
	    ADD_CALL_RECEIVER(recv, line);
......
5332 5534
	int asgnflag;
5333 5535

  
5334 5536
	/* optimization shortcut
5335
	 *   obj["literal"] = value -> opt_aset_with(obj, "literal", value)
5537
	 *   obj["literal"] = val -> send(obj, :[]=, opt_str_lit("lit"), val)
5538
	 * TODO: ideally this should be done inside iseq_peephole_optimize,
5539
	 * but that would require a lot of scanning as the `val' (2nd arg)
5540
	 * is of variable distance between the :putstring and :send insns
5336 5541
	 */
5337
	if (node->nd_mid == idASET && !private_recv_p(node) && node->nd_args &&
5542
	if (iseq->compile_data->option->peephole_optimization &&
5543
	    node->nd_mid == idASET && !private_recv_p(node) && node->nd_args &&
5338 5544
	    nd_type(node->nd_args) == NODE_ARRAY && node->nd_args->nd_alen == 2 &&
5339 5545
	    nd_type(node->nd_args->nd_head) == NODE_STR)
5340 5546
	{
5341 5547
	    VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
5548
	    VALUE recv_info = new_recvinfo_for_arg(iseq, str, idASET, Hash, 0);
5549

  
5342 5550
	    node->nd_args->nd_head->nd_lit = str;
5343
	    iseq_add_mark_object(iseq, str);
5551
	    if (!poped) {
5552
		ADD_INSN(ret, line, putnil);
5553
	    }
5344 5554
	    COMPILE(ret, "recv", node->nd_recv);
5555
	    ADD_INSN1(ret, line, opt_str_lit_tmask, recv_info);
5345 5556
	    COMPILE(ret, "value", node->nd_args->nd_next->nd_head);
5346 5557
	    if (!poped) {
5347
		ADD_INSN(ret, line, swap);
5348
		ADD_INSN1(ret, line, topn, INT2FIX(1));
5558
		ADD_INSN1(ret, line, setn, INT2FIX(3));
5349 5559
	    }
5350
	    ADD_INSN2(ret, line, opt_aset_with,
5351
		      new_callinfo(iseq, idASET, 2, 0, 0, NULL), str);
5560
	    flag = VM_CALL_ARGS_SIMPLE;
5561
	    ADD_SEND_WITH_FLAG(ret, line, node->nd_mid, INT2FIX(2),
5562
				INT2FIX(flag));
5352 5563
	    ADD_INSN(ret, line, pop);
5353 5564
	    break;
5354 5565
	}
......
5997 6208
{
5998 6209
    return GET_THREAD()->parse_in_eval < 0;
5999 6210
}
6211

  
6212
/*
6213
 * Live bytecode patch:
6214
 *   - opt_str_lit(recv_info)
6215
 *   + putstring(str) # str is recv_info[0]
6216
 *
6217
 * If allocation optimization fails at this call site once, assume it
6218
 * will fail in the future.  This prevents performance regressions for
6219
 * things like #include? calls which may be used with unoptimized
6220
 * classes (Set,*DBM and many others) as well as optimized core classes
6221
 * (Array/Hash/String).  Call sites which only use optimized core
6222
 * classes will never get here.
6223
 */
6224
void
6225
rb_undo_opt_str_lit(rb_control_frame_t *cfp)
6226
{
6227
    VALUE *insn = cfp->pc - insn_len(BIN(opt_str_lit_tmask));
6228

  
6229
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
6230
    const void * const *table = rb_vm_get_insns_address_table();
6231

  
6232
    assert(((VALUE)table[BIN(opt_str_lit_tmask)] == insn[0] ||
6233
            (VALUE)table[BIN(opt_str_lit_data)] == insn[0] ||
6234
            (VALUE)table[BIN(opt_str_lit_recv)] == insn[0]) &&
6235
	    "mismatch");
6236
    insn[0] = (VALUE)table[BIN(putstring)];
6237
#else
6238
    assert(((VALUE)BIN(opt_str_lit_tmask) == insn[0] ||
6239
            (VALUE)BIN(opt_str_lit_data) == insn[0] ||
6240
            (VALUE)BIN(opt_str_lit_recv) == insn[0]) &&
6241
	    "mismatch");
6242
    insn[0] = (VALUE)BIN(putstring);
6243
#endif
6244
    assert(insn_len(BIN(putstring)) == insn_len(BIN(opt_str_lit_tmask)));
6245
    assert(insn_len(BIN(putstring)) == insn_len(BIN(opt_str_lit_data)));
6246
    assert(insn_len(BIN(putstring)) == insn_len(BIN(opt_str_lit_recv)));
6247

  
6248
    assert(T_ARRAY == BUILTIN_TYPE(insn[1]));
6249

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

  
63 100
class KeywordError < RuntimeError
......
84 121
    token = "_#{token.gsub(/\W+/, '_')}"
85 122
  else
86 123
    token = token.sub(/\?/, 'P').sub(/\A[a-z]/) {$&.upcase}
124
    token.sub!(/!\z/, "_bang")
87 125
    token.sub!(/\A\$/, "_G_")
88 126
    token.sub!(/\A@@/, "_C_")
89 127
    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
}
... This diff was truncated because it exceeds the maximum size that can be displayed.