* Merge YARV
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11439 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
3e7566d8fb
commit
a3e1b1ce7e
@ -1,3 +1,7 @@
|
||||
Mon Jan 01 00:00:00 2007 Koichi Sasada <ko1@atdot.net>
|
||||
|
||||
* Merge YARV
|
||||
|
||||
Sun Dec 31 16:22:48 2006 Eric Hodel <drbrain@segment7.net>
|
||||
|
||||
* array.c: Fix Array#reject.
|
||||
|
69
array.c
69
array.c
@ -44,7 +44,7 @@ static void
|
||||
ary_iter_check(VALUE ary)
|
||||
{
|
||||
if (FL_TEST(ary, ARY_ITERLOCK)) {
|
||||
rb_raise(rb_eRuntimeError, "can't modify array during iteration");
|
||||
rb_raise(rb_eRuntimeError, "can't modify array during iteration");
|
||||
}
|
||||
}
|
||||
#define ARY_SORTLOCK FL_USER3
|
||||
@ -143,7 +143,7 @@ ary_new(VALUE klass, long len)
|
||||
rb_raise(rb_eArgError, "array size too big");
|
||||
}
|
||||
ary = ary_alloc(klass);
|
||||
if (len == 0) len++;
|
||||
if (len == 0) len++;
|
||||
RARRAY(ary)->ptr = ALLOC_N(VALUE, len);
|
||||
RARRAY(ary)->aux.capa = len;
|
||||
|
||||
@ -250,8 +250,6 @@ rb_check_array_type(VALUE ary)
|
||||
return rb_check_convert_type(ary, T_ARRAY, "Array", "to_ary");
|
||||
}
|
||||
|
||||
static VALUE rb_ary_replace(VALUE, VALUE);
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Array.new(size=0, obj=nil)
|
||||
@ -325,7 +323,7 @@ rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
|
||||
rb_raise(rb_eArgError, "array size too big");
|
||||
}
|
||||
rb_ary_modify(ary);
|
||||
RESIZE_CAPA(ary, len);
|
||||
RESIZE_CAPA(ary, len);
|
||||
if (rb_block_given_p()) {
|
||||
long i;
|
||||
|
||||
@ -543,10 +541,10 @@ rb_ary_shift(VALUE ary)
|
||||
top = RARRAY_PTR(ary)[0];
|
||||
if (!ARY_SHARED_P(ary)) {
|
||||
if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) {
|
||||
MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+1, VALUE, RARRAY_LEN(ary)-1);
|
||||
MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+1, VALUE, RARRAY_LEN(ary)-1);
|
||||
RARRAY(ary)->len--;
|
||||
return top;
|
||||
}
|
||||
return top;
|
||||
}
|
||||
RARRAY_PTR(ary)[0] = Qnil;
|
||||
ary_make_shared(ary);
|
||||
}
|
||||
@ -590,7 +588,7 @@ rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
|
||||
if (ARY_SHARED_P(ary)) {
|
||||
RARRAY(ary)->ptr += n;
|
||||
RARRAY(ary)->len -= n;
|
||||
}
|
||||
}
|
||||
else {
|
||||
MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+n, VALUE, RARRAY_LEN(ary)-n);
|
||||
RARRAY(ary)->len -= n;
|
||||
@ -675,7 +673,7 @@ rb_ary_subseq(VALUE ary, long beg, long len)
|
||||
if (len == 0) return ary_new(klass, 0);
|
||||
|
||||
shared = ary_make_shared(ary);
|
||||
ptr = RARRAY_PTR(ary);
|
||||
ptr = RARRAY_PTR(ary);
|
||||
ary2 = ary_alloc(klass);
|
||||
RARRAY(ary2)->ptr = ptr + beg;
|
||||
RARRAY(ary2)->len = len;
|
||||
@ -775,8 +773,8 @@ rb_ary_at(VALUE ary, VALUE pos)
|
||||
/*
|
||||
* call-seq:
|
||||
* array.first -> obj or nil
|
||||
* array.first(n) -> an_array
|
||||
*
|
||||
* array.first(n) -> an_array
|
||||
*
|
||||
* Returns the first element, or the first +n+ elements, of the array.
|
||||
* If the array is empty, the first form returns <code>nil</code>, and the
|
||||
* second form returns an empty array.
|
||||
@ -931,7 +929,7 @@ rb_ary_rindex(int argc, VALUE *argv, VALUE ary)
|
||||
long i = RARRAY_LEN(ary);
|
||||
|
||||
if (rb_scan_args(argc, argv, "01", &val) == 0) {
|
||||
RETURN_ENUMERATOR(ary, 0, 0);
|
||||
RETURN_ENUMERATOR(ary, 0, 0);
|
||||
while (i--) {
|
||||
if (RTEST(rb_yield(RARRAY_PTR(ary)[i])))
|
||||
return LONG2NUM(i);
|
||||
@ -1145,11 +1143,23 @@ each_i(VALUE ary)
|
||||
* a -- b -- c --
|
||||
*/
|
||||
|
||||
VALUE yarv_invoke_Array_each_special_block(VALUE ary);
|
||||
|
||||
VALUE
|
||||
rb_ary_each(VALUE ary)
|
||||
{
|
||||
long i;
|
||||
VALUE val;
|
||||
|
||||
RETURN_ENUMERATOR(ary, 0, 0);
|
||||
|
||||
val = yarv_invoke_Array_each_special_block(ary);
|
||||
if(val != Qundef){
|
||||
return val;
|
||||
}
|
||||
|
||||
ITERATE(each_i, ary);
|
||||
return ary;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
@ -1158,7 +1168,7 @@ each_index_i(VALUE ary)
|
||||
long i;
|
||||
|
||||
for (i=0; i<RARRAY_LEN(ary); i++) {
|
||||
rb_yield(LONG2NUM(i));
|
||||
rb_yield(LONG2NUM(i));
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
@ -1530,7 +1540,7 @@ sort_i(VALUE ary)
|
||||
data.ary = ary;
|
||||
data.ptr = RARRAY_PTR(ary); data.len = RARRAY_LEN(ary);
|
||||
ruby_qsort(RARRAY_PTR(ary), RARRAY_LEN(ary), sizeof(VALUE),
|
||||
rb_block_given_p()?sort_1:sort_2, &data);
|
||||
rb_block_given_p()?sort_1:sort_2, &data);
|
||||
return ary;
|
||||
}
|
||||
|
||||
@ -1890,7 +1900,6 @@ rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary)
|
||||
return rb_ary_delete_at(ary, NUM2LONG(arg1));
|
||||
}
|
||||
|
||||
|
||||
static VALUE
|
||||
reject_bang_i(VALUE ary)
|
||||
{
|
||||
@ -1905,10 +1914,10 @@ reject_bang_i(VALUE ary)
|
||||
}
|
||||
i2++;
|
||||
}
|
||||
|
||||
if (RARRAY_LEN(ary) == i2) return Qnil;
|
||||
if (i2 < RARRAY_LEN(ary))
|
||||
RARRAY(ary)->len = i2;
|
||||
|
||||
return ary;
|
||||
}
|
||||
|
||||
@ -2075,7 +2084,7 @@ rb_ary_transpose(VALUE ary)
|
||||
* a #=> ["x", "y", "z"]
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
VALUE
|
||||
rb_ary_replace(VALUE copy, VALUE orig)
|
||||
{
|
||||
VALUE shared;
|
||||
@ -2087,7 +2096,7 @@ rb_ary_replace(VALUE copy, VALUE orig)
|
||||
if (copy == orig) return copy;
|
||||
shared = ary_make_shared(orig);
|
||||
ptr = RARRAY(copy)->ptr;
|
||||
xfree(ptr);
|
||||
xfree(ptr);
|
||||
RARRAY(copy)->ptr = RARRAY(shared)->ptr;
|
||||
RARRAY(copy)->len = RARRAY(shared)->len;
|
||||
RARRAY(copy)->aux.shared = shared;
|
||||
@ -2804,16 +2813,16 @@ flatten(VALUE ary, long idx, VALUE ary2, VALUE memo, int level)
|
||||
rb_ary_push(memo, id);
|
||||
rb_ary_splice(ary, idx, 1, ary2);
|
||||
if (level != 0) {
|
||||
while (i < lim) {
|
||||
VALUE tmp;
|
||||
while (i < lim) {
|
||||
VALUE tmp;
|
||||
|
||||
tmp = rb_check_array_type(rb_ary_elt(ary, i));
|
||||
if (!NIL_P(tmp)) {
|
||||
tmp = rb_check_array_type(rb_ary_elt(ary, i));
|
||||
if (!NIL_P(tmp)) {
|
||||
n = flatten(ary, i, tmp, memo, level);
|
||||
i += n; lim += n;
|
||||
}
|
||||
i++;
|
||||
i += n; lim += n;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
rb_ary_pop(memo);
|
||||
|
||||
@ -2822,7 +2831,7 @@ flatten(VALUE ary, long idx, VALUE ary2, VALUE memo, int level)
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* array.flatten! -> array or nil
|
||||
* array.flatten! -> array or nil
|
||||
* array.flatten!(level) -> array or nil
|
||||
*
|
||||
* Flattens _self_ in place.
|
||||
@ -2831,9 +2840,9 @@ flatten(VALUE ary, long idx, VALUE ary2, VALUE memo, int level)
|
||||
* argument determins the level of recursion to flatten.
|
||||
*
|
||||
* a = [ 1, 2, [3, [4, 5] ] ]
|
||||
* a.flatten! #=> [1, 2, 3, 4, 5]
|
||||
* a.flatten! #=> nil
|
||||
* a #=> [1, 2, 3, 4, 5]
|
||||
* a.flatten! #=> [1, 2, 3, 4, 5]
|
||||
* a.flatten! #=> nil
|
||||
* a #=> [1, 2, 3, 4, 5]
|
||||
* a = [ 1, 2, [3, [4, 5] ] ]
|
||||
* a.flatten!(1) #=> [1, 2, 3, [4, 5]]
|
||||
*/
|
||||
|
15
benchmark/bm_app_answer.rb
Normal file
15
benchmark/bm_app_answer.rb
Normal file
@ -0,0 +1,15 @@
|
||||
def ack(m, n)
|
||||
if m == 0 then
|
||||
n + 1
|
||||
elsif n == 0 then
|
||||
ack(m - 1, 1)
|
||||
else
|
||||
ack(m - 1, ack(m, n - 1))
|
||||
end
|
||||
end
|
||||
|
||||
def the_answer_to_life_the_universe_and_everything
|
||||
(ack(3,7).to_s.split(//).inject(0){|s,x| s+x.to_i}.to_s + "2" ).to_i
|
||||
end
|
||||
|
||||
answer = the_answer_to_life_the_universe_and_everything
|
11
benchmark/bm_app_factorial.rb
Normal file
11
benchmark/bm_app_factorial.rb
Normal file
@ -0,0 +1,11 @@
|
||||
def fact(n)
|
||||
if(n > 1)
|
||||
n * fact(n-1)
|
||||
else
|
||||
1
|
||||
end
|
||||
end
|
||||
|
||||
8.times{
|
||||
fact(5000)
|
||||
}
|
10
benchmark/bm_app_fib.rb
Normal file
10
benchmark/bm_app_fib.rb
Normal file
@ -0,0 +1,10 @@
|
||||
def fib n
|
||||
if n < 3
|
||||
1
|
||||
else
|
||||
fib(n-1) + fib(n-2)
|
||||
end
|
||||
end
|
||||
|
||||
fib(34)
|
||||
|
23
benchmark/bm_app_mandelbrot.rb
Normal file
23
benchmark/bm_app_mandelbrot.rb
Normal file
@ -0,0 +1,23 @@
|
||||
require 'complex'
|
||||
|
||||
def mandelbrot? z
|
||||
i = 0
|
||||
while i<100
|
||||
i+=1
|
||||
z = z * z
|
||||
return false if z.abs > 2
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
ary = []
|
||||
|
||||
(0..100).each{|dx|
|
||||
(0..100).each{|dy|
|
||||
x = dx / 50.0
|
||||
y = dy / 50.0
|
||||
c = Complex(x, y)
|
||||
ary << c if mandelbrot?(c)
|
||||
}
|
||||
}
|
||||
|
259
benchmark/bm_app_pentomino.rb
Normal file
259
benchmark/bm_app_pentomino.rb
Normal file
@ -0,0 +1,259 @@
|
||||
#!/usr/local/bin/ruby
|
||||
# This program is contributed by Shin Nishiyama
|
||||
|
||||
|
||||
# modified by K.Sasada
|
||||
|
||||
NP = 5
|
||||
ROW = 8 + NP
|
||||
COL = 8
|
||||
|
||||
$p = []
|
||||
$b = []
|
||||
$no = 0
|
||||
|
||||
def piece(n, a, nb)
|
||||
nb.each{|x|
|
||||
a[n] = x
|
||||
if n == NP-1
|
||||
$p << [a.sort]
|
||||
else
|
||||
nbc=nb.clone
|
||||
[-ROW, -1, 1, ROW].each{|d|
|
||||
if x+d > 0 and not a.include?(x+d) and not nbc.include?(x+d)
|
||||
nbc << x+d
|
||||
end
|
||||
}
|
||||
nbc.delete x
|
||||
piece(n+1,a[0..n],nbc)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def kikaku(a)
|
||||
a.collect {|x| x - a[0]}
|
||||
end
|
||||
def ud(a)
|
||||
kikaku(a.collect {|x| ((x+NP)%ROW)-ROW*((x+NP)/ROW) }.sort)
|
||||
end
|
||||
def rl(a)
|
||||
kikaku(a.collect {|x| ROW*((x+NP)/ROW)+ROW-((x+NP)%ROW)}.sort)
|
||||
end
|
||||
def xy(a)
|
||||
kikaku(a.collect {|x| ROW*((x+NP)%ROW) + (x+NP)/ROW }.sort)
|
||||
end
|
||||
|
||||
def mkpieces
|
||||
piece(0,[],[0])
|
||||
$p.each do |a|
|
||||
a0 = a[0]
|
||||
a[1] = ud(a0)
|
||||
a[2] = rl(a0)
|
||||
a[3] = ud(rl(a0))
|
||||
a[4] = xy(a0)
|
||||
a[5] = ud(xy(a0))
|
||||
a[6] = rl(xy(a0))
|
||||
a[7] = ud(rl(xy(a0)))
|
||||
a.sort!
|
||||
a.uniq!
|
||||
end
|
||||
$p.uniq!.sort! {|x,y| x[0] <=> y[0] }
|
||||
end
|
||||
|
||||
def mkboard
|
||||
(0...ROW*COL).each{|i|
|
||||
if i % ROW >= ROW-NP
|
||||
$b[i] = -2
|
||||
else
|
||||
$b[i] = -1
|
||||
end
|
||||
$b[3*ROW+3]=$b[3*ROW+4]=$b[4*ROW+3]=$b[4*ROW+4]=-2
|
||||
}
|
||||
end
|
||||
|
||||
def pboard
|
||||
return # skip print
|
||||
print "No. #$no\n"
|
||||
(0...COL).each{|i|
|
||||
print "|"
|
||||
(0...ROW-NP).each{|j|
|
||||
x = $b[i*ROW+j]
|
||||
if x < 0
|
||||
print "..|"
|
||||
else
|
||||
printf "%2d|",x+1
|
||||
end
|
||||
}
|
||||
print "\n"
|
||||
}
|
||||
print "\n"
|
||||
end
|
||||
|
||||
$pnum=[]
|
||||
def setpiece(a,pos)
|
||||
if a.length == $p.length then
|
||||
$no += 1
|
||||
pboard
|
||||
return
|
||||
end
|
||||
while $b[pos] != -1
|
||||
pos += 1
|
||||
end
|
||||
($pnum - a).each do |i|
|
||||
$p[i].each do |x|
|
||||
f = 0
|
||||
x.each{|s|
|
||||
if $b[pos+s] != -1
|
||||
f=1
|
||||
break
|
||||
end
|
||||
}
|
||||
if f == 0 then
|
||||
x.each{|s|
|
||||
$b[pos+s] = i
|
||||
}
|
||||
a << i
|
||||
setpiece(a.clone, pos)
|
||||
a.pop
|
||||
x.each{|s|
|
||||
$b[pos+s] = -1
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mkpieces
|
||||
mkboard
|
||||
$p[4] = [$p[4][0]]
|
||||
$pnum = (0...$p.length).to_a
|
||||
setpiece([],0)
|
||||
|
||||
|
||||
__END__
|
||||
|
||||
# original
|
||||
|
||||
NP = 5
|
||||
ROW = 8 + NP
|
||||
COL = 8
|
||||
|
||||
$p = []
|
||||
$b = []
|
||||
$no = 0
|
||||
|
||||
def piece(n,a,nb)
|
||||
for x in nb
|
||||
a[n] = x
|
||||
if n == NP-1
|
||||
$p << [a.sort]
|
||||
else
|
||||
nbc=nb.clone
|
||||
for d in [-ROW, -1, 1, ROW]
|
||||
if x+d > 0 and not a.include?(x+d) and not nbc.include?(x+d)
|
||||
nbc << x+d
|
||||
end
|
||||
end
|
||||
nbc.delete x
|
||||
piece(n+1,a[0..n],nbc)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def kikaku(a)
|
||||
a.collect {|x| x - a[0]}
|
||||
end
|
||||
def ud(a)
|
||||
kikaku(a.collect {|x| ((x+NP)%ROW)-ROW*((x+NP)/ROW) }.sort)
|
||||
end
|
||||
def rl(a)
|
||||
kikaku(a.collect {|x| ROW*((x+NP)/ROW)+ROW-((x+NP)%ROW)}.sort)
|
||||
end
|
||||
def xy(a)
|
||||
kikaku(a.collect {|x| ROW*((x+NP)%ROW) + (x+NP)/ROW }.sort)
|
||||
end
|
||||
|
||||
def mkpieces
|
||||
piece(0,[],[0])
|
||||
$p.each do |a|
|
||||
a0 = a[0]
|
||||
a[1] = ud(a0)
|
||||
a[2] = rl(a0)
|
||||
a[3] = ud(rl(a0))
|
||||
a[4] = xy(a0)
|
||||
a[5] = ud(xy(a0))
|
||||
a[6] = rl(xy(a0))
|
||||
a[7] = ud(rl(xy(a0)))
|
||||
a.sort!
|
||||
a.uniq!
|
||||
end
|
||||
$p.uniq!.sort! {|x,y| x[0] <=> y[0] }
|
||||
end
|
||||
|
||||
def mkboard
|
||||
for i in 0...ROW*COL
|
||||
if i % ROW >= ROW-NP
|
||||
$b[i] = -2
|
||||
else
|
||||
$b[i] = -1
|
||||
end
|
||||
$b[3*ROW+3]=$b[3*ROW+4]=$b[4*ROW+3]=$b[4*ROW+4]=-2
|
||||
end
|
||||
end
|
||||
|
||||
def pboard
|
||||
print "No. #$no\n"
|
||||
for i in 0...COL
|
||||
print "|"
|
||||
for j in 0...ROW-NP
|
||||
x = $b[i*ROW+j]
|
||||
if x < 0
|
||||
print "..|"
|
||||
else
|
||||
printf "%2d|",x+1
|
||||
end
|
||||
end
|
||||
print "\n"
|
||||
end
|
||||
print "\n"
|
||||
end
|
||||
|
||||
$pnum=[]
|
||||
def setpiece(a,pos)
|
||||
if a.length == $p.length then
|
||||
$no += 1
|
||||
pboard
|
||||
return
|
||||
end
|
||||
while $b[pos] != -1
|
||||
pos += 1
|
||||
end
|
||||
($pnum - a).each do |i|
|
||||
$p[i].each do |x|
|
||||
f = 0
|
||||
for s in x do
|
||||
if $b[pos+s] != -1
|
||||
f=1
|
||||
break
|
||||
end
|
||||
end
|
||||
if f == 0 then
|
||||
for s in x do
|
||||
$b[pos+s] = i
|
||||
end
|
||||
a << i
|
||||
setpiece(a.clone, pos)
|
||||
a.pop
|
||||
for s in x do
|
||||
$b[pos+s] = -1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mkpieces
|
||||
mkboard
|
||||
$p[4] = [$p[4][0]]
|
||||
$pnum = (0...$p.length).to_a
|
||||
setpiece([],0)
|
8
benchmark/bm_app_raise.rb
Normal file
8
benchmark/bm_app_raise.rb
Normal file
@ -0,0 +1,8 @@
|
||||
i=0
|
||||
while i<300000
|
||||
i+=1
|
||||
begin
|
||||
raise
|
||||
rescue
|
||||
end
|
||||
end
|
5
benchmark/bm_app_strconcat.rb
Normal file
5
benchmark/bm_app_strconcat.rb
Normal file
@ -0,0 +1,5 @@
|
||||
i=0
|
||||
while i<500000
|
||||
"#{1+1} #{1+1} #{1+1}"
|
||||
i+=1
|
||||
end
|
13
benchmark/bm_app_tak.rb
Normal file
13
benchmark/bm_app_tak.rb
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
def tak x, y, z
|
||||
unless y < x
|
||||
z
|
||||
else
|
||||
tak( tak(x-1, y, z),
|
||||
tak(y-1, z, x),
|
||||
tak(z-1, x, y))
|
||||
end
|
||||
end
|
||||
|
||||
tak(18, 9, 0)
|
||||
|
10
benchmark/bm_app_tarai.rb
Normal file
10
benchmark/bm_app_tarai.rb
Normal file
@ -0,0 +1,10 @@
|
||||
def tarai( x, y, z )
|
||||
if x <= y
|
||||
then y
|
||||
else tarai(tarai(x-1, y, z),
|
||||
tarai(y-1, z, x),
|
||||
tarai(z-1, x, y))
|
||||
end
|
||||
end
|
||||
|
||||
tarai(12, 6, 0)
|
1
benchmark/bm_loop_times.rb
Normal file
1
benchmark/bm_loop_times.rb
Normal file
@ -0,0 +1 @@
|
||||
30000000.times{|e|}
|
4
benchmark/bm_loop_whileloop.rb
Normal file
4
benchmark/bm_loop_whileloop.rb
Normal file
@ -0,0 +1,4 @@
|
||||
i = 0
|
||||
while i<30000000 # benchmark loop 1
|
||||
i+=1
|
||||
end
|
5
benchmark/bm_loop_whileloop2.rb
Normal file
5
benchmark/bm_loop_whileloop2.rb
Normal file
@ -0,0 +1,5 @@
|
||||
i=0
|
||||
while i<6000000 # benchmark loop 2
|
||||
i+=1
|
||||
end
|
||||
|
19
benchmark/bm_so_ackermann.rb
Normal file
19
benchmark/bm_so_ackermann.rb
Normal file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/ruby
|
||||
# -*- mode: ruby -*-
|
||||
# $Id: ackermann-ruby.code,v 1.4 2004/11/13 07:40:41 bfulgham Exp $
|
||||
# http://www.bagley.org/~doug/shootout/
|
||||
|
||||
def ack(m, n)
|
||||
if m == 0 then
|
||||
n + 1
|
||||
elsif n == 0 then
|
||||
ack(m - 1, 1)
|
||||
else
|
||||
ack(m - 1, ack(m, n - 1))
|
||||
end
|
||||
end
|
||||
|
||||
NUM = 9
|
||||
ack(3, NUM)
|
||||
|
||||
|
23
benchmark/bm_so_array.rb
Normal file
23
benchmark/bm_so_array.rb
Normal file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/ruby
|
||||
# -*- mode: ruby -*-
|
||||
# $Id: ary-ruby.code,v 1.4 2004/11/13 07:41:27 bfulgham Exp $
|
||||
# http://www.bagley.org/~doug/shootout/
|
||||
# with help from Paul Brannan and Mark Hubbart
|
||||
|
||||
n = 9000 # Integer(ARGV.shift || 1)
|
||||
|
||||
x = Array.new(n)
|
||||
y = Array.new(n, 0)
|
||||
|
||||
n.times{|bi|
|
||||
x[bi] = bi + 1
|
||||
}
|
||||
|
||||
(0 .. 999).each do |e|
|
||||
(n-1).step(0,-1) do |bi|
|
||||
y[bi] += x.at(bi)
|
||||
end
|
||||
end
|
||||
# puts "#{y.first} #{y.last}"
|
||||
|
||||
|
18
benchmark/bm_so_concatenate.rb
Normal file
18
benchmark/bm_so_concatenate.rb
Normal file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/ruby
|
||||
# -*- mode: ruby -*-
|
||||
# $Id: strcat-ruby.code,v 1.4 2004/11/13 07:43:28 bfulgham Exp $
|
||||
# http://www.bagley.org/~doug/shootout/
|
||||
# based on code from Aristarkh A Zagorodnikov and Dat Nguyen
|
||||
|
||||
STUFF = "hello\n"
|
||||
i=0
|
||||
while i<10
|
||||
i+=1
|
||||
hello = ''
|
||||
400000.times do |e|
|
||||
hello << STUFF
|
||||
end
|
||||
end
|
||||
# puts hello.length
|
||||
|
||||
|
18
benchmark/bm_so_count_words.rb
Normal file
18
benchmark/bm_so_count_words.rb
Normal file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/ruby
|
||||
# -*- mode: ruby -*-
|
||||
# $Id: wc-ruby.code,v 1.4 2004/11/13 07:43:32 bfulgham Exp $
|
||||
# http://www.bagley.org/~doug/shootout/
|
||||
# with help from Paul Brannan
|
||||
|
||||
input = open(File.join(File.dirname($0), 'wc.input'), 'rb')
|
||||
|
||||
nl = nw = nc = 0
|
||||
while true
|
||||
data = (input.read(4096) or break) << (input.gets || "")
|
||||
nc += data.length
|
||||
nl += data.count("\n")
|
||||
((data.strip! || data).tr!("\n", " ") || data).squeeze!
|
||||
#nw += data.count(" ") + 1
|
||||
end
|
||||
# STDERR.puts "#{nl} #{nw} #{nc}"
|
||||
|
61
benchmark/bm_so_exception.rb
Normal file
61
benchmark/bm_so_exception.rb
Normal file
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/ruby
|
||||
# -*- mode: ruby -*-
|
||||
# $Id: except-ruby.code,v 1.4 2004/11/13 07:41:33 bfulgham Exp $
|
||||
# http://www.bagley.org/~doug/shootout/
|
||||
|
||||
$HI = 0
|
||||
$LO = 0
|
||||
NUM = 250000 # Integer(ARGV[0] || 1)
|
||||
|
||||
|
||||
class Lo_Exception < Exception
|
||||
def initialize(num)
|
||||
@value = num
|
||||
end
|
||||
end
|
||||
|
||||
class Hi_Exception < Exception
|
||||
def initialize(num)
|
||||
@value = num
|
||||
end
|
||||
end
|
||||
|
||||
def some_function(num)
|
||||
begin
|
||||
hi_function(num)
|
||||
rescue
|
||||
print "We shouldn't get here, exception is: #{$!.type}\n"
|
||||
end
|
||||
end
|
||||
|
||||
def hi_function(num)
|
||||
begin
|
||||
lo_function(num)
|
||||
rescue Hi_Exception
|
||||
$HI = $HI + 1
|
||||
end
|
||||
end
|
||||
|
||||
def lo_function(num)
|
||||
begin
|
||||
blowup(num)
|
||||
rescue Lo_Exception
|
||||
$LO = $LO + 1
|
||||
end
|
||||
end
|
||||
|
||||
def blowup(num)
|
||||
if num % 2 == 0
|
||||
raise Lo_Exception.new(num)
|
||||
else
|
||||
raise Hi_Exception.new(num)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
i = 1
|
||||
max = NUM+1
|
||||
while i < max
|
||||
i+=1
|
||||
some_function(i+1)
|
||||
end
|
47
benchmark/bm_so_lists.rb
Normal file
47
benchmark/bm_so_lists.rb
Normal file
@ -0,0 +1,47 @@
|
||||
#from http://www.bagley.org/~doug/shootout/bench/lists/lists.ruby
|
||||
|
||||
NUM = 100
|
||||
SIZE = 10000
|
||||
|
||||
def test_lists()
|
||||
# create a list of integers (Li1) from 1 to SIZE
|
||||
li1 = (1..SIZE).to_a
|
||||
# copy the list to li2 (not by individual items)
|
||||
li2 = li1.dup
|
||||
# remove each individual item from left side of li2 and
|
||||
# append to right side of li3 (preserving order)
|
||||
li3 = Array.new
|
||||
while (not li2.empty?)
|
||||
li3.push(li2.shift)
|
||||
end
|
||||
# li2 must now be empty
|
||||
# remove each individual item from right side of li3 and
|
||||
# append to right side of li2 (reversing list)
|
||||
while (not li3.empty?)
|
||||
li2.push(li3.pop)
|
||||
end
|
||||
# li3 must now be empty
|
||||
# reverse li1 in place
|
||||
li1.reverse!
|
||||
# check that first item is now SIZE
|
||||
if li1[0] != SIZE then
|
||||
p "not SIZE"
|
||||
0
|
||||
else
|
||||
# compare li1 and li2 for equality
|
||||
if li1 != li2 then
|
||||
return(0)
|
||||
else
|
||||
# return the length of the list
|
||||
li1.length
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
i = 0
|
||||
while i<NUM
|
||||
i+=1
|
||||
result = test_lists()
|
||||
end
|
||||
|
||||
result
|
48
benchmark/bm_so_matrix.rb
Normal file
48
benchmark/bm_so_matrix.rb
Normal file
@ -0,0 +1,48 @@
|
||||
#!/usr/bin/ruby
|
||||
# -*- mode: ruby -*-
|
||||
# $Id: matrix-ruby.code,v 1.4 2004/11/13 07:42:14 bfulgham Exp $
|
||||
# http://www.bagley.org/~doug/shootout/
|
||||
|
||||
n = 60 #Integer(ARGV.shift || 1)
|
||||
|
||||
size = 30
|
||||
|
||||
def mkmatrix(rows, cols)
|
||||
count = 1
|
||||
mx = Array.new(rows)
|
||||
(0 .. (rows - 1)).each do |bi|
|
||||
row = Array.new(cols, 0)
|
||||
(0 .. (cols - 1)).each do |j|
|
||||
row[j] = count
|
||||
count += 1
|
||||
end
|
||||
mx[bi] = row
|
||||
end
|
||||
mx
|
||||
end
|
||||
|
||||
def mmult(rows, cols, m1, m2)
|
||||
m3 = Array.new(rows)
|
||||
(0 .. (rows - 1)).each do |bi|
|
||||
row = Array.new(cols, 0)
|
||||
(0 .. (cols - 1)).each do |j|
|
||||
val = 0
|
||||
(0 .. (cols - 1)).each do |k|
|
||||
val += m1.at(bi).at(k) * m2.at(k).at(j)
|
||||
end
|
||||
row[j] = val
|
||||
end
|
||||
m3[bi] = row
|
||||
end
|
||||
m3
|
||||
end
|
||||
|
||||
m1 = mkmatrix(size, size)
|
||||
m2 = mkmatrix(size, size)
|
||||
mm = Array.new
|
||||
n.times do
|
||||
mm = mmult(size, size, m1, m2)
|
||||
end
|
||||
# puts "#{mm[0][0]} #{mm[2][3]} #{mm[3][2]} #{mm[4][4]}"
|
||||
|
||||
|
24
benchmark/bm_so_nested_loop.rb
Normal file
24
benchmark/bm_so_nested_loop.rb
Normal file
@ -0,0 +1,24 @@
|
||||
#!/usr/bin/ruby
|
||||
# -*- mode: ruby -*-
|
||||
# $Id: nestedloop-ruby.code,v 1.4 2004/11/13 07:42:22 bfulgham Exp $
|
||||
# http://www.bagley.org/~doug/shootout/
|
||||
# from Avi Bryant
|
||||
|
||||
n = 16 # Integer(ARGV.shift || 1)
|
||||
x = 0
|
||||
n.times do
|
||||
n.times do
|
||||
n.times do
|
||||
n.times do
|
||||
n.times do
|
||||
n.times do
|
||||
x += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
# puts x
|
||||
|
||||
|
56
benchmark/bm_so_object.rb
Normal file
56
benchmark/bm_so_object.rb
Normal file
@ -0,0 +1,56 @@
|
||||
#!/usr/bin/ruby
|
||||
# -*- mode: ruby -*-
|
||||
# $Id: objinst-ruby.code,v 1.4 2004/11/13 07:42:25 bfulgham Exp $
|
||||
# http://www.bagley.org/~doug/shootout/
|
||||
# with help from Aristarkh Zagorodnikov
|
||||
|
||||
class Toggle
|
||||
def initialize(start_state)
|
||||
@bool = start_state
|
||||
end
|
||||
|
||||
def value
|
||||
@bool
|
||||
end
|
||||
|
||||
def activate
|
||||
@bool = !@bool
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
class NthToggle < Toggle
|
||||
def initialize(start_state, max_counter)
|
||||
super start_state
|
||||
@count_max = max_counter
|
||||
@counter = 0
|
||||
end
|
||||
|
||||
def activate
|
||||
@counter += 1
|
||||
if @counter >= @count_max
|
||||
@bool = !@bool
|
||||
@counter = 0
|
||||
end
|
||||
self
|
||||
end
|
||||
end
|
||||
|
||||
n = 1500000 # (ARGV.shift || 1).to_i
|
||||
|
||||
toggle = Toggle.new 1
|
||||
5.times do
|
||||
toggle.activate.value ? 'true' : 'false'
|
||||
end
|
||||
n.times do
|
||||
toggle = Toggle.new 1
|
||||
end
|
||||
|
||||
ntoggle = NthToggle.new 1, 3
|
||||
8.times do
|
||||
ntoggle.activate.value ? 'true' : 'false'
|
||||
end
|
||||
n.times do
|
||||
ntoggle = NthToggle.new 1, 3
|
||||
end
|
||||
|
20
benchmark/bm_so_random.rb
Normal file
20
benchmark/bm_so_random.rb
Normal file
@ -0,0 +1,20 @@
|
||||
# from http://www.bagley.org/~doug/shootout/bench/random/random.ruby
|
||||
|
||||
IM = 139968.0
|
||||
IA = 3877.0
|
||||
IC = 29573.0
|
||||
|
||||
$last = 42.0
|
||||
|
||||
def gen_random(max)
|
||||
(max * ($last = ($last * IA + IC) % IM)) / IM
|
||||
end
|
||||
|
||||
N = 1000000
|
||||
|
||||
i=0
|
||||
while i<N
|
||||
i+=1
|
||||
gen_random(100.0)
|
||||
end
|
||||
# "%.9f" % gen_random(100.0)
|
24
benchmark/bm_so_sieve.rb
Normal file
24
benchmark/bm_so_sieve.rb
Normal file
@ -0,0 +1,24 @@
|
||||
# from http://www.bagley.org/~doug/shootout/bench/sieve/sieve.ruby
|
||||
num = 40
|
||||
count = i = j = 0
|
||||
flags0 = Array.new(8192,1)
|
||||
k = 0
|
||||
while k < num
|
||||
k+=1
|
||||
count = 0
|
||||
flags = flags0.dup
|
||||
i = 2
|
||||
while i<8192
|
||||
i+=1
|
||||
if flags[i]
|
||||
# remove all multiples of prime: i
|
||||
j = i*i
|
||||
while j < 8192
|
||||
j += i
|
||||
flags[j] = nil
|
||||
end
|
||||
count += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
count
|
10
benchmark/bm_vm1_block.rb
Normal file
10
benchmark/bm_vm1_block.rb
Normal file
@ -0,0 +1,10 @@
|
||||
def m
|
||||
yield
|
||||
end
|
||||
|
||||
i=0
|
||||
while i<30000000 # while loop 1
|
||||
i+=1
|
||||
m{
|
||||
}
|
||||
end
|
8
benchmark/bm_vm1_const.rb
Normal file
8
benchmark/bm_vm1_const.rb
Normal file
@ -0,0 +1,8 @@
|
||||
Const = 1
|
||||
|
||||
i = 0
|
||||
while i<30000000 # while loop 1
|
||||
i+= 1
|
||||
j = Const
|
||||
k = Const
|
||||
end
|
11
benchmark/bm_vm1_ensure.rb
Normal file
11
benchmark/bm_vm1_ensure.rb
Normal file
@ -0,0 +1,11 @@
|
||||
i=0
|
||||
while i<30000000 # benchmark loop 1
|
||||
i+=1
|
||||
begin
|
||||
begin
|
||||
ensure
|
||||
end
|
||||
ensure
|
||||
end
|
||||
end
|
||||
|
9
benchmark/bm_vm1_length.rb
Normal file
9
benchmark/bm_vm1_length.rb
Normal file
@ -0,0 +1,9 @@
|
||||
a = 'abc'
|
||||
b = [1, 2, 3]
|
||||
i=0
|
||||
while i<30000000 # while loop 1
|
||||
i+=1
|
||||
a.length
|
||||
b.length
|
||||
end
|
||||
|
7
benchmark/bm_vm1_rescue.rb
Normal file
7
benchmark/bm_vm1_rescue.rb
Normal file
@ -0,0 +1,7 @@
|
||||
i=0
|
||||
while i<30000000 # while loop 1
|
||||
i+=1
|
||||
begin
|
||||
rescue
|
||||
end
|
||||
end
|
9
benchmark/bm_vm1_simplereturn.rb
Normal file
9
benchmark/bm_vm1_simplereturn.rb
Normal file
@ -0,0 +1,9 @@
|
||||
def m
|
||||
return 1
|
||||
end
|
||||
i=0
|
||||
while i<30000000 # while loop 1
|
||||
i+=1
|
||||
m
|
||||
end
|
||||
|
8
benchmark/bm_vm1_swap.rb
Normal file
8
benchmark/bm_vm1_swap.rb
Normal file
@ -0,0 +1,8 @@
|
||||
a = 1
|
||||
b = 2
|
||||
i=0
|
||||
while i<30000000 # while loop 1
|
||||
i+=1
|
||||
a, b = b, a
|
||||
end
|
||||
|
5
benchmark/bm_vm2_array.rb
Normal file
5
benchmark/bm_vm2_array.rb
Normal file
@ -0,0 +1,5 @@
|
||||
i=0
|
||||
while i<6000000 # benchmark loop 2
|
||||
i+=1
|
||||
a = [1,2,3,4,5,6,7,8,9,10]
|
||||
end
|
9
benchmark/bm_vm2_method.rb
Normal file
9
benchmark/bm_vm2_method.rb
Normal file
@ -0,0 +1,9 @@
|
||||
def m
|
||||
nil
|
||||
end
|
||||
|
||||
i=0
|
||||
while i<6000000 # benchmark loop 2
|
||||
i+=1
|
||||
m; m; m; m; m; m; m; m;
|
||||
end
|
20
benchmark/bm_vm2_poly_method.rb
Normal file
20
benchmark/bm_vm2_poly_method.rb
Normal file
@ -0,0 +1,20 @@
|
||||
class C1
|
||||
def m
|
||||
1
|
||||
end
|
||||
end
|
||||
class C2
|
||||
def m
|
||||
2
|
||||
end
|
||||
end
|
||||
|
||||
o1 = C1.new
|
||||
o2 = C2.new
|
||||
|
||||
i=0
|
||||
while i<6000000 # benchmark loop 2
|
||||
o = (i % 2 == 0) ? o1 : o2
|
||||
o.m; o.m; o.m; o.m; o.m; o.m; o.m; o.m
|
||||
i+=1
|
||||
end
|
20
benchmark/bm_vm2_poly_method_ov.rb
Normal file
20
benchmark/bm_vm2_poly_method_ov.rb
Normal file
@ -0,0 +1,20 @@
|
||||
class C1
|
||||
def m
|
||||
1
|
||||
end
|
||||
end
|
||||
class C2
|
||||
def m
|
||||
2
|
||||
end
|
||||
end
|
||||
|
||||
o1 = C1.new
|
||||
o2 = C2.new
|
||||
|
||||
i=0
|
||||
while i<6000000 # benchmark loop 2
|
||||
o = (i % 2 == 0) ? o1 : o2
|
||||
# o.m; o.m; o.m; o.m; o.m; o.m; o.m; o.m
|
||||
i+=1
|
||||
end
|
14
benchmark/bm_vm2_proc.rb
Normal file
14
benchmark/bm_vm2_proc.rb
Normal file
@ -0,0 +1,14 @@
|
||||
def m &b
|
||||
b
|
||||
end
|
||||
|
||||
pr = m{
|
||||
a = 1
|
||||
}
|
||||
|
||||
i=0
|
||||
while i<6000000 # benchmark loop 2
|
||||
i+=1
|
||||
pr.call
|
||||
end
|
||||
|
6
benchmark/bm_vm2_regexp.rb
Normal file
6
benchmark/bm_vm2_regexp.rb
Normal file
@ -0,0 +1,6 @@
|
||||
i=0
|
||||
str = 'xxxhogexxx'
|
||||
while i<6000000 # benchmark loop 2
|
||||
/hoge/ =~ str
|
||||
i+=1
|
||||
end
|
12
benchmark/bm_vm2_send.rb
Normal file
12
benchmark/bm_vm2_send.rb
Normal file
@ -0,0 +1,12 @@
|
||||
class C
|
||||
def m
|
||||
end
|
||||
end
|
||||
|
||||
o = C.new
|
||||
|
||||
i=0
|
||||
while i<6000000 # benchmark loop 2
|
||||
i+=1
|
||||
o.__send__ :m
|
||||
end
|
20
benchmark/bm_vm2_super.rb
Normal file
20
benchmark/bm_vm2_super.rb
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
class C
|
||||
def m
|
||||
1
|
||||
end
|
||||
end
|
||||
|
||||
class CC < C
|
||||
def m
|
||||
super()
|
||||
end
|
||||
end
|
||||
|
||||
obj = CC.new
|
||||
|
||||
i = 0
|
||||
while i<6000000 # benchmark loop 2
|
||||
obj.m
|
||||
i+=1
|
||||
end
|
8
benchmark/bm_vm2_unif1.rb
Normal file
8
benchmark/bm_vm2_unif1.rb
Normal file
@ -0,0 +1,8 @@
|
||||
i = 0
|
||||
def m a, b
|
||||
end
|
||||
|
||||
while i<6000000 # benchmark loop 2
|
||||
i+=1
|
||||
m 100, 200
|
||||
end
|
20
benchmark/bm_vm2_zsuper.rb
Normal file
20
benchmark/bm_vm2_zsuper.rb
Normal file
@ -0,0 +1,20 @@
|
||||
i = 0
|
||||
|
||||
class C
|
||||
def m a
|
||||
1
|
||||
end
|
||||
end
|
||||
|
||||
class CC < C
|
||||
def m a
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
obj = CC.new
|
||||
|
||||
while i<6000000 # benchmark loop 2
|
||||
obj.m 10
|
||||
i+=1
|
||||
end
|
6
benchmark/bm_vm3_thread_create_join.rb
Normal file
6
benchmark/bm_vm3_thread_create_join.rb
Normal file
@ -0,0 +1,6 @@
|
||||
i=0
|
||||
while i<1000 # benchmark loop 3
|
||||
i+=1
|
||||
Thread.new{
|
||||
}.join
|
||||
end
|
57
benchmark/bmx_temp.rb
Normal file
57
benchmark/bmx_temp.rb
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
i=0
|
||||
while i<20000000
|
||||
x = 1 # "foo"
|
||||
i+=1
|
||||
end
|
||||
|
||||
__END__
|
||||
|
||||
class Range
|
||||
def each
|
||||
f = self.first
|
||||
l = self.last
|
||||
while f < l
|
||||
yield
|
||||
f = f.succ
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
(0..10000000).each{
|
||||
}
|
||||
|
||||
__END__
|
||||
class Fixnum_
|
||||
def times
|
||||
i = 0
|
||||
while i<self
|
||||
yield(i)
|
||||
i+=1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
10000000.times{
|
||||
}
|
||||
__END__
|
||||
|
||||
ths = (1..10).map{
|
||||
Thread.new{
|
||||
1000000.times{
|
||||
}
|
||||
}
|
||||
}
|
||||
ths.each{|e|
|
||||
e.join
|
||||
}
|
||||
|
||||
__END__
|
||||
$pr = proc{}
|
||||
def m
|
||||
$pr.call
|
||||
end
|
||||
|
||||
1000000.times{|e|
|
||||
m
|
||||
}
|
11
benchmark/other-lang/ack.pl
Normal file
11
benchmark/other-lang/ack.pl
Normal file
@ -0,0 +1,11 @@
|
||||
use integer;
|
||||
|
||||
sub Ack {
|
||||
return $_[0] ? ($_[1] ? Ack($_[0]-1, Ack($_[0], $_[1]-1))
|
||||
: Ack($_[0]-1, 1))
|
||||
: $_[1]+1;
|
||||
}
|
||||
|
||||
my $NUM = 9;
|
||||
$NUM = 1 if ($NUM < 1);
|
||||
my $ack = Ack(3, $NUM);
|
16
benchmark/other-lang/ack.py
Normal file
16
benchmark/other-lang/ack.py
Normal file
@ -0,0 +1,16 @@
|
||||
import sys
|
||||
sys.setrecursionlimit(5000000)
|
||||
|
||||
def Ack(M, N):
|
||||
if (not M):
|
||||
return( N + 1 )
|
||||
if (not N):
|
||||
return( Ack(M-1, 1) )
|
||||
return( Ack(M-1, Ack(M, N-1)) )
|
||||
|
||||
def main():
|
||||
NUM = 9
|
||||
sys.setrecursionlimit(10000)
|
||||
Ack(3, NUM)
|
||||
|
||||
main()
|
12
benchmark/other-lang/ack.rb
Normal file
12
benchmark/other-lang/ack.rb
Normal file
@ -0,0 +1,12 @@
|
||||
def ack(m, n)
|
||||
if m == 0 then
|
||||
n + 1
|
||||
elsif n == 0 then
|
||||
ack(m - 1, 1)
|
||||
else
|
||||
ack(m - 1, ack(m, n - 1))
|
||||
end
|
||||
end
|
||||
|
||||
NUM = 9
|
||||
ack(3, NUM)
|
7
benchmark/other-lang/ack.scm
Normal file
7
benchmark/other-lang/ack.scm
Normal file
@ -0,0 +1,7 @@
|
||||
(define (ack m n)
|
||||
(cond ((zero? m) (+ n 1))
|
||||
((zero? n) (ack (- m 1) 1))
|
||||
(else (ack (- m 1) (ack m (- n 1))))))
|
||||
|
||||
(ack 3 9)
|
||||
|
66
benchmark/other-lang/eval.rb
Normal file
66
benchmark/other-lang/eval.rb
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
Bench = %w(
|
||||
loop
|
||||
ack
|
||||
fib
|
||||
tak
|
||||
fact
|
||||
)
|
||||
|
||||
Lang = <<EOP.map{|l| l.strip}
|
||||
ruby-cyg
|
||||
../../../test6/miniruby
|
||||
perl
|
||||
python
|
||||
gosh
|
||||
EOP
|
||||
|
||||
Bench.replace ['loop2']
|
||||
Lang.replace ['ruby-cyg']
|
||||
|
||||
Ext = %w(
|
||||
.rb
|
||||
.rb
|
||||
.pl
|
||||
.py
|
||||
.scm
|
||||
)
|
||||
|
||||
p Bench
|
||||
p Lang
|
||||
|
||||
require 'benchmark'
|
||||
|
||||
def bench cmd
|
||||
m = Benchmark.measure{
|
||||
#p cmd
|
||||
system(cmd)
|
||||
}
|
||||
[m.utime, m.real]
|
||||
end
|
||||
|
||||
Result = []
|
||||
Bench.each{|b|
|
||||
r = []
|
||||
Lang.each_with_index{|l, idx|
|
||||
cmd = "#{l} #{b}#{Ext[idx]}"
|
||||
r << bench(cmd)
|
||||
}
|
||||
Result << r
|
||||
}
|
||||
|
||||
require 'pp'
|
||||
# utime
|
||||
puts Lang.join("\t")
|
||||
Bench.each_with_index{|b, bi|
|
||||
print b, "\t"
|
||||
puts Result[bi].map{|e| e[0]}.join("\t")
|
||||
}
|
||||
|
||||
# rtime
|
||||
puts Lang.join("\t")
|
||||
Bench.each_with_index{|b, bi|
|
||||
print b, "\t"
|
||||
puts Result[bi].map{|e| e[1]}.join("\t")
|
||||
}
|
||||
|
13
benchmark/other-lang/fact.pl
Normal file
13
benchmark/other-lang/fact.pl
Normal file
@ -0,0 +1,13 @@
|
||||
sub fact{
|
||||
my $n = @_[0];
|
||||
if($n < 2){
|
||||
return 1;
|
||||
}
|
||||
else{
|
||||
return $n * fact($n-1);
|
||||
}
|
||||
}
|
||||
|
||||
for($i=0; $i<10000; $i++){
|
||||
&fact(100);
|
||||
}
|
18
benchmark/other-lang/fact.py
Normal file
18
benchmark/other-lang/fact.py
Normal file
@ -0,0 +1,18 @@
|
||||
#import sys
|
||||
#sys.setrecursionlimit(1000)
|
||||
|
||||
def factL(n):
|
||||
r = 1
|
||||
for x in range(2, n):
|
||||
r *= x
|
||||
return r
|
||||
|
||||
def factR(n):
|
||||
if n < 2:
|
||||
return 1
|
||||
else:
|
||||
return n * factR(n-1)
|
||||
|
||||
for i in range(10000):
|
||||
factR(100)
|
||||
|
13
benchmark/other-lang/fact.rb
Normal file
13
benchmark/other-lang/fact.rb
Normal file
@ -0,0 +1,13 @@
|
||||
def fact(n)
|
||||
if n < 2
|
||||
1
|
||||
else
|
||||
n * fact(n-1)
|
||||
end
|
||||
end
|
||||
|
||||
i=0
|
||||
while i<10000
|
||||
i+=1
|
||||
fact(100)
|
||||
end
|
8
benchmark/other-lang/fact.scm
Normal file
8
benchmark/other-lang/fact.scm
Normal file
@ -0,0 +1,8 @@
|
||||
(define (fact n)
|
||||
(if (< n 2)
|
||||
1
|
||||
(* n (fact (- n 1)))))
|
||||
|
||||
(dotimes (i 10000)
|
||||
(fact 100))
|
||||
|
11
benchmark/other-lang/fib.pl
Normal file
11
benchmark/other-lang/fib.pl
Normal file
@ -0,0 +1,11 @@
|
||||
sub fib{
|
||||
my $n = $_[0];
|
||||
if($n < 3){
|
||||
return 1;
|
||||
}
|
||||
else{
|
||||
return fib($n-1) + fib($n-2);
|
||||
}
|
||||
};
|
||||
|
||||
&fib(34);
|
7
benchmark/other-lang/fib.py
Normal file
7
benchmark/other-lang/fib.py
Normal file
@ -0,0 +1,7 @@
|
||||
def fib(n):
|
||||
if n < 3:
|
||||
return 1
|
||||
else:
|
||||
return fib(n-1) + fib(n-2)
|
||||
|
||||
fib(34)
|
9
benchmark/other-lang/fib.rb
Normal file
9
benchmark/other-lang/fib.rb
Normal file
@ -0,0 +1,9 @@
|
||||
def fib n
|
||||
if n < 3
|
||||
1
|
||||
else
|
||||
fib(n-1) + fib(n-2)
|
||||
end
|
||||
end
|
||||
|
||||
fib(34)
|
7
benchmark/other-lang/fib.scm
Normal file
7
benchmark/other-lang/fib.scm
Normal file
@ -0,0 +1,7 @@
|
||||
(define (fib n)
|
||||
(if (< n 3)
|
||||
1
|
||||
(+ (fib (- n 1)) (fib (- n 2)))))
|
||||
|
||||
(fib 34)
|
||||
|
3
benchmark/other-lang/loop.pl
Normal file
3
benchmark/other-lang/loop.pl
Normal file
@ -0,0 +1,3 @@
|
||||
for($i=0; $i<30000000; $i++){
|
||||
}
|
||||
|
2
benchmark/other-lang/loop.py
Normal file
2
benchmark/other-lang/loop.py
Normal file
@ -0,0 +1,2 @@
|
||||
for i in xrange(30000000):
|
||||
pass
|
4
benchmark/other-lang/loop.rb
Normal file
4
benchmark/other-lang/loop.rb
Normal file
@ -0,0 +1,4 @@
|
||||
i=0
|
||||
while i<30000000
|
||||
i+=1
|
||||
end
|
1
benchmark/other-lang/loop.scm
Normal file
1
benchmark/other-lang/loop.scm
Normal file
@ -0,0 +1 @@
|
||||
(dotimes (x 30000000))
|
1
benchmark/other-lang/loop2.rb
Normal file
1
benchmark/other-lang/loop2.rb
Normal file
@ -0,0 +1 @@
|
||||
30000000.times{}
|
11
benchmark/other-lang/tak.pl
Normal file
11
benchmark/other-lang/tak.pl
Normal file
@ -0,0 +1,11 @@
|
||||
sub tak {
|
||||
local($x, $y, $z) = @_;
|
||||
if (!($y < $x)) {
|
||||
return $z;
|
||||
} else {
|
||||
return &tak(&tak($x - 1, $y, $z),
|
||||
&tak($y - 1, $z, $x),
|
||||
&tak($z - 1, $x, $y));
|
||||
}
|
||||
}
|
||||
&tak(18, 9, 0);
|
8
benchmark/other-lang/tak.py
Normal file
8
benchmark/other-lang/tak.py
Normal file
@ -0,0 +1,8 @@
|
||||
def tak(x, y, z):
|
||||
if not(y<x):
|
||||
return z
|
||||
else:
|
||||
return tak(tak(x-1, y, z),
|
||||
tak(y-1, z, x),
|
||||
tak(z-1, x, y))
|
||||
tak(18, 9, 0)
|
13
benchmark/other-lang/tak.rb
Normal file
13
benchmark/other-lang/tak.rb
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
def tak x, y, z
|
||||
unless y < x
|
||||
z
|
||||
else
|
||||
tak( tak(x-1, y, z),
|
||||
tak(y-1, z, x),
|
||||
tak(z-1, x, y))
|
||||
end
|
||||
end
|
||||
|
||||
tak(18, 9, 0)
|
||||
|
10
benchmark/other-lang/tak.scm
Normal file
10
benchmark/other-lang/tak.scm
Normal file
@ -0,0 +1,10 @@
|
||||
(define (tak x y z)
|
||||
(if (not (< y x))
|
||||
z
|
||||
(tak (tak (- x 1) y z)
|
||||
(tak (- y 1) z x)
|
||||
(tak (- z 1) x y))))
|
||||
|
||||
(tak 18 9 0)
|
||||
|
||||
|
81
benchmark/report.rb
Normal file
81
benchmark/report.rb
Normal file
@ -0,0 +1,81 @@
|
||||
#
|
||||
# YARV benchmark driver
|
||||
#
|
||||
|
||||
require 'yarvutil'
|
||||
require 'benchmark'
|
||||
require 'rbconfig'
|
||||
|
||||
def exec_command type, file, w
|
||||
<<-EOP
|
||||
$DRIVER_PATH = '#{File.dirname($0)}'
|
||||
$LOAD_PATH.replace $LOAD_PATH | #{$LOAD_PATH.inspect}
|
||||
require 'benchmark'
|
||||
require 'yarvutil'
|
||||
# print '#{type}'
|
||||
begin
|
||||
puts Benchmark.measure{
|
||||
#{w}('#{file}')
|
||||
}.utime
|
||||
rescue Exception => exec_command_error_variable
|
||||
puts "\t" + exec_command_error_variable.message
|
||||
end
|
||||
EOP
|
||||
end
|
||||
|
||||
def benchmark cmd
|
||||
rubybin = ENV['RUBY'] || File.join(
|
||||
Config::CONFIG["bindir"],
|
||||
Config::CONFIG["ruby_install_name"] + Config::CONFIG["EXEEXT"])
|
||||
|
||||
IO.popen(rubybin, 'r+'){|io|
|
||||
io.write cmd
|
||||
io.close_write
|
||||
return io.gets
|
||||
}
|
||||
end
|
||||
|
||||
def ruby_exec file
|
||||
prog = exec_command 'ruby', file, 'load'
|
||||
benchmark prog
|
||||
end
|
||||
|
||||
def yarv_exec file
|
||||
prog = exec_command 'yarv', file, 'YARVUtil.load_bm'
|
||||
benchmark prog
|
||||
end
|
||||
|
||||
$wr = $wy = nil
|
||||
|
||||
def measure bench
|
||||
file = File.dirname($0) + "/bm_#{bench}.rb"
|
||||
r = ruby_exec(file).to_f
|
||||
y = yarv_exec(file).to_f
|
||||
puts "#{bench}\t#{r}\t#{y}"
|
||||
end
|
||||
|
||||
def measure2
|
||||
r = ruby_exec.to_f
|
||||
y = yarv_exec.to_f
|
||||
puts r/y
|
||||
end
|
||||
|
||||
if $0 == __FILE__
|
||||
%w{
|
||||
whileloop
|
||||
whileloop2
|
||||
times
|
||||
const
|
||||
method
|
||||
poly_method
|
||||
block
|
||||
rescue
|
||||
rescue2
|
||||
}.each{|bench|
|
||||
measure bench
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
137
benchmark/run.rb
Normal file
137
benchmark/run.rb
Normal file
@ -0,0 +1,137 @@
|
||||
#
|
||||
# YARV benchmark driver
|
||||
#
|
||||
|
||||
require 'yarvutil'
|
||||
require 'benchmark'
|
||||
require 'rbconfig'
|
||||
|
||||
$yarvonly = false
|
||||
$rubyonly = false
|
||||
|
||||
$results = []
|
||||
|
||||
puts "ruby #{RUBY_VERSION} #{RUBY_PLATFORM}(#{RUBY_RELEASE_DATE})"
|
||||
puts YARVCore::VERSION + " rev: #{YARVCore::REV} (#{YARVCore::DATE})"
|
||||
puts YARVCore::OPTS
|
||||
puts
|
||||
|
||||
def bm file
|
||||
prog = File.read(file).map{|e| e.rstrip}.join("\n")
|
||||
return if prog.empty?
|
||||
|
||||
/[a-z]+_(.+)\.rb/ =~ file
|
||||
bm_name = $1
|
||||
puts '-----------------------------------------------------------' unless $yarvonly || $rubyonly
|
||||
puts "#{bm_name}: "
|
||||
|
||||
|
||||
puts <<EOS unless $yarvonly || $rubyonly
|
||||
#{prog}
|
||||
--
|
||||
EOS
|
||||
#iseq = YARVUtil.parse(File.read(file))
|
||||
#vm = YARVCore::VM.new
|
||||
begin
|
||||
Benchmark.bm{|x|
|
||||
# x.report("yarv"){ YARVUtil.load_bm(file) }
|
||||
} unless $yarvonly || $rubyonly
|
||||
|
||||
result = [bm_name]
|
||||
result << ruby_exec(file) unless $yarvonly
|
||||
result << yarv_exec(file) unless $rubyonly
|
||||
$results << result
|
||||
|
||||
# puts YARVUtil.parse(File.read(file), file, 1).disasm
|
||||
|
||||
# x.report("ruby"){ load(file, false) }
|
||||
# x.report("yarv"){ vm.eval iseq }
|
||||
rescue Exception => e
|
||||
puts
|
||||
puts "** benchmark failure: #{e}"
|
||||
puts e.backtrace
|
||||
end
|
||||
end
|
||||
|
||||
def exec_command type, file, w
|
||||
<<-EOP
|
||||
$DRIVER_PATH = '#{File.dirname($0)}'
|
||||
$LOAD_PATH.replace $LOAD_PATH | #{$LOAD_PATH.inspect}
|
||||
require 'benchmark'
|
||||
require 'yarvutil'
|
||||
print '#{type}'
|
||||
begin
|
||||
puts Benchmark.measure{
|
||||
#{w}('#{file}')
|
||||
}
|
||||
rescue Exception => exec_command_error_variable
|
||||
puts "\t" + exec_command_error_variable.message
|
||||
end
|
||||
EOP
|
||||
end
|
||||
|
||||
def benchmark prog
|
||||
rubybin = ENV['RUBY'] || File.join(
|
||||
Config::CONFIG["bindir"],
|
||||
Config::CONFIG["ruby_install_name"] + Config::CONFIG["EXEEXT"])
|
||||
|
||||
#
|
||||
tmpfile = Tempfile.new('yarvbench')
|
||||
tmpfile.write(prog)
|
||||
tmpfile.close
|
||||
|
||||
cmd = "#{rubybin} #{tmpfile.path}"
|
||||
result = `#{cmd}`
|
||||
puts result
|
||||
tmpfile.close(true)
|
||||
result
|
||||
end
|
||||
|
||||
def ruby_exec file
|
||||
prog = exec_command 'ruby', file, 'load'
|
||||
benchmark prog
|
||||
end
|
||||
|
||||
def yarv_exec file
|
||||
prog = exec_command 'yarv', file, 'YARVUtil.load_bm'
|
||||
benchmark prog
|
||||
end
|
||||
|
||||
if $0 == __FILE__
|
||||
ARGV.each{|arg|
|
||||
if /\A(--yarv)|(-y)/ =~ arg
|
||||
$yarvonly = true
|
||||
elsif /\A(--ruby)|(-r)/ =~ arg
|
||||
$rubyonly = true
|
||||
end
|
||||
}
|
||||
ARGV.delete_if{|arg|
|
||||
/\A-/ =~ arg
|
||||
}
|
||||
|
||||
if ARGV.empty?
|
||||
Dir.glob(File.dirname(__FILE__) + '/bm_*.rb').sort.each{|file|
|
||||
bm file
|
||||
}
|
||||
else
|
||||
ARGV.each{|file|
|
||||
Dir.glob(File.join(File.dirname(__FILE__), file + '*')){|ef|
|
||||
# file = "#{File.dirname(__FILE__)}/#{file}.rb"
|
||||
bm ef
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
puts
|
||||
puts "-- benchmark summary ---------------------------"
|
||||
$results.each{|res|
|
||||
print res.shift, "\t"
|
||||
(res||[]).each{|result|
|
||||
/([\d\.]+)/ =~ result
|
||||
print $1 + "\t" if $1
|
||||
}
|
||||
puts
|
||||
}
|
||||
end
|
||||
|
||||
|
129
benchmark/run_rite.rb
Normal file
129
benchmark/run_rite.rb
Normal file
@ -0,0 +1,129 @@
|
||||
#
|
||||
# YARV benchmark driver
|
||||
#
|
||||
|
||||
require 'benchmark'
|
||||
require 'rbconfig'
|
||||
|
||||
$yarvonly = false
|
||||
$rubyonly = false
|
||||
|
||||
$results = []
|
||||
|
||||
# prepare 'wc.input'
|
||||
def prepare_wc_input
|
||||
wcinput = File.join(File.dirname($0), 'wc.input')
|
||||
wcbase = File.join(File.dirname($0), 'wc.input.base')
|
||||
unless FileTest.exist?(wcinput)
|
||||
data = File.read(wcbase)
|
||||
13.times{
|
||||
data << data
|
||||
}
|
||||
open(wcinput, 'w'){|f| f.write data}
|
||||
end
|
||||
end
|
||||
|
||||
prepare_wc_input
|
||||
|
||||
def bm file
|
||||
prog = File.read(file).map{|e| e.rstrip}.join("\n")
|
||||
return if prog.empty?
|
||||
|
||||
/[a-z]+_(.+)\.rb/ =~ file
|
||||
bm_name = $1
|
||||
puts '-----------------------------------------------------------' unless $yarvonly || $rubyonly
|
||||
puts "#{bm_name}: "
|
||||
|
||||
|
||||
puts <<EOS unless $yarvonly || $rubyonly
|
||||
#{prog}
|
||||
--
|
||||
EOS
|
||||
#iseq = YARVUtil.parse(File.read(file))
|
||||
#vm = YARVCore::VM.new
|
||||
begin
|
||||
result = [bm_name]
|
||||
result << ruby_exec(file) unless $yarvonly
|
||||
result << yarv_exec(file) unless $rubyonly
|
||||
$results << result
|
||||
|
||||
# puts YARVUtil.parse(File.read(file), file, 1).disasm
|
||||
|
||||
# x.report("ruby"){ load(file, false) }
|
||||
# x.report("yarv"){ vm.eval iseq }
|
||||
rescue Exception => e
|
||||
puts
|
||||
puts "** benchmark failure: #{e}"
|
||||
puts e.backtrace
|
||||
end
|
||||
end
|
||||
|
||||
def benchmark file, bin
|
||||
m = Benchmark.measure{
|
||||
`#{bin} #{$opts} #{file}`
|
||||
}
|
||||
sec = '%.3f' % m.real
|
||||
puts " #{sec}"
|
||||
sec
|
||||
end
|
||||
|
||||
def ruby_exec file
|
||||
print 'ruby'
|
||||
benchmark file, $ruby_program
|
||||
end
|
||||
|
||||
def yarv_exec file
|
||||
print 'yarv'
|
||||
benchmark file, $yarv_program
|
||||
end
|
||||
|
||||
if $0 == __FILE__
|
||||
ARGV.each{|arg|
|
||||
case arg
|
||||
when /\A--yarv-program=(.+)/
|
||||
$yarv_program = $1
|
||||
when /\A--ruby-program=(.+)/
|
||||
$ruby_program = $1
|
||||
when /\A--opts=(.+)/
|
||||
$opts = $1
|
||||
when /\A(--yarv)|(-y)/
|
||||
$yarvonly = true
|
||||
when /\A(--ruby)|(-r)/
|
||||
$rubyonly = true
|
||||
end
|
||||
}
|
||||
ARGV.delete_if{|arg|
|
||||
/\A-/ =~ arg
|
||||
}
|
||||
|
||||
puts "Ruby:"
|
||||
system("#{$ruby_program} -v")
|
||||
puts
|
||||
puts "YARV:"
|
||||
system("#{$yarv_program} -v")
|
||||
|
||||
if ARGV.empty?
|
||||
Dir.glob(File.dirname(__FILE__) + '/bm_*.rb').sort.each{|file|
|
||||
bm file
|
||||
}
|
||||
else
|
||||
ARGV.each{|file|
|
||||
Dir.glob(File.join(File.dirname(__FILE__), file + '*')){|ef|
|
||||
# file = "#{File.dirname(__FILE__)}/#{file}.rb"
|
||||
bm ef
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
puts
|
||||
puts "-- benchmark summary ---------------------------"
|
||||
$results.each{|res|
|
||||
print res.shift, "\t"
|
||||
(res||[]).each{|result|
|
||||
/([\d\.]+)/ =~ result
|
||||
print $1 + "\t" if $1
|
||||
}
|
||||
puts
|
||||
}
|
||||
end
|
||||
|
29
benchmark/runc.rb
Normal file
29
benchmark/runc.rb
Normal file
@ -0,0 +1,29 @@
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
require 'benchmark'
|
||||
require 'rbconfig'
|
||||
|
||||
$rubybin = ENV['RUBY'] || File.join(
|
||||
Config::CONFIG["bindir"],
|
||||
Config::CONFIG["ruby_install_name"] + Config::CONFIG["EXEEXT"])
|
||||
|
||||
def runfile file
|
||||
puts file
|
||||
file = File.join(File.dirname($0), 'contrib', file)
|
||||
Benchmark.bm{|x|
|
||||
x.report('ruby'){
|
||||
system("#{$rubybin} #{file}")
|
||||
}
|
||||
x.report('yarv'){
|
||||
system("#{$rubybin} -rite -I.. #{file}")
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
ARGV.each{|file|
|
||||
runfile file
|
||||
}
|
||||
|
||||
|
25
benchmark/wc.input.base
Normal file
25
benchmark/wc.input.base
Normal file
File diff suppressed because one or more lines are too long
461
blockinlining.c
Normal file
461
blockinlining.c
Normal file
@ -0,0 +1,461 @@
|
||||
/**********************************************************************
|
||||
|
||||
blockinlining.c -
|
||||
|
||||
$Author$
|
||||
$Date$
|
||||
|
||||
Copyright (C) 2004-2006 Koichi Sasada
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "ruby.h"
|
||||
#include "node.h"
|
||||
#include "yarvcore.h"
|
||||
|
||||
VALUE yarv_new_iseqval(VALUE node, VALUE name, VALUE file,
|
||||
VALUE parent, VALUE type, VALUE block_opt, VALUE opt);
|
||||
|
||||
static VALUE
|
||||
yarv_iseq_special_block(yarv_iseq_t *iseq, void *builder)
|
||||
{
|
||||
#if OPT_BLOCKINLINING
|
||||
VALUE parent = Qfalse;
|
||||
VALUE iseqval;
|
||||
|
||||
if (iseq->argc > 1 || iseq->arg_simple == 0) {
|
||||
/* argument check */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (iseq->cached_special_block_builder) {
|
||||
if (iseq->cached_special_block_builder == builder) {
|
||||
return iseq->cached_special_block;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
iseq->cached_special_block_builder = (void *)1;
|
||||
}
|
||||
|
||||
if (iseq->parent_iseq) {
|
||||
parent = iseq->parent_iseq->self;
|
||||
}
|
||||
iseqval = yarv_iseq_new_with_bopt(iseq->node, iseq->name, iseq->file_name,
|
||||
parent, iseq->type,
|
||||
GC_GUARDED_PTR(builder));
|
||||
if (0) {
|
||||
printf("%s\n", RSTRING_PTR(iseq_disasm(iseqval)));
|
||||
}
|
||||
iseq->cached_special_block = iseqval;
|
||||
iseq->cached_special_block_builder = builder;
|
||||
return iseqval;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static NODE *
|
||||
new_block(NODE * head, NODE * tail)
|
||||
{
|
||||
head = NEW_BLOCK(head);
|
||||
tail = NEW_BLOCK(tail);
|
||||
head->nd_next = tail;
|
||||
return head;
|
||||
}
|
||||
|
||||
static NODE *
|
||||
new_ary(NODE * head, NODE * tail)
|
||||
{
|
||||
head = NEW_ARRAY(head);
|
||||
head->nd_next = tail;
|
||||
return head;
|
||||
}
|
||||
|
||||
static NODE *
|
||||
new_assign(NODE * lnode, NODE * rhs)
|
||||
{
|
||||
switch (nd_type(lnode)) {
|
||||
case NODE_LASGN:{
|
||||
return NEW_NODE(NODE_LASGN, lnode->nd_vid, rhs, lnode->nd_cnt);
|
||||
/* NEW_LASGN(lnode->nd_vid, rhs); */
|
||||
}
|
||||
case NODE_GASGN:{
|
||||
return NEW_GASGN(lnode->nd_vid, rhs);
|
||||
}
|
||||
case NODE_DASGN:{
|
||||
return NEW_DASGN(lnode->nd_vid, rhs);
|
||||
}
|
||||
case NODE_ATTRASGN:{
|
||||
NODE *args = 0;
|
||||
if (lnode->nd_args) {
|
||||
args = NEW_ARRAY(lnode->nd_args->nd_head);
|
||||
args->nd_next = NEW_ARRAY(rhs);
|
||||
args->nd_alen = 2;
|
||||
}
|
||||
else {
|
||||
args = NEW_ARRAY(rhs);
|
||||
}
|
||||
|
||||
return NEW_ATTRASGN(lnode->nd_recv,
|
||||
lnode->nd_mid,
|
||||
args);
|
||||
}
|
||||
default:
|
||||
rb_bug("unimplemented (block inlining): %s", node_name(nd_type(lnode)));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static NODE *
|
||||
build_Integer_times_node(yarv_iseq_t *iseq, NODE * node, NODE * lnode,
|
||||
VALUE param_vars, VALUE local_vars)
|
||||
{
|
||||
/* Special Block for Integer#times
|
||||
{|e, _self|
|
||||
_e = e
|
||||
while(e < _self)
|
||||
e = _e
|
||||
redo_point:
|
||||
BODY
|
||||
next_point:
|
||||
_e = _e.succ
|
||||
end
|
||||
}
|
||||
|
||||
{|e, _self|
|
||||
while(e < _self)
|
||||
BODY
|
||||
next_point:
|
||||
e = e.succ
|
||||
end
|
||||
}
|
||||
*/
|
||||
ID _self = rb_intern("#_self");
|
||||
if (iseq->argc == 0) {
|
||||
ID e = rb_intern("#e");
|
||||
rb_ary_push(param_vars, ID2SYM(e));
|
||||
rb_ary_push(param_vars, ID2SYM(_self));
|
||||
iseq->argc += 2;
|
||||
|
||||
node =
|
||||
NEW_WHILE(NEW_CALL
|
||||
(NEW_DVAR(e), idLT, new_ary(NEW_DVAR(_self), 0)),
|
||||
new_block(NEW_OPTBLOCK(node),
|
||||
NEW_DASGN(e,
|
||||
NEW_CALL(NEW_DVAR(e), idSucc, 0))),
|
||||
Qundef);
|
||||
}
|
||||
else {
|
||||
ID _e = rb_intern("#_e");
|
||||
ID e = SYM2ID(rb_ary_entry(param_vars, 0));
|
||||
NODE *assign;
|
||||
|
||||
rb_ary_push(param_vars, ID2SYM(_self));
|
||||
rb_ary_push(local_vars, ID2SYM(_e));
|
||||
iseq->argc++;
|
||||
|
||||
if (nd_type(lnode) == NODE_DASGN_CURR) {
|
||||
assign = NEW_DASGN(e, NEW_DVAR(_e));
|
||||
}
|
||||
else {
|
||||
assign = new_assign(lnode, NEW_DVAR(_e));
|
||||
}
|
||||
|
||||
node =
|
||||
new_block(NEW_DASGN(_e, NEW_DVAR(e)),
|
||||
NEW_WHILE(NEW_CALL
|
||||
(NEW_DVAR(_e), idLT,
|
||||
new_ary(NEW_DVAR(_self), 0)),
|
||||
new_block(assign,
|
||||
new_block(NEW_OPTBLOCK(node),
|
||||
NEW_DASGN(_e,
|
||||
NEW_CALL
|
||||
(NEW_DVAR(_e),
|
||||
idSucc, 0)))),
|
||||
Qundef));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
VALUE
|
||||
yarv_invoke_Integer_times_special_block(VALUE num)
|
||||
{
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
yarv_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
|
||||
|
||||
if (orig_block && BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
|
||||
VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq,
|
||||
build_Integer_times_node);
|
||||
yarv_iseq_t *tsiseq;
|
||||
VALUE argv[2], val;
|
||||
|
||||
if (tsiseqval) {
|
||||
yarv_block_t block = *orig_block;
|
||||
GetISeqPtr(tsiseqval, tsiseq);
|
||||
block.iseq = tsiseq;
|
||||
th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
|
||||
argv[0] = INT2FIX(0);
|
||||
argv[1] = num;
|
||||
val = th_invoke_yield(th, 2, argv);
|
||||
if (val == Qundef) {
|
||||
return num;
|
||||
}
|
||||
else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Qundef;
|
||||
}
|
||||
|
||||
static NODE *
|
||||
build_Range_each_node(yarv_iseq_t *iseq, NODE * node, NODE * lnode,
|
||||
VALUE param_vars, VALUE local_vars, ID mid)
|
||||
{
|
||||
/* Special Block for Range#each
|
||||
{|e, _last|
|
||||
_e = e
|
||||
while _e < _last
|
||||
e = _e
|
||||
next_point:
|
||||
BODY
|
||||
redo_point:
|
||||
_e = _e.succ
|
||||
end
|
||||
}
|
||||
{|e, _last|
|
||||
while e < _last
|
||||
BODY
|
||||
redo_point:
|
||||
e = e.succ
|
||||
end
|
||||
}
|
||||
*/
|
||||
ID _last = rb_intern("#_last");
|
||||
if (iseq->argc == 0) {
|
||||
ID e = rb_intern("#e");
|
||||
rb_ary_push(param_vars, ID2SYM(e));
|
||||
rb_ary_push(param_vars, ID2SYM(_last));
|
||||
iseq->argc += 2;
|
||||
|
||||
node =
|
||||
NEW_WHILE(NEW_CALL(NEW_DVAR(e), mid, new_ary(NEW_DVAR(_last), 0)),
|
||||
new_block(NEW_OPTBLOCK(node),
|
||||
NEW_DASGN(e,
|
||||
NEW_CALL(NEW_DVAR(e), idSucc, 0))),
|
||||
Qundef);
|
||||
}
|
||||
else {
|
||||
ID _e = rb_intern("#_e");
|
||||
ID e = SYM2ID(rb_ary_entry(param_vars, 0));
|
||||
NODE *assign;
|
||||
|
||||
rb_ary_push(param_vars, ID2SYM(_last));
|
||||
rb_ary_push(local_vars, ID2SYM(_e));
|
||||
iseq->argc++;
|
||||
|
||||
if (nd_type(lnode) == NODE_DASGN_CURR) {
|
||||
assign = NEW_DASGN(e, NEW_DVAR(_e));
|
||||
}
|
||||
else {
|
||||
assign = new_assign(lnode, NEW_DVAR(_e));
|
||||
}
|
||||
|
||||
node =
|
||||
new_block(NEW_DASGN(_e, NEW_DVAR(e)),
|
||||
NEW_WHILE(NEW_CALL
|
||||
(NEW_DVAR(_e), mid,
|
||||
new_ary(NEW_DVAR(_last), 0)),
|
||||
new_block(assign,
|
||||
new_block(NEW_OPTBLOCK(node),
|
||||
NEW_DASGN(_e,
|
||||
NEW_CALL
|
||||
(NEW_DVAR(_e),
|
||||
idSucc, 0)))),
|
||||
Qundef));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static NODE *
|
||||
build_Range_each_node_LE(yarv_iseq_t *iseq, NODE * node, NODE * lnode,
|
||||
VALUE param_vars, VALUE local_vars)
|
||||
{
|
||||
return build_Range_each_node(iseq, node, lnode,
|
||||
param_vars, local_vars, idLE);
|
||||
}
|
||||
|
||||
static NODE *
|
||||
build_Range_each_node_LT(yarv_iseq_t *iseq, NODE * node, NODE * lnode,
|
||||
VALUE param_vars, VALUE local_vars)
|
||||
{
|
||||
return build_Range_each_node(iseq, node, lnode,
|
||||
param_vars, local_vars, idLT);
|
||||
}
|
||||
|
||||
VALUE
|
||||
yarv_invoke_Range_each_special_block(VALUE range,
|
||||
VALUE beg, VALUE end, int excl)
|
||||
{
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
yarv_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
|
||||
|
||||
if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
|
||||
void *builder =
|
||||
excl ? build_Range_each_node_LT : build_Range_each_node_LE;
|
||||
VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq, builder);
|
||||
yarv_iseq_t *tsiseq;
|
||||
VALUE argv[2];
|
||||
|
||||
if (tsiseqval) {
|
||||
VALUE val;
|
||||
yarv_block_t block = *orig_block;
|
||||
GetISeqPtr(tsiseqval, tsiseq);
|
||||
block.iseq = tsiseq;
|
||||
th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
|
||||
argv[0] = beg;
|
||||
argv[1] = end;
|
||||
val = th_invoke_yield(th, 2, argv);
|
||||
if (val == Qundef) {
|
||||
return range;
|
||||
}
|
||||
else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Qundef;
|
||||
}
|
||||
|
||||
|
||||
static NODE *
|
||||
build_Array_each_node(yarv_iseq_t *iseq, NODE * node, NODE * lnode,
|
||||
VALUE param_vars, VALUE local_vars)
|
||||
{
|
||||
/* Special block for Array#each
|
||||
ary.each{|e|
|
||||
BODY
|
||||
}
|
||||
=>
|
||||
{|e, _self|
|
||||
_i = 0
|
||||
while _i < _self.length
|
||||
e = _self[_i]
|
||||
redo_point:
|
||||
BODY
|
||||
next_point:
|
||||
_i = _i.succ
|
||||
end
|
||||
}
|
||||
|
||||
ary.each{
|
||||
BODY
|
||||
}
|
||||
=>
|
||||
{|_i, _self|
|
||||
_i = 0
|
||||
while _i < _self.length
|
||||
redo_point:
|
||||
BODY
|
||||
next_point:
|
||||
_i = _i.succ
|
||||
end
|
||||
}
|
||||
*/
|
||||
|
||||
ID _self = rb_intern("#_self");
|
||||
ID _i = rb_intern("#_i");
|
||||
|
||||
if (iseq->argc == 0) {
|
||||
ID _e = rb_intern("#_e");
|
||||
rb_ary_push(param_vars, ID2SYM(_e));
|
||||
rb_ary_push(param_vars, ID2SYM(_self));
|
||||
iseq->argc += 2;
|
||||
rb_ary_push(local_vars, ID2SYM(_i));
|
||||
|
||||
node =
|
||||
new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))),
|
||||
NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT,
|
||||
new_ary(NEW_CALL
|
||||
(NEW_DVAR(_self), idLength,
|
||||
0), 0)),
|
||||
new_block(NEW_OPTBLOCK(node),
|
||||
NEW_DASGN(_i,
|
||||
NEW_CALL(NEW_DVAR(_i),
|
||||
idSucc, 0))),
|
||||
Qundef));
|
||||
}
|
||||
else {
|
||||
ID e = SYM2ID(rb_ary_entry(param_vars, 0));
|
||||
NODE *assign;
|
||||
|
||||
rb_ary_push(param_vars, ID2SYM(_self));
|
||||
iseq->argc++;
|
||||
rb_ary_push(local_vars, ID2SYM(_i));
|
||||
|
||||
if (nd_type(lnode) == NODE_DASGN_CURR) {
|
||||
assign = NEW_DASGN(e,
|
||||
NEW_CALL(NEW_DVAR(_self), idAREF,
|
||||
new_ary(NEW_DVAR(_i), 0)));
|
||||
}
|
||||
else {
|
||||
assign = new_assign(lnode,
|
||||
NEW_CALL(NEW_DVAR(_self), idAREF,
|
||||
new_ary(NEW_DVAR(_i), 0)));
|
||||
}
|
||||
|
||||
node =
|
||||
new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))),
|
||||
NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT,
|
||||
new_ary(NEW_CALL
|
||||
(NEW_DVAR(_self), idLength,
|
||||
0), 0)), new_block(assign,
|
||||
new_block
|
||||
(NEW_OPTBLOCK
|
||||
(node),
|
||||
NEW_DASGN
|
||||
(_i,
|
||||
NEW_CALL
|
||||
(NEW_DVAR
|
||||
(_i),
|
||||
idSucc,
|
||||
0)))),
|
||||
Qundef));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
VALUE
|
||||
yarv_invoke_Array_each_special_block(VALUE ary)
|
||||
{
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
yarv_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
|
||||
|
||||
if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
|
||||
VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq,
|
||||
build_Array_each_node);
|
||||
yarv_iseq_t *tsiseq;
|
||||
VALUE argv[2];
|
||||
|
||||
if (tsiseqval) {
|
||||
VALUE val;
|
||||
yarv_block_t block = *orig_block;
|
||||
GetISeqPtr(tsiseqval, tsiseq);
|
||||
block.iseq = tsiseq;
|
||||
th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
|
||||
argv[0] = 0;
|
||||
argv[1] = ary;
|
||||
val = th_invoke_yield(th, 2, argv);
|
||||
if (val == Qundef) {
|
||||
return ary;
|
||||
}
|
||||
else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Qundef;
|
||||
}
|
94
call_cfunc.ci
Normal file
94
call_cfunc.ci
Normal file
@ -0,0 +1,94 @@
|
||||
/* -*-c-*- */
|
||||
|
||||
/* from ruby1.9/eval.c */
|
||||
|
||||
static inline VALUE
|
||||
call_cfunc(func, recv, len, argc, argv)
|
||||
VALUE (*func) ();
|
||||
VALUE recv;
|
||||
int len, argc;
|
||||
const VALUE *argv;
|
||||
{
|
||||
// printf("len: %d, argc: %d\n", len, argc);
|
||||
|
||||
if (len >= 0 && argc != len) {
|
||||
rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)",
|
||||
argc, len);
|
||||
}
|
||||
|
||||
switch (len) {
|
||||
case -2:
|
||||
return (*func) (recv, rb_ary_new4(argc, argv));
|
||||
break;
|
||||
case -1:
|
||||
return (*func) (argc, argv, recv);
|
||||
break;
|
||||
case 0:
|
||||
return (*func) (recv);
|
||||
break;
|
||||
case 1:
|
||||
return (*func) (recv, argv[0]);
|
||||
break;
|
||||
case 2:
|
||||
return (*func) (recv, argv[0], argv[1]);
|
||||
break;
|
||||
case 3:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2]);
|
||||
break;
|
||||
case 4:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3]);
|
||||
break;
|
||||
case 5:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
|
||||
break;
|
||||
case 6:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||
argv[5]);
|
||||
break;
|
||||
case 7:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||
argv[5], argv[6]);
|
||||
break;
|
||||
case 8:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||
argv[5], argv[6], argv[7]);
|
||||
break;
|
||||
case 9:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||
argv[5], argv[6], argv[7], argv[8]);
|
||||
break;
|
||||
case 10:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||
argv[5], argv[6], argv[7], argv[8], argv[9]);
|
||||
break;
|
||||
case 11:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||
argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||
argv[10]);
|
||||
break;
|
||||
case 12:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||
argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||
argv[10], argv[11]);
|
||||
break;
|
||||
case 13:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||
argv[11], argv[12]);
|
||||
break;
|
||||
case 14:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||
argv[11], argv[12], argv[13]);
|
||||
break;
|
||||
case 15:
|
||||
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||
argv[11], argv[12], argv[13], argv[14]);
|
||||
break;
|
||||
default:
|
||||
rb_raise(rb_eArgError, "too many arguments(%d)", len);
|
||||
break;
|
||||
}
|
||||
return Qnil; /* not reached */
|
||||
}
|
81
class.c
81
class.c
@ -56,10 +56,26 @@ rb_class_new(VALUE super)
|
||||
return rb_class_boot(super);
|
||||
}
|
||||
|
||||
struct clone_method_data {
|
||||
st_table *tbl;
|
||||
VALUE klass;
|
||||
};
|
||||
|
||||
static int
|
||||
clone_method(ID mid, NODE *body, st_table *tbl)
|
||||
clone_method(ID mid, NODE *body, struct clone_method_data *data)
|
||||
{
|
||||
st_insert(tbl, mid, (st_data_t)NEW_METHOD(body->nd_body, body->nd_noex));
|
||||
if (body == 0) {
|
||||
st_insert(data->tbl, mid, 0);
|
||||
}
|
||||
else {
|
||||
st_insert(data->tbl, mid,
|
||||
(st_data_t)
|
||||
NEW_FBODY(
|
||||
NEW_METHOD(body->nd_body->nd_body,
|
||||
data->klass, /* TODO */
|
||||
body->nd_body->nd_noex),
|
||||
0));
|
||||
}
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
@ -82,9 +98,11 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
|
||||
st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0);
|
||||
}
|
||||
if (RCLASS(orig)->m_tbl) {
|
||||
RCLASS(clone)->m_tbl = st_init_numtable();
|
||||
struct clone_method_data data;
|
||||
data.tbl = RCLASS(clone)->m_tbl = st_init_numtable();
|
||||
data.klass = clone;
|
||||
st_foreach(RCLASS(orig)->m_tbl, clone_method,
|
||||
(st_data_t)RCLASS(clone)->m_tbl);
|
||||
(st_data_t)&data);
|
||||
}
|
||||
|
||||
return clone;
|
||||
@ -111,6 +129,7 @@ rb_singleton_class_clone(VALUE obj)
|
||||
if (!FL_TEST(klass, FL_SINGLETON))
|
||||
return klass;
|
||||
else {
|
||||
struct clone_method_data data;
|
||||
/* copy singleton(unnamed) class */
|
||||
NEWOBJ(clone, struct RClass);
|
||||
OBJSETUP(clone, 0, RBASIC(klass)->flags);
|
||||
@ -129,8 +148,10 @@ rb_singleton_class_clone(VALUE obj)
|
||||
clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl);
|
||||
}
|
||||
clone->m_tbl = st_init_numtable();
|
||||
data.tbl = clone->m_tbl;
|
||||
data.klass = (VALUE)clone;
|
||||
st_foreach(RCLASS(klass)->m_tbl, clone_method,
|
||||
(st_data_t)clone->m_tbl);
|
||||
(st_data_t)&data);
|
||||
rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
|
||||
FL_SET(clone, FL_SINGLETON);
|
||||
return (VALUE)clone;
|
||||
@ -359,27 +380,27 @@ rb_include_module(VALUE klass, VALUE module)
|
||||
OBJ_INFECT(klass, module);
|
||||
c = klass;
|
||||
while (module) {
|
||||
int superclass_seen = Qfalse;
|
||||
int superclass_seen = Qfalse;
|
||||
|
||||
if (RCLASS(klass)->m_tbl == RCLASS(module)->m_tbl)
|
||||
rb_raise(rb_eArgError, "cyclic include detected");
|
||||
/* ignore if the module included already in superclasses */
|
||||
for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) {
|
||||
switch (BUILTIN_TYPE(p)) {
|
||||
case T_ICLASS:
|
||||
if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) {
|
||||
if (!superclass_seen) {
|
||||
c = p; /* move insertion point */
|
||||
}
|
||||
goto skip;
|
||||
}
|
||||
break;
|
||||
case T_CLASS:
|
||||
superclass_seen = Qtrue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super);
|
||||
/* ignore if the module included already in superclasses */
|
||||
for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) {
|
||||
switch (BUILTIN_TYPE(p)) {
|
||||
case T_ICLASS:
|
||||
if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) {
|
||||
if (!superclass_seen) {
|
||||
c = p; /* move insertion point */
|
||||
}
|
||||
goto skip;
|
||||
}
|
||||
break;
|
||||
case T_CLASS:
|
||||
superclass_seen = Qtrue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super);
|
||||
changed = 1;
|
||||
skip:
|
||||
module = RCLASS(module)->super;
|
||||
@ -492,6 +513,7 @@ static int
|
||||
ins_methods_push(ID name, long type, VALUE ary, long visi)
|
||||
{
|
||||
if (type == -1) return ST_CONTINUE;
|
||||
|
||||
switch (visi) {
|
||||
case NOEX_PRIVATE:
|
||||
case NOEX_PROTECTED:
|
||||
@ -544,10 +566,17 @@ method_entry(ID key, NODE *body, st_table *list)
|
||||
{
|
||||
long type;
|
||||
|
||||
if (key == ID_ALLOCATOR) return ST_CONTINUE;
|
||||
if (key == ID_ALLOCATOR) {
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
if (!st_lookup(list, key, 0)) {
|
||||
if (!body->nd_body) type = -1; /* none */
|
||||
else type = VISI(body->nd_noex);
|
||||
if (body ==0 || !body->nd_body->nd_body) {
|
||||
type = -1; /* none */
|
||||
}
|
||||
else {
|
||||
type = VISI(body->nd_body->nd_noex);
|
||||
}
|
||||
st_add_direct(list, key, type);
|
||||
}
|
||||
return ST_CONTINUE;
|
||||
|
403
common.mk
403
common.mk
@ -1,15 +1,11 @@
|
||||
bin: $(PROGRAM) $(WPROGRAM)
|
||||
lib: $(LIBRUBY)
|
||||
dll: $(LIBRUBY_SO)
|
||||
lib: $(LIBRUBY);
|
||||
dll: $(LIBRUBY_SO);
|
||||
|
||||
RUBYOPT =
|
||||
|
||||
STATIC_RUBY = static-ruby
|
||||
|
||||
EXTCONF = extconf.rb
|
||||
RBCONFIG = ./.rbconfig.time
|
||||
LIBRUBY_EXTS = ./.libruby-with-ext.time
|
||||
RDOCOUT = $(EXTOUT)/rdoc
|
||||
|
||||
DMYEXT = dmyext.$(OBJEXT)
|
||||
MAINOBJ = main.$(OBJEXT)
|
||||
@ -28,6 +24,9 @@ OBJS = array.$(OBJEXT) \
|
||||
error.$(OBJEXT) \
|
||||
euc_jp.$(OBJEXT) \
|
||||
eval.$(OBJEXT) \
|
||||
eval_load.$(OBJEXT) \
|
||||
eval_proc.$(OBJEXT) \
|
||||
eval_thread.$(OBJEXT) \
|
||||
file.$(OBJEXT) \
|
||||
gc.$(OBJEXT) \
|
||||
hash.$(OBJEXT) \
|
||||
@ -61,218 +60,94 @@ OBJS = array.$(OBJEXT) \
|
||||
util.$(OBJEXT) \
|
||||
variable.$(OBJEXT) \
|
||||
version.$(OBJEXT) \
|
||||
blockinlining.$(OBJEXT) \
|
||||
compile.$(OBJEXT) \
|
||||
debug.$(OBJEXT) \
|
||||
iseq.$(OBJEXT) \
|
||||
vm.$(OBJEXT) \
|
||||
vm_dump.$(OBJEXT) \
|
||||
yarvcore.$(OBJEXT) \
|
||||
thread.$(OBJEXT) \
|
||||
$(MISSING)
|
||||
|
||||
SCRIPT_ARGS = --dest-dir="$(DESTDIR)" \
|
||||
--extout="$(EXTOUT)" \
|
||||
--make="$(MAKE)" \
|
||||
--mflags="$(MFLAGS)" \
|
||||
--make-flags="$(MAKEFLAGS)"
|
||||
EXTMK_ARGS = $(SCRIPT_ARGS) --extension $(EXTS) --extstatic $(EXTSTATIC) --
|
||||
INSTRUBY_ARGS = $(SCRIPT_ARGS) --installed-list $(INSTALLED_LIST)
|
||||
|
||||
PRE_LIBRUBY_UPDATE = $(MINIRUBY) -e 'ARGV[1] or File.unlink(ARGV[0]) rescue nil' -- \
|
||||
$(LIBRUBY_EXTS) $(LIBRUBY_SO_UPDATE)
|
||||
|
||||
TESTSDIR = $(srcdir)/test
|
||||
TESTWORKDIR = testwork
|
||||
EXTMK_ARGS = $(SCRIPT_ARGS) --extout="$(EXTOUT)" --extension $(EXTS) --extstatic $(EXTSTATIC) --
|
||||
|
||||
all: $(MKFILES) $(PREP) $(RBCONFIG) $(LIBRUBY)
|
||||
@$(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS)
|
||||
$(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS)
|
||||
|
||||
prog: $(PROGRAM) $(WPROGRAM)
|
||||
|
||||
miniruby$(EXEEXT): config.status $(LIBRUBY_A) $(MAINOBJ) $(MINIOBJS) $(OBJS) $(DMYEXT)
|
||||
|
||||
$(PROGRAM): $(LIBRUBY) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(SETUP) $(PREP)
|
||||
|
||||
$(LIBRUBY_A): $(OBJS) $(DMYEXT) $(ARCHFILE)
|
||||
$(LIBRUBY_A): $(OBJS) $(DMYEXT)
|
||||
|
||||
$(LIBRUBY_SO): $(OBJS) $(DLDOBJS) $(LIBRUBY_A) $(PREP) $(LIBRUBY_SO_UPDATE)
|
||||
$(LIBRUBY_SO): $(OBJS) $(DLDOBJS) $(LIBRUBY_A) $(PREP) $(ARCHFILE)
|
||||
|
||||
$(LIBRUBY_EXTS):
|
||||
@exit > $@
|
||||
|
||||
$(STATIC_RUBY)$(EXEEXT): $(MAINOBJ) $(DLDOBJS) $(EXTOBJS) $(LIBRUBY_A)
|
||||
static-ruby: $(MAINOBJ) $(EXTOBJS) $(LIBRUBY_A)
|
||||
@$(RM) $@
|
||||
$(PURIFY) $(CC) $(MAINOBJ) $(DLDOBJS) $(EXTOBJS) $(LIBRUBY_A) $(MAINLIBS) $(EXTLIBS) $(LIBS) $(OUTFLAG)$@ $(LDFLAGS) $(XLDFLAGS)
|
||||
$(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBY_A) $(LIBS) $(OUTFLAG)$@
|
||||
|
||||
ruby.imp: $(OBJS)
|
||||
@$(NM) -Pgp $(OBJS) | awk 'BEGIN{print "#!"}; $$2~/^[BD]$$/{print $$1}' | sort -u -o $@
|
||||
ruby.imp: $(LIBRUBY_A)
|
||||
@$(NM) -Pgp $(LIBRUBY_A) | awk 'BEGIN{print "#!"}; $$2~/^[BD]$$/{print $$1}' | sort -u -o $@
|
||||
|
||||
install: install-nodoc $(RDOCTARGET)
|
||||
install-all: install-nodoc install-doc
|
||||
|
||||
install-nodoc: pre-install-nodoc do-install-nodoc post-install-nodoc
|
||||
pre-install-nodoc:: pre-install-local pre-install-ext
|
||||
do-install-nodoc:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --mantype="$(MANTYPE)"
|
||||
post-install-nodoc:: post-install-local post-install-ext
|
||||
|
||||
install-nodoc: install-local install-ext
|
||||
install-local: pre-install-local do-install-local post-install-local
|
||||
pre-install-local:: pre-install-bin pre-install-lib pre-install-man
|
||||
do-install-local:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=local --mantype="$(MANTYPE)"
|
||||
post-install-local:: post-install-bin post-install-lib post-install-man
|
||||
|
||||
install-ext: pre-install-ext do-install-ext post-install-ext
|
||||
pre-install-ext:: pre-install-ext-arch pre-install-ext-comm
|
||||
do-install-ext:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=ext
|
||||
post-install-ext:: post-install-ext-arch post-install-ext-comm
|
||||
|
||||
install-arch: pre-install-arch do-install-arch post-install-arch
|
||||
pre-install-arch:: pre-install-bin pre-install-ext-arch
|
||||
do-install-arch:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=bin --install=ext-arch
|
||||
post-install-arch:: post-install-bin post-install-ext-arch
|
||||
do-install-local: $(RBCONFIG)
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --mantype="$(MANTYPE)"
|
||||
do-install-ext: $(RBCONFIG)
|
||||
$(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS) install
|
||||
|
||||
install-comm: pre-install-comm do-install-comm post-install-comm
|
||||
pre-install-comm:: pre-install-lib pre-install-ext-comm pre-install-man
|
||||
do-install-comm:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=lib --install=ext-comm --install=man
|
||||
post-install-comm:: post-install-lib post-install-ext-comm post-install-man
|
||||
|
||||
install-bin: pre-install-bin do-install-bin post-install-bin
|
||||
pre-install-bin:: install-prereq
|
||||
do-install-bin:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=bin
|
||||
post-install-bin::
|
||||
@$(NULLCMD)
|
||||
|
||||
install-lib: pre-install-lib do-install-lib post-install-lib
|
||||
pre-install-lib:: install-prereq
|
||||
do-install-lib:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=lib
|
||||
post-install-lib::
|
||||
@$(NULLCMD)
|
||||
|
||||
install-ext-comm: pre-install-ext-comm do-install-ext-comm post-install-ext-comm
|
||||
pre-install-ext-comm:: install-prereq
|
||||
do-install-ext-comm:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=ext-comm
|
||||
post-install-ext-comm::
|
||||
@$(NULLCMD)
|
||||
|
||||
install-ext-arch: pre-install-ext-arch do-install-ext-arch post-install-ext-arch
|
||||
pre-install-ext-arch:: install-prereq
|
||||
do-install-ext-arch:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=ext-arch
|
||||
post-install-ext-arch::
|
||||
@$(NULLCMD)
|
||||
|
||||
install-man: pre-install-man do-install-man post-install-man
|
||||
pre-install-man:: install-prereq
|
||||
do-install-man:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=man --mantype="$(MANTYPE)"
|
||||
post-install-man::
|
||||
@$(NULLCMD)
|
||||
|
||||
what-where: no-install
|
||||
no-install: no-install-nodoc no-install-doc
|
||||
what-where-all: no-install-all
|
||||
no-install-all: no-install-nodoc
|
||||
|
||||
what-where-nodoc: no-install-nodoc
|
||||
no-install-nodoc: pre-no-install-nodoc dont-install-nodoc post-no-install-nodoc
|
||||
pre-no-install-nodoc:: pre-no-install-local pre-no-install-ext
|
||||
dont-install-nodoc:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --mantype="$(MANTYPE)"
|
||||
post-no-install-nodoc:: post-no-install-local post-no-install-ext
|
||||
install-bin: $(RBCONFIG)
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --install=bin
|
||||
install-lib: $(RBCONFIG)
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --install=lib
|
||||
install-man: $(RBCONFIG)
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --install=man --mantype="$(MANTYPE)"
|
||||
|
||||
what-where-all no-install-all: no-install no-install-doc
|
||||
what-where no-install: no-install-local no-install-ext
|
||||
what-where-local: no-install-local
|
||||
no-install-local: pre-no-install-local dont-install-local post-no-install-local
|
||||
pre-no-install-local:: pre-no-install-bin pre-no-install-lib pre-no-install-man
|
||||
dont-install-local:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --install=local --mantype="$(MANTYPE)"
|
||||
post-no-install-local:: post-no-install-bin post-no-install-lib post-no-install-man
|
||||
|
||||
no-install-local: $(RBCONFIG)
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(SCRIPT_ARGS) --mantype="$(MANTYPE)"
|
||||
what-where-ext: no-install-ext
|
||||
no-install-ext: pre-no-install-ext dont-install-ext post-no-install-ext
|
||||
pre-no-install-ext:: pre-no-install-ext-arch pre-no-install-ext-comm
|
||||
dont-install-ext:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --install=ext
|
||||
post-no-install-ext:: post-no-install-ext-arch post-no-install-ext-comm
|
||||
no-install-ext: $(RBCONFIG)
|
||||
$(MINIRUBY) $(srcdir)/ext/extmk.rb -n $(EXTMK_ARGS) install
|
||||
|
||||
what-where-arch: no-install-arch
|
||||
no-install-arch: pre-no-install-arch dont-install-arch post-no-install-arch
|
||||
pre-no-install-arch:: pre-no-install-bin pre-no-install-ext-arch
|
||||
dont-install-arch:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --install=bin --install=ext-arch
|
||||
post-no-install-arch:: post-no-install-lib post-no-install-man post-no-install-ext-arch
|
||||
|
||||
what-where-comm: no-install-comm
|
||||
no-install-comm: pre-no-install-comm dont-install-comm post-no-install-comm
|
||||
pre-no-install-comm:: pre-no-install-lib pre-no-install-ext-comm pre-no-install-man
|
||||
dont-install-comm:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --install=lib --install=ext-comm --install=man
|
||||
post-no-install-comm:: post-no-install-lib post-no-install-ext-comm post-no-install-man
|
||||
|
||||
what-where-bin: no-install-bin
|
||||
no-install-bin: pre-no-install-bin dont-install-bin post-no-install-bin
|
||||
pre-no-install-bin:: install-prereq
|
||||
dont-install-bin:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --install=bin
|
||||
post-no-install-bin::
|
||||
@$(NULLCMD)
|
||||
|
||||
what-where-lib: no-install-lib
|
||||
no-install-lib: pre-no-install-lib dont-install-lib post-no-install-lib
|
||||
pre-no-install-lib:: install-prereq
|
||||
dont-install-lib:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --install=lib
|
||||
post-no-install-lib::
|
||||
@$(NULLCMD)
|
||||
|
||||
what-where-ext-comm: no-install-ext-comm
|
||||
no-install-ext-comm: pre-no-install-ext-comm dont-install-ext-comm post-no-install-ext-comm
|
||||
pre-no-install-ext-comm:: install-prereq
|
||||
dont-install-ext-comm:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --install=ext-comm
|
||||
post-no-install-ext-comm::
|
||||
@$(NULLCMD)
|
||||
|
||||
what-where-ext-arch: no-install-ext-arch
|
||||
no-install-ext-arch: pre-no-install-ext-arch dont-install-ext-arch post-no-install-ext-arch
|
||||
pre-no-install-ext-arch:: install-prereq
|
||||
dont-install-ext-arch:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --install=ext-arch
|
||||
post-no-install-ext-arch::
|
||||
@$(NULLCMD)
|
||||
|
||||
what-where-man: no-install-man
|
||||
no-install-man: pre-no-install-man dont-install-man post-no-install-man
|
||||
pre-no-install-man:: install-prereq
|
||||
dont-install-man:
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --install=man --mantype="$(MANTYPE)"
|
||||
post-no-install-man::
|
||||
@$(NULLCMD)
|
||||
|
||||
install-doc: rdoc pre-install-doc do-install-doc post-install-doc
|
||||
pre-install-doc:: install-prereq
|
||||
install-doc: pre-install-doc do-install-doc post-install-doc
|
||||
do-install-doc: $(PROGRAM)
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=rdoc --rdoc-output="$(RDOCOUT)"
|
||||
post-install-doc::
|
||||
@$(NULLCMD)
|
||||
|
||||
rdoc: $(PROGRAM) PHONY
|
||||
@echo Generating RDoc documentation
|
||||
$(RUNRUBY) "$(srcdir)/bin/rdoc" --all --ri --op "$(RDOCOUT)" "$(srcdir)"
|
||||
$(RUNRUBY) "$(srcdir)/bin/rdoc" --all --ri --op "$(RIDATADIR)" "$(srcdir)"
|
||||
|
||||
what-where-doc: no-install-doc
|
||||
no-install-doc: pre-no-install-doc dont-install-doc post-no-install-doc
|
||||
pre-no-install-doc:: install-prereq
|
||||
dont-install-doc::
|
||||
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --install=rdoc --rdoc-output="$(RDOCOUT)"
|
||||
post-no-install-doc::
|
||||
@$(NULLCMD)
|
||||
pre-install: pre-install-local pre-install-ext
|
||||
pre-install-local:: PHONY
|
||||
pre-install-ext:: PHONY
|
||||
pre-install-doc:: PHONY
|
||||
|
||||
install-prereq:
|
||||
@exit > $(INSTALLED_LIST)
|
||||
post-install: post-install-local post-install-ext
|
||||
post-install-local:: PHONY
|
||||
post-install-ext:: PHONY
|
||||
post-install-doc:: PHONY
|
||||
|
||||
# no ext
|
||||
# clean: clean-ext clean-local
|
||||
clean: clean-local
|
||||
|
||||
clean: clean-ext clean-local
|
||||
clean-local::
|
||||
@$(RM) $(OBJS) $(MAINOBJ) $(WINMAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
|
||||
@$(RM) $(PROGRAM) $(WPROGRAM) miniruby$(EXEEXT) dmyext.$(OBJEXT) $(ARCHFILE) .*.time
|
||||
@$(RM) $(PROGRAM) $(WPROGRAM) miniruby$(EXEEXT) dmyext.$(OBJEXT) $(ARCHFILE)
|
||||
@$(RM) *.inc
|
||||
|
||||
clean-ext:
|
||||
@-$(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS) clean
|
||||
|
||||
@ -292,15 +167,15 @@ check: test test-all
|
||||
test: miniruby$(EXEEXT) $(RBCONFIG) $(PROGRAM) PHONY
|
||||
@$(MINIRUBY) $(srcdir)/rubytest.rb
|
||||
|
||||
test-all:
|
||||
$(RUNRUBY) "$(srcdir)/test/runner.rb" --basedir="$(TESTSDIR)" --runner=$(TESTUI) $(TESTS)
|
||||
test-all: miniruby$(EXEEXT) ruby
|
||||
$(RUNRUBY) -C "$(srcdir)/test" runner.rb --runner=$(TESTUI) $(TESTS)
|
||||
|
||||
extconf:
|
||||
$(MINIRUBY) -I$(srcdir)/lib -run -e mkdir -- -p "$(EXTCONFDIR)"
|
||||
$(RUNRUBY) -C "$(EXTCONFDIR)" $(EXTCONF) $(EXTCONFARGS)
|
||||
|
||||
$(RBCONFIG): $(srcdir)/mkconfig.rb config.status $(PREP)
|
||||
@$(MINIRUBY) $(srcdir)/mkconfig.rb -timestamp=$@ \
|
||||
$(MINIRUBY) $(srcdir)/mkconfig.rb -timestamp=$@ \
|
||||
-install_name=$(RUBY_INSTALL_NAME) \
|
||||
-so_name=$(RUBY_SO_NAME) rbconfig.rb
|
||||
|
||||
@ -336,8 +211,6 @@ nt.$(OBJEXT): {$(VPATH)}nt.c
|
||||
x68.$(OBJEXT): {$(VPATH)}x68.c
|
||||
os2.$(OBJEXT): {$(VPATH)}os2.c
|
||||
dl_os2.$(OBJEXT): {$(VPATH)}dl_os2.c
|
||||
ia64.$(OBJEXT): {$(VPATH)}ia64.s
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
# when I use -I., there is confliction at "OpenFile"
|
||||
# so, set . into environment varible "include"
|
||||
@ -374,13 +247,41 @@ enumerator.$(OBJEXT): {$(VPATH)}enumerator.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
|
||||
error.$(OBJEXT): {$(VPATH)}error.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}env.h {$(VPATH)}st.h
|
||||
{$(VPATH)}st.h vm_opts.h
|
||||
euc_jp.$(OBJEXT): {$(VPATH)}euc_jp.c {$(VPATH)}regenc.h \
|
||||
{$(VPATH)}oniguruma.h
|
||||
eval.$(OBJEXT): {$(VPATH)}eval.c {$(VPATH)}ruby.h config.h \
|
||||
|
||||
eval.$(OBJEXT): {$(VPATH)}eval.c {$(VPATH)}eval_intern.h \
|
||||
{$(VPATH)}eval_method.h {$(VPATH)}eval_safe.h {$(VPATH)}eval_jump.h \
|
||||
{$(VPATH)}ruby.h config.h {$(VPATH)}yarvcore.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}node.h {$(VPATH)}env.h {$(VPATH)}util.h \
|
||||
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h
|
||||
{$(VPATH)}node.h {$(VPATH)}util.h \
|
||||
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h {$(VPATH)}yarv.h
|
||||
eval_load.$(OBJEXT): {$(VPATH)}eval_load.c {$(VPATH)}eval_intern.h \
|
||||
{$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}node.h {$(VPATH)}util.h {$(VPATH)}yarvcore.h \
|
||||
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h {$(VPATH)}yarv.h
|
||||
eval_thread.$(OBJEXT): {$(VPATH)}eval_thread.c {$(VPATH)}eval_intern.h \
|
||||
{$(VPATH)}ruby.h config.h {$(VPATH)}yarvcore.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}node.h {$(VPATH)}util.h \
|
||||
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h {$(VPATH)}yarv.h
|
||||
eval_proc.$(OBJEXT): {$(VPATH)}eval_proc.c {$(VPATH)}eval_intern.h \
|
||||
{$(VPATH)}ruby.h config.h {$(VPATH)}yarvcore.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}node.h {$(VPATH)}util.h \
|
||||
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h {$(VPATH)}yarv.h
|
||||
|
||||
thread.$(OBJEXT): {$(VPATH)}thread.c {$(VPATH)}eval_intern.h \
|
||||
{$(VPATH)}thread_win32.h {$(VPATH)}thread_pthread.h \
|
||||
{$(VPATH)}thread_win32.ci {$(VPATH)}thread_pthread.ci \
|
||||
{$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}node.h {$(VPATH)}util.h \
|
||||
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h \
|
||||
{$(VPATH)}yarv.h {$(VPATH)}yarvcore.h
|
||||
|
||||
file.$(OBJEXT): {$(VPATH)}file.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}rubyio.h {$(VPATH)}rubysig.h {$(VPATH)}util.h \
|
||||
@ -388,8 +289,7 @@ file.$(OBJEXT): {$(VPATH)}file.c {$(VPATH)}ruby.h config.h \
|
||||
gc.$(OBJEXT): {$(VPATH)}gc.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}node.h \
|
||||
{$(VPATH)}env.h {$(VPATH)}re.h {$(VPATH)}regex.h {$(VPATH)}regint.h \
|
||||
{$(VPATH)}oniguruma.h
|
||||
{$(VPATH)}re.h {$(VPATH)}regex.h {$(VPATH)}yarvcore.h
|
||||
hash.$(OBJEXT): {$(VPATH)}hash.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}st.h {$(VPATH)}util.h {$(VPATH)}rubysig.h
|
||||
@ -406,7 +306,7 @@ marshal.$(OBJEXT): {$(VPATH)}marshal.c {$(VPATH)}ruby.h config.h \
|
||||
math.$(OBJEXT): {$(VPATH)}math.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
|
||||
numeric.$(OBJEXT): {$(VPATH)}numeric.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}env.h {$(VPATH)}defines.h {$(VPATH)}intern.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h \
|
||||
{$(VPATH)}missing.h
|
||||
object.$(OBJEXT): {$(VPATH)}object.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
@ -415,7 +315,7 @@ pack.$(OBJEXT): {$(VPATH)}pack.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
|
||||
parse.$(OBJEXT): {$(VPATH)}parse.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}env.h {$(VPATH)}node.h {$(VPATH)}st.h \
|
||||
{$(VPATH)}node.h {$(VPATH)}st.h \
|
||||
{$(VPATH)}regex.h {$(VPATH)}util.h {$(VPATH)}lex.c
|
||||
prec.$(OBJEXT): {$(VPATH)}prec.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
|
||||
@ -428,7 +328,7 @@ range.$(OBJEXT): {$(VPATH)}range.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
|
||||
re.$(OBJEXT): {$(VPATH)}re.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}re.h {$(VPATH)}regex.h {$(VPATH)}regint.h {$(VPATH)}oniguruma.h
|
||||
{$(VPATH)}re.h {$(VPATH)}regex.h
|
||||
regcomp.$(OBJEXT): {$(VPATH)}regcomp.c {$(VPATH)}oniguruma.h \
|
||||
{$(VPATH)}regint.h {$(VPATH)}regparse.h {$(VPATH)}regenc.h config.h
|
||||
regenc.$(OBJEXT): {$(VPATH)}regenc.c {$(VPATH)}regint.h \
|
||||
@ -444,7 +344,7 @@ ruby.$(OBJEXT): {$(VPATH)}ruby.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}dln.h {$(VPATH)}node.h {$(VPATH)}util.h
|
||||
signal.$(OBJEXT): {$(VPATH)}signal.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}rubysig.h
|
||||
{$(VPATH)}rubysig.h {$(VPATH)}yarvcore.h
|
||||
sjis.$(OBJEXT): {$(VPATH)}sjis.c {$(VPATH)}regenc.h \
|
||||
{$(VPATH)}oniguruma.h config.h
|
||||
sprintf.$(OBJEXT): {$(VPATH)}sprintf.c {$(VPATH)}ruby.h config.h \
|
||||
@ -452,7 +352,7 @@ sprintf.$(OBJEXT): {$(VPATH)}sprintf.c {$(VPATH)}ruby.h config.h \
|
||||
st.$(OBJEXT): {$(VPATH)}st.c config.h {$(VPATH)}st.h
|
||||
string.$(OBJEXT): {$(VPATH)}string.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}re.h {$(VPATH)}regex.h {$(VPATH)}regint.h {$(VPATH)}oniguruma.h
|
||||
{$(VPATH)}re.h {$(VPATH)}regex.h
|
||||
struct.$(OBJEXT): {$(VPATH)}struct.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
|
||||
time.$(OBJEXT): {$(VPATH)}time.c {$(VPATH)}ruby.h config.h \
|
||||
@ -464,7 +364,112 @@ util.$(OBJEXT): {$(VPATH)}util.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}util.h
|
||||
variable.$(OBJEXT): {$(VPATH)}variable.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}env.h {$(VPATH)}node.h {$(VPATH)}st.h {$(VPATH)}util.h
|
||||
{$(VPATH)}node.h {$(VPATH)}st.h {$(VPATH)}util.h
|
||||
version.$(OBJEXT): {$(VPATH)}version.c {$(VPATH)}ruby.h config.h \
|
||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||
{$(VPATH)}version.h
|
||||
{$(VPATH)}version.h {$(VPATH)}yarv_version.h
|
||||
|
||||
compile.$(OBJEXT): {$(VPATH)}compile.c {$(VPATH)}yarvcore.h \
|
||||
{$(VPATH)}compile.h {$(VPATH)}debug.h \
|
||||
insns.inc insns_info.inc optinsn.inc opt_sc.inc optunifs.inc vm_opts.h
|
||||
iseq.$(OBJEXT): {$(VPATH)}iseq.c {$(VPATH)}yarvcore.h {$(VPATH)}debug.h vm_opts.h
|
||||
vm.$(OBJEXT): {$(VPATH)}vm.c {$(VPATH)}vm.h {$(VPATH)}insnhelper.h \
|
||||
{$(VPATH)}yarvcore.h {$(VPATH)}debug.h \
|
||||
{$(VPATH)}vm_evalbody.ci {$(VPATH)}call_cfunc.ci \
|
||||
insns.inc vm.inc vmtc.inc vm_macro.inc vm_opts.h {$(VPATH)}eval_intern.h
|
||||
vm_dump.$(OBJEXT): {$(VPATH)}yarvcore.h {$(VPATH)}vm.h
|
||||
yarvcore.$(OBJEXT): {$(VPATH)}yarvcore.c {$(VPATH)}yarvcore.h \
|
||||
{$(VPATH)}yarv_version.h {$(VPATH)}debug.h
|
||||
debug.$(OBJEXT): {$(VPATH)}debug.h
|
||||
blockinlining.$(OBJEXT): {$(VPATH)}yarv.h {$(VPATH)}yarvcore.h vm_opts.h
|
||||
|
||||
|
||||
BASERUBY = ruby
|
||||
|
||||
INSNS2VMOPT = $(CPPFLAGS) --srcdir=$(srcdir)
|
||||
|
||||
minsns.inc:
|
||||
$(BASERUBY) $(srcdir)/tool/insns2vm.rb $(INSNS2VMOPT)
|
||||
|
||||
opt_sc.inc:
|
||||
$(BASERUBY) $(srcdir)/tool/insns2vm.rb $(INSNS2VMOPT)
|
||||
|
||||
optinsn.inc:
|
||||
$(BASERUBY) $(srcdir)/tool/insns2vm.rb $(INSNS2VMOPT) optinsn.inc
|
||||
|
||||
optunifs.inc:
|
||||
$(BASERUBY) $(srcdir)/tool/insns2vm.rb $(INSNS2VMOPT) optunifs.inc
|
||||
|
||||
insns.inc:
|
||||
$(BASERUBY) $(srcdir)/tool/insns2vm.rb $(INSNS2VMOPT)
|
||||
|
||||
vmtc.inc:
|
||||
$(BASERUBY) $(srcdir)/tool/insns2vm.rb $(INSNS2VMOPT) vmtc.inc
|
||||
|
||||
vm.inc: $(srcdir)/insns.def
|
||||
$(BASERUBY) $(srcdir)/tool/insns2vm.rb $(INSNS2VMOPT) vm.inc
|
||||
|
||||
vm_macro.inc: $(srcdir)/vm_macro.def
|
||||
$(BASERUBY) $(srcdir)/rb/insns2vm.rb $(INSNS2VMOPT) vm_macro.inc
|
||||
|
||||
vm_opts.h: $(srcdir)/vm_opts.h.base
|
||||
$(BASERUBY) $(srcdir)/tool/insns2vm.rb $(INSNS2VMOPT)
|
||||
|
||||
incs:
|
||||
$(BASERUBY) $(srcdir)/tool/insns2vm.rb $(INSNS2VMOPT)
|
||||
|
||||
docs:
|
||||
$(BASERUBY) -I$(srcdir) $(srcdir)/tool/makedocs.rb $(INSNS2VMOPT)
|
||||
|
||||
yarv-test-all: miniruby$(EXEEXT)
|
||||
$(BASERUBY) -I$(srcdir) $(srcdir)/yarvtest/runner.rb $(OPT) yarv=$(MINIRUBY) ruby=$(BASERUBY)
|
||||
|
||||
yarv-test-each: miniruby$(EXEEXT)
|
||||
$(BASERUBY) -I$(srcdir) $(srcdir)/yarvtest/test_$(ITEM).rb $(OPT) yarv=$(MINIRUBY) ruby=$(BASERUBY)
|
||||
|
||||
allload: miniruby$(EXEEXT)
|
||||
$(MINIRUBY) -I$(srcdir) $(srcdir)/tool/allload.rb `$(BASERUBY) -rrbconfig -e 'print Config::CONFIG["rubylibdir"]'`
|
||||
|
||||
run: miniruby$(EXEEXT)
|
||||
$(MINIRUBY) -I$(srcdir)/lib $(srcdir)/test.rb $(RUNOPT)
|
||||
|
||||
runruby: $(RUBY)
|
||||
./$(RUBY) -I$(srcdir)/lib -I. $(srcdir)/tool/runruby.rb $(srcdir)/test.rb
|
||||
|
||||
parse: miniruby$(EXEEXT)
|
||||
$(MINIRUBY) $(srcdir)/tool/parse.rb $(srcdir)/test.rb
|
||||
|
||||
benchmark: $(RUBY)
|
||||
$(BASERUBY) -I$(srcdir) -I$(srcdir)/lib $(srcdir)/benchmark/run_rite.rb $(OPT) $(ITEMS) --yarv-program=./$(PROGRAM) --ruby-program=$(BASERUBY) --opts=-I$(srcdir)/lib
|
||||
|
||||
tbench: prog
|
||||
$(BASERUBY) -I$(srcdir) -I$(srcdir)/lib $(srcdir)/benchmark/run_rite.rb bmx $(OPT) --yarv-program=./$(PROGRAM) --ruby-program=$(BASERUBY) --opts=-I$(srcdir)/lib
|
||||
|
||||
bench-each: $(RUBY)
|
||||
$(BASERUBY) -I$(srcdir) $(srcdir)/benchmark/run_rite.rb bm_$(ITEM) $(OPT) --yarv-program=./$(RUBY) --ruby-program=$(BASERUBY) --opts=-I$(srcdir)/lib
|
||||
|
||||
aotc:
|
||||
$(RUBY) -I$(srcdir) -I. $(srcdir)/tool/aotcompile.rb $(INSNS2VMOPT)
|
||||
|
||||
# for GCC
|
||||
vmasm:
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -S $(srcdir)/vm.c
|
||||
|
||||
# vm.o : CFLAGS += -fno-crossjumping
|
||||
|
||||
run.gdb:
|
||||
echo b debug_breakpoint > run.gdb
|
||||
echo handle SIGINT nostop
|
||||
echo handle SIGPIPE nostop
|
||||
echo run >> run.gdb
|
||||
|
||||
gdb: miniruby$(EXEEXT) run.gdb
|
||||
gdb -x run.gdb --quiet --args $(MINIRUBY) -I$(srcdir)/lib $(srcdir)/test.rb
|
||||
|
||||
# Intel VTune
|
||||
|
||||
vtune: miniruby$(EXEEXT)
|
||||
vtl activity -c sampling -app ".\miniruby$(EXEEXT)","-I$(srcdir)/lib $(srcdir)/test.rb" run
|
||||
vtl view -hf -mn miniruby$(EXEEXT) -sum -sort -cd
|
||||
vtl view -ha -mn miniruby$(EXEEXT) -sum -sort -cd | $(BASERUBY) $(srcdir)/tool/vtlh.rb > ha.lines
|
||||
|
||||
|
210
compile.h
Normal file
210
compile.h
Normal file
@ -0,0 +1,210 @@
|
||||
/**********************************************************************
|
||||
|
||||
compile.h -
|
||||
|
||||
$Author$
|
||||
$Date$
|
||||
created at: 04/01/01 23:36:57 JST
|
||||
|
||||
Copyright (C) 2004-2006 Koichi Sasada
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _COMPILER_H_INCLUDED_
|
||||
#define _COMPILER_H_INCLUDED_
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#if YARVDEBUG > CPDEBUG
|
||||
#undef CPDEBUG
|
||||
#define CPDEBUG YARVDEBUG
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/**
|
||||
* debug function(macro) interface depend on CPDEBUG
|
||||
*
|
||||
* debug level:
|
||||
* 0: no debug output
|
||||
* 1: show node type
|
||||
* 2: show node important parameters
|
||||
* ...
|
||||
* 5: show other parameters
|
||||
* 10: show every AST array
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#undef CPDEBUG
|
||||
#define CPDEBUG 2
|
||||
#endif
|
||||
|
||||
#if CPDEBUG > 0
|
||||
|
||||
#define debugp(header, value) \
|
||||
(debug_indent(0, CPDEBUG, gl_node_level * 2), \
|
||||
debug_value(0, CPDEBUG, header, value))
|
||||
|
||||
#define debugi(header, id) \
|
||||
(debug_indent(0, CPDEBUG, gl_node_level * 2), \
|
||||
debug_id(0, CPDEBUG, header, id))
|
||||
|
||||
#define debugp_param(header, value) \
|
||||
(debug_indent(1, CPDEBUG, gl_node_level * 2), \
|
||||
debug_value(1, CPDEBUG, header, value))
|
||||
|
||||
#define debugp_verbose(header, value) \
|
||||
(debug_indent(2, CPDEBUG, gl_node_level * 2), \
|
||||
debug_value(2, CPDEBUG, header, value))
|
||||
|
||||
#define debugp_verbose_node(header, value) \
|
||||
(debug_indent(10, CPDEBUG, gl_node_level * 2), \
|
||||
debug_value(10, CPDEBUG, header, value))
|
||||
|
||||
#define debug_nodeprint(node) \
|
||||
debug_indent(-1, CPDEBUG, gl_node_level*2); \
|
||||
printf("node: %s (%d)\n", node_name(nd_type(node)), nd_line(node)); \
|
||||
gl_node_level ++;
|
||||
|
||||
#define debug_nodeprint_close() gl_node_level --;
|
||||
|
||||
#else
|
||||
|
||||
static inline ID
|
||||
r_id(ID id)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
r_value(VALUE value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
#define debugi(header, id) r_id(id)
|
||||
#define debugp(header, value) r_value(value)
|
||||
#define debugp_verbose(header, value) r_value(value)
|
||||
#define debugp_verbose_node(header, value) r_value(value)
|
||||
#define debugp_param(header, value) r_value(value)
|
||||
#define debug_nodeprint(node)
|
||||
#define debug_nodeprint_close()
|
||||
#endif
|
||||
|
||||
#if CPDEBUG > 1
|
||||
#define debugs debug_indent(-1, CPDEBUG, gl_node_level*2), printf
|
||||
#define debug_compile(msg, v) (debug_indent(-1, CPDEBUG, gl_node_level*2), printf("%s", msg), (v))
|
||||
#else
|
||||
#define debugs if(0)printf
|
||||
#define debug_compile(msg, v) (v)
|
||||
#endif
|
||||
|
||||
|
||||
/* create new label */
|
||||
#define NEW_LABEL(l) new_label_body(iseq, l)
|
||||
|
||||
#define iseq_filename(iseq) \
|
||||
(((yarv_iseq_t*)DATA_PTR(iseq))->file_name)
|
||||
|
||||
#define NEW_ISEQVAL(node, name, type) \
|
||||
new_child_iseq(iseq, node, name, 0, type)
|
||||
|
||||
#define NEW_CHILD_ISEQVAL(node, name, type) \
|
||||
new_child_iseq(iseq, node, name, iseq->self, type)
|
||||
|
||||
#define NEW_SPECIAQL_BLOCK_ISEQVAL(iseq, sym) \
|
||||
new_child_iseq(iseq, iseq->node, iseq->name, iseq->parent_iseq, iseq->type, sym)
|
||||
|
||||
/* add instructions */
|
||||
#define ADD_SEQ(seq1, seq2) \
|
||||
APPEND_LIST(seq1, seq2)
|
||||
|
||||
/* add an instruction */
|
||||
#define ADD_INSN(seq, line, insn) \
|
||||
ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line, BIN(insn), 0))
|
||||
|
||||
/* add an instruction with label operand */
|
||||
#define ADD_INSNL(seq, line, insn, label) \
|
||||
ADD_ELEM(seq, (LINK_ELEMENT *) \
|
||||
new_insn_body(iseq, line, BIN(insn), 1, (VALUE)label))
|
||||
|
||||
/* add an instruction with some operands (1, 2, 3, 5) */
|
||||
#define ADD_INSN1(seq, line, insn, op1) \
|
||||
ADD_ELEM(seq, (LINK_ELEMENT *) \
|
||||
new_insn_body(iseq, line, BIN(insn), 1, (VALUE)op1))
|
||||
|
||||
#define ADD_INSN2(seq, line, insn, op1, op2) \
|
||||
ADD_ELEM(seq, (LINK_ELEMENT *) \
|
||||
new_insn_body(iseq, line, BIN(insn), 2, (VALUE)op1, (VALUE)op2))
|
||||
|
||||
#define ADD_INSN3(seq, line, insn, op1, op2, op3) \
|
||||
ADD_ELEM(seq, (LINK_ELEMENT *) \
|
||||
new_insn_body(iseq, line, BIN(insn), 3, (VALUE)op1, (VALUE)op2, (VALUE)op3))
|
||||
|
||||
/* Specific Insn factory */
|
||||
#define ADD_SEND(seq, line, id, argc) \
|
||||
ADD_SEND_R(seq, line, id, argc, (VALUE)Qfalse, (VALUE)INT2FIX(0))
|
||||
|
||||
#define ADD_CALL(seq, line, id, argc) \
|
||||
ADD_SEND_R(seq, line, id, argc, (VALUE)Qfalse, (VALUE)INT2FIX(VM_CALL_FCALL_BIT))
|
||||
|
||||
#define ADD_SEND_R(seq, line, id, argc, block, flag) \
|
||||
ADD_ELEM(seq, (LINK_ELEMENT *) \
|
||||
new_insn_send(iseq, line, \
|
||||
(VALUE)id, (VALUE)argc, (VALUE)block, (VALUE)flag))
|
||||
|
||||
/* add label */
|
||||
#define ADD_LABEL(seq, label) \
|
||||
ADD_ELEM(seq, (LINK_ELEMENT *)label)
|
||||
|
||||
#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) \
|
||||
(tmp = rb_ary_new(), \
|
||||
rb_ary_push(tmp, type), \
|
||||
rb_ary_push(tmp, (VALUE) ls | 1), \
|
||||
rb_ary_push(tmp, (VALUE) le | 1), \
|
||||
rb_ary_push(tmp, iseqv), \
|
||||
rb_ary_push(tmp, (VALUE) lc | 1), \
|
||||
rb_ary_push(iseq->compile_data->catch_table_ary, tmp))
|
||||
|
||||
/* compile node */
|
||||
#define COMPILE(anchor, desc, node) \
|
||||
(debug_compile("== " desc "\n", \
|
||||
iseq_compile_each(iseq, anchor, node, 0)))
|
||||
|
||||
/* compile node, this node's value will be poped */
|
||||
#define COMPILE_POPED(anchor, desc, node) \
|
||||
(debug_compile("== " desc "\n", \
|
||||
iseq_compile_each(iseq, anchor, node, 1)))
|
||||
|
||||
/* compile node, which is poped when 'poped' is true */
|
||||
#define COMPILE_(anchor, desc, node, poped) \
|
||||
(debug_compile("== " desc "\n", \
|
||||
iseq_compile_each(iseq, anchor, node, poped)))
|
||||
|
||||
#define OPERAND_AT(insn, idx) \
|
||||
(((INSN*)(insn))->operands[idx])
|
||||
|
||||
#define INSN_OF(insn) \
|
||||
(((INSN*)(insn))->insn_id)
|
||||
|
||||
/* error */
|
||||
#define COMPILE_ERROR(strs) \
|
||||
{ \
|
||||
VALUE tmp = GET_THREAD()->errinfo; \
|
||||
if(CPDEBUG)rb_bug strs; \
|
||||
GET_THREAD()->errinfo = iseq->compile_data->err_info; \
|
||||
rb_compile_error strs; \
|
||||
iseq->compile_data->err_info = GET_THREAD()->errinfo; \
|
||||
GET_THREAD()->errinfo = tmp; \
|
||||
ret = 0; \
|
||||
break; \
|
||||
}
|
||||
|
||||
|
||||
#define COMPILE_OK 1
|
||||
#define COMPILE_NG 0
|
||||
|
||||
#define DECL_ANCHOR(name) \
|
||||
LINK_ANCHOR name##_body__ = {{0,}, &name##_body__.anchor}; \
|
||||
LINK_ANCHOR *name = & name##_body__
|
||||
|
||||
#endif // _COMPILER_H_INCLUDED_
|
15
configure.in
15
configure.in
@ -71,6 +71,7 @@ fi
|
||||
if test "$program_prefix" = NONE; then
|
||||
program_prefix=
|
||||
fi
|
||||
|
||||
AC_CANONICAL_TARGET
|
||||
target_os=`echo $target_os | sed 's/linux-gnu$/linux/;s/linux-gnu/linux-/'`
|
||||
ac_install_sh='' # unusable for extension libraries.
|
||||
@ -183,7 +184,7 @@ cygwin*|mingw*)
|
||||
AC_TRY_LINK([#include <stdio.h>],
|
||||
[FILE* volatile f = stdin; return 0;],
|
||||
[rb_cv_msvcrt=`$OBJDUMP -p conftest$ac_exeext |
|
||||
tr A-Z a-z |
|
||||
tr A-Z a-z |
|
||||
sed -n '/^[[ ]]*dll name: \(msvc.*\)\.dll$/{s//\1/p;q;}'`],
|
||||
[rb_cv_msvcrt=msvcrt])
|
||||
test "$rb_cv_msvcrt" = "" && rb_cv_msvcrt=msvcrt])
|
||||
@ -345,7 +346,7 @@ AC_ARG_WITH(libc_r,
|
||||
|
||||
AC_ARG_ENABLE(pthread,
|
||||
[ --enable-pthread use pthread library.],
|
||||
[enable_pthread=$enableval], [enable_pthread=no])
|
||||
[enable_pthread=$enableval], [enable_pthread=yes])
|
||||
|
||||
dnl Checks for libraries.
|
||||
case "$target_os" in
|
||||
@ -831,6 +832,8 @@ if test x"$ac_cv_header_ucontext_h" = xyes; then
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_CHECK_FUNCS(backtrace)
|
||||
|
||||
dnl default value for $KANJI
|
||||
DEFAULT_KCODE="KCODE_NONE"
|
||||
|
||||
@ -1004,11 +1007,11 @@ if test "$with_dln_a_out" != yes; then
|
||||
LDFLAGS='-brtl'
|
||||
XLDFLAGS='-bE:ruby.imp'
|
||||
fi
|
||||
: ${ARCHFILE="ruby.imp"}
|
||||
: ${ARCHFILE="ruby.imp"}
|
||||
TRY_LINK='$(CC) $(LDFLAGS) -oconftest $(INCFLAGS) -I$(hdrdir) $(CPPFLAGS)'
|
||||
TRY_LINK="$TRY_LINK"' $(CFLAGS) $(src) $(LIBPATH) $(LOCAL_LIBS) $(LIBS)'
|
||||
: ${LIBPATHENV=SHLIB_PATH}
|
||||
rb_cv_dlopen=yes ;;
|
||||
: ${LIBPATHENV=SHLIB_PATH}
|
||||
rb_cv_dlopen=yes ;;
|
||||
human*) : ${DLDFLAGS=''}
|
||||
: ${LDSHARED=''}
|
||||
: ${LDFLAGS=''}
|
||||
@ -1354,7 +1357,7 @@ if test "$enable_shared" = 'yes'; then
|
||||
fi
|
||||
if test "$enable_rpath" = yes; then
|
||||
if test "$GCC" = yes; then
|
||||
LIBRUBYARG_SHARED='-Wl,-R -Wl,$(libdir) -L$(libdir) -L. '"$LIBRUBYARG_SHARED"
|
||||
LIBRUBYARG_SHARED='-Wl,-R -Wl,$(libdir) -L$(libdir) -L. '"$LIBRUBYARG_SHARED"
|
||||
else
|
||||
LIBRUBYARG_SHARED='-R $(libdir) -L$(libdir) -L. '"$LIBRUBYARG_SHARED"
|
||||
fi
|
||||
|
71
debug.c
Normal file
71
debug.c
Normal file
@ -0,0 +1,71 @@
|
||||
/**********************************************************************
|
||||
|
||||
debug.c -
|
||||
|
||||
$Author$
|
||||
$Date$
|
||||
created at: 04/08/25 02:31:54 JST
|
||||
|
||||
Copyright (C) 2004-2006 Koichi Sasada
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "ruby.h"
|
||||
|
||||
void
|
||||
debug_indent(int level, int debug_level, int indent_level)
|
||||
{
|
||||
if (level < debug_level) {
|
||||
int i;
|
||||
for (i = 0; i < indent_level; i++) {
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
VALUE
|
||||
debug_value(int level, int debug_level, char *header, VALUE obj)
|
||||
{
|
||||
if (level < debug_level) {
|
||||
VALUE str;
|
||||
str = rb_inspect(obj);
|
||||
fprintf(stderr, "DBG> %s: %s\n", header,
|
||||
obj == -1 ? "" : StringValueCStr(str));
|
||||
fflush(stderr);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
void
|
||||
debug_v(VALUE v)
|
||||
{
|
||||
debug_value(0, 1, "", v);
|
||||
}
|
||||
|
||||
ID
|
||||
debug_id(int level, int debug_level, char *header, ID id)
|
||||
{
|
||||
if (level < debug_level) {
|
||||
fprintf(stderr, "DBG> %s: %s\n", header, rb_id2name(id));
|
||||
fflush(stderr);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
gc_check_func(void)
|
||||
{
|
||||
int i;
|
||||
#define GCMKMAX 0x10
|
||||
for (i = 0; i < GCMKMAX; i++) {
|
||||
rb_ary_new2(1000);
|
||||
}
|
||||
rb_gc();
|
||||
}
|
||||
|
||||
void
|
||||
debug_breakpoint(void)
|
||||
{
|
||||
/* */
|
||||
}
|
47
debug.h
Normal file
47
debug.h
Normal file
@ -0,0 +1,47 @@
|
||||
/**********************************************************************
|
||||
|
||||
debug.h - YARV Debug function interface
|
||||
|
||||
$Author$
|
||||
$Date$
|
||||
created at: 04/08/25 02:33:49 JST
|
||||
|
||||
Copyright (C) 2004-2006 Koichi Sasada
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _DEBUG_H_INCLUDED_
|
||||
#define _DEBUG_H_INCLUDED_
|
||||
|
||||
#include <ruby.h>
|
||||
|
||||
VALUE debug_value(int level, int debug_level, char *header, VALUE v);
|
||||
ID debug_id(int level, int debug_level, char *header, ID id);
|
||||
void debug_indent(int level, int debug_level, int indent_level);
|
||||
|
||||
#define dpv(h,v) debug_value(-1, 0, h, v)
|
||||
#define dp(v) debug_value(-1, 0, "", v)
|
||||
#define dpi(i) debug_id (-1, 0, "", i)
|
||||
#define bp() debug_breakpoint()
|
||||
|
||||
void gc_check_func();
|
||||
|
||||
#if GCDEBUG == 1
|
||||
|
||||
#define GC_CHECK() \
|
||||
gc_check_func()
|
||||
|
||||
#elif GCDEBUG == 2
|
||||
|
||||
#define GC_CHECK() \
|
||||
(printf("** %s:%d gc start\n", __FILE__, __LINE__), \
|
||||
gc_check_func(), \
|
||||
printf("** end\n"))
|
||||
|
||||
#else
|
||||
|
||||
#define GC_CHECK()
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _DEBUG_H_INCLUDED_
|
6917
doc/ChangeLog-YARV
Normal file
6917
doc/ChangeLog-YARV
Normal file
File diff suppressed because it is too large
Load Diff
57
error.c
57
error.c
@ -11,8 +11,8 @@
|
||||
**********************************************************************/
|
||||
|
||||
#include "ruby.h"
|
||||
#include "env.h"
|
||||
#include "st.h"
|
||||
#include "yarv.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
@ -24,21 +24,23 @@
|
||||
#endif
|
||||
|
||||
extern const char ruby_version[], ruby_release_date[], ruby_platform[];
|
||||
|
||||
int ruby_nerrs;
|
||||
|
||||
const char *rb_sourcefile();
|
||||
int rb_sourceline();
|
||||
|
||||
static int
|
||||
err_position(char *buf, long len)
|
||||
{
|
||||
ruby_set_current_source();
|
||||
if (!ruby_sourcefile) {
|
||||
if (!rb_sourcefile()) {
|
||||
return 0;
|
||||
}
|
||||
else if (ruby_sourceline == 0) {
|
||||
return snprintf(buf, len, "%s: ", ruby_sourcefile);
|
||||
else if (rb_sourceline() == 0) {
|
||||
return snprintf(buf, len, "%s: ", rb_sourcefile());
|
||||
}
|
||||
else {
|
||||
return snprintf(buf, len, "%s:%d: ", ruby_sourcefile, ruby_sourceline);
|
||||
return snprintf(buf, len, "%s:%d: ", rb_sourcefile(), rb_sourceline());
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,7 +69,6 @@ void
|
||||
rb_compile_error(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
err_print(fmt, args);
|
||||
va_end(args);
|
||||
@ -147,6 +148,8 @@ rb_warn_m(VALUE self, VALUE mesg)
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
void yarv_bug();
|
||||
|
||||
void
|
||||
rb_bug(const char *fmt, ...)
|
||||
{
|
||||
@ -157,6 +160,7 @@ rb_bug(const char *fmt, ...)
|
||||
|
||||
if (fwrite(buf, 1, len, out) == len ||
|
||||
fwrite(buf, 1, len, (out = stdout)) == len) {
|
||||
yarv_bug();
|
||||
fputs("[BUG] ", out);
|
||||
va_start(args, fmt);
|
||||
vfprintf(out, fmt, args);
|
||||
@ -164,6 +168,7 @@ rb_bug(const char *fmt, ...)
|
||||
fprintf(out, "\nruby %s (%s) [%s]\n\n",
|
||||
ruby_version, ruby_release_date, ruby_platform);
|
||||
}
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
@ -190,8 +195,6 @@ static struct types {
|
||||
{T_SYMBOL, "Symbol"}, /* :symbol */
|
||||
{T_DATA, "Data"}, /* internal use: wrapped C pointers */
|
||||
{T_MATCH, "MatchData"}, /* data of $~ */
|
||||
{T_VARMAP, "Varmap"}, /* internal use: dynamic variables */
|
||||
{T_SCOPE, "Scope"}, /* internal use: variable scope */
|
||||
{T_NODE, "Node"}, /* internal use: syntax tree node */
|
||||
{T_UNDEF, "undef"}, /* internal use: #undef; should not happen */
|
||||
{-1, 0}
|
||||
@ -1024,9 +1027,9 @@ rb_loaderror(const char *fmt, ...)
|
||||
void
|
||||
rb_notimplement(void)
|
||||
{
|
||||
rb_raise(rb_eNotImpError,
|
||||
"The %s() function is unimplemented on this machine",
|
||||
rb_id2name(ruby_frame->callee));
|
||||
rb_raise(rb_eNotImpError,
|
||||
"The %s() function is unimplemented on this machine",
|
||||
rb_id2name(rb_frame_callee()));
|
||||
}
|
||||
|
||||
void
|
||||
@ -1039,7 +1042,6 @@ rb_fatal(const char *fmt, ...)
|
||||
vsnprintf(buf, BUFSIZ, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
ruby_in_eval = 0;
|
||||
rb_exc_fatal(rb_exc_new2(rb_eFatal, buf));
|
||||
}
|
||||
|
||||
@ -1471,22 +1473,21 @@ Init_syserr(void)
|
||||
static void
|
||||
err_append(const char *s)
|
||||
{
|
||||
extern VALUE ruby_errinfo;
|
||||
|
||||
if (ruby_in_eval) {
|
||||
if (NIL_P(ruby_errinfo)) {
|
||||
ruby_errinfo = rb_exc_new2(rb_eSyntaxError, s);
|
||||
}
|
||||
else {
|
||||
VALUE str = rb_obj_as_string(ruby_errinfo);
|
||||
|
||||
rb_str_cat2(str, "\n");
|
||||
rb_str_cat2(str, s);
|
||||
ruby_errinfo = rb_exc_new3(rb_eSyntaxError, str);
|
||||
}
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
if (th->parse_in_eval) {
|
||||
if (NIL_P(th->errinfo)) {
|
||||
th->errinfo = rb_exc_new2(rb_eSyntaxError, s);
|
||||
}
|
||||
else {
|
||||
rb_write_error(s);
|
||||
rb_write_error("\n");
|
||||
VALUE str = rb_obj_as_string(GET_THREAD()->errinfo);
|
||||
|
||||
rb_str_cat2(str, "\n");
|
||||
rb_str_cat2(str, s);
|
||||
th->errinfo = rb_exc_new3(rb_eSyntaxError, str);
|
||||
}
|
||||
}
|
||||
else {
|
||||
rb_write_error(s);
|
||||
rb_write_error("\n");
|
||||
}
|
||||
}
|
||||
|
250
eval_error.h
Normal file
250
eval_error.h
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* included by eval.c
|
||||
*/
|
||||
|
||||
#define SET_CURRENT_SOURCE() ((void)0)
|
||||
|
||||
void
|
||||
ruby_set_current_source(void)
|
||||
{
|
||||
if (ruby_current_node) {
|
||||
ruby_sourcefile = ruby_current_node->nd_file;
|
||||
ruby_sourceline = nd_line(ruby_current_node);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
warn_printf(const char *fmt, ...)
|
||||
{
|
||||
char buf[BUFSIZ];
|
||||
va_list args;
|
||||
|
||||
va_init_list(args, fmt);
|
||||
vsnprintf(buf, BUFSIZ, fmt, args);
|
||||
va_end(args);
|
||||
rb_write_error(buf);
|
||||
}
|
||||
|
||||
#define warn_print(x) rb_write_error(x)
|
||||
#define warn_print2(x,l) rb_write_error2(x,l)
|
||||
|
||||
static void
|
||||
error_pos(void)
|
||||
{
|
||||
ruby_set_current_source();
|
||||
if (ruby_sourcefile) {
|
||||
if (ruby_sourceline == 0) {
|
||||
warn_printf("%s", ruby_sourcefile);
|
||||
}
|
||||
else if (rb_frame_callee()) {
|
||||
warn_printf("%s:%d:in `%s'", ruby_sourcefile, ruby_sourceline,
|
||||
rb_id2name(rb_frame_callee()));
|
||||
}
|
||||
else {
|
||||
warn_printf("%s:%d", ruby_sourcefile, ruby_sourceline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
get_backtrace(VALUE info)
|
||||
{
|
||||
if (NIL_P(info))
|
||||
return Qnil;
|
||||
info = rb_funcall(info, rb_intern("backtrace"), 0);
|
||||
if (NIL_P(info))
|
||||
return Qnil;
|
||||
return rb_check_array_type(info);
|
||||
}
|
||||
|
||||
static void
|
||||
set_backtrace(VALUE info, VALUE bt)
|
||||
{
|
||||
rb_funcall(info, rb_intern("set_backtrace"), 1, bt);
|
||||
}
|
||||
|
||||
static void
|
||||
error_print(void)
|
||||
{
|
||||
VALUE errat = Qnil; /* OK */
|
||||
volatile VALUE eclass, e;
|
||||
char *einfo;
|
||||
long elen;
|
||||
|
||||
if (NIL_P(GET_THREAD()->errinfo))
|
||||
return;
|
||||
|
||||
PUSH_TAG(PROT_NONE);
|
||||
if (EXEC_TAG() == 0) {
|
||||
errat = get_backtrace(GET_THREAD()->errinfo);
|
||||
}
|
||||
else {
|
||||
errat = Qnil;
|
||||
}
|
||||
if (EXEC_TAG())
|
||||
goto error;
|
||||
if (NIL_P(errat)) {
|
||||
ruby_set_current_source();
|
||||
if (ruby_sourcefile)
|
||||
warn_printf("%s:%d", ruby_sourcefile, ruby_sourceline);
|
||||
else
|
||||
warn_printf("%d", ruby_sourceline);
|
||||
}
|
||||
else if (RARRAY_LEN(errat) == 0) {
|
||||
error_pos();
|
||||
}
|
||||
else {
|
||||
VALUE mesg = RARRAY_PTR(errat)[0];
|
||||
|
||||
if (NIL_P(mesg))
|
||||
error_pos();
|
||||
else {
|
||||
warn_print2(RSTRING_PTR(mesg), RSTRING_LEN(mesg));
|
||||
}
|
||||
}
|
||||
|
||||
eclass = CLASS_OF(GET_THREAD()->errinfo);
|
||||
if (EXEC_TAG() == 0) {
|
||||
e = rb_funcall(GET_THREAD()->errinfo, rb_intern("message"), 0, 0);
|
||||
StringValue(e);
|
||||
einfo = RSTRING_PTR(e);
|
||||
elen = RSTRING_LEN(e);
|
||||
}
|
||||
else {
|
||||
einfo = "";
|
||||
elen = 0;
|
||||
}
|
||||
if (EXEC_TAG())
|
||||
goto error;
|
||||
if (eclass == rb_eRuntimeError && elen == 0) {
|
||||
warn_print(": unhandled exception\n");
|
||||
}
|
||||
else {
|
||||
VALUE epath;
|
||||
|
||||
epath = rb_class_name(eclass);
|
||||
if (elen == 0) {
|
||||
warn_print(": ");
|
||||
warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
|
||||
warn_print("\n");
|
||||
}
|
||||
else {
|
||||
char *tail = 0;
|
||||
long len = elen;
|
||||
|
||||
if (RSTRING_PTR(epath)[0] == '#')
|
||||
epath = 0;
|
||||
if (tail = memchr(einfo, '\n', elen)) {
|
||||
len = tail - einfo;
|
||||
tail++; /* skip newline */
|
||||
}
|
||||
warn_print(": ");
|
||||
warn_print2(einfo, len);
|
||||
if (epath) {
|
||||
warn_print(" (");
|
||||
warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
|
||||
warn_print(")\n");
|
||||
}
|
||||
if (tail) {
|
||||
warn_print2(tail, elen - len - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!NIL_P(errat)) {
|
||||
long i;
|
||||
long len = RARRAY_LEN(errat);
|
||||
VALUE *ptr = RARRAY_PTR(errat);
|
||||
|
||||
#define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
|
||||
#define TRACE_HEAD 8
|
||||
#define TRACE_TAIL 5
|
||||
|
||||
for (i = 1; i < len; i++) {
|
||||
if (TYPE(ptr[i]) == T_STRING) {
|
||||
warn_printf("\tfrom %s\n", RSTRING_PTR(ptr[i]));
|
||||
}
|
||||
if (i == TRACE_HEAD && len > TRACE_MAX) {
|
||||
warn_printf("\t ... %ld levels...\n",
|
||||
len - TRACE_HEAD - TRACE_TAIL);
|
||||
i = len - TRACE_TAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
error:
|
||||
POP_TAG();
|
||||
}
|
||||
|
||||
void
|
||||
print_undef(VALUE klass, ID id)
|
||||
{
|
||||
rb_name_error(id, "undefined method `%s' for %s `%s'",
|
||||
rb_id2name(id),
|
||||
(TYPE(klass) == T_MODULE) ? "module" : "class",
|
||||
rb_class2name(klass));
|
||||
}
|
||||
|
||||
VALUE exception_error;
|
||||
VALUE sysstack_error;
|
||||
|
||||
static int
|
||||
sysexit_status(VALUE err)
|
||||
{
|
||||
VALUE st = rb_iv_get(err, "status");
|
||||
return NUM2INT(st);
|
||||
}
|
||||
|
||||
static int
|
||||
error_handle(int ex)
|
||||
{
|
||||
int status = EXIT_FAILURE;
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
|
||||
if (thread_set_raised(th))
|
||||
return EXIT_FAILURE;
|
||||
switch (ex & TAG_MASK) {
|
||||
case 0:
|
||||
status = EXIT_SUCCESS;
|
||||
break;
|
||||
|
||||
case TAG_RETURN:
|
||||
error_pos();
|
||||
warn_print(": unexpected return\n");
|
||||
break;
|
||||
case TAG_NEXT:
|
||||
error_pos();
|
||||
warn_print(": unexpected next\n");
|
||||
break;
|
||||
case TAG_BREAK:
|
||||
error_pos();
|
||||
warn_print(": unexpected break\n");
|
||||
break;
|
||||
case TAG_REDO:
|
||||
error_pos();
|
||||
warn_print(": unexpected redo\n");
|
||||
break;
|
||||
case TAG_RETRY:
|
||||
error_pos();
|
||||
warn_print(": retry outside of rescue clause\n");
|
||||
break;
|
||||
case TAG_THROW:
|
||||
// TODO: fix me
|
||||
error_pos();
|
||||
warn_printf(": unexpected throw\n");
|
||||
break;
|
||||
case TAG_RAISE:
|
||||
case TAG_FATAL:
|
||||
if (rb_obj_is_kind_of(GET_THREAD()->errinfo, rb_eSystemExit)) {
|
||||
status = sysexit_status(GET_THREAD()->errinfo);
|
||||
}
|
||||
else {
|
||||
error_print();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rb_bug("Unknown longjmp status %d", ex);
|
||||
break;
|
||||
}
|
||||
thread_reset_raised(th);
|
||||
return status;
|
||||
}
|
328
eval_intern.h
Normal file
328
eval_intern.h
Normal file
@ -0,0 +1,328 @@
|
||||
|
||||
#ifndef EVAL_INTERN_H_INCLUDED
|
||||
#define EVAL_INTERN_H_INCLUDED
|
||||
|
||||
#define PASS_PASSED_BLOCK() \
|
||||
(GET_THREAD()->passed_block = \
|
||||
GC_GUARDED_PTR_REF((yarv_block_t *)GET_THREAD()->cfp->lfp[0]))
|
||||
|
||||
|
||||
#define UNSUPPORTED(func) \
|
||||
{ \
|
||||
int *a = 0; \
|
||||
fprintf(stderr, "%s", "-- unsupported: " #func "\n"); fflush(stderr); \
|
||||
*a = 0; \
|
||||
rb_bug("unsupported: " #func); \
|
||||
}
|
||||
|
||||
#include "ruby.h"
|
||||
#include "node.h"
|
||||
#include "util.h"
|
||||
#include "rubysig.h"
|
||||
#include "yarv.h"
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifndef EXIT_SUCCESS
|
||||
#define EXIT_SUCCESS 0
|
||||
#endif
|
||||
#ifndef EXIT_FAILURE
|
||||
#define EXIT_FAILURE 1
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "st.h"
|
||||
#include "dln.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <crt_externs.h>
|
||||
#endif
|
||||
|
||||
/* Make alloca work the best possible way. */
|
||||
#ifdef __GNUC__
|
||||
# ifndef atarist
|
||||
# ifndef alloca
|
||||
# define alloca __builtin_alloca
|
||||
# endif
|
||||
# endif /* atarist */
|
||||
#else
|
||||
# ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# ifdef _AIX
|
||||
#pragma alloca
|
||||
# else
|
||||
# ifndef alloca /* predefined by HP cc +Olibcalls */
|
||||
void *alloca();
|
||||
# endif
|
||||
# endif /* AIX */
|
||||
# endif /* HAVE_ALLOCA_H */
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#ifdef HAVE_STDARG_PROTOTYPES
|
||||
#include <stdarg.h>
|
||||
#define va_init_list(a,b) va_start(a,b)
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#define va_init_list(a,b) va_start(a)
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRING_H
|
||||
char *strrchr _((const char *, const char));
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __BEOS__
|
||||
#include <net/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef __MACOS__
|
||||
#include "macruby_private.h"
|
||||
#endif
|
||||
|
||||
#ifdef __VMS
|
||||
#include "vmsruby_private.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_CONTEXT
|
||||
|
||||
NORETURN(static void rb_jump_context(rb_jmpbuf_t, int));
|
||||
static inline void
|
||||
rb_jump_context(rb_jmpbuf_t env, int val)
|
||||
{
|
||||
env->status = val;
|
||||
setcontext(&env->context);
|
||||
abort(); /* ensure noreturn */
|
||||
}
|
||||
|
||||
/*
|
||||
* FUNCTION_CALL_MAY_RETURN_TWICE is a magic for getcontext, gcc,
|
||||
* IA64 register stack and SPARC register window combination problem.
|
||||
*
|
||||
* Assume following code sequence.
|
||||
*
|
||||
* 1. set a register in the register stack/window such as r32/l0.
|
||||
* 2. call getcontext.
|
||||
* 3. use the register.
|
||||
* 4. update the register for other use.
|
||||
* 5. call setcontext indirectly (or directly).
|
||||
*
|
||||
* This code should be run as 1->2->3->4->5->3->4.
|
||||
* But after second getcontext return (second 3),
|
||||
* the register is broken (updated).
|
||||
* It's because getcontext/setcontext doesn't preserve the content of the
|
||||
* register stack/window.
|
||||
*
|
||||
* setjmp also doesn't preserve the content of the register stack/window.
|
||||
* But it has not the problem because gcc knows setjmp may return twice.
|
||||
* gcc detects setjmp and generates setjmp safe code.
|
||||
*
|
||||
* So setjmp call before getcontext call makes the code somewhat safe.
|
||||
* It fix the problem on IA64.
|
||||
* It is not required that setjmp is called at run time, since the problem is
|
||||
* register usage.
|
||||
*
|
||||
* Since the magic setjmp is not enough for SPARC,
|
||||
* inline asm is used to prohibit registers in register windows.
|
||||
*/
|
||||
#if defined (__GNUC__) && (defined(sparc) || defined(__sparc__))
|
||||
#define FUNCTION_CALL_MAY_RETURN_TWICE \
|
||||
({ __asm__ volatile ("" : : : \
|
||||
"%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o7", \
|
||||
"%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", \
|
||||
"%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%i7"); })
|
||||
#else
|
||||
extern jmp_buf function_call_may_return_twice_jmp_buf;
|
||||
extern int function_call_may_return_twice_false;
|
||||
#define FUNCTION_CALL_MAY_RETURN_TWICE \
|
||||
(function_call_may_return_twice_false ? \
|
||||
setjmp(function_call_may_return_twice_jmp_buf) : \
|
||||
0)
|
||||
#endif
|
||||
#define ruby_longjmp(env, val) rb_jump_context(env, val)
|
||||
#define ruby_setjmp(j) ((j)->status = 0, \
|
||||
FUNCTION_CALL_MAY_RETURN_TWICE, \
|
||||
getcontext(&(j)->context), \
|
||||
(j)->status)
|
||||
#else
|
||||
#if !defined(setjmp) && defined(HAVE__SETJMP)
|
||||
#define ruby_setjmp(env) _setjmp(env)
|
||||
#define ruby_longjmp(env,val) _longjmp(env,val)
|
||||
#else
|
||||
#define ruby_setjmp(env) setjmp(env)
|
||||
#define ruby_longjmp(env,val) longjmp(env,val)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(__VMS)
|
||||
#pragma nostandard
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
Solaris sys/select.h switches select to select_large_fdset to support larger
|
||||
file descriptors if FD_SETSIZE is larger than 1024 on 32bit environment.
|
||||
But Ruby doesn't change FD_SETSIZE because fd_set is allocated dynamically.
|
||||
So following definition is required to use select_large_fdset.
|
||||
*/
|
||||
#ifdef HAVE_SELECT_LARGE_FDSET
|
||||
#define select(n, r, w, e, t) select_large_fdset(n, r, w, e, t)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define TH_PUSH_TAG(th) do { \
|
||||
yarv_thread_t * const _th = th; \
|
||||
struct yarv_tag _tag; \
|
||||
_tag.tag = 0; \
|
||||
_tag.prev = _th->tag; \
|
||||
_th->tag = &_tag;
|
||||
|
||||
#define TH_POP_TAG() \
|
||||
_th->tag = _tag.prev; \
|
||||
} while (0)
|
||||
|
||||
#define TH_POP_TAG2() \
|
||||
_th->tag = _tag.prev
|
||||
|
||||
#define PUSH_TAG(ptag) TH_PUSH_TAG(GET_THREAD())
|
||||
#define POP_TAG() TH_POP_TAG()
|
||||
#define POP_TAG_INIT() } while (0)
|
||||
|
||||
#define PUSH_THREAD_TAG() \
|
||||
PUSH_TAG(PROT_THREAD)
|
||||
|
||||
#define POP_THREAD_TAG() \
|
||||
POP_TAG()
|
||||
|
||||
#define PROT_NONE Qfalse /* 0 */
|
||||
#define PROT_THREAD Qtrue /* 2 */
|
||||
#define PROT_FUNC INT2FIX(0) /* 1 */
|
||||
#define PROT_LOOP INT2FIX(1) /* 3 */
|
||||
#define PROT_LAMBDA INT2FIX(2) /* 5 */
|
||||
#define PROT_YIELD INT2FIX(3) /* 7 */
|
||||
#define PROT_TOP INT2FIX(4) /* 9 */
|
||||
|
||||
#define TH_EXEC_TAG() \
|
||||
(FLUSH_REGISTER_WINDOWS, ruby_setjmp(_th->tag->buf))
|
||||
|
||||
#define EXEC_TAG() \
|
||||
TH_EXEC_TAG()
|
||||
|
||||
#define TH_JUMP_TAG(th, st) do { \
|
||||
ruby_longjmp(th->tag->buf,(st)); \
|
||||
} while (0)
|
||||
|
||||
#define JUMP_TAG(st) TH_JUMP_TAG(GET_THREAD(), st)
|
||||
|
||||
#define TAG_RETURN 0x1
|
||||
#define TAG_BREAK 0x2
|
||||
#define TAG_NEXT 0x3
|
||||
#define TAG_RETRY 0x4
|
||||
#define TAG_REDO 0x5
|
||||
#define TAG_RAISE 0x6
|
||||
#define TAG_THROW 0x7
|
||||
#define TAG_FATAL 0x8
|
||||
#define TAG_CONTCALL 0x9
|
||||
#define TAG_THREAD 0xa
|
||||
#define TAG_MASK 0xf
|
||||
|
||||
#define SCOPE_TEST(f) \
|
||||
(ruby_cref()->nd_visi & (f))
|
||||
|
||||
#define SCOPE_CHECK(f) \
|
||||
(ruby_cref()->nd_visi == (f))
|
||||
|
||||
#define SCOPE_SET(f) \
|
||||
{ \
|
||||
ruby_cref()->nd_visi = (f); \
|
||||
}
|
||||
|
||||
struct ruby_env {
|
||||
struct ruby_env *prev;
|
||||
struct FRAME *frame;
|
||||
struct SCOPE *scope;
|
||||
struct BLOCK *block;
|
||||
struct iter *iter;
|
||||
struct tag *tag;
|
||||
NODE *cref;
|
||||
};
|
||||
|
||||
typedef struct thread *rb_thread_t;
|
||||
|
||||
extern VALUE rb_cBinding;
|
||||
extern VALUE rb_eThreadError;
|
||||
extern VALUE rb_eLocalJumpError;
|
||||
extern VALUE rb_eSysStackError;
|
||||
extern VALUE exception_error;
|
||||
extern VALUE sysstack_error;
|
||||
|
||||
|
||||
void rb_thread_cleanup _((void));
|
||||
void rb_thread_wait_other_threads _((void));
|
||||
|
||||
int thread_set_raised(yarv_thread_t *th);
|
||||
int thread_reset_raised(yarv_thread_t *th);
|
||||
|
||||
VALUE rb_f_eval(int argc, VALUE *argv, VALUE self);
|
||||
VALUE rb_make_exception _((int argc, VALUE *argv));
|
||||
|
||||
NORETURN(void rb_raise_jump _((VALUE)));
|
||||
NORETURN(void print_undef _((VALUE, ID)));
|
||||
NORETURN(void th_localjump_error(const char *, VALUE, int));
|
||||
NORETURN(void th_jump_tag_but_local_jump(int, VALUE));
|
||||
|
||||
rb_thread_t rb_vm_curr_thread();
|
||||
VALUE th_compile(yarv_thread_t *th, VALUE str, VALUE file, VALUE line);
|
||||
|
||||
NODE *th_get_cref(yarv_thread_t *th, yarv_iseq_t *iseq, yarv_control_frame_t *cfp);
|
||||
NODE *th_cref_push(yarv_thread_t *th, VALUE, int);
|
||||
NODE *th_set_special_cref(yarv_thread_t *th, VALUE *lfp, NODE * cref_stack);
|
||||
|
||||
static yarv_control_frame_t *
|
||||
th_get_ruby_level_cfp(yarv_thread_t *th, yarv_control_frame_t *cfp)
|
||||
{
|
||||
yarv_iseq_t *iseq = 0;
|
||||
while (!YARV_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
|
||||
if (YARV_NORMAL_ISEQ_P(cfp->iseq)) {
|
||||
iseq = cfp->iseq;
|
||||
break;
|
||||
}
|
||||
cfp = YARV_PREVIOUS_CONTROL_FRAME(cfp);
|
||||
}
|
||||
if (!iseq) {
|
||||
return 0;
|
||||
}
|
||||
return cfp;
|
||||
}
|
||||
|
||||
static NODE *
|
||||
ruby_cref()
|
||||
{
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
yarv_control_frame_t *cfp = th_get_ruby_level_cfp(th, th->cfp);
|
||||
return th_get_cref(th, cfp->iseq, cfp);
|
||||
}
|
||||
|
||||
VALUE th_get_cbase(yarv_thread_t *th);
|
||||
|
||||
#define ruby_cbase() th_get_cbase(GET_THREAD())
|
||||
|
||||
#endif /* EVAL_INTERN_H_INCLUDED */
|
411
eval_jump.h
Normal file
411
eval_jump.h
Normal file
@ -0,0 +1,411 @@
|
||||
/*
|
||||
* from eval.c
|
||||
*/
|
||||
|
||||
#include "eval_intern.h"
|
||||
|
||||
NORETURN(static VALUE rb_f_throw _((int, VALUE *)));
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* throw(symbol [, obj])
|
||||
*
|
||||
* Transfers control to the end of the active +catch+ block
|
||||
* waiting for _symbol_. Raises +NameError+ if there
|
||||
* is no +catch+ block for the symbol. The optional second
|
||||
* parameter supplies a return value for the +catch+ block,
|
||||
* which otherwise defaults to +nil+. For examples, see
|
||||
* <code>Kernel::catch</code>.
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_f_throw(int argc, VALUE *argv)
|
||||
{
|
||||
VALUE tag, value;
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
struct yarv_tag *tt = th->tag;
|
||||
|
||||
rb_scan_args(argc, argv, "11", &tag, &value);
|
||||
tag = ID2SYM(rb_to_id(tag));
|
||||
|
||||
while (tt) {
|
||||
if (tt->tag == tag) {
|
||||
tt->retval = value;
|
||||
break;
|
||||
}
|
||||
tt = tt->prev;
|
||||
}
|
||||
if (!tt) {
|
||||
rb_name_error(SYM2ID(tag), "uncaught throw `%s'",
|
||||
rb_id2name(SYM2ID(tag)));
|
||||
}
|
||||
rb_trap_restore_mask();
|
||||
th->errinfo = tag;
|
||||
|
||||
JUMP_TAG(TAG_THROW);
|
||||
#ifndef __GNUC__
|
||||
return Qnil; /* not reached */
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
rb_throw(const char *tag, VALUE val)
|
||||
{
|
||||
VALUE argv[2];
|
||||
|
||||
argv[0] = ID2SYM(rb_intern(tag));
|
||||
argv[1] = val;
|
||||
rb_f_throw(2, argv);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* catch(symbol) {| | block } > obj
|
||||
*
|
||||
* +catch+ executes its block. If a +throw+ is
|
||||
* executed, Ruby searches up its stack for a +catch+ block
|
||||
* with a tag corresponding to the +throw+'s
|
||||
* _symbol_. If found, that block is terminated, and
|
||||
* +catch+ returns the value given to +throw+. If
|
||||
* +throw+ is not called, the block terminates normally, and
|
||||
* the value of +catch+ is the value of the last expression
|
||||
* evaluated. +catch+ expressions may be nested, and the
|
||||
* +throw+ call need not be in lexical scope.
|
||||
*
|
||||
* def routine(n)
|
||||
* puts n
|
||||
* throw :done if n <= 0
|
||||
* routine(n-1)
|
||||
* end
|
||||
*
|
||||
*
|
||||
* catch(:done) { routine(3) }
|
||||
*
|
||||
* <em>produces:</em>
|
||||
*
|
||||
* 3
|
||||
* 2
|
||||
* 1
|
||||
* 0
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_f_catch(VALUE dmy, VALUE tag)
|
||||
{
|
||||
int state;
|
||||
VALUE val = Qnil; /* OK */
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
|
||||
tag = ID2SYM(rb_to_id(tag));
|
||||
PUSH_TAG(tag);
|
||||
|
||||
th->tag->tag = tag;
|
||||
|
||||
if ((state = EXEC_TAG()) == 0) {
|
||||
val = rb_yield_0(tag, 0, 0, 0, Qfalse);
|
||||
}
|
||||
else if (state == TAG_THROW && th->errinfo == tag) {
|
||||
val = th->tag->retval;
|
||||
th->errinfo = 0;
|
||||
state = 0;
|
||||
}
|
||||
POP_TAG();
|
||||
if (state)
|
||||
JUMP_TAG(state);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
catch_i(VALUE tag)
|
||||
{
|
||||
return rb_funcall(Qnil, rb_intern("catch"), 1, tag);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_catch(const char *tag, VALUE (*func)(), VALUE data)
|
||||
{
|
||||
return rb_iterate((VALUE (*)_((VALUE)))catch_i, ID2SYM(rb_intern(tag)),
|
||||
func, data);
|
||||
}
|
||||
|
||||
|
||||
/* exit */
|
||||
|
||||
NORETURN(static VALUE terminate_process _((int, const char *, long)));
|
||||
|
||||
static VALUE
|
||||
terminate_process(int status, const char *mesg, long mlen)
|
||||
{
|
||||
VALUE args[2];
|
||||
yarv_vm_t *vm = GET_THREAD()->vm;
|
||||
|
||||
args[0] = INT2NUM(status);
|
||||
args[1] = rb_str_new(mesg, mlen);
|
||||
|
||||
vm->exit_code = status;
|
||||
rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rb_exit(int status)
|
||||
{
|
||||
if (GET_THREAD()->tag) {
|
||||
terminate_process(status, "exit", 4);
|
||||
}
|
||||
ruby_finalize();
|
||||
exit(status);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* exit(integer=0)
|
||||
* Kernel::exit(integer=0)
|
||||
* Process::exit(integer=0)
|
||||
*
|
||||
* Initiates the termination of the Ruby script by raising the
|
||||
* <code>SystemExit</code> exception. This exception may be caught. The
|
||||
* optional parameter is used to return a status code to the invoking
|
||||
* environment.
|
||||
*
|
||||
* begin
|
||||
* exit
|
||||
* puts "never get here"
|
||||
* rescue SystemExit
|
||||
* puts "rescued a SystemExit exception"
|
||||
* end
|
||||
* puts "after begin block"
|
||||
*
|
||||
* <em>produces:</em>
|
||||
*
|
||||
* rescued a SystemExit exception
|
||||
* after begin block
|
||||
*
|
||||
* Just prior to termination, Ruby executes any <code>at_exit</code> functions
|
||||
* (see Kernel::at_exit) and runs any object finalizers (see
|
||||
* ObjectSpace::define_finalizer).
|
||||
*
|
||||
* at_exit { puts "at_exit function" }
|
||||
* ObjectSpace.define_finalizer("string", proc { puts "in finalizer" })
|
||||
* exit
|
||||
*
|
||||
* <em>produces:</em>
|
||||
*
|
||||
* at_exit function
|
||||
* in finalizer
|
||||
*/
|
||||
|
||||
VALUE
|
||||
rb_f_exit(int argc, VALUE *argv)
|
||||
{
|
||||
VALUE status;
|
||||
int istatus;
|
||||
|
||||
rb_secure(4);
|
||||
if (rb_scan_args(argc, argv, "01", &status) == 1) {
|
||||
switch (status) {
|
||||
case Qtrue:
|
||||
istatus = EXIT_SUCCESS;
|
||||
break;
|
||||
case Qfalse:
|
||||
istatus = EXIT_FAILURE;
|
||||
break;
|
||||
default:
|
||||
istatus = NUM2INT(status);
|
||||
#if EXIT_SUCCESS != 0
|
||||
if (istatus == 0)
|
||||
istatus = EXIT_SUCCESS;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
istatus = EXIT_SUCCESS;
|
||||
}
|
||||
rb_exit(istatus);
|
||||
return Qnil; /* not reached */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* abort
|
||||
* Kernel::abort
|
||||
* Process::abort
|
||||
*
|
||||
* Terminate execution immediately, effectively by calling
|
||||
* <code>Kernel.exit(1)</code>. If _msg_ is given, it is written
|
||||
* to STDERR prior to terminating.
|
||||
*/
|
||||
|
||||
VALUE
|
||||
rb_f_abort(int argc, VALUE *argv)
|
||||
{
|
||||
rb_secure(4);
|
||||
if (argc == 0) {
|
||||
if (!NIL_P(GET_THREAD()->errinfo)) {
|
||||
error_print();
|
||||
}
|
||||
rb_exit(EXIT_FAILURE);
|
||||
}
|
||||
else {
|
||||
VALUE mesg;
|
||||
|
||||
rb_scan_args(argc, argv, "1", &mesg);
|
||||
StringValue(argv[0]);
|
||||
rb_io_puts(argc, argv, rb_stderr);
|
||||
terminate_process(EXIT_FAILURE, RSTRING_PTR(argv[0]),
|
||||
RSTRING_LEN(argv[0]));
|
||||
}
|
||||
return Qnil; /* not reached */
|
||||
}
|
||||
|
||||
static void call_end_proc _((VALUE data));
|
||||
|
||||
static void
|
||||
call_end_proc(VALUE data)
|
||||
{
|
||||
// TODO: fix me
|
||||
proc_invoke(data, rb_ary_new2(0), Qundef, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* at_exit { block } -> proc
|
||||
*
|
||||
* Converts _block_ to a +Proc+ object (and therefore
|
||||
* binds it at the point of call) and registers it for execution when
|
||||
* the program exits. If multiple handlers are registered, they are
|
||||
* executed in reverse order of registration.
|
||||
*
|
||||
* def do_at_exit(str1)
|
||||
* at_exit { print str1 }
|
||||
* end
|
||||
* at_exit { puts "cruel world" }
|
||||
* do_at_exit("goodbye ")
|
||||
* exit
|
||||
*
|
||||
* <em>produces:</em>
|
||||
*
|
||||
* goodbye cruel world
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_f_at_exit(void)
|
||||
{
|
||||
VALUE proc;
|
||||
|
||||
if (!rb_block_given_p()) {
|
||||
rb_raise(rb_eArgError, "called without a block");
|
||||
}
|
||||
proc = rb_block_proc();
|
||||
rb_set_end_proc(call_end_proc, proc);
|
||||
return proc;
|
||||
}
|
||||
|
||||
struct end_proc_data {
|
||||
void (*func) ();
|
||||
VALUE data;
|
||||
int safe;
|
||||
struct end_proc_data *next;
|
||||
};
|
||||
|
||||
static struct end_proc_data *end_procs, *ephemeral_end_procs, *tmp_end_procs;
|
||||
|
||||
void
|
||||
rb_set_end_proc(void (*func)(VALUE), VALUE data)
|
||||
{
|
||||
struct end_proc_data *link = ALLOC(struct end_proc_data);
|
||||
struct end_proc_data **list;
|
||||
|
||||
if (ruby_wrapper) {
|
||||
list = &ephemeral_end_procs;
|
||||
}
|
||||
else {
|
||||
list = &end_procs;
|
||||
}
|
||||
link->next = *list;
|
||||
link->func = func;
|
||||
link->data = data;
|
||||
link->safe = rb_safe_level();
|
||||
*list = link;
|
||||
}
|
||||
|
||||
void
|
||||
rb_mark_end_proc(void)
|
||||
{
|
||||
struct end_proc_data *link;
|
||||
|
||||
link = end_procs;
|
||||
while (link) {
|
||||
rb_gc_mark(link->data);
|
||||
link = link->next;
|
||||
}
|
||||
link = ephemeral_end_procs;
|
||||
while (link) {
|
||||
rb_gc_mark(link->data);
|
||||
link = link->next;
|
||||
}
|
||||
link = tmp_end_procs;
|
||||
while (link) {
|
||||
rb_gc_mark(link->data);
|
||||
link = link->next;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_exec_end_proc(void)
|
||||
{
|
||||
struct end_proc_data *link, *tmp;
|
||||
int status;
|
||||
volatile int safe = rb_safe_level();
|
||||
|
||||
while (ephemeral_end_procs) {
|
||||
tmp_end_procs = link = ephemeral_end_procs;
|
||||
ephemeral_end_procs = 0;
|
||||
while (link) {
|
||||
PUSH_TAG(PROT_NONE);
|
||||
if ((status = EXEC_TAG()) == 0) {
|
||||
rb_set_safe_level_force(link->safe);
|
||||
(*link->func) (link->data);
|
||||
}
|
||||
POP_TAG();
|
||||
if (status) {
|
||||
error_handle(status);
|
||||
}
|
||||
tmp = link;
|
||||
tmp_end_procs = link = link->next;
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
while (end_procs) {
|
||||
tmp_end_procs = link = end_procs;
|
||||
end_procs = 0;
|
||||
while (link) {
|
||||
PUSH_TAG(PROT_NONE);
|
||||
if ((status = EXEC_TAG()) == 0) {
|
||||
rb_set_safe_level_force(link->safe);
|
||||
(*link->func) (link->data);
|
||||
}
|
||||
POP_TAG();
|
||||
if (status) {
|
||||
error_handle(status);
|
||||
}
|
||||
tmp = link;
|
||||
tmp_end_procs = link = link->next;
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
rb_set_safe_level_force(safe);
|
||||
}
|
||||
|
||||
void
|
||||
Init_jump()
|
||||
{
|
||||
rb_define_global_function("catch", rb_f_catch, 1);
|
||||
rb_define_global_function("throw", rb_f_throw, -1);
|
||||
rb_define_global_function("exit", rb_f_exit, -1);
|
||||
rb_define_global_function("abort", rb_f_abort, -1);
|
||||
rb_define_global_function("at_exit", rb_f_at_exit, 0);
|
||||
}
|
508
eval_load.c
Normal file
508
eval_load.c
Normal file
@ -0,0 +1,508 @@
|
||||
/*
|
||||
* load methods from eval.c
|
||||
*/
|
||||
|
||||
#include "eval_intern.h"
|
||||
|
||||
extern VALUE ruby_top_self;
|
||||
|
||||
VALUE ruby_dln_librefs;
|
||||
static VALUE rb_features;
|
||||
static st_table *loading_tbl;
|
||||
|
||||
NORETURN(void jump_tag_but_local_jump(int, VALUE));
|
||||
|
||||
#define IS_SOEXT(e) (strcmp(e, ".so") == 0 || strcmp(e, ".o") == 0)
|
||||
#ifdef DLEXT2
|
||||
#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0 || strcmp(e, DLEXT2) == 0)
|
||||
#else
|
||||
#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0)
|
||||
#endif
|
||||
|
||||
static int
|
||||
rb_feature_p(const char *feature, const char *ext, int rb)
|
||||
{
|
||||
VALUE v;
|
||||
char *f, *e;
|
||||
long i, len, elen;
|
||||
|
||||
if (ext) {
|
||||
len = ext - feature;
|
||||
elen = strlen(ext);
|
||||
}
|
||||
else {
|
||||
len = strlen(feature);
|
||||
elen = 0;
|
||||
}
|
||||
for (i = 0; i < RARRAY_LEN(rb_features); ++i) {
|
||||
v = RARRAY_PTR(rb_features)[i];
|
||||
f = StringValuePtr(v);
|
||||
if (strncmp(f, feature, len) != 0)
|
||||
continue;
|
||||
if (!*(e = f + len)) {
|
||||
if (ext)
|
||||
continue;
|
||||
return 'u';
|
||||
}
|
||||
if (*e != '.')
|
||||
continue;
|
||||
if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
|
||||
return 's';
|
||||
}
|
||||
if ((rb || !ext) && (strcmp(e, ".rb") == 0)) {
|
||||
return 'r';
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *const loadable_ext[] = {
|
||||
".rb", DLEXT,
|
||||
#ifdef DLEXT2
|
||||
DLEXT2,
|
||||
#endif
|
||||
0
|
||||
};
|
||||
|
||||
static int search_required _((VALUE, VALUE *));
|
||||
|
||||
int
|
||||
rb_provided(const char *feature)
|
||||
{
|
||||
int i;
|
||||
char *buf;
|
||||
VALUE fname;
|
||||
|
||||
if (rb_feature_p(feature, 0, Qfalse))
|
||||
return Qtrue;
|
||||
if (loading_tbl) {
|
||||
if (st_lookup(loading_tbl, (st_data_t) feature, 0))
|
||||
return Qtrue;
|
||||
buf = ALLOCA_N(char, strlen(feature) + 8);
|
||||
strcpy(buf, feature);
|
||||
for (i = 0; loadable_ext[i]; i++) {
|
||||
strcpy(buf + strlen(feature), loadable_ext[i]);
|
||||
if (st_lookup(loading_tbl, (st_data_t) buf, 0))
|
||||
return Qtrue;
|
||||
}
|
||||
}
|
||||
if (search_required(rb_str_new2(feature), &fname)) {
|
||||
feature = RSTRING_PTR(fname);
|
||||
if (rb_feature_p(feature, 0, Qfalse))
|
||||
return Qtrue;
|
||||
if (loading_tbl && st_lookup(loading_tbl, (st_data_t) feature, 0))
|
||||
return Qtrue;
|
||||
}
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
static void
|
||||
rb_provide_feature(VALUE feature)
|
||||
{
|
||||
rb_ary_push(rb_features, feature);
|
||||
}
|
||||
|
||||
void
|
||||
rb_provide(const char *feature)
|
||||
{
|
||||
rb_provide_feature(rb_str_new2(feature));
|
||||
}
|
||||
|
||||
VALUE rb_load_path;
|
||||
|
||||
NORETURN(static void load_failed _((VALUE)));
|
||||
void th_klass_init(yarv_thread_t *);
|
||||
|
||||
void
|
||||
rb_load(VALUE fname, int wrap)
|
||||
{
|
||||
VALUE tmp;
|
||||
int state;
|
||||
volatile VALUE self = ruby_top_self;
|
||||
|
||||
FilePathValue(fname);
|
||||
fname = rb_str_new4(fname);
|
||||
tmp = rb_find_file(fname);
|
||||
if (!tmp) {
|
||||
load_failed(fname);
|
||||
}
|
||||
fname = tmp;
|
||||
|
||||
GET_THREAD()->errinfo = Qnil; /* ensure */
|
||||
|
||||
if (!wrap) {
|
||||
rb_secure(4); /* should alter global state */
|
||||
}
|
||||
else {
|
||||
/* load in anonymous module as toplevel */
|
||||
self = rb_obj_clone(ruby_top_self);
|
||||
}
|
||||
|
||||
PUSH_TAG(PROT_NONE);
|
||||
state = EXEC_TAG();
|
||||
if (state == 0) {
|
||||
yarv_load(RSTRING_PTR(fname));
|
||||
}
|
||||
POP_TAG();
|
||||
|
||||
if (ruby_nerrs > 0) {
|
||||
ruby_nerrs = 0;
|
||||
rb_exc_raise(GET_THREAD()->errinfo);
|
||||
}
|
||||
if (state) {
|
||||
th_jump_tag_but_local_jump(state, Qundef);
|
||||
}
|
||||
|
||||
if (!NIL_P(GET_THREAD()->errinfo)) {
|
||||
/* exception during load */
|
||||
rb_exc_raise(GET_THREAD()->errinfo);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_load_protect(VALUE fname, int wrap, int *state)
|
||||
{
|
||||
int status;
|
||||
|
||||
PUSH_THREAD_TAG();
|
||||
if ((status = EXEC_TAG()) == 0) {
|
||||
rb_load(fname, wrap);
|
||||
}
|
||||
POP_THREAD_TAG();
|
||||
if (state)
|
||||
*state = status;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* load(filename, wrap=false) => true
|
||||
*
|
||||
* Loads and executes the Ruby
|
||||
* program in the file _filename_. If the filename does not
|
||||
* resolve to an absolute path, the file is searched for in the library
|
||||
* directories listed in <code>$:</code>. If the optional _wrap_
|
||||
* parameter is +true+, the loaded script will be executed
|
||||
* under an anonymous module, protecting the calling program's global
|
||||
* namespace. In no circumstance will any local variables in the loaded
|
||||
* file be propagated to the loading environment.
|
||||
*/
|
||||
|
||||
|
||||
static VALUE
|
||||
rb_f_load(argc, argv)
|
||||
int argc;
|
||||
VALUE *argv;
|
||||
{
|
||||
VALUE fname, wrap;
|
||||
|
||||
rb_scan_args(argc, argv, "11", &fname, &wrap);
|
||||
rb_load(fname, RTEST(wrap));
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static int
|
||||
load_wait(char *ftptr)
|
||||
{
|
||||
st_data_t th;
|
||||
if (!loading_tbl) {
|
||||
return Qfalse;
|
||||
}
|
||||
if (!st_lookup(loading_tbl, (st_data_t) ftptr, &th)) {
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
// TODO: write wait routine
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* require(string) => true or false
|
||||
*
|
||||
* Ruby tries to load the library named _string_, returning
|
||||
* +true+ if successful. If the filename does not resolve to
|
||||
* an absolute path, it will be searched for in the directories listed
|
||||
* in <code>$:</code>. If the file has the extension ``.rb'', it is
|
||||
* loaded as a source file; if the extension is ``.so'', ``.o'', or
|
||||
* ``.dll'', or whatever the default shared library extension is on
|
||||
* the current platform, Ruby loads the shared library as a Ruby
|
||||
* extension. Otherwise, Ruby tries adding ``.rb'', ``.so'', and so on
|
||||
* to the name. The name of the loaded feature is added to the array in
|
||||
* <code>$"</code>. A feature will not be loaded if it's name already
|
||||
* appears in <code>$"</code>. However, the file name is not converted
|
||||
* to an absolute path, so that ``<code>require 'a';require
|
||||
* './a'</code>'' will load <code>a.rb</code> twice.
|
||||
*
|
||||
* require "my-library.rb"
|
||||
* require "db-driver"
|
||||
*/
|
||||
|
||||
VALUE
|
||||
rb_f_require(VALUE obj, VALUE fname)
|
||||
{
|
||||
return rb_require_safe(fname, rb_safe_level());
|
||||
}
|
||||
|
||||
static int
|
||||
search_required(VALUE fname, VALUE *path)
|
||||
{
|
||||
VALUE tmp;
|
||||
char *ext, *ftptr;
|
||||
int type, ft = 0;
|
||||
|
||||
*path = 0;
|
||||
ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
|
||||
if (ext && !strchr(ext, '/')) {
|
||||
if (strcmp(".rb", ext) == 0) {
|
||||
if (rb_feature_p(ftptr, ext, Qtrue))
|
||||
return 'r';
|
||||
if (tmp = rb_find_file(fname)) {
|
||||
tmp = rb_file_expand_path(tmp, Qnil);
|
||||
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||
if (!rb_feature_p(ftptr, ext, Qtrue))
|
||||
*path = tmp;
|
||||
return 'r';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else if (IS_SOEXT(ext)) {
|
||||
if (rb_feature_p(ftptr, ext, Qfalse))
|
||||
return 's';
|
||||
tmp = rb_str_new(RSTRING_PTR(fname), ext - RSTRING_PTR(fname));
|
||||
#ifdef DLEXT2
|
||||
OBJ_FREEZE(tmp);
|
||||
if (rb_find_file_ext(&tmp, loadable_ext + 1)) {
|
||||
tmp = rb_file_expand_path(tmp, Qnil);
|
||||
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||
if (!rb_feature_p(ftptr, ext, Qfalse))
|
||||
*path = tmp;
|
||||
return 's';
|
||||
}
|
||||
#else
|
||||
rb_str_cat2(tmp, DLEXT);
|
||||
OBJ_FREEZE(tmp);
|
||||
if (tmp = rb_find_file(tmp)) {
|
||||
tmp = rb_file_expand_path(tmp, Qnil);
|
||||
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||
if (!rb_feature_p(ftptr, ext, Qfalse))
|
||||
*path = tmp;
|
||||
return 's';
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (IS_DLEXT(ext)) {
|
||||
if (rb_feature_p(ftptr, ext, Qfalse))
|
||||
return 's';
|
||||
if (tmp = rb_find_file(fname)) {
|
||||
tmp = rb_file_expand_path(tmp, Qnil);
|
||||
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||
if (!rb_feature_p(ftptr, ext, Qfalse))
|
||||
*path = tmp;
|
||||
return 's';
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((ft = rb_feature_p(ftptr, 0, Qfalse)) == 'r') {
|
||||
return 'r';
|
||||
}
|
||||
tmp = fname;
|
||||
type = rb_find_file_ext(&tmp, loadable_ext);
|
||||
tmp = rb_file_expand_path(tmp, Qnil);
|
||||
switch (type) {
|
||||
case 0:
|
||||
ftptr = RSTRING_PTR(tmp);
|
||||
if (ft)
|
||||
break;
|
||||
return rb_feature_p(ftptr, 0, Qfalse);
|
||||
|
||||
default:
|
||||
if (ft)
|
||||
break;
|
||||
case 1:
|
||||
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||
if (rb_feature_p(ftptr, ext, !--type))
|
||||
break;
|
||||
*path = tmp;
|
||||
}
|
||||
return type ? 's' : 'r';
|
||||
}
|
||||
|
||||
static void
|
||||
load_failed(VALUE fname)
|
||||
{
|
||||
rb_raise(rb_eLoadError, "no such file to load -- %s",
|
||||
RSTRING_PTR(fname));
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_require_safe(VALUE fname, int safe)
|
||||
{
|
||||
VALUE result = Qnil;
|
||||
volatile VALUE errinfo = GET_THREAD()->errinfo;
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
int state;
|
||||
char *volatile ftptr = 0;
|
||||
|
||||
PUSH_TAG(PROT_NONE);
|
||||
if ((state = EXEC_TAG()) == 0) {
|
||||
VALUE path;
|
||||
long handle;
|
||||
int found;
|
||||
|
||||
rb_set_safe_level_force(safe);
|
||||
FilePathValue(fname);
|
||||
*(volatile VALUE *)&fname = rb_str_new4(fname);
|
||||
found = search_required(fname, &path);
|
||||
if (found) {
|
||||
if (!path || load_wait(RSTRING_PTR(path))) {
|
||||
result = Qfalse;
|
||||
}
|
||||
else {
|
||||
rb_set_safe_level_force(0);
|
||||
switch (found) {
|
||||
case 'r':
|
||||
/* loading ruby library should be serialized. */
|
||||
if (!loading_tbl) {
|
||||
loading_tbl = st_init_strtable();
|
||||
}
|
||||
/* partial state */
|
||||
ftptr = ruby_strdup(RSTRING_PTR(path));
|
||||
st_insert(loading_tbl, (st_data_t) ftptr,
|
||||
(st_data_t) GET_THREAD()->self);
|
||||
rb_load(path, 0);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
ruby_current_node = 0;
|
||||
ruby_sourcefile = rb_source_filename(RSTRING_PTR(path));
|
||||
ruby_sourceline = 0;
|
||||
//SCOPE_SET(NOEX_PUBLIC);
|
||||
handle = (long)dln_load(RSTRING_PTR(path));
|
||||
rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
|
||||
break;
|
||||
}
|
||||
rb_provide_feature(path);
|
||||
result = Qtrue;
|
||||
}
|
||||
}
|
||||
}
|
||||
POP_TAG();
|
||||
|
||||
if (ftptr) {
|
||||
if (st_delete(loading_tbl, (st_data_t *) & ftptr, 0)) { /* loading done */
|
||||
free(ftptr);
|
||||
}
|
||||
}
|
||||
if (state) {
|
||||
JUMP_TAG(state);
|
||||
}
|
||||
|
||||
if (NIL_P(result)) {
|
||||
load_failed(fname);
|
||||
}
|
||||
|
||||
th->errinfo = errinfo;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_require(const char *fname)
|
||||
{
|
||||
VALUE fn = rb_str_new2(fname);
|
||||
OBJ_FREEZE(fn);
|
||||
return rb_require_safe(fn, rb_safe_level());
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* mod.autoload(name, filename) => nil
|
||||
*
|
||||
* Registers _filename_ to be loaded (using <code>Kernel::require</code>)
|
||||
* the first time that _module_ (which may be a <code>String</code> or
|
||||
* a symbol) is accessed in the namespace of _mod_.
|
||||
*
|
||||
* module A
|
||||
* end
|
||||
* A.autoload(:B, "b")
|
||||
* A::B.doit # autoloads "b"
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
|
||||
{
|
||||
ID id = rb_to_id(sym);
|
||||
|
||||
Check_SafeStr(file);
|
||||
rb_autoload(mod, id, RSTRING_PTR(file));
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
/*
|
||||
* MISSING: documentation
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_mod_autoload_p(VALUE mod, VALUE sym)
|
||||
{
|
||||
return rb_autoload_p(mod, rb_to_id(sym));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* autoload(module, filename) => nil
|
||||
*
|
||||
* Registers _filename_ to be loaded (using <code>Kernel::require</code>)
|
||||
* the first time that _module_ (which may be a <code>String</code> or
|
||||
* a symbol) is accessed.
|
||||
*
|
||||
* autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
|
||||
{
|
||||
VALUE klass = ruby_cbase();
|
||||
if (NIL_P(klass)) {
|
||||
rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
|
||||
}
|
||||
return rb_mod_autoload(klass, sym, file);
|
||||
}
|
||||
|
||||
/*
|
||||
* MISSING: documentation
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_f_autoload_p(VALUE obj, VALUE sym)
|
||||
{
|
||||
/* use ruby_cbase() as same as rb_f_autoload. */
|
||||
VALUE klass = ruby_cbase();
|
||||
if (NIL_P(klass)) {
|
||||
return Qnil;
|
||||
}
|
||||
return rb_mod_autoload_p(klass, sym);
|
||||
}
|
||||
|
||||
void
|
||||
Init_load()
|
||||
{
|
||||
rb_load_path = rb_ary_new();
|
||||
rb_define_readonly_variable("$:", &rb_load_path);
|
||||
rb_define_readonly_variable("$-I", &rb_load_path);
|
||||
rb_define_readonly_variable("$LOAD_PATH", &rb_load_path);
|
||||
|
||||
rb_features = rb_ary_new();
|
||||
rb_define_readonly_variable("$\"", &rb_features);
|
||||
rb_define_readonly_variable("$LOADED_FEATURES", &rb_features);
|
||||
|
||||
rb_define_global_function("load", rb_f_load, -1);
|
||||
rb_define_global_function("require", rb_f_require, 1);
|
||||
rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
|
||||
rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1);
|
||||
rb_define_global_function("autoload", rb_f_autoload, 2);
|
||||
rb_define_global_function("autoload?", rb_f_autoload_p, 1);
|
||||
|
||||
ruby_dln_librefs = rb_ary_new();
|
||||
rb_register_mark_object(ruby_dln_librefs);
|
||||
}
|
612
eval_method.h
Normal file
612
eval_method.h
Normal file
@ -0,0 +1,612 @@
|
||||
/*
|
||||
* This file is included by eval.c
|
||||
*/
|
||||
|
||||
#define CACHE_SIZE 0x800
|
||||
#define CACHE_MASK 0x7ff
|
||||
#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
|
||||
|
||||
struct cache_entry { /* method hash table. */
|
||||
ID mid; /* method's id */
|
||||
ID mid0; /* method's original id */
|
||||
VALUE klass; /* receiver's class */
|
||||
NODE *method;
|
||||
};
|
||||
|
||||
static struct cache_entry cache[CACHE_SIZE];
|
||||
static int ruby_running = 0;
|
||||
|
||||
void
|
||||
rb_clear_cache(void)
|
||||
{
|
||||
struct cache_entry *ent, *end;
|
||||
|
||||
rb_vm_change_state();
|
||||
|
||||
if (!ruby_running)
|
||||
return;
|
||||
ent = cache;
|
||||
end = ent + CACHE_SIZE;
|
||||
while (ent < end) {
|
||||
ent->mid = 0;
|
||||
ent++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rb_clear_cache_for_undef(VALUE klass, ID id)
|
||||
{
|
||||
struct cache_entry *ent, *end;
|
||||
|
||||
rb_vm_change_state();
|
||||
|
||||
if (!ruby_running)
|
||||
return;
|
||||
ent = cache;
|
||||
end = ent + CACHE_SIZE;
|
||||
while (ent < end) {
|
||||
if (ent->method && ent->method->nd_clss == klass && ent->mid == id) {
|
||||
ent->mid = 0;
|
||||
}
|
||||
ent++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rb_clear_cache_by_id(ID id)
|
||||
{
|
||||
struct cache_entry *ent, *end;
|
||||
|
||||
rb_vm_change_state();
|
||||
|
||||
if (!ruby_running)
|
||||
return;
|
||||
ent = cache;
|
||||
end = ent + CACHE_SIZE;
|
||||
while (ent < end) {
|
||||
if (ent->mid == id) {
|
||||
ent->mid = 0;
|
||||
}
|
||||
ent++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_clear_cache_by_class(VALUE klass)
|
||||
{
|
||||
struct cache_entry *ent, *end;
|
||||
|
||||
rb_vm_change_state();
|
||||
|
||||
if (!ruby_running)
|
||||
return;
|
||||
ent = cache;
|
||||
end = ent + CACHE_SIZE;
|
||||
while (ent < end) {
|
||||
if ((ent->klass == klass) ||
|
||||
(ent->method && ent->method->nd_clss == klass)) {
|
||||
ent->mid = 0;
|
||||
}
|
||||
ent++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_add_method(VALUE klass, ID mid, NODE * node, int noex)
|
||||
{
|
||||
NODE *body;
|
||||
|
||||
if (NIL_P(klass)) {
|
||||
klass = rb_cObject;
|
||||
}
|
||||
if (rb_safe_level() >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) {
|
||||
rb_raise(rb_eSecurityError, "Insecure: can't define method");
|
||||
}
|
||||
if (!FL_TEST(klass, FL_SINGLETON) &&
|
||||
node && nd_type(node) != NODE_ZSUPER &&
|
||||
(mid == rb_intern("initialize") || mid == rb_intern("initialize_copy"))) {
|
||||
noex = NOEX_PRIVATE | noex;
|
||||
}
|
||||
else if (FL_TEST(klass, FL_SINGLETON) && node
|
||||
&& nd_type(node) == NODE_CFUNC && mid == rb_intern("allocate")) {
|
||||
rb_warn
|
||||
("defining %s.allocate is deprecated; use rb_define_alloc_func()",
|
||||
rb_class2name(rb_iv_get(klass, "__attached__")));
|
||||
mid = ID_ALLOCATOR;
|
||||
}
|
||||
if (OBJ_FROZEN(klass)) {
|
||||
rb_error_frozen("class/module");
|
||||
}
|
||||
rb_clear_cache_by_id(mid);
|
||||
|
||||
/*
|
||||
* NODE_METHOD (NEW_METHOD(body, klass, vis)):
|
||||
* nd_body : method body // (2) // mark
|
||||
* nd_clss : klass // (1) // mark
|
||||
* nd_noex : visibility // (3)
|
||||
*
|
||||
* NODE_FBODY (NEW_FBODY(method, alias)):
|
||||
* nd_body : method (NODE_METHOD) // (2) // mark
|
||||
* nd_oid : original id // (1)
|
||||
* nd_cnt : alias count // (3)
|
||||
*/
|
||||
if (node) {
|
||||
body = NEW_FBODY(NEW_METHOD(node, klass, noex), 0);
|
||||
}
|
||||
else {
|
||||
body = 0;
|
||||
}
|
||||
|
||||
{
|
||||
/* check re-definition */
|
||||
NODE *old_node;
|
||||
|
||||
if (st_lookup(RCLASS(klass)->m_tbl, mid, (st_data_t *)&old_node)) {
|
||||
if (old_node) {
|
||||
if (nd_type(old_node->nd_body->nd_body) == NODE_CFUNC) {
|
||||
yarv_check_redefinition_opt_method(old_node);
|
||||
}
|
||||
}
|
||||
if (klass == rb_cObject && node->nd_mid == init) {
|
||||
rb_warn("redefining Object#initialize may cause infinite loop");
|
||||
}
|
||||
if (RTEST(ruby_verbose) && old_node->nd_cnt == 0 && old_node->nd_body) {
|
||||
rb_warning("method redefined; discarding old %s", rb_id2name(mid));
|
||||
}
|
||||
}
|
||||
|
||||
if (mid == object_id || mid == __send || mid == __send_bang) {
|
||||
if (node && nd_type(node) == YARV_METHOD_NODE) {
|
||||
rb_warn("redefining `%s' may cause serious problem",
|
||||
rb_id2name(mid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
st_insert(RCLASS(klass)->m_tbl, mid, (st_data_t) body);
|
||||
|
||||
if (node && mid != ID_ALLOCATOR && ruby_running) {
|
||||
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||
rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1,
|
||||
ID2SYM(mid));
|
||||
}
|
||||
else {
|
||||
rb_funcall(klass, added, 1, ID2SYM(mid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_define_alloc_func(VALUE klass, VALUE (*func) _((VALUE)))
|
||||
{
|
||||
Check_Type(klass, T_CLASS);
|
||||
rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, NEW_CFUNC(func, 0),
|
||||
NOEX_PRIVATE);
|
||||
}
|
||||
|
||||
void
|
||||
rb_undef_alloc_func(VALUE klass)
|
||||
{
|
||||
Check_Type(klass, T_CLASS);
|
||||
rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, 0, NOEX_UNDEF);
|
||||
}
|
||||
|
||||
static NODE *
|
||||
search_method(VALUE klass, ID id, VALUE *klassp)
|
||||
{
|
||||
NODE *body;
|
||||
|
||||
if (!klass) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!st_lookup(RCLASS(klass)->m_tbl, id, (st_data_t *) & body)) {
|
||||
klass = RCLASS(klass)->super;
|
||||
if (!klass)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (klassp) {
|
||||
*klassp = klass;
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
/*
|
||||
* search method body (NODE_METHOD)
|
||||
* with : klass and id
|
||||
* without : method cache
|
||||
*
|
||||
* if you need method node with method cache, use
|
||||
* rb_method_node()
|
||||
*/
|
||||
NODE *
|
||||
rb_get_method_body(VALUE klass, ID id, ID *idp)
|
||||
{
|
||||
NODE *volatile fbody, *body;
|
||||
NODE *method;
|
||||
|
||||
if ((fbody = search_method(klass, id, 0)) == 0 || !fbody->nd_body) {
|
||||
/* store empty info in cache */
|
||||
struct cache_entry *ent;
|
||||
ent = cache + EXPR1(klass, id);
|
||||
ent->klass = klass;
|
||||
ent->mid = ent->mid0 = id;
|
||||
ent->method = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
method = fbody->nd_body;
|
||||
|
||||
if (ruby_running) {
|
||||
/* store in cache */
|
||||
struct cache_entry *ent;
|
||||
ent = cache + EXPR1(klass, id);
|
||||
ent->klass = klass;
|
||||
ent->mid = id;
|
||||
ent->mid0 = fbody->nd_oid;
|
||||
ent->method = body = method;
|
||||
}
|
||||
else {
|
||||
body = method;
|
||||
}
|
||||
|
||||
if (idp) {
|
||||
*idp = fbody->nd_oid;
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
NODE *
|
||||
rb_method_node(VALUE klass, ID id)
|
||||
{
|
||||
struct cache_entry *ent;
|
||||
|
||||
ent = cache + EXPR1(klass, id);
|
||||
if (ent->mid == id && ent->klass == klass && ent->method) {
|
||||
return ent->method;
|
||||
}
|
||||
|
||||
return rb_get_method_body(klass, id, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_method(VALUE klass, ID mid)
|
||||
{
|
||||
NODE *body;
|
||||
|
||||
if (klass == rb_cObject) {
|
||||
rb_secure(4);
|
||||
}
|
||||
if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
|
||||
rb_raise(rb_eSecurityError, "Insecure: can't remove method");
|
||||
}
|
||||
if (OBJ_FROZEN(klass))
|
||||
rb_error_frozen("class/module");
|
||||
if (mid == object_id || mid == __send || mid == __send_bang || mid == init) {
|
||||
rb_warn("removing `%s' may cause serious problem", rb_id2name(mid));
|
||||
}
|
||||
if (!st_delete(RCLASS(klass)->m_tbl, &mid, (st_data_t *) & body) ||
|
||||
!body->nd_body) {
|
||||
rb_name_error(mid, "method `%s' not defined in %s",
|
||||
rb_id2name(mid), rb_class2name(klass));
|
||||
}
|
||||
rb_clear_cache_for_undef(klass, mid);
|
||||
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||
rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1,
|
||||
ID2SYM(mid));
|
||||
}
|
||||
else {
|
||||
rb_funcall(klass, removed, 1, ID2SYM(mid));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_remove_method(VALUE klass, const char *name)
|
||||
{
|
||||
remove_method(klass, rb_intern(name));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* remove_method(symbol) => self
|
||||
*
|
||||
* Removes the method identified by _symbol_ from the current
|
||||
* class. For an example, see <code>Module.undef_method</code>.
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_mod_remove_method(int argc, VALUE *argv, VALUE mod)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
remove_method(mod, rb_to_id(argv[i]));
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
#undef rb_disable_super
|
||||
#undef rb_enable_super
|
||||
|
||||
void
|
||||
rb_disable_super(VALUE klass, const char *name)
|
||||
{
|
||||
/* obsolete - no use */
|
||||
}
|
||||
|
||||
void
|
||||
rb_enable_super(VALUE klass, const char *name)
|
||||
{
|
||||
rb_warning("rb_enable_super() is obsolete");
|
||||
}
|
||||
|
||||
static void
|
||||
rb_export_method(VALUE klass, ID name, ID noex)
|
||||
{
|
||||
NODE *fbody;
|
||||
VALUE origin;
|
||||
|
||||
if (klass == rb_cObject) {
|
||||
rb_secure(4);
|
||||
}
|
||||
fbody = search_method(klass, name, &origin);
|
||||
if (!fbody && TYPE(klass) == T_MODULE) {
|
||||
fbody = search_method(rb_cObject, name, &origin);
|
||||
}
|
||||
if (!fbody || !fbody->nd_body) {
|
||||
print_undef(klass, name);
|
||||
}
|
||||
if (fbody->nd_body->nd_noex != noex) {
|
||||
if (klass == origin) {
|
||||
fbody->nd_body->nd_noex = noex;
|
||||
}
|
||||
else {
|
||||
rb_add_method(klass, name, NEW_ZSUPER(), noex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
rb_method_boundp(VALUE klass, ID id, int ex)
|
||||
{
|
||||
NODE *method;
|
||||
|
||||
if ((method = rb_method_node(klass, id)) != 0) {
|
||||
if (ex && (method->nd_noex & NOEX_PRIVATE)) {
|
||||
return Qfalse;
|
||||
}
|
||||
return Qtrue;
|
||||
}
|
||||
return Qfalse;
|
||||
}
|
||||
|
||||
void
|
||||
rb_attr(VALUE klass, ID id, int read, int write, int ex)
|
||||
{
|
||||
const char *name;
|
||||
char *buf;
|
||||
ID attriv;
|
||||
int noex;
|
||||
size_t len;
|
||||
|
||||
if (!ex) {
|
||||
noex = NOEX_PUBLIC;
|
||||
}
|
||||
else {
|
||||
if (SCOPE_TEST(NOEX_PRIVATE)) {
|
||||
noex = NOEX_PRIVATE;
|
||||
rb_warning((SCOPE_CHECK(NOEX_MODFUNC)) ?
|
||||
"attribute accessor as module_function" :
|
||||
"private attribute?");
|
||||
}
|
||||
else if (SCOPE_TEST(NOEX_PROTECTED)) {
|
||||
noex = NOEX_PROTECTED;
|
||||
}
|
||||
else {
|
||||
noex = NOEX_PUBLIC;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rb_is_local_id(id) && !rb_is_const_id(id)) {
|
||||
rb_name_error(id, "invalid attribute name `%s'", rb_id2name(id));
|
||||
}
|
||||
name = rb_id2name(id);
|
||||
if (!name) {
|
||||
rb_raise(rb_eArgError, "argument needs to be symbol or string");
|
||||
}
|
||||
len = strlen(name) + 2;
|
||||
buf = ALLOCA_N(char, len);
|
||||
snprintf(buf, len, "@%s", name);
|
||||
attriv = rb_intern(buf);
|
||||
if (read) {
|
||||
rb_add_method(klass, id, NEW_IVAR(attriv), noex);
|
||||
}
|
||||
if (write) {
|
||||
rb_add_method(klass, rb_id_attrset(id), NEW_ATTRSET(attriv), noex);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_undef(VALUE klass, ID id)
|
||||
{
|
||||
VALUE origin;
|
||||
NODE *body;
|
||||
|
||||
if (ruby_cbase() == rb_cObject && klass == rb_cObject) {
|
||||
rb_secure(4);
|
||||
}
|
||||
if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
|
||||
rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'",
|
||||
rb_id2name(id));
|
||||
}
|
||||
rb_frozen_class_p(klass);
|
||||
if (id == object_id || id == __send || id == __send_bang || id == init) {
|
||||
rb_warn("undefining `%s' may cause serious problem", rb_id2name(id));
|
||||
}
|
||||
body = search_method(klass, id, &origin);
|
||||
if (!body || !body->nd_body) {
|
||||
char *s0 = " class";
|
||||
VALUE c = klass;
|
||||
|
||||
if (FL_TEST(c, FL_SINGLETON)) {
|
||||
VALUE obj = rb_iv_get(klass, "__attached__");
|
||||
|
||||
switch (TYPE(obj)) {
|
||||
case T_MODULE:
|
||||
case T_CLASS:
|
||||
c = obj;
|
||||
s0 = "";
|
||||
}
|
||||
}
|
||||
else if (TYPE(c) == T_MODULE) {
|
||||
s0 = " module";
|
||||
}
|
||||
rb_name_error(id, "undefined method `%s' for%s `%s'",
|
||||
rb_id2name(id), s0, rb_class2name(c));
|
||||
}
|
||||
|
||||
rb_add_method(klass, id, 0, NOEX_PUBLIC);
|
||||
|
||||
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||
rb_funcall(rb_iv_get(klass, "__attached__"),
|
||||
singleton_undefined, 1, ID2SYM(id));
|
||||
}
|
||||
else {
|
||||
rb_funcall(klass, undefined, 1, ID2SYM(id));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* undef_method(symbol) => self
|
||||
*
|
||||
* Prevents the current class from responding to calls to the named
|
||||
* method. Contrast this with <code>remove_method</code>, which deletes
|
||||
* the method from the particular class; Ruby will still search
|
||||
* superclasses and mixed-in modules for a possible receiver.
|
||||
*
|
||||
* class Parent
|
||||
* def hello
|
||||
* puts "In parent"
|
||||
* end
|
||||
* end
|
||||
* class Child < Parent
|
||||
* def hello
|
||||
* puts "In child"
|
||||
* end
|
||||
* end
|
||||
*
|
||||
*
|
||||
* c = Child.new
|
||||
* c.hello
|
||||
*
|
||||
*
|
||||
* class Child
|
||||
* remove_method :hello # remove from child, still in parent
|
||||
* end
|
||||
* c.hello
|
||||
*
|
||||
*
|
||||
* class Child
|
||||
* undef_method :hello # prevent any calls to 'hello'
|
||||
* end
|
||||
* c.hello
|
||||
*
|
||||
* <em>produces:</em>
|
||||
*
|
||||
* In child
|
||||
* In parent
|
||||
* prog.rb:23: undefined method `hello' for #<Child:0x401b3bb4> (NoMethodError)
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < argc; i++) {
|
||||
rb_undef(mod, rb_to_id(argv[i]));
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
void
|
||||
rb_alias(VALUE klass, ID name, ID def)
|
||||
{
|
||||
NODE *orig_fbody, *node;
|
||||
VALUE singleton = 0;
|
||||
|
||||
rb_frozen_class_p(klass);
|
||||
if (name == def)
|
||||
return;
|
||||
if (klass == rb_cObject) {
|
||||
rb_secure(4);
|
||||
}
|
||||
orig_fbody = search_method(klass, def, 0);
|
||||
if (!orig_fbody || !orig_fbody->nd_body) {
|
||||
if (TYPE(klass) == T_MODULE) {
|
||||
orig_fbody = search_method(rb_cObject, def, 0);
|
||||
}
|
||||
}
|
||||
if (!orig_fbody || !orig_fbody->nd_body) {
|
||||
print_undef(klass, def);
|
||||
}
|
||||
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||
singleton = rb_iv_get(klass, "__attached__");
|
||||
}
|
||||
|
||||
orig_fbody->nd_cnt++;
|
||||
|
||||
if (RTEST(ruby_verbose) &&
|
||||
st_lookup(RCLASS(klass)->m_tbl, name, (st_data_t *) & node)) {
|
||||
if (node->nd_cnt == 0 && node->nd_body) {
|
||||
rb_warning("discarding old %s", rb_id2name(name));
|
||||
}
|
||||
}
|
||||
|
||||
st_insert(RCLASS(klass)->m_tbl, name,
|
||||
(st_data_t) NEW_FBODY(
|
||||
NEW_METHOD(orig_fbody->nd_body->nd_body,
|
||||
orig_fbody->nd_body->nd_clss,
|
||||
orig_fbody->nd_body->nd_noex), def));
|
||||
|
||||
rb_clear_cache_by_id(name);
|
||||
|
||||
if (singleton) {
|
||||
rb_funcall(singleton, singleton_added, 1, ID2SYM(name));
|
||||
}
|
||||
else {
|
||||
rb_funcall(klass, added, 1, ID2SYM(name));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* alias_method(new_name, old_name) => self
|
||||
*
|
||||
* Makes <i>new_name</i> a new copy of the method <i>old_name</i>. This can
|
||||
* be used to retain access to methods that are overridden.
|
||||
*
|
||||
* module Mod
|
||||
* alias_method :orig_exit, :exit
|
||||
* def exit(code=0)
|
||||
* puts "Exiting with code #{code}"
|
||||
* orig_exit(code)
|
||||
* end
|
||||
* end
|
||||
* include Mod
|
||||
* exit(99)
|
||||
*
|
||||
* <em>produces:</em>
|
||||
*
|
||||
* Exiting with code 99
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname)
|
||||
{
|
||||
rb_alias(mod, rb_to_id(newname), rb_to_id(oldname));
|
||||
return mod;
|
||||
}
|
1195
eval_proc.c
Normal file
1195
eval_proc.c
Normal file
File diff suppressed because it is too large
Load Diff
117
eval_safe.h
Normal file
117
eval_safe.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* This file is included by eval.c
|
||||
*/
|
||||
|
||||
/* safe-level:
|
||||
0 - strings from streams/environment/ARGV are tainted (default)
|
||||
1 - no dangerous operation by tainted value
|
||||
2 - process/file operations prohibited
|
||||
3 - all generated objects are tainted
|
||||
4 - no global (non-tainted) variable modification/no direct output
|
||||
*/
|
||||
|
||||
int
|
||||
rb_safe_level(void)
|
||||
{
|
||||
return GET_THREAD()->safe_level;
|
||||
}
|
||||
|
||||
void
|
||||
rb_set_safe_level_force(int safe)
|
||||
{
|
||||
GET_THREAD()->safe_level = safe;
|
||||
}
|
||||
|
||||
static VALUE safe_getter _((void));
|
||||
static void safe_setter _((VALUE val));
|
||||
|
||||
#define PROC_TSHIFT (FL_USHIFT+1)
|
||||
#define PROC_TMASK (FL_USER1|FL_USER2|FL_USER3)
|
||||
#define PROC_TMAX (PROC_TMASK >> PROC_TSHIFT)
|
||||
#define PROC_NOSAFE FL_USER4
|
||||
|
||||
#define SAFE_LEVEL_MAX PROC_TMASK
|
||||
|
||||
/* $SAFE accessor */
|
||||
void
|
||||
rb_set_safe_level(int level)
|
||||
{
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
|
||||
if (level > th->safe_level) {
|
||||
if (level > SAFE_LEVEL_MAX) {
|
||||
level = SAFE_LEVEL_MAX;
|
||||
}
|
||||
th->safe_level = level;
|
||||
}
|
||||
}
|
||||
|
||||
static VALUE
|
||||
safe_getter(void)
|
||||
{
|
||||
return INT2NUM(rb_safe_level());
|
||||
}
|
||||
|
||||
static void
|
||||
safe_setter(VALUE val)
|
||||
{
|
||||
int level = NUM2INT(val);
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
|
||||
if (level < th->safe_level) {
|
||||
rb_raise(rb_eSecurityError,
|
||||
"tried to downgrade safe level from %d to %d",
|
||||
th->safe_level, level);
|
||||
}
|
||||
if (level > SAFE_LEVEL_MAX) {
|
||||
level = SAFE_LEVEL_MAX;
|
||||
}
|
||||
th->safe_level = level;
|
||||
}
|
||||
|
||||
void
|
||||
rb_secure(int level)
|
||||
{
|
||||
if (level <= rb_safe_level()) {
|
||||
if (rb_frame_callee()) {
|
||||
rb_raise(rb_eSecurityError, "Insecure operation `%s' at level %d",
|
||||
rb_id2name(rb_frame_callee()), rb_safe_level());
|
||||
}
|
||||
else {
|
||||
rb_raise(rb_eSecurityError, "Insecure operation at level %d",
|
||||
rb_safe_level());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_secure_update(VALUE obj)
|
||||
{
|
||||
if (!OBJ_TAINTED(obj))
|
||||
rb_secure(4);
|
||||
}
|
||||
|
||||
void
|
||||
rb_check_safe_obj(VALUE x)
|
||||
{
|
||||
if (rb_safe_level() > 0 && OBJ_TAINTED(x)) {
|
||||
if (rb_frame_callee()) {
|
||||
rb_raise(rb_eSecurityError, "Insecure operation - %s",
|
||||
rb_id2name(rb_frame_callee()));
|
||||
}
|
||||
else {
|
||||
rb_raise(rb_eSecurityError, "Insecure operation: -r");
|
||||
}
|
||||
}
|
||||
rb_secure(4);
|
||||
}
|
||||
|
||||
void
|
||||
rb_check_safe_str(VALUE x)
|
||||
{
|
||||
rb_check_safe_obj(x);
|
||||
if (TYPE(x) != T_STRING) {
|
||||
rb_raise(rb_eTypeError, "wrong argument type %s (expected String)",
|
||||
rb_obj_classname(x));
|
||||
}
|
||||
}
|
683
eval_thread.c
Normal file
683
eval_thread.c
Normal file
@ -0,0 +1,683 @@
|
||||
/*
|
||||
* Thread from eval.c
|
||||
*/
|
||||
|
||||
#include "eval_intern.h"
|
||||
|
||||
#ifdef __ia64__
|
||||
#if defined(__FreeBSD__)
|
||||
/*
|
||||
* FreeBSD/ia64 currently does not have a way for a process to get the
|
||||
* base address for the RSE backing store, so hardcode it.
|
||||
*/
|
||||
#define __libc_ia64_register_backing_store_base (4ULL<<61)
|
||||
#else
|
||||
#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF)
|
||||
#include <unwind.h>
|
||||
#else
|
||||
#pragma weak __libc_ia64_register_backing_store_base
|
||||
extern unsigned long __libc_ia64_register_backing_store_base;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Windows SEH refers data on the stack. */
|
||||
#undef SAVE_WIN32_EXCEPTION_LIST
|
||||
#if defined _WIN32 || defined __CYGWIN__
|
||||
#if defined __CYGWIN__
|
||||
typedef unsigned long DWORD;
|
||||
#endif
|
||||
|
||||
static inline DWORD
|
||||
win32_get_exception_list()
|
||||
{
|
||||
DWORD p;
|
||||
# if defined _MSC_VER
|
||||
# ifdef _M_IX86
|
||||
# define SAVE_WIN32_EXCEPTION_LIST
|
||||
# if _MSC_VER >= 1310
|
||||
/* warning: unsafe assignment to fs:0 ... this is ok */
|
||||
# pragma warning(disable: 4733)
|
||||
# endif
|
||||
__asm mov eax, fs:[0];
|
||||
__asm mov p, eax;
|
||||
# endif
|
||||
# elif defined __GNUC__
|
||||
# ifdef __i386__
|
||||
# define SAVE_WIN32_EXCEPTION_LIST
|
||||
__asm__("movl %%fs:0,%0":"=r"(p));
|
||||
# endif
|
||||
# elif defined __BORLANDC__
|
||||
# define SAVE_WIN32_EXCEPTION_LIST
|
||||
__emit__(0x64, 0xA1, 0, 0, 0, 0); /* mov eax, fs:[0] */
|
||||
p = _EAX;
|
||||
# endif
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline void
|
||||
win32_set_exception_list(p)
|
||||
DWORD p;
|
||||
{
|
||||
# if defined _MSC_VER
|
||||
# ifdef _M_IX86
|
||||
__asm mov eax, p;
|
||||
__asm mov fs:[0], eax;
|
||||
# endif
|
||||
# elif defined __GNUC__
|
||||
# ifdef __i386__
|
||||
__asm__("movl %0,%%fs:0"::"r"(p));
|
||||
# endif
|
||||
# elif defined __BORLANDC__
|
||||
_EAX = p;
|
||||
__emit__(0x64, 0xA3, 0, 0, 0, 0); /* mov fs:[0], eax */
|
||||
# endif
|
||||
}
|
||||
|
||||
#if !defined SAVE_WIN32_EXCEPTION_LIST && !defined _WIN32_WCE
|
||||
# error unsupported platform
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int rb_thread_pending = 0;
|
||||
|
||||
VALUE rb_cThread;
|
||||
|
||||
extern VALUE rb_last_status;
|
||||
|
||||
#define WAIT_FD (1<<0)
|
||||
#define WAIT_SELECT (1<<1)
|
||||
#define WAIT_TIME (1<<2)
|
||||
#define WAIT_JOIN (1<<3)
|
||||
#define WAIT_PID (1<<4)
|
||||
|
||||
/* +infty, for this purpose */
|
||||
#define DELAY_INFTY 1E30
|
||||
|
||||
|
||||
#ifdef NFDBITS
|
||||
void
|
||||
rb_fd_init(fds)
|
||||
volatile rb_fdset_t *fds;
|
||||
{
|
||||
fds->maxfd = 0;
|
||||
fds->fdset = ALLOC(fd_set);
|
||||
FD_ZERO(fds->fdset);
|
||||
}
|
||||
|
||||
void
|
||||
rb_fd_term(fds)
|
||||
rb_fdset_t *fds;
|
||||
{
|
||||
if (fds->fdset)
|
||||
free(fds->fdset);
|
||||
fds->maxfd = 0;
|
||||
fds->fdset = 0;
|
||||
}
|
||||
|
||||
void
|
||||
rb_fd_zero(fds)
|
||||
rb_fdset_t *fds;
|
||||
{
|
||||
if (fds->fdset) {
|
||||
MEMZERO(fds->fdset, fd_mask, howmany(fds->maxfd, NFDBITS));
|
||||
FD_ZERO(fds->fdset);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rb_fd_resize(n, fds)
|
||||
int n;
|
||||
rb_fdset_t *fds;
|
||||
{
|
||||
int m = howmany(n + 1, NFDBITS) * sizeof(fd_mask);
|
||||
int o = howmany(fds->maxfd, NFDBITS) * sizeof(fd_mask);
|
||||
|
||||
if (m < sizeof(fd_set))
|
||||
m = sizeof(fd_set);
|
||||
if (o < sizeof(fd_set))
|
||||
o = sizeof(fd_set);
|
||||
|
||||
if (m > o) {
|
||||
fds->fdset = realloc(fds->fdset, m);
|
||||
memset((char *)fds->fdset + o, 0, m - o);
|
||||
}
|
||||
if (n >= fds->maxfd)
|
||||
fds->maxfd = n + 1;
|
||||
}
|
||||
|
||||
void
|
||||
rb_fd_set(n, fds)
|
||||
int n;
|
||||
rb_fdset_t *fds;
|
||||
{
|
||||
rb_fd_resize(n, fds);
|
||||
FD_SET(n, fds->fdset);
|
||||
}
|
||||
|
||||
void
|
||||
rb_fd_clr(n, fds)
|
||||
int n;
|
||||
rb_fdset_t *fds;
|
||||
{
|
||||
if (n >= fds->maxfd)
|
||||
return;
|
||||
FD_CLR(n, fds->fdset);
|
||||
}
|
||||
|
||||
int
|
||||
rb_fd_isset(n, fds)
|
||||
int n;
|
||||
const rb_fdset_t *fds;
|
||||
{
|
||||
if (n >= fds->maxfd)
|
||||
return 0;
|
||||
return FD_ISSET(n, fds->fdset);
|
||||
}
|
||||
|
||||
void
|
||||
rb_fd_copy(dst, src, max)
|
||||
rb_fdset_t *dst;
|
||||
const fd_set *src;
|
||||
int max;
|
||||
{
|
||||
int size = howmany(max, NFDBITS) * sizeof(fd_mask);
|
||||
|
||||
if (size < sizeof(fd_set))
|
||||
size = sizeof(fd_set);
|
||||
dst->maxfd = max;
|
||||
dst->fdset = realloc(dst->fdset, size);
|
||||
memcpy(dst->fdset, src, size);
|
||||
}
|
||||
|
||||
int
|
||||
rb_fd_select(n, readfds, writefds, exceptfds, timeout)
|
||||
int n;
|
||||
rb_fdset_t *readfds, *writefds, *exceptfds;
|
||||
struct timeval *timeout;
|
||||
{
|
||||
rb_fd_resize(n - 1, readfds);
|
||||
rb_fd_resize(n - 1, writefds);
|
||||
rb_fd_resize(n - 1, exceptfds);
|
||||
return select(n, rb_fd_ptr(readfds), rb_fd_ptr(writefds),
|
||||
rb_fd_ptr(exceptfds), timeout);
|
||||
}
|
||||
|
||||
#undef FD_ZERO
|
||||
#undef FD_SET
|
||||
#undef FD_CLR
|
||||
#undef FD_ISSET
|
||||
|
||||
#define FD_ZERO(f) rb_fd_zero(f)
|
||||
#define FD_SET(i, f) rb_fd_set(i, f)
|
||||
#define FD_CLR(i, f) rb_fd_clr(i, f)
|
||||
#define FD_ISSET(i, f) rb_fd_isset(i, f)
|
||||
|
||||
#endif
|
||||
|
||||
/* typedef struct thread * rb_thread_t; */
|
||||
|
||||
struct thread {
|
||||
/* obsolete */
|
||||
struct thread *next, *prev;
|
||||
rb_jmpbuf_t context;
|
||||
#ifdef SAVE_WIN32_EXCEPTION_LIST
|
||||
DWORD win32_exception_list;
|
||||
#endif
|
||||
|
||||
VALUE result;
|
||||
|
||||
long stk_len;
|
||||
long stk_max;
|
||||
VALUE *stk_ptr;
|
||||
VALUE *stk_pos;
|
||||
#ifdef __ia64__
|
||||
VALUE *bstr_ptr;
|
||||
long bstr_len;
|
||||
#endif
|
||||
|
||||
struct FRAME *frame;
|
||||
struct SCOPE *scope;
|
||||
struct RVarmap *dyna_vars;
|
||||
struct BLOCK *block;
|
||||
struct iter *iter;
|
||||
struct tag *tag;
|
||||
VALUE klass;
|
||||
VALUE wrapper;
|
||||
NODE *cref;
|
||||
struct ruby_env *anchor;
|
||||
|
||||
int flags; /* misc. states (vmode/rb_trap_immediate/raised) */
|
||||
|
||||
NODE *node;
|
||||
|
||||
int tracing;
|
||||
VALUE errinfo;
|
||||
VALUE last_status;
|
||||
VALUE last_line;
|
||||
VALUE last_match;
|
||||
|
||||
int safe;
|
||||
|
||||
enum yarv_thread_status status;
|
||||
int wait_for;
|
||||
int fd;
|
||||
rb_fdset_t readfds;
|
||||
rb_fdset_t writefds;
|
||||
rb_fdset_t exceptfds;
|
||||
int select_value;
|
||||
double delay;
|
||||
rb_thread_t join;
|
||||
|
||||
int abort;
|
||||
int priority;
|
||||
VALUE thgroup;
|
||||
|
||||
st_table *locals;
|
||||
|
||||
VALUE thread;
|
||||
};
|
||||
|
||||
#define THREAD_RAISED 0x200 /* temporary flag */
|
||||
#define THREAD_TERMINATING 0x400 /* persistent flag */
|
||||
#define THREAD_FLAGS_MASK 0x400 /* mask for persistent flags */
|
||||
|
||||
#define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next;
|
||||
#define END_FOREACH_FROM(f,x) } while (x != f)
|
||||
|
||||
#define FOREACH_THREAD(x) FOREACH_THREAD_FROM(curr_thread,x)
|
||||
#define END_FOREACH(x) END_FOREACH_FROM(curr_thread,x)
|
||||
|
||||
struct thread_status_t {
|
||||
NODE *node;
|
||||
|
||||
int tracing;
|
||||
VALUE errinfo;
|
||||
VALUE last_status;
|
||||
VALUE last_line;
|
||||
VALUE last_match;
|
||||
|
||||
int safe;
|
||||
|
||||
enum yarv_thread_status status;
|
||||
int wait_for;
|
||||
int fd;
|
||||
rb_fdset_t readfds;
|
||||
rb_fdset_t writefds;
|
||||
rb_fdset_t exceptfds;
|
||||
int select_value;
|
||||
double delay;
|
||||
rb_thread_t join;
|
||||
};
|
||||
|
||||
#define THREAD_COPY_STATUS(src, dst) (void)( \
|
||||
(dst)->node = (src)->node, \
|
||||
\
|
||||
(dst)->tracing = (src)->tracing, \
|
||||
(dst)->errinfo = (src)->errinfo, \
|
||||
(dst)->last_status = (src)->last_status, \
|
||||
(dst)->last_line = (src)->last_line, \
|
||||
(dst)->last_match = (src)->last_match, \
|
||||
\
|
||||
(dst)->safe = (src)->safe, \
|
||||
\
|
||||
(dst)->status = (src)->status, \
|
||||
(dst)->wait_for = (src)->wait_for, \
|
||||
(dst)->fd = (src)->fd, \
|
||||
(dst)->readfds = (src)->readfds, \
|
||||
(dst)->writefds = (src)->writefds, \
|
||||
(dst)->exceptfds = (src)->exceptfds, \
|
||||
rb_fd_init(&(src)->readfds), \
|
||||
rb_fd_init(&(src)->writefds), \
|
||||
rb_fd_init(&(src)->exceptfds), \
|
||||
(dst)->select_value = (src)->select_value, \
|
||||
(dst)->delay = (src)->delay, \
|
||||
(dst)->join = (src)->join, \
|
||||
0)
|
||||
|
||||
int
|
||||
thread_set_raised(yarv_thread_t *th)
|
||||
{
|
||||
if (th->raised_flag) {
|
||||
return 1;
|
||||
}
|
||||
th->raised_flag = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
thread_reset_raised(yarv_thread_t *th)
|
||||
{
|
||||
if (th->raised_flag == 0) {
|
||||
return 0;
|
||||
}
|
||||
th->raised_flag = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
rb_thread_fd_close(fd)
|
||||
int fd;
|
||||
{
|
||||
// TODO: fix me
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_thread_current()
|
||||
{
|
||||
return GET_THREAD()->self;
|
||||
}
|
||||
|
||||
static rb_thread_t
|
||||
rb_thread_alloc(klass)
|
||||
VALUE klass;
|
||||
{
|
||||
UNSUPPORTED(rb_thread_alloc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_thread_start_0(fn, arg, th)
|
||||
VALUE (*fn) ();
|
||||
void *arg;
|
||||
rb_thread_t th;
|
||||
{
|
||||
rb_bug("unsupported: rb_thread_start_0");
|
||||
return 0; /* not reached */
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_thread_create(VALUE (*fn) (), void *arg)
|
||||
{
|
||||
Init_stack((VALUE *)&arg);
|
||||
return rb_thread_start_0(fn, arg, rb_thread_alloc(rb_cThread));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Thread.new([arg]*) {|args| block } => thread
|
||||
*
|
||||
* Creates and runs a new thread to execute the instructions given in
|
||||
* <i>block</i>. Any arguments passed to <code>Thread::new</code> are passed
|
||||
* into the block.
|
||||
*
|
||||
* x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
|
||||
* a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
|
||||
* x.join # Let the threads finish before
|
||||
* a.join # main thread exits...
|
||||
*
|
||||
* <em>produces:</em>
|
||||
*
|
||||
* abxyzc
|
||||
*/
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Thread.new([arg]*) {|args| block } => thread
|
||||
*
|
||||
* Creates and runs a new thread to execute the instructions given in
|
||||
* <i>block</i>. Any arguments passed to <code>Thread::new</code> are passed
|
||||
* into the block.
|
||||
*
|
||||
* x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
|
||||
* a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
|
||||
* x.join # Let the threads finish before
|
||||
* a.join # main thread exits...
|
||||
*
|
||||
* <em>produces:</em>
|
||||
*
|
||||
* abxyzc
|
||||
*/
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Thread.start([args]*) {|args| block } => thread
|
||||
* Thread.fork([args]*) {|args| block } => thread
|
||||
*
|
||||
* Basically the same as <code>Thread::new</code>. However, if class
|
||||
* <code>Thread</code> is subclassed, then calling <code>start</code> in that
|
||||
* subclass will not invoke the subclass's <code>initialize</code> method.
|
||||
*/
|
||||
|
||||
int rb_thread_critical;
|
||||
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Thread.critical => true or false
|
||||
*
|
||||
* Returns the status of the global ``thread critical'' condition.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* Thread.critical= boolean => true or false
|
||||
*
|
||||
* Sets the status of the global ``thread critical'' condition and returns
|
||||
* it. When set to <code>true</code>, prohibits scheduling of any existing
|
||||
* thread. Does not block new threads from being created and run. Certain
|
||||
* thread operations (such as stopping or killing a thread, sleeping in the
|
||||
* current thread, and raising an exception) may cause a thread to be scheduled
|
||||
* even when in a critical section. <code>Thread::critical</code> is not
|
||||
* intended for daily use: it is primarily there to support folks writing
|
||||
* threading libraries.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Document-class: Continuation
|
||||
*
|
||||
* Continuation objects are generated by
|
||||
* <code>Kernel#callcc</code>. They hold a return address and execution
|
||||
* context, allowing a nonlocal return to the end of the
|
||||
* <code>callcc</code> block from anywhere within a program.
|
||||
* Continuations are somewhat analogous to a structured version of C's
|
||||
* <code>setjmp/longjmp</code> (although they contain more state, so
|
||||
* you might consider them closer to threads).
|
||||
*
|
||||
* For instance:
|
||||
*
|
||||
* arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
|
||||
* callcc{|$cc|}
|
||||
* puts(message = arr.shift)
|
||||
* $cc.call unless message =~ /Max/
|
||||
*
|
||||
* <em>produces:</em>
|
||||
*
|
||||
* Freddie
|
||||
* Herbie
|
||||
* Ron
|
||||
* Max
|
||||
*
|
||||
* This (somewhat contrived) example allows the inner loop to abandon
|
||||
* processing early:
|
||||
*
|
||||
* callcc {|cont|
|
||||
* for i in 0..4
|
||||
* print "\n#{i}: "
|
||||
* for j in i*5...(i+1)*5
|
||||
* cont.call() if j == 17
|
||||
* printf "%3d", j
|
||||
* end
|
||||
* end
|
||||
* }
|
||||
* print "\n"
|
||||
*
|
||||
* <em>produces:</em>
|
||||
*
|
||||
* 0: 0 1 2 3 4
|
||||
* 1: 5 6 7 8 9
|
||||
* 2: 10 11 12 13 14
|
||||
* 3: 15 16
|
||||
*/
|
||||
|
||||
VALUE rb_cCont;
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* callcc {|cont| block } => obj
|
||||
*
|
||||
* Generates a <code>Continuation</code> object, which it passes to the
|
||||
* associated block. Performing a <em>cont</em><code>.call</code> will
|
||||
* cause the <code>callcc</code> to return (as will falling through the
|
||||
* end of the block). The value returned by the <code>callcc</code> is
|
||||
* the value of the block, or the value passed to
|
||||
* <em>cont</em><code>.call</code>. See class <code>Continuation</code>
|
||||
* for more details. Also see <code>Kernel::throw</code> for
|
||||
* an alternative mechanism for unwinding a call stack.
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_callcc(self)
|
||||
VALUE self;
|
||||
{
|
||||
UNSUPPORTED(rb_callcc);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* cont.call(args, ...)
|
||||
* cont[args, ...]
|
||||
*
|
||||
* Invokes the continuation. The program continues from the end of the
|
||||
* <code>callcc</code> block. If no arguments are given, the original
|
||||
* <code>callcc</code> returns <code>nil</code>. If one argument is
|
||||
* given, <code>callcc</code> returns it. Otherwise, an array
|
||||
* containing <i>args</i> is returned.
|
||||
*
|
||||
* callcc {|cont| cont.call } #=> nil
|
||||
* callcc {|cont| cont.call 1 } #=> 1
|
||||
* callcc {|cont| cont.call 1, 2, 3 } #=> [1, 2, 3]
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_cont_call(argc, argv, cont)
|
||||
int argc;
|
||||
VALUE *argv;
|
||||
VALUE cont;
|
||||
{
|
||||
UNSUPPORTED(rb_cont_call);
|
||||
}
|
||||
|
||||
|
||||
/* variables for recursive traversals */
|
||||
static ID recursive_key;
|
||||
|
||||
|
||||
/*
|
||||
* +Thread+ encapsulates the behavior of a thread of
|
||||
* execution, including the main thread of the Ruby script.
|
||||
*
|
||||
* In the descriptions of the methods in this class, the parameter _sym_
|
||||
* refers to a symbol, which is either a quoted string or a
|
||||
* +Symbol+ (such as <code>:name</code>).
|
||||
*/
|
||||
|
||||
void
|
||||
Init_Thread()
|
||||
{
|
||||
recursive_key = rb_intern("__recursive_key__");
|
||||
rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
|
||||
rb_cCont = rb_define_class("Continuation", rb_cObject);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
recursive_check(obj)
|
||||
VALUE obj;
|
||||
{
|
||||
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
||||
|
||||
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
||||
return Qfalse;
|
||||
}
|
||||
else {
|
||||
VALUE list = rb_hash_aref(hash, ID2SYM(rb_frame_this_func()));
|
||||
|
||||
if (NIL_P(list) || TYPE(list) != T_ARRAY)
|
||||
return Qfalse;
|
||||
return rb_ary_includes(list, rb_obj_id(obj));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
recursive_push(obj)
|
||||
VALUE obj;
|
||||
{
|
||||
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
||||
VALUE list, sym;
|
||||
|
||||
sym = ID2SYM(rb_frame_this_func());
|
||||
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
||||
hash = rb_hash_new();
|
||||
rb_thread_local_aset(rb_thread_current(), recursive_key, hash);
|
||||
list = Qnil;
|
||||
}
|
||||
else {
|
||||
list = rb_hash_aref(hash, sym);
|
||||
}
|
||||
if (NIL_P(list) || TYPE(list) != T_ARRAY) {
|
||||
list = rb_ary_new();
|
||||
rb_hash_aset(hash, sym, list);
|
||||
}
|
||||
rb_ary_push(list, rb_obj_id(obj));
|
||||
}
|
||||
|
||||
static void
|
||||
recursive_pop()
|
||||
{
|
||||
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
||||
VALUE list, sym;
|
||||
|
||||
sym = ID2SYM(rb_frame_this_func());
|
||||
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
||||
VALUE symname;
|
||||
VALUE thrname;
|
||||
symname = rb_inspect(sym);
|
||||
thrname = rb_inspect(rb_thread_current());
|
||||
|
||||
rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s",
|
||||
StringValuePtr(symname), StringValuePtr(thrname));
|
||||
}
|
||||
list = rb_hash_aref(hash, sym);
|
||||
if (NIL_P(list) || TYPE(list) != T_ARRAY) {
|
||||
VALUE symname = rb_inspect(sym);
|
||||
VALUE thrname = rb_inspect(rb_thread_current());
|
||||
rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s",
|
||||
StringValuePtr(symname), StringValuePtr(thrname));
|
||||
}
|
||||
rb_ary_pop(list);
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
|
||||
{
|
||||
if (recursive_check(obj)) {
|
||||
return (*func) (obj, arg, Qtrue);
|
||||
}
|
||||
else {
|
||||
VALUE result = Qundef;
|
||||
int state;
|
||||
|
||||
recursive_push(obj);
|
||||
PUSH_TAG(PROT_NONE);
|
||||
if ((state = EXEC_TAG()) == 0) {
|
||||
result = (*func) (obj, arg, Qfalse);
|
||||
}
|
||||
POP_TAG();
|
||||
recursive_pop();
|
||||
if (state)
|
||||
JUMP_TAG(state);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* flush_register_windows must not be inlined because flushrs doesn't flush
|
||||
* current frame in register stack. */
|
||||
#ifdef __ia64__
|
||||
void
|
||||
flush_register_windows(void)
|
||||
{
|
||||
__asm__("flushrs");
|
||||
}
|
||||
#endif
|
@ -118,12 +118,12 @@ module DL
|
||||
f = import_function(symname, ctype, argtype, opt[:call_type])
|
||||
name = symname.gsub(/@.+/,'')
|
||||
@func_map[name] = f
|
||||
define_method(name){|*args,&block| f.call(*args,&block)}
|
||||
#module_eval(<<-EOS)
|
||||
# def #{name}(*args, &block)
|
||||
# @func_map['#{name}'].call(*args,&block)
|
||||
# end
|
||||
#EOS
|
||||
# define_method(name){|*args,&block| f.call(*args,&block)}
|
||||
module_eval(<<-EOS)
|
||||
def #{name}(*args, &block)
|
||||
@func_map['#{name}'].call(*args,&block)
|
||||
end
|
||||
EOS
|
||||
module_function(name)
|
||||
f
|
||||
end
|
||||
@ -142,12 +142,12 @@ module DL
|
||||
raise(RuntimeError, "unknown callback type: #{h[:callback_type]}")
|
||||
end
|
||||
@func_map[name] = f
|
||||
define_method(name){|*args,&block| f.call(*args,&block)}
|
||||
#module_eval(<<-EOS)
|
||||
# def #{name}(*args,&block)
|
||||
# @func_map['#{name}'].call(*args,&block)
|
||||
# end
|
||||
#EOS
|
||||
#define_method(name){|*args,&block| f.call(*args,&block)}
|
||||
module_eval(<<-EOS)
|
||||
def #{name}(*args,&block)
|
||||
@func_map['#{name}'].call(*args,&block)
|
||||
end
|
||||
EOS
|
||||
module_function(name)
|
||||
f
|
||||
end
|
||||
|
@ -1,4 +1,3 @@
|
||||
Makefile
|
||||
mkmf.log
|
||||
*.def
|
||||
extconf.h
|
||||
|
@ -512,7 +512,6 @@ Init_etc(void)
|
||||
rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0);
|
||||
rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0);
|
||||
|
||||
rb_global_variable(&sPasswd);
|
||||
sPasswd = rb_struct_define("Passwd",
|
||||
"name", "passwd", "uid", "gid",
|
||||
#ifdef HAVE_ST_PW_GECOS
|
||||
@ -539,12 +538,15 @@ Init_etc(void)
|
||||
#endif
|
||||
NULL);
|
||||
|
||||
rb_register_mark_object(sPasswd);
|
||||
|
||||
#ifdef HAVE_GETGRENT
|
||||
rb_global_variable(&sGroup);
|
||||
sGroup = rb_struct_define("Group", "name",
|
||||
#ifdef HAVE_ST_GR_PASSWD
|
||||
"passwd",
|
||||
#endif
|
||||
"gid", "mem", NULL);
|
||||
|
||||
rb_register_mark_object(sGroup);
|
||||
#endif
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ iconv_fail(VALUE error, VALUE success, VALUE failed, struct iconv_env_t* env, co
|
||||
}
|
||||
error = rb_class_new_instance(3, args, error);
|
||||
if (!rb_block_given_p()) rb_exc_raise(error);
|
||||
ruby_errinfo = error;
|
||||
rb_set_errinfo(error);
|
||||
return rb_yield(failed);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,6 @@ static char **readline_attempted_completion_function(const char *text,
|
||||
static int
|
||||
readline_event()
|
||||
{
|
||||
CHECK_INTS;
|
||||
rb_thread_schedule();
|
||||
return 0;
|
||||
}
|
||||
|
@ -4,6 +4,9 @@ require 'mkmf'
|
||||
require 'rbconfig'
|
||||
|
||||
def main
|
||||
Logging.message "YARV doesn't support Ripper"
|
||||
return
|
||||
|
||||
unless find_executable('bison')
|
||||
unless File.exist?('ripper.c') or File.exist?("#{$srcdir}/ripper.c")
|
||||
Logging.message 'missing bison; abort'
|
||||
|
@ -1801,7 +1801,7 @@ fole_s_connect(int argc, VALUE *argv, VALUE self)
|
||||
ole_initialize();
|
||||
|
||||
rb_scan_args(argc, argv, "1*", &svr_name, &others);
|
||||
if (ruby_safe_level > 0 && OBJ_TAINTED(svr_name)) {
|
||||
if (rb_safe_level() > 0 && OBJ_TAINTED(svr_name)) {
|
||||
rb_raise(rb_eSecurityError, "Insecure Object Connection - %s",
|
||||
StringValuePtr(svr_name));
|
||||
}
|
||||
@ -2182,12 +2182,12 @@ fole_initialize(int argc, VALUE *argv, VALUE self)
|
||||
rb_call_super(0, 0);
|
||||
rb_scan_args(argc, argv, "11*", &svr_name, &host, &others);
|
||||
|
||||
if (ruby_safe_level > 0 && OBJ_TAINTED(svr_name)) {
|
||||
if (rb_safe_level() > 0 && OBJ_TAINTED(svr_name)) {
|
||||
rb_raise(rb_eSecurityError, "Insecure Object Creation - %s",
|
||||
StringValuePtr(svr_name));
|
||||
}
|
||||
if (!NIL_P(host)) {
|
||||
if (ruby_safe_level > 0 && OBJ_TAINTED(host)) {
|
||||
if (rb_safe_level() > 0 && OBJ_TAINTED(host)) {
|
||||
rb_raise(rb_eSecurityError, "Insecure Object Creation - %s",
|
||||
StringValuePtr(svr_name));
|
||||
}
|
||||
@ -6645,7 +6645,7 @@ fev_initialize(int argc, VALUE *argv, VALUE self)
|
||||
}
|
||||
|
||||
if(TYPE(itf) != T_NIL) {
|
||||
if (ruby_safe_level > 0 && OBJ_TAINTED(itf)) {
|
||||
if (rb_safe_level() > 0 && OBJ_TAINTED(itf)) {
|
||||
rb_raise(rb_eSecurityError, "Insecure Event Creation - %s",
|
||||
StringValuePtr(itf));
|
||||
}
|
||||
@ -6854,8 +6854,8 @@ folevariant_value(VALUE self)
|
||||
void
|
||||
Init_win32ole()
|
||||
{
|
||||
rb_global_variable(&ary_ole_event);
|
||||
ary_ole_event = rb_ary_new();
|
||||
rb_register_mark_object(ary_ole_event);
|
||||
id_events = rb_intern("events");
|
||||
|
||||
com_vtbl.QueryInterface = QueryInterface;
|
||||
@ -6865,8 +6865,8 @@ Init_win32ole()
|
||||
com_vtbl.GetTypeInfo = GetTypeInfo;
|
||||
com_vtbl.GetIDsOfNames = GetIDsOfNames;
|
||||
com_vtbl.Invoke = Invoke;
|
||||
rb_global_variable(&com_hash);
|
||||
com_hash = Data_Wrap_Struct(rb_cData, rb_mark_hash, st_free_table, st_init_numtable());
|
||||
rb_register_mark_object(com_hash);
|
||||
|
||||
cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject);
|
||||
|
||||
|
@ -1759,7 +1759,7 @@ gzfile_read_raw_rescue(VALUE arg)
|
||||
{
|
||||
struct gzfile *gz = (struct gzfile*)arg;
|
||||
VALUE str = Qnil;
|
||||
if (rb_obj_is_kind_of(ruby_errinfo, rb_eNoMethodError)) {
|
||||
if (rb_obj_is_kind_of(ruby_errinfo(), rb_eNoMethodError)) {
|
||||
str = rb_funcall(gz->io, id_read, 1, INT2FIX(GZFILE_READ_SIZE));
|
||||
if (!NIL_P(str)) {
|
||||
Check_Type(str, T_STRING);
|
||||
|
547
gc.c
547
gc.c
@ -16,8 +16,8 @@
|
||||
#include "rubysig.h"
|
||||
#include "st.h"
|
||||
#include "node.h"
|
||||
#include "env.h"
|
||||
#include "re.h"
|
||||
#include "yarvcore.h"
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/types.h>
|
||||
@ -51,7 +51,9 @@ int rb_io_fptr_finalize(struct OpenFile*);
|
||||
# ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# ifndef _AIX
|
||||
# ifdef _AIX
|
||||
#pragma alloca
|
||||
# else
|
||||
# ifndef alloca /* predefined by HP cc +Olibcalls */
|
||||
void *alloca ();
|
||||
# endif
|
||||
@ -69,15 +71,115 @@ void *alloca ();
|
||||
|
||||
static unsigned long malloc_increase = 0;
|
||||
static unsigned long malloc_limit = GC_MALLOC_LIMIT;
|
||||
static void run_final(VALUE obj);
|
||||
static VALUE nomem_error;
|
||||
|
||||
static int dont_gc;
|
||||
static int during_gc;
|
||||
static int need_call_final = 0;
|
||||
static st_table *finalizer_table = 0;
|
||||
|
||||
#define MARK_STACK_MAX 1024
|
||||
static VALUE mark_stack[MARK_STACK_MAX];
|
||||
static VALUE *mark_stack_ptr;
|
||||
static int mark_stack_overflow;
|
||||
|
||||
#undef GC_DEBUG
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
|
||||
#pragma pack(push, 1) /* magic for reducing sizeof(RVALUE): 24 -> 20 */
|
||||
#endif
|
||||
|
||||
typedef struct RVALUE {
|
||||
union {
|
||||
struct {
|
||||
unsigned long flags; /* always 0 for freed obj */
|
||||
struct RVALUE *next;
|
||||
} free;
|
||||
struct RBasic basic;
|
||||
struct RObject object;
|
||||
struct RClass klass;
|
||||
struct RFloat flonum;
|
||||
struct RString string;
|
||||
struct RArray array;
|
||||
struct RRegexp regexp;
|
||||
struct RHash hash;
|
||||
struct RData data;
|
||||
struct RStruct rstruct;
|
||||
struct RBignum bignum;
|
||||
struct RFile file;
|
||||
struct RNode node;
|
||||
struct RMatch match;
|
||||
} as;
|
||||
#ifdef GC_DEBUG
|
||||
char *file;
|
||||
int line;
|
||||
#endif
|
||||
} RVALUE;
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
static RVALUE *freelist = 0;
|
||||
static RVALUE *deferred_final_list = 0;
|
||||
|
||||
#define HEAPS_INCREMENT 10
|
||||
static struct heaps_slot {
|
||||
void *membase;
|
||||
RVALUE *slot;
|
||||
int limit;
|
||||
} *heaps;
|
||||
static int heaps_length = 0;
|
||||
static int heaps_used = 0;
|
||||
|
||||
#define HEAP_MIN_SLOTS 10000
|
||||
static int heap_slots = HEAP_MIN_SLOTS;
|
||||
|
||||
#define FREE_MIN 4096
|
||||
|
||||
static RVALUE *himem, *lomem;
|
||||
|
||||
extern st_table *rb_class_tbl;
|
||||
VALUE *rb_gc_stack_start = 0;
|
||||
#ifdef __ia64
|
||||
VALUE *rb_gc_register_stack_start = 0;
|
||||
#endif
|
||||
|
||||
int gc_stress = 0;
|
||||
|
||||
|
||||
#ifdef DJGPP
|
||||
/* set stack size (http://www.delorie.com/djgpp/v2faq/faq15_9.html) */
|
||||
unsigned int _stklen = 0x180000; /* 1.5 kB */
|
||||
#endif
|
||||
|
||||
#if defined(DJGPP) || defined(_WIN32_WCE)
|
||||
static unsigned int STACK_LEVEL_MAX = 65535;
|
||||
#elif defined(__human68k__)
|
||||
unsigned int _stacksize = 262144;
|
||||
# define STACK_LEVEL_MAX (_stacksize - 4096)
|
||||
# undef HAVE_GETRLIMIT
|
||||
#elif defined(HAVE_GETRLIMIT) || defined(_WIN32)
|
||||
static unsigned int STACK_LEVEL_MAX = 655300;
|
||||
#else
|
||||
# define STACK_LEVEL_MAX 655300
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static void run_final(VALUE obj);
|
||||
static int garbage_collect(void);
|
||||
|
||||
void
|
||||
rb_global_variable(VALUE *var)
|
||||
{
|
||||
rb_gc_register_address(var);
|
||||
}
|
||||
|
||||
void
|
||||
rb_memerror(void)
|
||||
{
|
||||
static int recurse = 0;
|
||||
|
||||
static int recurse = 0;
|
||||
if (!nomem_error || (recurse > 0 && rb_safe_level() < 4)) {
|
||||
fprintf(stderr, "[FATAL] failed to allocate memory\n");
|
||||
exit(1);
|
||||
@ -86,8 +188,6 @@ rb_memerror(void)
|
||||
rb_exc_raise(nomem_error);
|
||||
}
|
||||
|
||||
int gc_stress = 0;
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* GC.stress => true or false
|
||||
@ -211,11 +311,6 @@ ruby_xfree(void *x)
|
||||
RUBY_CRITICAL(free(x));
|
||||
}
|
||||
|
||||
static int dont_gc;
|
||||
static int during_gc;
|
||||
static int need_call_final = 0;
|
||||
static st_table *finalizer_table = 0;
|
||||
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
@ -278,6 +373,13 @@ rb_gc_register_address(VALUE *addr)
|
||||
global_List = tmp;
|
||||
}
|
||||
|
||||
void
|
||||
rb_register_mark_object(VALUE obj)
|
||||
{
|
||||
VALUE ary = GET_THREAD()->vm->mark_object_ary;
|
||||
rb_ary_push(ary, obj);
|
||||
}
|
||||
|
||||
void
|
||||
rb_gc_unregister_address(VALUE *addr)
|
||||
{
|
||||
@ -300,70 +402,6 @@ rb_gc_unregister_address(VALUE *addr)
|
||||
}
|
||||
}
|
||||
|
||||
#undef GC_DEBUG
|
||||
|
||||
void
|
||||
rb_global_variable(VALUE *var)
|
||||
{
|
||||
rb_gc_register_address(var);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
|
||||
#pragma pack(push, 1) /* magic for reducing sizeof(RVALUE): 24 -> 20 */
|
||||
#endif
|
||||
|
||||
typedef struct RVALUE {
|
||||
union {
|
||||
struct {
|
||||
unsigned long flags; /* always 0 for freed obj */
|
||||
struct RVALUE *next;
|
||||
} free;
|
||||
struct RBasic basic;
|
||||
struct RObject object;
|
||||
struct RClass klass;
|
||||
struct RFloat flonum;
|
||||
struct RString string;
|
||||
struct RArray array;
|
||||
struct RRegexp regexp;
|
||||
struct RHash hash;
|
||||
struct RData data;
|
||||
struct RStruct rstruct;
|
||||
struct RBignum bignum;
|
||||
struct RFile file;
|
||||
struct RNode node;
|
||||
struct RMatch match;
|
||||
struct RVarmap varmap;
|
||||
struct SCOPE scope;
|
||||
} as;
|
||||
#ifdef GC_DEBUG
|
||||
char *file;
|
||||
int line;
|
||||
#endif
|
||||
} RVALUE;
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CYGWIN__)
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
static RVALUE *freelist = 0;
|
||||
static RVALUE *deferred_final_list = 0;
|
||||
|
||||
#define HEAPS_INCREMENT 10
|
||||
static struct heaps_slot {
|
||||
void *membase;
|
||||
RVALUE *slot;
|
||||
int limit;
|
||||
} *heaps;
|
||||
static int heaps_length = 0;
|
||||
static int heaps_used = 0;
|
||||
|
||||
#define HEAP_MIN_SLOTS 10000
|
||||
static int heap_slots = HEAP_MIN_SLOTS;
|
||||
|
||||
#define FREE_MIN 4096
|
||||
|
||||
static RVALUE *himem, *lomem;
|
||||
|
||||
static void
|
||||
add_heap(void)
|
||||
{
|
||||
@ -396,13 +434,13 @@ add_heap(void)
|
||||
heap_slots = HEAP_MIN_SLOTS;
|
||||
continue;
|
||||
}
|
||||
heaps[heaps_used].membase = p;
|
||||
if ((VALUE)p % sizeof(RVALUE) == 0)
|
||||
heap_slots += 1;
|
||||
else
|
||||
p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
|
||||
heaps[heaps_used].slot = p;
|
||||
heaps[heaps_used].limit = heap_slots;
|
||||
heaps[heaps_used].membase = p;
|
||||
if ((VALUE)p % sizeof(RVALUE) == 0)
|
||||
heap_slots += 1;
|
||||
else
|
||||
p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
|
||||
heaps[heaps_used].slot = p;
|
||||
heaps[heaps_used].limit = heap_slots;
|
||||
break;
|
||||
}
|
||||
pend = p + heap_slots;
|
||||
@ -410,7 +448,6 @@ add_heap(void)
|
||||
if (himem < pend) himem = pend;
|
||||
heaps_used++;
|
||||
heap_slots *= 1.8;
|
||||
if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS;
|
||||
|
||||
while (p < pend) {
|
||||
p->as.free.flags = 0;
|
||||
@ -421,16 +458,20 @@ add_heap(void)
|
||||
}
|
||||
#define RANY(o) ((RVALUE*)(o))
|
||||
|
||||
VALUE
|
||||
rb_newobj(void)
|
||||
static VALUE
|
||||
rb_newobj_from_heap(void)
|
||||
{
|
||||
VALUE obj;
|
||||
|
||||
if ((gc_stress || !freelist) && !garbage_collect())
|
||||
rb_memerror();
|
||||
if (gc_stress || !freelist) {
|
||||
if(!garbage_collect()) {
|
||||
rb_memerror();
|
||||
}
|
||||
}
|
||||
|
||||
obj = (VALUE)freelist;
|
||||
freelist = freelist->as.free.next;
|
||||
|
||||
MEMZERO((void*)obj, RVALUE, 1);
|
||||
#ifdef GC_DEBUG
|
||||
RANY(obj)->file = ruby_sourcefile;
|
||||
@ -439,6 +480,52 @@ rb_newobj(void)
|
||||
return obj;
|
||||
}
|
||||
|
||||
#if USE_VALUE_CACHE
|
||||
static VALUE
|
||||
rb_fill_value_cache(yarv_thread_t *th)
|
||||
{
|
||||
int i;
|
||||
VALUE rv;
|
||||
|
||||
// LOCK
|
||||
for (i=0; i<YARV_VALUE_CACHE_SIZE; i++) {
|
||||
VALUE v = rb_newobj_from_heap();
|
||||
|
||||
th->value_cache[i] = v;
|
||||
RBASIC(v)->flags = FL_MARK;
|
||||
}
|
||||
th->value_cache_ptr = &th->value_cache[0];
|
||||
rv = rb_newobj_from_heap();
|
||||
// UNLOCK
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
VALUE
|
||||
rb_newobj(void)
|
||||
{
|
||||
#if USE_VALUE_CACHE && 1
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
VALUE v = *th->value_cache_ptr;
|
||||
|
||||
if (v) {
|
||||
RBASIC(v)->flags = 0;
|
||||
th->value_cache_ptr++;
|
||||
}
|
||||
else {
|
||||
v = rb_fill_value_cache(th);
|
||||
}
|
||||
|
||||
#if defined(GC_DEBUG)
|
||||
printf("cache index: %d, v: %p, th: %p\n",
|
||||
th->value_cache_ptr - th->value_cache, v, th);
|
||||
#endif
|
||||
return v;
|
||||
#else
|
||||
return rb_newobj_from_heap();
|
||||
#endif
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_data_object_alloc(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
|
||||
{
|
||||
@ -452,50 +539,21 @@ rb_data_object_alloc(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_F
|
||||
return (VALUE)data;
|
||||
}
|
||||
|
||||
extern st_table *rb_class_tbl;
|
||||
VALUE *rb_gc_stack_start = 0;
|
||||
#ifdef __ia64
|
||||
VALUE *rb_gc_register_stack_start = 0;
|
||||
#endif
|
||||
NOINLINE(void yarv_set_stack_end(VALUE **stack_end_p));
|
||||
|
||||
|
||||
#ifdef DJGPP
|
||||
/* set stack size (http://www.delorie.com/djgpp/v2faq/faq15_9.html) */
|
||||
unsigned int _stklen = 0x180000; /* 1.5 kB */
|
||||
#endif
|
||||
|
||||
#if defined(DJGPP) || defined(_WIN32_WCE)
|
||||
static unsigned int STACK_LEVEL_MAX = 65535;
|
||||
#elif defined(__human68k__)
|
||||
unsigned int _stacksize = 262144;
|
||||
# define STACK_LEVEL_MAX (_stacksize - 4096)
|
||||
# undef HAVE_GETRLIMIT
|
||||
#elif defined(HAVE_GETRLIMIT) || defined(_WIN32)
|
||||
static unsigned int STACK_LEVEL_MAX = 655300;
|
||||
#else
|
||||
# define STACK_LEVEL_MAX 655300
|
||||
#endif
|
||||
|
||||
NOINLINE(static void set_stack_end(VALUE **stack_end_p));
|
||||
|
||||
static void
|
||||
set_stack_end(VALUE **stack_end_p)
|
||||
{
|
||||
VALUE stack_end;
|
||||
*stack_end_p = &stack_end;
|
||||
}
|
||||
#define SET_STACK_END VALUE *stack_end; set_stack_end(&stack_end)
|
||||
#define STACK_END (stack_end)
|
||||
#define YARV_SET_STACK_END yarv_set_stack_end(&th->machine_stack_end)
|
||||
#define STACK_START (th->machine_stack_start)
|
||||
#define STACK_END (th->machine_stack_end)
|
||||
|
||||
#if defined(sparc) || defined(__sparc__)
|
||||
# define STACK_LENGTH (rb_gc_stack_start - STACK_END + 0x80)
|
||||
# define STACK_LENGTH (STACK_START - STACK_END + 0x80)
|
||||
#elif STACK_GROW_DIRECTION < 0
|
||||
# define STACK_LENGTH (rb_gc_stack_start - STACK_END)
|
||||
# define STACK_LENGTH (STACK_START - STACK_END)
|
||||
#elif STACK_GROW_DIRECTION > 0
|
||||
# define STACK_LENGTH (STACK_END - rb_gc_stack_start + 1)
|
||||
# define STACK_LENGTH (STACK_END - STACK_START + 1)
|
||||
#else
|
||||
# define STACK_LENGTH ((STACK_END < rb_gc_stack_start) ? rb_gc_stack_start - STACK_END\
|
||||
: STACK_END - rb_gc_stack_start + 1)
|
||||
# define STACK_LENGTH ((STACK_END < STACK_START) ? STACK_START - STACK_END\
|
||||
: STACK_END - STACK_START + 1)
|
||||
#endif
|
||||
#if STACK_GROW_DIRECTION > 0
|
||||
# define STACK_UPPER(x, a, b) a
|
||||
@ -506,10 +564,11 @@ static int grow_direction;
|
||||
static int
|
||||
stack_grow_direction(VALUE *addr)
|
||||
{
|
||||
SET_STACK_END;
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
YARV_SET_STACK_END;
|
||||
|
||||
if (STACK_END > addr) return grow_direction = 1;
|
||||
return grow_direction = -1;
|
||||
if (STACK_END > addr) return grow_direction = 1;
|
||||
return grow_direction = -1;
|
||||
}
|
||||
# define stack_growup_p(x) ((grow_direction ? grow_direction : stack_grow_direction(x)) > 0)
|
||||
# define STACK_UPPER(x, a, b) (stack_growup_p(x) ? a : b)
|
||||
@ -518,32 +577,28 @@ stack_grow_direction(VALUE *addr)
|
||||
#define GC_WATER_MARK 512
|
||||
|
||||
#define CHECK_STACK(ret) do {\
|
||||
SET_STACK_END;\
|
||||
YARV_SET_STACK_END;\
|
||||
(ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\
|
||||
} while (0)
|
||||
|
||||
int
|
||||
ruby_stack_length(VALUE **p)
|
||||
{
|
||||
SET_STACK_END;
|
||||
if (p) *p = STACK_UPPER(STACK_END, rb_gc_stack_start, STACK_END);
|
||||
return STACK_LENGTH;
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
YARV_SET_STACK_END;
|
||||
if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END);
|
||||
return STACK_LENGTH;
|
||||
}
|
||||
|
||||
int
|
||||
ruby_stack_check(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
CHECK_STACK(ret);
|
||||
return ret;
|
||||
int ret;
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
CHECK_STACK(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define MARK_STACK_MAX 1024
|
||||
static VALUE mark_stack[MARK_STACK_MAX];
|
||||
static VALUE *mark_stack_ptr;
|
||||
static int mark_stack_overflow;
|
||||
|
||||
static void
|
||||
init_mark_stack(void)
|
||||
{
|
||||
@ -624,7 +679,7 @@ gc_mark_rest(void)
|
||||
MEMCPY(tmp_arry, mark_stack, VALUE, MARK_STACK_MAX);
|
||||
|
||||
init_mark_stack();
|
||||
while (p != tmp_arry){
|
||||
while(p != tmp_arry){
|
||||
p--;
|
||||
gc_mark_children(*p, 0);
|
||||
}
|
||||
@ -644,7 +699,7 @@ is_pointer_to_heap(void *ptr)
|
||||
for (i=0; i < heaps_used; i++) {
|
||||
heap_org = heaps[i].slot;
|
||||
if (heap_org <= p && p < heap_org + heaps[i].limit)
|
||||
return Qtrue;
|
||||
return Qtrue;
|
||||
}
|
||||
return Qfalse;
|
||||
}
|
||||
@ -785,6 +840,7 @@ gc_mark_children(VALUE ptr, int lev)
|
||||
case NODE_IF: /* 1,2,3 */
|
||||
case NODE_FOR:
|
||||
case NODE_ITER:
|
||||
case NODE_CREF:
|
||||
case NODE_WHEN:
|
||||
case NODE_MASGN:
|
||||
case NODE_RESCUE:
|
||||
@ -795,17 +851,16 @@ gc_mark_children(VALUE ptr, int lev)
|
||||
gc_mark((VALUE)obj->as.node.u2.node, lev);
|
||||
/* fall through */
|
||||
case NODE_BLOCK: /* 1,3 */
|
||||
case NODE_OPTBLOCK:
|
||||
case NODE_ARRAY:
|
||||
case NODE_DSTR:
|
||||
case NODE_DXSTR:
|
||||
case NODE_DREGX:
|
||||
case NODE_DREGX_ONCE:
|
||||
case NODE_FBODY:
|
||||
case NODE_ENSURE:
|
||||
case NODE_CALL:
|
||||
case NODE_DEFS:
|
||||
case NODE_OP_ASGN1:
|
||||
case NODE_CREF:
|
||||
gc_mark((VALUE)obj->as.node.u1.node, lev);
|
||||
/* fall through */
|
||||
case NODE_SUPER: /* 3 */
|
||||
@ -814,7 +869,8 @@ gc_mark_children(VALUE ptr, int lev)
|
||||
ptr = (VALUE)obj->as.node.u3.node;
|
||||
goto again;
|
||||
|
||||
case NODE_WHILE: /* 1,2 */
|
||||
case NODE_METHOD: /* 1,2 */
|
||||
case NODE_WHILE:
|
||||
case NODE_UNTIL:
|
||||
case NODE_AND:
|
||||
case NODE_OR:
|
||||
@ -831,10 +887,9 @@ gc_mark_children(VALUE ptr, int lev)
|
||||
case NODE_MODULE:
|
||||
case NODE_ALIAS:
|
||||
case NODE_VALIAS:
|
||||
case NODE_LAMBDA:
|
||||
gc_mark((VALUE)obj->as.node.u1.node, lev);
|
||||
/* fall through */
|
||||
case NODE_METHOD: /* 2 */
|
||||
case NODE_FBODY: /* 2 */
|
||||
case NODE_NOT:
|
||||
case NODE_GASGN:
|
||||
case NODE_LASGN:
|
||||
@ -932,7 +987,6 @@ gc_mark_children(VALUE ptr, int lev)
|
||||
else {
|
||||
long i, len = RARRAY_LEN(obj);
|
||||
VALUE *ptr = RARRAY_PTR(obj);
|
||||
|
||||
for (i=0; i < len; i++) {
|
||||
gc_mark(*ptr++, lev);
|
||||
}
|
||||
@ -968,29 +1022,13 @@ gc_mark_children(VALUE ptr, int lev)
|
||||
break;
|
||||
|
||||
case T_MATCH:
|
||||
gc_mark(obj->as.match.regexp, lev);
|
||||
gc_mark(obj->as.match.regexp, lev);
|
||||
if (obj->as.match.str) {
|
||||
ptr = obj->as.match.str;
|
||||
goto again;
|
||||
}
|
||||
break;
|
||||
|
||||
case T_VARMAP:
|
||||
gc_mark(obj->as.varmap.val, lev);
|
||||
ptr = (VALUE)obj->as.varmap.next;
|
||||
goto again;
|
||||
|
||||
case T_SCOPE:
|
||||
if (obj->as.scope.local_vars && (obj->as.scope.flags & SCOPE_MALLOC)) {
|
||||
int n = obj->as.scope.local_tbl[0]+1;
|
||||
VALUE *vars = &obj->as.scope.local_vars[-1];
|
||||
|
||||
while (n--) {
|
||||
gc_mark(*vars++, lev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case T_STRUCT:
|
||||
{
|
||||
long len = RSTRUCT_LEN(obj);
|
||||
@ -1002,6 +1040,15 @@ gc_mark_children(VALUE ptr, int lev)
|
||||
}
|
||||
break;
|
||||
|
||||
case T_VALUES:
|
||||
{
|
||||
rb_gc_mark(RVALUES(obj)->v1);
|
||||
rb_gc_mark(RVALUES(obj)->v2);
|
||||
ptr = RVALUES(obj)->v3;
|
||||
goto again;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
rb_bug("rb_gc_mark(): unknown data type 0x%lx(%p) %s",
|
||||
obj->as.basic.flags & T_MASK, obj,
|
||||
@ -1054,14 +1101,6 @@ gc_sweep(void)
|
||||
int freed = 0;
|
||||
int i;
|
||||
unsigned long live = 0;
|
||||
unsigned long free_min = 0;
|
||||
|
||||
for (i = 0; i < heaps_used; i++) {
|
||||
free_min += heaps[i].limit;
|
||||
}
|
||||
free_min = free_min * 0.2;
|
||||
if (free_min < FREE_MIN)
|
||||
free_min = FREE_MIN;
|
||||
|
||||
mark_source_filename(ruby_sourcefile);
|
||||
if (source_filenames) {
|
||||
@ -1104,12 +1143,12 @@ gc_sweep(void)
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if (n == heaps[i].limit && freed > free_min) {
|
||||
if (n == heaps[i].limit && freed > FREE_MIN) {
|
||||
RVALUE *pp;
|
||||
|
||||
heaps[i].limit = 0;
|
||||
for (pp = final_list; pp != final; pp = pp->as.free.next) {
|
||||
pp->as.free.flags |= FL_SINGLETON; /* freeing page mark */
|
||||
p->as.free.flags |= FL_SINGLETON; /* freeing page mark */
|
||||
}
|
||||
freelist = free; /* cancel this page from freelist */
|
||||
}
|
||||
@ -1122,7 +1161,7 @@ gc_sweep(void)
|
||||
if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
|
||||
}
|
||||
malloc_increase = 0;
|
||||
if (freed < free_min) {
|
||||
if (freed < FREE_MIN) {
|
||||
add_heap();
|
||||
}
|
||||
during_gc = 0;
|
||||
@ -1218,9 +1257,10 @@ obj_free(VALUE obj)
|
||||
break;
|
||||
|
||||
case T_FLOAT:
|
||||
case T_VARMAP:
|
||||
case T_BLOCK:
|
||||
break;
|
||||
case T_VALUES:
|
||||
break;
|
||||
|
||||
case T_BIGNUM:
|
||||
if (RANY(obj)->as.bignum.digits) {
|
||||
@ -1240,17 +1280,6 @@ obj_free(VALUE obj)
|
||||
}
|
||||
return; /* no need to free iv_tbl */
|
||||
|
||||
case T_SCOPE:
|
||||
if (RANY(obj)->as.scope.local_vars &&
|
||||
RANY(obj)->as.scope.flags != SCOPE_ALLOCA) {
|
||||
VALUE *vars = RANY(obj)->as.scope.local_vars-1;
|
||||
if (vars[0] == 0)
|
||||
RUBY_CRITICAL(free(RANY(obj)->as.scope.local_tbl));
|
||||
if (RANY(obj)->as.scope.flags & SCOPE_MALLOC)
|
||||
RUBY_CRITICAL(free(vars));
|
||||
}
|
||||
break;
|
||||
|
||||
case T_STRUCT:
|
||||
if (RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK == 0 &&
|
||||
RANY(obj)->as.rstruct.as.heap.ptr) {
|
||||
@ -1264,12 +1293,6 @@ obj_free(VALUE obj)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_gc_mark_frame(struct FRAME *frame)
|
||||
{
|
||||
gc_mark((VALUE)frame->node, 0);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if defined(__human68k__) || defined(DJGPP)
|
||||
#if defined(__human68k__)
|
||||
@ -1308,20 +1331,21 @@ int rb_setjmp (rb_jmp_buf);
|
||||
#endif /* __human68k__ or DJGPP */
|
||||
#endif /* __GNUC__ */
|
||||
|
||||
#define GC_NOTIFY 0
|
||||
|
||||
static int
|
||||
garbage_collect(void)
|
||||
{
|
||||
struct gc_list *list;
|
||||
struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */
|
||||
jmp_buf save_regs_gc_mark;
|
||||
SET_STACK_END;
|
||||
yarv_thread_t *th = GET_THREAD();
|
||||
|
||||
if (!heaps) return Qfalse;
|
||||
#ifdef HAVE_NATIVETHREAD
|
||||
if (!is_ruby_native_thread()) {
|
||||
rb_bug("cross-thread violation on rb_gc()");
|
||||
if (GC_NOTIFY) printf("start garbage_collect()\n");
|
||||
|
||||
if (!heaps) {
|
||||
return Qfalse;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dont_gc || during_gc) {
|
||||
if (!freelist) {
|
||||
add_heap();
|
||||
@ -1330,23 +1354,13 @@ garbage_collect(void)
|
||||
}
|
||||
during_gc++;
|
||||
|
||||
YARV_SET_STACK_END;
|
||||
|
||||
init_mark_stack();
|
||||
|
||||
gc_mark((VALUE)ruby_current_node, 0);
|
||||
rb_gc_mark(th->vm->self);
|
||||
rb_gc_mark(th->vm->mark_object_ary);
|
||||
|
||||
/* mark frame stack */
|
||||
for (frame = ruby_frame; frame; frame = frame->prev) {
|
||||
rb_gc_mark_frame(frame);
|
||||
if (frame->tmp) {
|
||||
struct FRAME *tmp = frame->tmp;
|
||||
while (tmp) {
|
||||
rb_gc_mark_frame(tmp);
|
||||
tmp = tmp->prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
gc_mark((VALUE)ruby_scope, 0);
|
||||
gc_mark((VALUE)ruby_dyna_vars, 0);
|
||||
if (finalizer_table) {
|
||||
mark_tbl(finalizer_table, 0);
|
||||
}
|
||||
@ -1355,24 +1369,45 @@ garbage_collect(void)
|
||||
/* This assumes that all registers are saved into the jmp_buf (and stack) */
|
||||
setjmp(save_regs_gc_mark);
|
||||
mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
|
||||
|
||||
#if STACK_GROW_DIRECTION < 0
|
||||
rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start);
|
||||
rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start);
|
||||
#elif STACK_GROW_DIRECTION > 0
|
||||
rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1);
|
||||
rb_gc_mark_locations(th->machin_stack_start, th->machine_stack_end + 1);
|
||||
#else
|
||||
if ((VALUE*)STACK_END < rb_gc_stack_start)
|
||||
rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start);
|
||||
if (th->machine_stack_end < th->machin_stack_start)
|
||||
rb_gc_mark_locations(th->machine_stack_end, th->machin_stack_start);
|
||||
else
|
||||
rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1);
|
||||
rb_gc_mark_locations(th->machin_stack_start, th->machine_stack_end + 1);
|
||||
#endif
|
||||
#ifdef __ia64
|
||||
/* mark backing store (flushed register stack) */
|
||||
#ifdef __ia64__
|
||||
/* mark backing store (flushed register window on the stack) */
|
||||
/* the basic idea from guile GC code */
|
||||
rb_gc_mark_locations(rb_gc_register_stack_start, (VALUE*)rb_ia64_bsp());
|
||||
{
|
||||
ucontext_t ctx;
|
||||
VALUE *top, *bot;
|
||||
#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF)
|
||||
_Unwind_Context *unwctx = _UNW_createContextForSelf();
|
||||
#endif
|
||||
|
||||
getcontext(&ctx);
|
||||
mark_locations_array((VALUE*)&ctx.uc_mcontext,
|
||||
((size_t)(sizeof(VALUE)-1 + sizeof ctx.uc_mcontext)/sizeof(VALUE)));
|
||||
#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF)
|
||||
_UNW_currentContext(unwctx);
|
||||
bot = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSP);
|
||||
top = (VALUE*)(long)_UNW_getAR(unwctx, _UNW_AR_BSPSTORE);
|
||||
_UNW_destroyContext(unwctx);
|
||||
#else
|
||||
bot = (VALUE*)__libc_ia64_register_backing_store_base;
|
||||
top = (VALUE*)ctx.uc_mcontext.IA64_BSPSTORE;
|
||||
#endif
|
||||
rb_gc_mark_locations(bot, top);
|
||||
}
|
||||
#endif
|
||||
#if defined(__human68k__) || defined(__mc68000__)
|
||||
rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2),
|
||||
(VALUE*)((char*)rb_gc_stack_start + 2));
|
||||
(VALUE*)((char*)STACK_START + 2));
|
||||
#endif
|
||||
rb_gc_mark_threads();
|
||||
rb_gc_mark_symbols();
|
||||
@ -1393,23 +1428,38 @@ garbage_collect(void)
|
||||
rb_gc_mark_parser();
|
||||
|
||||
/* gc_mark objects whose marking are not completed*/
|
||||
do {
|
||||
while (!MARK_STACK_EMPTY) {
|
||||
if (mark_stack_overflow){
|
||||
gc_mark_all();
|
||||
}
|
||||
else {
|
||||
gc_mark_rest();
|
||||
}
|
||||
while (!MARK_STACK_EMPTY){
|
||||
if (mark_stack_overflow){
|
||||
gc_mark_all();
|
||||
}
|
||||
rb_gc_abort_threads();
|
||||
} while (!MARK_STACK_EMPTY);
|
||||
else {
|
||||
gc_mark_rest();
|
||||
}
|
||||
}
|
||||
|
||||
gc_sweep();
|
||||
|
||||
if (GC_NOTIFY) printf("end garbage_collect()\n");
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
void
|
||||
yarv_machine_stack_mark(yarv_thread_t *th)
|
||||
{
|
||||
#if STACK_GROW_DIRECTION < 0
|
||||
rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start);
|
||||
#elif STACK_GROW_DIRECTION > 0
|
||||
rb_gc_mark_locations(th->machin_stack_start, th->machine_stack_end);
|
||||
#else
|
||||
if (th->machin_stack_start < th->machine_stack_end) {
|
||||
rb_gc_mark_locations(th->machin_stack_start, th->machine_stack_end);
|
||||
}
|
||||
else {
|
||||
rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
rb_gc(void)
|
||||
{
|
||||
@ -1604,8 +1654,6 @@ os_live_obj(void)
|
||||
if (p->as.basic.flags) {
|
||||
switch (TYPE(p)) {
|
||||
case T_ICLASS:
|
||||
case T_VARMAP:
|
||||
case T_SCOPE:
|
||||
case T_NODE:
|
||||
continue;
|
||||
case T_CLASS:
|
||||
@ -1636,8 +1684,6 @@ os_obj_of(VALUE of)
|
||||
if (p->as.basic.flags) {
|
||||
switch (TYPE(p)) {
|
||||
case T_ICLASS:
|
||||
case T_VARMAP:
|
||||
case T_SCOPE:
|
||||
case T_NODE:
|
||||
continue;
|
||||
case T_CLASS:
|
||||
@ -1796,7 +1842,7 @@ define_final(int argc, VALUE *argv, VALUE os)
|
||||
need_call_final = 1;
|
||||
FL_SET(obj, FL_FINALIZE);
|
||||
|
||||
block = rb_ary_new3(2, INT2FIX(ruby_safe_level), block);
|
||||
block = rb_ary_new3(2, INT2FIX(rb_safe_level()), block);
|
||||
|
||||
if (!finalizer_table) {
|
||||
finalizer_table = st_init_numtable();
|
||||
@ -1840,7 +1886,7 @@ run_final(VALUE obj)
|
||||
objid = rb_obj_id(obj); /* make obj into id */
|
||||
rb_thread_critical = Qtrue;
|
||||
args[1] = 0;
|
||||
args[2] = (VALUE)ruby_safe_level;
|
||||
args[2] = (VALUE)rb_safe_level();
|
||||
for (i=0; i<RARRAY_LEN(finalizers); i++) {
|
||||
args[0] = RARRAY_PTR(finalizers)[i];
|
||||
if (!args[1]) args[1] = rb_ary_new3(1, objid);
|
||||
@ -1960,8 +2006,8 @@ id2ref(VALUE obj, VALUE objid)
|
||||
if ((ptr % sizeof(RVALUE)) == (4 << 2)) {
|
||||
ID symid = ptr / sizeof(RVALUE);
|
||||
if (rb_id2name(symid) == 0)
|
||||
rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
|
||||
return ID2SYM(symid);
|
||||
rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
|
||||
return ID2SYM(symid);
|
||||
}
|
||||
|
||||
if (!is_pointer_to_heap((void *)ptr)|| BUILTIN_TYPE(ptr) >= T_BLOCK) {
|
||||
@ -2011,7 +2057,7 @@ rb_obj_id(VALUE obj)
|
||||
* nil 00000000000000000000000000000100
|
||||
* undef 00000000000000000000000000000110
|
||||
* symbol ssssssssssssssssssssssss00001110
|
||||
* object oooooooooooooooooooooooooooooo00 = 0 (mod sizeof(RVALUE))
|
||||
* object oooooooooooooooooooooooooooooo00 = 0 (mod sizeof(RVALUE)
|
||||
* fixnum fffffffffffffffffffffffffffffff1
|
||||
*
|
||||
* object_id space
|
||||
@ -2020,7 +2066,7 @@ rb_obj_id(VALUE obj)
|
||||
* true 00000000000000000000000000000010
|
||||
* nil 00000000000000000000000000000100
|
||||
* undef 00000000000000000000000000000110
|
||||
* symbol 000SSSSSSSSSSSSSSSSSSSSSSSSSSS0 S...S % A = 4 (S...S = s...s * A + 4)
|
||||
* symbol 000SSSSSSSSSSSSSSSSSSSSSSSSSSS0 S...S % A = 4 (S...S =
|
||||
* object oooooooooooooooooooooooooooooo0 o...o % A = 0
|
||||
* fixnum fffffffffffffffffffffffffffffff1 bignum if required
|
||||
*
|
||||
@ -2031,6 +2077,9 @@ rb_obj_id(VALUE obj)
|
||||
* 24 if 32-bit, double is 8-byte aligned
|
||||
* 40 if 64-bit
|
||||
*/
|
||||
if (TYPE(obj) == T_SYMBOL) {
|
||||
return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
|
||||
}
|
||||
if (SPECIAL_CONST_P(obj)) {
|
||||
return LONG2NUM((long)obj);
|
||||
}
|
||||
@ -2079,7 +2128,7 @@ Init_GC(void)
|
||||
rb_global_variable(&nomem_error);
|
||||
nomem_error = rb_exc_new2(rb_eNoMemError, "failed to allocate memory");
|
||||
|
||||
rb_define_method(rb_cBasicObject, "__id__", rb_obj_id, 0);
|
||||
rb_define_method(rb_cBasicObject, "object_id", rb_obj_id, 0);
|
||||
rb_define_method(rb_mKernel, "hash", rb_obj_id, 0);
|
||||
rb_define_method(rb_mKernel, "__id__", rb_obj_id, 0);
|
||||
rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user