1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* Merge YARV

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11439 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ko1 2006-12-31 15:02:22 +00:00
parent 3e7566d8fb
commit a3e1b1ce7e
233 changed files with 46004 additions and 13653 deletions

View file

@ -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> Sun Dec 31 16:22:48 2006 Eric Hodel <drbrain@segment7.net>
* array.c: Fix Array#reject. * array.c: Fix Array#reject.

69
array.c
View file

@ -44,7 +44,7 @@ static void
ary_iter_check(VALUE ary) ary_iter_check(VALUE ary)
{ {
if (FL_TEST(ary, ARY_ITERLOCK)) { 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 #define ARY_SORTLOCK FL_USER3
@ -143,7 +143,7 @@ ary_new(VALUE klass, long len)
rb_raise(rb_eArgError, "array size too big"); rb_raise(rb_eArgError, "array size too big");
} }
ary = ary_alloc(klass); ary = ary_alloc(klass);
if (len == 0) len++; if (len == 0) len++;
RARRAY(ary)->ptr = ALLOC_N(VALUE, len); RARRAY(ary)->ptr = ALLOC_N(VALUE, len);
RARRAY(ary)->aux.capa = 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"); return rb_check_convert_type(ary, T_ARRAY, "Array", "to_ary");
} }
static VALUE rb_ary_replace(VALUE, VALUE);
/* /*
* call-seq: * call-seq:
* Array.new(size=0, obj=nil) * 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_raise(rb_eArgError, "array size too big");
} }
rb_ary_modify(ary); rb_ary_modify(ary);
RESIZE_CAPA(ary, len); RESIZE_CAPA(ary, len);
if (rb_block_given_p()) { if (rb_block_given_p()) {
long i; long i;
@ -543,10 +541,10 @@ rb_ary_shift(VALUE ary)
top = RARRAY_PTR(ary)[0]; top = RARRAY_PTR(ary)[0];
if (!ARY_SHARED_P(ary)) { if (!ARY_SHARED_P(ary)) {
if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) { 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--; RARRAY(ary)->len--;
return top; return top;
} }
RARRAY_PTR(ary)[0] = Qnil; RARRAY_PTR(ary)[0] = Qnil;
ary_make_shared(ary); ary_make_shared(ary);
} }
@ -590,7 +588,7 @@ rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
if (ARY_SHARED_P(ary)) { if (ARY_SHARED_P(ary)) {
RARRAY(ary)->ptr += n; RARRAY(ary)->ptr += n;
RARRAY(ary)->len -= n; RARRAY(ary)->len -= n;
} }
else { else {
MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+n, VALUE, RARRAY_LEN(ary)-n); MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+n, VALUE, RARRAY_LEN(ary)-n);
RARRAY(ary)->len -= 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); if (len == 0) return ary_new(klass, 0);
shared = ary_make_shared(ary); shared = ary_make_shared(ary);
ptr = RARRAY_PTR(ary); ptr = RARRAY_PTR(ary);
ary2 = ary_alloc(klass); ary2 = ary_alloc(klass);
RARRAY(ary2)->ptr = ptr + beg; RARRAY(ary2)->ptr = ptr + beg;
RARRAY(ary2)->len = len; RARRAY(ary2)->len = len;
@ -775,8 +773,8 @@ rb_ary_at(VALUE ary, VALUE pos)
/* /*
* call-seq: * call-seq:
* array.first -> obj or nil * 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. * 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 * If the array is empty, the first form returns <code>nil</code>, and the
* second form returns an empty array. * second form returns an empty array.
@ -931,7 +929,7 @@ rb_ary_rindex(int argc, VALUE *argv, VALUE ary)
long i = RARRAY_LEN(ary); long i = RARRAY_LEN(ary);
if (rb_scan_args(argc, argv, "01", &val) == 0) { if (rb_scan_args(argc, argv, "01", &val) == 0) {
RETURN_ENUMERATOR(ary, 0, 0); RETURN_ENUMERATOR(ary, 0, 0);
while (i--) { while (i--) {
if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) if (RTEST(rb_yield(RARRAY_PTR(ary)[i])))
return LONG2NUM(i); return LONG2NUM(i);
@ -1145,11 +1143,23 @@ each_i(VALUE ary)
* a -- b -- c -- * a -- b -- c --
*/ */
VALUE yarv_invoke_Array_each_special_block(VALUE ary);
VALUE VALUE
rb_ary_each(VALUE ary) rb_ary_each(VALUE ary)
{ {
long i;
VALUE val;
RETURN_ENUMERATOR(ary, 0, 0); RETURN_ENUMERATOR(ary, 0, 0);
val = yarv_invoke_Array_each_special_block(ary);
if(val != Qundef){
return val;
}
ITERATE(each_i, ary); ITERATE(each_i, ary);
return ary;
} }
static VALUE static VALUE
@ -1158,7 +1168,7 @@ each_index_i(VALUE ary)
long i; long i;
for (i=0; i<RARRAY_LEN(ary); i++) { for (i=0; i<RARRAY_LEN(ary); i++) {
rb_yield(LONG2NUM(i)); rb_yield(LONG2NUM(i));
} }
return ary; return ary;
} }
@ -1530,7 +1540,7 @@ sort_i(VALUE ary)
data.ary = ary; data.ary = ary;
data.ptr = RARRAY_PTR(ary); data.len = RARRAY_LEN(ary); data.ptr = RARRAY_PTR(ary); data.len = RARRAY_LEN(ary);
ruby_qsort(RARRAY_PTR(ary), RARRAY_LEN(ary), sizeof(VALUE), 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; return ary;
} }
@ -1890,7 +1900,6 @@ rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary)
return rb_ary_delete_at(ary, NUM2LONG(arg1)); return rb_ary_delete_at(ary, NUM2LONG(arg1));
} }
static VALUE static VALUE
reject_bang_i(VALUE ary) reject_bang_i(VALUE ary)
{ {
@ -1905,10 +1914,10 @@ reject_bang_i(VALUE ary)
} }
i2++; i2++;
} }
if (RARRAY_LEN(ary) == i2) return Qnil; if (RARRAY_LEN(ary) == i2) return Qnil;
if (i2 < RARRAY_LEN(ary)) if (i2 < RARRAY_LEN(ary))
RARRAY(ary)->len = i2; RARRAY(ary)->len = i2;
return ary; return ary;
} }
@ -2075,7 +2084,7 @@ rb_ary_transpose(VALUE ary)
* a #=> ["x", "y", "z"] * a #=> ["x", "y", "z"]
*/ */
static VALUE VALUE
rb_ary_replace(VALUE copy, VALUE orig) rb_ary_replace(VALUE copy, VALUE orig)
{ {
VALUE shared; VALUE shared;
@ -2087,7 +2096,7 @@ rb_ary_replace(VALUE copy, VALUE orig)
if (copy == orig) return copy; if (copy == orig) return copy;
shared = ary_make_shared(orig); shared = ary_make_shared(orig);
ptr = RARRAY(copy)->ptr; ptr = RARRAY(copy)->ptr;
xfree(ptr); xfree(ptr);
RARRAY(copy)->ptr = RARRAY(shared)->ptr; RARRAY(copy)->ptr = RARRAY(shared)->ptr;
RARRAY(copy)->len = RARRAY(shared)->len; RARRAY(copy)->len = RARRAY(shared)->len;
RARRAY(copy)->aux.shared = shared; 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_push(memo, id);
rb_ary_splice(ary, idx, 1, ary2); rb_ary_splice(ary, idx, 1, ary2);
if (level != 0) { if (level != 0) {
while (i < lim) { while (i < lim) {
VALUE tmp; VALUE tmp;
tmp = rb_check_array_type(rb_ary_elt(ary, i)); tmp = rb_check_array_type(rb_ary_elt(ary, i));
if (!NIL_P(tmp)) { if (!NIL_P(tmp)) {
n = flatten(ary, i, tmp, memo, level); n = flatten(ary, i, tmp, memo, level);
i += n; lim += n; i += n; lim += n;
}
i++;
} }
i++;
}
} }
rb_ary_pop(memo); rb_ary_pop(memo);
@ -2822,7 +2831,7 @@ flatten(VALUE ary, long idx, VALUE ary2, VALUE memo, int level)
/* /*
* call-seq: * call-seq:
* array.flatten! -> array or nil * array.flatten! -> array or nil
* array.flatten!(level) -> array or nil * array.flatten!(level) -> array or nil
* *
* Flattens _self_ in place. * 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. * argument determins the level of recursion to flatten.
* *
* a = [ 1, 2, [3, [4, 5] ] ] * a = [ 1, 2, [3, [4, 5] ] ]
* a.flatten! #=> [1, 2, 3, 4, 5] * a.flatten! #=> [1, 2, 3, 4, 5]
* a.flatten! #=> nil * a.flatten! #=> nil
* a #=> [1, 2, 3, 4, 5] * a #=> [1, 2, 3, 4, 5]
* a = [ 1, 2, [3, [4, 5] ] ] * a = [ 1, 2, [3, [4, 5] ] ]
* a.flatten!(1) #=> [1, 2, 3, [4, 5]] * a.flatten!(1) #=> [1, 2, 3, [4, 5]]
*/ */

View 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

View 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
View file

@ -0,0 +1,10 @@
def fib n
if n < 3
1
else
fib(n-1) + fib(n-2)
end
end
fib(34)

View 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)
}
}

View 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)

View file

@ -0,0 +1,8 @@
i=0
while i<300000
i+=1
begin
raise
rescue
end
end

View 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
View 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
View 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)

View file

@ -0,0 +1 @@
30000000.times{|e|}

View file

@ -0,0 +1,4 @@
i = 0
while i<30000000 # benchmark loop 1
i+=1
end

View file

@ -0,0 +1,5 @@
i=0
while i<6000000 # benchmark loop 2
i+=1
end

View 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
View 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}"

View 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

View 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}"

View 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
View 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
View 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]}"

View 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
View 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
View 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
View 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
View file

@ -0,0 +1,10 @@
def m
yield
end
i=0
while i<30000000 # while loop 1
i+=1
m{
}
end

View file

@ -0,0 +1,8 @@
Const = 1
i = 0
while i<30000000 # while loop 1
i+= 1
j = Const
k = Const
end

View file

@ -0,0 +1,11 @@
i=0
while i<30000000 # benchmark loop 1
i+=1
begin
begin
ensure
end
ensure
end
end

View 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

View file

@ -0,0 +1,7 @@
i=0
while i<30000000 # while loop 1
i+=1
begin
rescue
end
end

View 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
View file

@ -0,0 +1,8 @@
a = 1
b = 2
i=0
while i<30000000 # while loop 1
i+=1
a, b = b, a
end

View 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

View 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

View 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

View 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
View 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

View 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
View 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
View 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

View file

@ -0,0 +1,8 @@
i = 0
def m a, b
end
while i<6000000 # benchmark loop 2
i+=1
m 100, 200
end

View 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

View 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
View 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
}

View 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);

View 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()

View 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)

View 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)

View 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")
}

View 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);
}

View 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)

View 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

View file

@ -0,0 +1,8 @@
(define (fact n)
(if (< n 2)
1
(* n (fact (- n 1)))))
(dotimes (i 10000)
(fact 100))

View 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);

View file

@ -0,0 +1,7 @@
def fib(n):
if n < 3:
return 1
else:
return fib(n-1) + fib(n-2)
fib(34)

View file

@ -0,0 +1,9 @@
def fib n
if n < 3
1
else
fib(n-1) + fib(n-2)
end
end
fib(34)

View file

@ -0,0 +1,7 @@
(define (fib n)
(if (< n 3)
1
(+ (fib (- n 1)) (fib (- n 2)))))
(fib 34)

View file

@ -0,0 +1,3 @@
for($i=0; $i<30000000; $i++){
}

View file

@ -0,0 +1,2 @@
for i in xrange(30000000):
pass

View file

@ -0,0 +1,4 @@
i=0
while i<30000000
i+=1
end

View file

@ -0,0 +1 @@
(dotimes (x 30000000))

View file

@ -0,0 +1 @@
30000000.times{}

View 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);

View 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)

View 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)

View 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
View 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
View 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
View 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
View 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

File diff suppressed because one or more lines are too long

461
blockinlining.c Normal file
View 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
View 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
View file

@ -56,10 +56,26 @@ rb_class_new(VALUE super)
return rb_class_boot(super); return rb_class_boot(super);
} }
struct clone_method_data {
st_table *tbl;
VALUE klass;
};
static int 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; 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); st_delete(RCLASS(clone)->iv_tbl, (st_data_t*)&id, 0);
} }
if (RCLASS(orig)->m_tbl) { 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_foreach(RCLASS(orig)->m_tbl, clone_method,
(st_data_t)RCLASS(clone)->m_tbl); (st_data_t)&data);
} }
return clone; return clone;
@ -111,6 +129,7 @@ rb_singleton_class_clone(VALUE obj)
if (!FL_TEST(klass, FL_SINGLETON)) if (!FL_TEST(klass, FL_SINGLETON))
return klass; return klass;
else { else {
struct clone_method_data data;
/* copy singleton(unnamed) class */ /* copy singleton(unnamed) class */
NEWOBJ(clone, struct RClass); NEWOBJ(clone, struct RClass);
OBJSETUP(clone, 0, RBASIC(klass)->flags); 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->iv_tbl = st_copy(RCLASS(klass)->iv_tbl);
} }
clone->m_tbl = st_init_numtable(); clone->m_tbl = st_init_numtable();
data.tbl = clone->m_tbl;
data.klass = (VALUE)clone;
st_foreach(RCLASS(klass)->m_tbl, clone_method, 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); rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);
FL_SET(clone, FL_SINGLETON); FL_SET(clone, FL_SINGLETON);
return (VALUE)clone; return (VALUE)clone;
@ -359,27 +380,27 @@ rb_include_module(VALUE klass, VALUE module)
OBJ_INFECT(klass, module); OBJ_INFECT(klass, module);
c = klass; c = klass;
while (module) { while (module) {
int superclass_seen = Qfalse; int superclass_seen = Qfalse;
if (RCLASS(klass)->m_tbl == RCLASS(module)->m_tbl) if (RCLASS(klass)->m_tbl == RCLASS(module)->m_tbl)
rb_raise(rb_eArgError, "cyclic include detected"); rb_raise(rb_eArgError, "cyclic include detected");
/* ignore if the module included already in superclasses */ /* ignore if the module included already in superclasses */
for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) { for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) {
switch (BUILTIN_TYPE(p)) { switch (BUILTIN_TYPE(p)) {
case T_ICLASS: case T_ICLASS:
if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) { if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) {
if (!superclass_seen) { if (!superclass_seen) {
c = p; /* move insertion point */ c = p; /* move insertion point */
} }
goto skip; goto skip;
} }
break; break;
case T_CLASS: case T_CLASS:
superclass_seen = Qtrue; superclass_seen = Qtrue;
break; break;
} }
} }
c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super); c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super);
changed = 1; changed = 1;
skip: skip:
module = RCLASS(module)->super; module = RCLASS(module)->super;
@ -492,6 +513,7 @@ static int
ins_methods_push(ID name, long type, VALUE ary, long visi) ins_methods_push(ID name, long type, VALUE ary, long visi)
{ {
if (type == -1) return ST_CONTINUE; if (type == -1) return ST_CONTINUE;
switch (visi) { switch (visi) {
case NOEX_PRIVATE: case NOEX_PRIVATE:
case NOEX_PROTECTED: case NOEX_PROTECTED:
@ -544,10 +566,17 @@ method_entry(ID key, NODE *body, st_table *list)
{ {
long type; long type;
if (key == ID_ALLOCATOR) return ST_CONTINUE; if (key == ID_ALLOCATOR) {
return ST_CONTINUE;
}
if (!st_lookup(list, key, 0)) { if (!st_lookup(list, key, 0)) {
if (!body->nd_body) type = -1; /* none */ if (body ==0 || !body->nd_body->nd_body) {
else type = VISI(body->nd_noex); type = -1; /* none */
}
else {
type = VISI(body->nd_body->nd_noex);
}
st_add_direct(list, key, type); st_add_direct(list, key, type);
} }
return ST_CONTINUE; return ST_CONTINUE;

403
common.mk
View file

@ -1,15 +1,11 @@
bin: $(PROGRAM) $(WPROGRAM) bin: $(PROGRAM) $(WPROGRAM)
lib: $(LIBRUBY) lib: $(LIBRUBY);
dll: $(LIBRUBY_SO) dll: $(LIBRUBY_SO);
RUBYOPT = RUBYOPT =
STATIC_RUBY = static-ruby
EXTCONF = extconf.rb EXTCONF = extconf.rb
RBCONFIG = ./.rbconfig.time RBCONFIG = ./.rbconfig.time
LIBRUBY_EXTS = ./.libruby-with-ext.time
RDOCOUT = $(EXTOUT)/rdoc
DMYEXT = dmyext.$(OBJEXT) DMYEXT = dmyext.$(OBJEXT)
MAINOBJ = main.$(OBJEXT) MAINOBJ = main.$(OBJEXT)
@ -28,6 +24,9 @@ OBJS = array.$(OBJEXT) \
error.$(OBJEXT) \ error.$(OBJEXT) \
euc_jp.$(OBJEXT) \ euc_jp.$(OBJEXT) \
eval.$(OBJEXT) \ eval.$(OBJEXT) \
eval_load.$(OBJEXT) \
eval_proc.$(OBJEXT) \
eval_thread.$(OBJEXT) \
file.$(OBJEXT) \ file.$(OBJEXT) \
gc.$(OBJEXT) \ gc.$(OBJEXT) \
hash.$(OBJEXT) \ hash.$(OBJEXT) \
@ -61,218 +60,94 @@ OBJS = array.$(OBJEXT) \
util.$(OBJEXT) \ util.$(OBJEXT) \
variable.$(OBJEXT) \ variable.$(OBJEXT) \
version.$(OBJEXT) \ version.$(OBJEXT) \
blockinlining.$(OBJEXT) \
compile.$(OBJEXT) \
debug.$(OBJEXT) \
iseq.$(OBJEXT) \
vm.$(OBJEXT) \
vm_dump.$(OBJEXT) \
yarvcore.$(OBJEXT) \
thread.$(OBJEXT) \
$(MISSING) $(MISSING)
SCRIPT_ARGS = --dest-dir="$(DESTDIR)" \ SCRIPT_ARGS = --dest-dir="$(DESTDIR)" \
--extout="$(EXTOUT)" \
--make="$(MAKE)" \ --make="$(MAKE)" \
--mflags="$(MFLAGS)" \ --mflags="$(MFLAGS)" \
--make-flags="$(MAKEFLAGS)" --make-flags="$(MAKEFLAGS)"
EXTMK_ARGS = $(SCRIPT_ARGS) --extension $(EXTS) --extstatic $(EXTSTATIC) -- EXTMK_ARGS = $(SCRIPT_ARGS) --extout="$(EXTOUT)" --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
all: $(MKFILES) $(PREP) $(RBCONFIG) $(LIBRUBY) all: $(MKFILES) $(PREP) $(RBCONFIG) $(LIBRUBY)
@$(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS) $(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS)
prog: $(PROGRAM) $(WPROGRAM) prog: $(PROGRAM) $(WPROGRAM)
miniruby$(EXEEXT): config.status $(LIBRUBY_A) $(MAINOBJ) $(MINIOBJS) $(OBJS) $(DMYEXT) miniruby$(EXEEXT): config.status $(LIBRUBY_A) $(MAINOBJ) $(MINIOBJS) $(OBJS) $(DMYEXT)
$(PROGRAM): $(LIBRUBY) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(SETUP) $(PREP) $(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): static-ruby: $(MAINOBJ) $(EXTOBJS) $(LIBRUBY_A)
@exit > $@
$(STATIC_RUBY)$(EXEEXT): $(MAINOBJ) $(DLDOBJS) $(EXTOBJS) $(LIBRUBY_A)
@$(RM) $@ @$(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) ruby.imp: $(LIBRUBY_A)
@$(NM) -Pgp $(OBJS) | awk 'BEGIN{print "#!"}; $$2~/^[BD]$$/{print $$1}' | sort -u -o $@ @$(NM) -Pgp $(LIBRUBY_A) | awk 'BEGIN{print "#!"}; $$2~/^[BD]$$/{print $$1}' | sort -u -o $@
install: install-nodoc $(RDOCTARGET) install: install-nodoc $(RDOCTARGET)
install-all: install-nodoc install-doc install-all: install-nodoc install-doc
install-nodoc: pre-install-nodoc do-install-nodoc post-install-nodoc install-nodoc: install-local install-ext
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-local: pre-install-local do-install-local post-install-local 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 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 do-install-local: $(RBCONFIG)
pre-install-arch:: pre-install-bin pre-install-ext-arch $(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --mantype="$(MANTYPE)"
do-install-arch: do-install-ext: $(RBCONFIG)
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=bin --install=ext-arch $(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS) install
post-install-arch:: post-install-bin post-install-ext-arch
install-comm: pre-install-comm do-install-comm post-install-comm install-bin: $(RBCONFIG)
pre-install-comm:: pre-install-lib pre-install-ext-comm pre-install-man $(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --install=bin
do-install-comm: install-lib: $(RBCONFIG)
$(MINIRUBY) $(srcdir)/instruby.rb $(INSTRUBY_ARGS) --install=lib --install=ext-comm --install=man $(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --install=lib
post-install-comm:: post-install-lib post-install-ext-comm post-install-man install-man: $(RBCONFIG)
$(MINIRUBY) $(srcdir)/instruby.rb $(SCRIPT_ARGS) --install=man --mantype="$(MANTYPE)"
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
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 what-where-local: no-install-local
no-install-local: pre-no-install-local dont-install-local post-no-install-local no-install-local: $(RBCONFIG)
pre-no-install-local:: pre-no-install-bin pre-no-install-lib pre-no-install-man $(MINIRUBY) $(srcdir)/instruby.rb -n $(SCRIPT_ARGS) --mantype="$(MANTYPE)"
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
what-where-ext: no-install-ext what-where-ext: no-install-ext
no-install-ext: pre-no-install-ext dont-install-ext post-no-install-ext no-install-ext: $(RBCONFIG)
pre-no-install-ext:: pre-no-install-ext-arch pre-no-install-ext-comm $(MINIRUBY) $(srcdir)/ext/extmk.rb -n $(EXTMK_ARGS) install
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
what-where-arch: no-install-arch install-doc: pre-install-doc do-install-doc post-install-doc
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
do-install-doc: $(PROGRAM) 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 @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 pre-install: pre-install-local pre-install-ext
no-install-doc: pre-no-install-doc dont-install-doc post-no-install-doc pre-install-local:: PHONY
pre-no-install-doc:: install-prereq pre-install-ext:: PHONY
dont-install-doc:: pre-install-doc:: PHONY
$(MINIRUBY) $(srcdir)/instruby.rb -n $(INSTRUBY_ARGS) --install=rdoc --rdoc-output="$(RDOCOUT)"
post-no-install-doc::
@$(NULLCMD)
install-prereq: post-install: post-install-local post-install-ext
@exit > $(INSTALLED_LIST) 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:: clean-local::
@$(RM) $(OBJS) $(MAINOBJ) $(WINMAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES) @$(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: clean-ext:
@-$(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS) clean @-$(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS) clean
@ -292,15 +167,15 @@ check: test test-all
test: miniruby$(EXEEXT) $(RBCONFIG) $(PROGRAM) PHONY test: miniruby$(EXEEXT) $(RBCONFIG) $(PROGRAM) PHONY
@$(MINIRUBY) $(srcdir)/rubytest.rb @$(MINIRUBY) $(srcdir)/rubytest.rb
test-all: test-all: miniruby$(EXEEXT) ruby
$(RUNRUBY) "$(srcdir)/test/runner.rb" --basedir="$(TESTSDIR)" --runner=$(TESTUI) $(TESTS) $(RUNRUBY) -C "$(srcdir)/test" runner.rb --runner=$(TESTUI) $(TESTS)
extconf: extconf:
$(MINIRUBY) -I$(srcdir)/lib -run -e mkdir -- -p "$(EXTCONFDIR)" $(MINIRUBY) -I$(srcdir)/lib -run -e mkdir -- -p "$(EXTCONFDIR)"
$(RUNRUBY) -C "$(EXTCONFDIR)" $(EXTCONF) $(EXTCONFARGS) $(RUNRUBY) -C "$(EXTCONFDIR)" $(EXTCONF) $(EXTCONFARGS)
$(RBCONFIG): $(srcdir)/mkconfig.rb config.status $(PREP) $(RBCONFIG): $(srcdir)/mkconfig.rb config.status $(PREP)
@$(MINIRUBY) $(srcdir)/mkconfig.rb -timestamp=$@ \ $(MINIRUBY) $(srcdir)/mkconfig.rb -timestamp=$@ \
-install_name=$(RUBY_INSTALL_NAME) \ -install_name=$(RUBY_INSTALL_NAME) \
-so_name=$(RUBY_SO_NAME) rbconfig.rb -so_name=$(RUBY_SO_NAME) rbconfig.rb
@ -336,8 +211,6 @@ nt.$(OBJEXT): {$(VPATH)}nt.c
x68.$(OBJEXT): {$(VPATH)}x68.c x68.$(OBJEXT): {$(VPATH)}x68.c
os2.$(OBJEXT): {$(VPATH)}os2.c os2.$(OBJEXT): {$(VPATH)}os2.c
dl_os2.$(OBJEXT): {$(VPATH)}dl_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" # when I use -I., there is confliction at "OpenFile"
# so, set . into environment varible "include" # 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 {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
error.$(OBJEXT): {$(VPATH)}error.c {$(VPATH)}ruby.h config.h \ error.$(OBJEXT): {$(VPATH)}error.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.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 \ euc_jp.$(OBJEXT): {$(VPATH)}euc_jp.c {$(VPATH)}regenc.h \
{$(VPATH)}oniguruma.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)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
{$(VPATH)}node.h {$(VPATH)}env.h {$(VPATH)}util.h \ {$(VPATH)}node.h {$(VPATH)}util.h \
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.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 \ file.$(OBJEXT): {$(VPATH)}file.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
{$(VPATH)}rubyio.h {$(VPATH)}rubysig.h {$(VPATH)}util.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 \ gc.$(OBJEXT): {$(VPATH)}gc.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}node.h \ {$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}node.h \
{$(VPATH)}env.h {$(VPATH)}re.h {$(VPATH)}regex.h {$(VPATH)}regint.h \ {$(VPATH)}re.h {$(VPATH)}regex.h {$(VPATH)}yarvcore.h
{$(VPATH)}oniguruma.h
hash.$(OBJEXT): {$(VPATH)}hash.c {$(VPATH)}ruby.h config.h \ hash.$(OBJEXT): {$(VPATH)}hash.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
{$(VPATH)}st.h {$(VPATH)}util.h {$(VPATH)}rubysig.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 \ math.$(OBJEXT): {$(VPATH)}math.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
numeric.$(OBJEXT): {$(VPATH)}numeric.c {$(VPATH)}ruby.h config.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 {$(VPATH)}missing.h
object.$(OBJEXT): {$(VPATH)}object.c {$(VPATH)}ruby.h config.h \ object.$(OBJEXT): {$(VPATH)}object.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.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 {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
parse.$(OBJEXT): {$(VPATH)}parse.c {$(VPATH)}ruby.h config.h \ parse.$(OBJEXT): {$(VPATH)}parse.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.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 {$(VPATH)}regex.h {$(VPATH)}util.h {$(VPATH)}lex.c
prec.$(OBJEXT): {$(VPATH)}prec.c {$(VPATH)}ruby.h config.h \ prec.$(OBJEXT): {$(VPATH)}prec.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.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 {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
re.$(OBJEXT): {$(VPATH)}re.c {$(VPATH)}ruby.h config.h \ re.$(OBJEXT): {$(VPATH)}re.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.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 \ regcomp.$(OBJEXT): {$(VPATH)}regcomp.c {$(VPATH)}oniguruma.h \
{$(VPATH)}regint.h {$(VPATH)}regparse.h {$(VPATH)}regenc.h config.h {$(VPATH)}regint.h {$(VPATH)}regparse.h {$(VPATH)}regenc.h config.h
regenc.$(OBJEXT): {$(VPATH)}regenc.c {$(VPATH)}regint.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 {$(VPATH)}dln.h {$(VPATH)}node.h {$(VPATH)}util.h
signal.$(OBJEXT): {$(VPATH)}signal.c {$(VPATH)}ruby.h config.h \ signal.$(OBJEXT): {$(VPATH)}signal.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.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 \ sjis.$(OBJEXT): {$(VPATH)}sjis.c {$(VPATH)}regenc.h \
{$(VPATH)}oniguruma.h config.h {$(VPATH)}oniguruma.h config.h
sprintf.$(OBJEXT): {$(VPATH)}sprintf.c {$(VPATH)}ruby.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 st.$(OBJEXT): {$(VPATH)}st.c config.h {$(VPATH)}st.h
string.$(OBJEXT): {$(VPATH)}string.c {$(VPATH)}ruby.h config.h \ string.$(OBJEXT): {$(VPATH)}string.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.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 \ struct.$(OBJEXT): {$(VPATH)}struct.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h
time.$(OBJEXT): {$(VPATH)}time.c {$(VPATH)}ruby.h config.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 {$(VPATH)}util.h
variable.$(OBJEXT): {$(VPATH)}variable.c {$(VPATH)}ruby.h config.h \ variable.$(OBJEXT): {$(VPATH)}variable.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.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 \ version.$(OBJEXT): {$(VPATH)}version.c {$(VPATH)}ruby.h config.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.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

4914
compile.c Normal file

File diff suppressed because it is too large Load diff

210
compile.h Normal file
View 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_

View file

@ -71,6 +71,7 @@ fi
if test "$program_prefix" = NONE; then if test "$program_prefix" = NONE; then
program_prefix= program_prefix=
fi fi
AC_CANONICAL_TARGET AC_CANONICAL_TARGET
target_os=`echo $target_os | sed 's/linux-gnu$/linux/;s/linux-gnu/linux-/'` target_os=`echo $target_os | sed 's/linux-gnu$/linux/;s/linux-gnu/linux-/'`
ac_install_sh='' # unusable for extension libraries. ac_install_sh='' # unusable for extension libraries.
@ -183,7 +184,7 @@ cygwin*|mingw*)
AC_TRY_LINK([#include <stdio.h>], AC_TRY_LINK([#include <stdio.h>],
[FILE* volatile f = stdin; return 0;], [FILE* volatile f = stdin; return 0;],
[rb_cv_msvcrt=`$OBJDUMP -p conftest$ac_exeext | [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;}'`], sed -n '/^[[ ]]*dll name: \(msvc.*\)\.dll$/{s//\1/p;q;}'`],
[rb_cv_msvcrt=msvcrt]) [rb_cv_msvcrt=msvcrt])
test "$rb_cv_msvcrt" = "" && 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, AC_ARG_ENABLE(pthread,
[ --enable-pthread use pthread library.], [ --enable-pthread use pthread library.],
[enable_pthread=$enableval], [enable_pthread=no]) [enable_pthread=$enableval], [enable_pthread=yes])
dnl Checks for libraries. dnl Checks for libraries.
case "$target_os" in case "$target_os" in
@ -831,6 +832,8 @@ if test x"$ac_cv_header_ucontext_h" = xyes; then
fi fi
fi fi
AC_CHECK_FUNCS(backtrace)
dnl default value for $KANJI dnl default value for $KANJI
DEFAULT_KCODE="KCODE_NONE" DEFAULT_KCODE="KCODE_NONE"
@ -1004,11 +1007,11 @@ if test "$with_dln_a_out" != yes; then
LDFLAGS='-brtl' LDFLAGS='-brtl'
XLDFLAGS='-bE:ruby.imp' XLDFLAGS='-bE:ruby.imp'
fi fi
: ${ARCHFILE="ruby.imp"} : ${ARCHFILE="ruby.imp"}
TRY_LINK='$(CC) $(LDFLAGS) -oconftest $(INCFLAGS) -I$(hdrdir) $(CPPFLAGS)' TRY_LINK='$(CC) $(LDFLAGS) -oconftest $(INCFLAGS) -I$(hdrdir) $(CPPFLAGS)'
TRY_LINK="$TRY_LINK"' $(CFLAGS) $(src) $(LIBPATH) $(LOCAL_LIBS) $(LIBS)' TRY_LINK="$TRY_LINK"' $(CFLAGS) $(src) $(LIBPATH) $(LOCAL_LIBS) $(LIBS)'
: ${LIBPATHENV=SHLIB_PATH} : ${LIBPATHENV=SHLIB_PATH}
rb_cv_dlopen=yes ;; rb_cv_dlopen=yes ;;
human*) : ${DLDFLAGS=''} human*) : ${DLDFLAGS=''}
: ${LDSHARED=''} : ${LDSHARED=''}
: ${LDFLAGS=''} : ${LDFLAGS=''}
@ -1354,7 +1357,7 @@ if test "$enable_shared" = 'yes'; then
fi fi
if test "$enable_rpath" = yes; then if test "$enable_rpath" = yes; then
if test "$GCC" = 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 else
LIBRUBYARG_SHARED='-R $(libdir) -L$(libdir) -L. '"$LIBRUBYARG_SHARED" LIBRUBYARG_SHARED='-R $(libdir) -L$(libdir) -L. '"$LIBRUBYARG_SHARED"
fi fi

71
debug.c Normal file
View 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
View 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

File diff suppressed because it is too large Load diff

57
error.c
View file

@ -11,8 +11,8 @@
**********************************************************************/ **********************************************************************/
#include "ruby.h" #include "ruby.h"
#include "env.h"
#include "st.h" #include "st.h"
#include "yarv.h"
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
@ -24,21 +24,23 @@
#endif #endif
extern const char ruby_version[], ruby_release_date[], ruby_platform[]; extern const char ruby_version[], ruby_release_date[], ruby_platform[];
int ruby_nerrs; int ruby_nerrs;
const char *rb_sourcefile();
int rb_sourceline();
static int static int
err_position(char *buf, long len) err_position(char *buf, long len)
{ {
ruby_set_current_source(); ruby_set_current_source();
if (!ruby_sourcefile) { if (!rb_sourcefile()) {
return 0; return 0;
} }
else if (ruby_sourceline == 0) { else if (rb_sourceline() == 0) {
return snprintf(buf, len, "%s: ", ruby_sourcefile); return snprintf(buf, len, "%s: ", rb_sourcefile());
} }
else { 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, ...) rb_compile_error(const char *fmt, ...)
{ {
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
err_print(fmt, args); err_print(fmt, args);
va_end(args); va_end(args);
@ -147,6 +148,8 @@ rb_warn_m(VALUE self, VALUE mesg)
return Qnil; return Qnil;
} }
void yarv_bug();
void void
rb_bug(const char *fmt, ...) rb_bug(const char *fmt, ...)
{ {
@ -157,6 +160,7 @@ rb_bug(const char *fmt, ...)
if (fwrite(buf, 1, len, out) == len || if (fwrite(buf, 1, len, out) == len ||
fwrite(buf, 1, len, (out = stdout)) == len) { fwrite(buf, 1, len, (out = stdout)) == len) {
yarv_bug();
fputs("[BUG] ", out); fputs("[BUG] ", out);
va_start(args, fmt); va_start(args, fmt);
vfprintf(out, fmt, args); vfprintf(out, fmt, args);
@ -164,6 +168,7 @@ rb_bug(const char *fmt, ...)
fprintf(out, "\nruby %s (%s) [%s]\n\n", fprintf(out, "\nruby %s (%s) [%s]\n\n",
ruby_version, ruby_release_date, ruby_platform); ruby_version, ruby_release_date, ruby_platform);
} }
abort(); abort();
} }
@ -190,8 +195,6 @@ static struct types {
{T_SYMBOL, "Symbol"}, /* :symbol */ {T_SYMBOL, "Symbol"}, /* :symbol */
{T_DATA, "Data"}, /* internal use: wrapped C pointers */ {T_DATA, "Data"}, /* internal use: wrapped C pointers */
{T_MATCH, "MatchData"}, /* data of $~ */ {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_NODE, "Node"}, /* internal use: syntax tree node */
{T_UNDEF, "undef"}, /* internal use: #undef; should not happen */ {T_UNDEF, "undef"}, /* internal use: #undef; should not happen */
{-1, 0} {-1, 0}
@ -1024,9 +1027,9 @@ rb_loaderror(const char *fmt, ...)
void void
rb_notimplement(void) rb_notimplement(void)
{ {
rb_raise(rb_eNotImpError, rb_raise(rb_eNotImpError,
"The %s() function is unimplemented on this machine", "The %s() function is unimplemented on this machine",
rb_id2name(ruby_frame->callee)); rb_id2name(rb_frame_callee()));
} }
void void
@ -1039,7 +1042,6 @@ rb_fatal(const char *fmt, ...)
vsnprintf(buf, BUFSIZ, fmt, args); vsnprintf(buf, BUFSIZ, fmt, args);
va_end(args); va_end(args);
ruby_in_eval = 0;
rb_exc_fatal(rb_exc_new2(rb_eFatal, buf)); rb_exc_fatal(rb_exc_new2(rb_eFatal, buf));
} }
@ -1471,22 +1473,21 @@ Init_syserr(void)
static void static void
err_append(const char *s) err_append(const char *s)
{ {
extern VALUE ruby_errinfo; yarv_thread_t *th = GET_THREAD();
if (th->parse_in_eval) {
if (ruby_in_eval) { if (NIL_P(th->errinfo)) {
if (NIL_P(ruby_errinfo)) { th->errinfo = rb_exc_new2(rb_eSyntaxError, s);
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);
}
} }
else { else {
rb_write_error(s); VALUE str = rb_obj_as_string(GET_THREAD()->errinfo);
rb_write_error("\n");
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");
}
} }

12039
eval.c

File diff suppressed because it is too large Load diff

250
eval_error.h Normal file
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

117
eval_safe.h Normal file
View 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
View 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

View file

@ -118,12 +118,12 @@ module DL
f = import_function(symname, ctype, argtype, opt[:call_type]) f = import_function(symname, ctype, argtype, opt[:call_type])
name = symname.gsub(/@.+/,'') name = symname.gsub(/@.+/,'')
@func_map[name] = f @func_map[name] = f
define_method(name){|*args,&block| f.call(*args,&block)} # define_method(name){|*args,&block| f.call(*args,&block)}
#module_eval(<<-EOS) module_eval(<<-EOS)
# def #{name}(*args, &block) def #{name}(*args, &block)
# @func_map['#{name}'].call(*args,&block) @func_map['#{name}'].call(*args,&block)
# end end
#EOS EOS
module_function(name) module_function(name)
f f
end end
@ -142,12 +142,12 @@ module DL
raise(RuntimeError, "unknown callback type: #{h[:callback_type]}") raise(RuntimeError, "unknown callback type: #{h[:callback_type]}")
end end
@func_map[name] = f @func_map[name] = f
define_method(name){|*args,&block| f.call(*args,&block)} #define_method(name){|*args,&block| f.call(*args,&block)}
#module_eval(<<-EOS) module_eval(<<-EOS)
# def #{name}(*args,&block) def #{name}(*args,&block)
# @func_map['#{name}'].call(*args,&block) @func_map['#{name}'].call(*args,&block)
# end end
#EOS EOS
module_function(name) module_function(name)
f f
end end

View file

@ -1,4 +1,3 @@
Makefile Makefile
mkmf.log mkmf.log
*.def *.def
extconf.h

View file

@ -512,7 +512,6 @@ Init_etc(void)
rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0); rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0);
rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0); rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0);
rb_global_variable(&sPasswd);
sPasswd = rb_struct_define("Passwd", sPasswd = rb_struct_define("Passwd",
"name", "passwd", "uid", "gid", "name", "passwd", "uid", "gid",
#ifdef HAVE_ST_PW_GECOS #ifdef HAVE_ST_PW_GECOS
@ -539,12 +538,15 @@ Init_etc(void)
#endif #endif
NULL); NULL);
rb_register_mark_object(sPasswd);
#ifdef HAVE_GETGRENT #ifdef HAVE_GETGRENT
rb_global_variable(&sGroup);
sGroup = rb_struct_define("Group", "name", sGroup = rb_struct_define("Group", "name",
#ifdef HAVE_ST_GR_PASSWD #ifdef HAVE_ST_GR_PASSWD
"passwd", "passwd",
#endif #endif
"gid", "mem", NULL); "gid", "mem", NULL);
rb_register_mark_object(sGroup);
#endif #endif
} }

View file

@ -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); error = rb_class_new_instance(3, args, error);
if (!rb_block_given_p()) rb_exc_raise(error); if (!rb_block_given_p()) rb_exc_raise(error);
ruby_errinfo = error; rb_set_errinfo(error);
return rb_yield(failed); return rb_yield(failed);
} }

View file

@ -53,7 +53,6 @@ static char **readline_attempted_completion_function(const char *text,
static int static int
readline_event() readline_event()
{ {
CHECK_INTS;
rb_thread_schedule(); rb_thread_schedule();
return 0; return 0;
} }

View file

@ -4,6 +4,9 @@ require 'mkmf'
require 'rbconfig' require 'rbconfig'
def main def main
Logging.message "YARV doesn't support Ripper"
return
unless find_executable('bison') unless find_executable('bison')
unless File.exist?('ripper.c') or File.exist?("#{$srcdir}/ripper.c") unless File.exist?('ripper.c') or File.exist?("#{$srcdir}/ripper.c")
Logging.message 'missing bison; abort' Logging.message 'missing bison; abort'

View file

@ -1801,7 +1801,7 @@ fole_s_connect(int argc, VALUE *argv, VALUE self)
ole_initialize(); ole_initialize();
rb_scan_args(argc, argv, "1*", &svr_name, &others); 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", rb_raise(rb_eSecurityError, "Insecure Object Connection - %s",
StringValuePtr(svr_name)); StringValuePtr(svr_name));
} }
@ -2182,12 +2182,12 @@ fole_initialize(int argc, VALUE *argv, VALUE self)
rb_call_super(0, 0); rb_call_super(0, 0);
rb_scan_args(argc, argv, "11*", &svr_name, &host, &others); 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", rb_raise(rb_eSecurityError, "Insecure Object Creation - %s",
StringValuePtr(svr_name)); StringValuePtr(svr_name));
} }
if (!NIL_P(host)) { 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", rb_raise(rb_eSecurityError, "Insecure Object Creation - %s",
StringValuePtr(svr_name)); StringValuePtr(svr_name));
} }
@ -6645,7 +6645,7 @@ fev_initialize(int argc, VALUE *argv, VALUE self)
} }
if(TYPE(itf) != T_NIL) { 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", rb_raise(rb_eSecurityError, "Insecure Event Creation - %s",
StringValuePtr(itf)); StringValuePtr(itf));
} }
@ -6854,8 +6854,8 @@ folevariant_value(VALUE self)
void void
Init_win32ole() Init_win32ole()
{ {
rb_global_variable(&ary_ole_event);
ary_ole_event = rb_ary_new(); ary_ole_event = rb_ary_new();
rb_register_mark_object(ary_ole_event);
id_events = rb_intern("events"); id_events = rb_intern("events");
com_vtbl.QueryInterface = QueryInterface; com_vtbl.QueryInterface = QueryInterface;
@ -6865,8 +6865,8 @@ Init_win32ole()
com_vtbl.GetTypeInfo = GetTypeInfo; com_vtbl.GetTypeInfo = GetTypeInfo;
com_vtbl.GetIDsOfNames = GetIDsOfNames; com_vtbl.GetIDsOfNames = GetIDsOfNames;
com_vtbl.Invoke = Invoke; 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()); 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); cWIN32OLE = rb_define_class("WIN32OLE", rb_cObject);

View file

@ -1759,7 +1759,7 @@ gzfile_read_raw_rescue(VALUE arg)
{ {
struct gzfile *gz = (struct gzfile*)arg; struct gzfile *gz = (struct gzfile*)arg;
VALUE str = Qnil; 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)); str = rb_funcall(gz->io, id_read, 1, INT2FIX(GZFILE_READ_SIZE));
if (!NIL_P(str)) { if (!NIL_P(str)) {
Check_Type(str, T_STRING); Check_Type(str, T_STRING);

547
gc.c
View file

@ -16,8 +16,8 @@
#include "rubysig.h" #include "rubysig.h"
#include "st.h" #include "st.h"
#include "node.h" #include "node.h"
#include "env.h"
#include "re.h" #include "re.h"
#include "yarvcore.h"
#include <stdio.h> #include <stdio.h>
#include <setjmp.h> #include <setjmp.h>
#include <sys/types.h> #include <sys/types.h>
@ -51,7 +51,9 @@ int rb_io_fptr_finalize(struct OpenFile*);
# ifdef HAVE_ALLOCA_H # ifdef HAVE_ALLOCA_H
# include <alloca.h> # include <alloca.h>
# else # else
# ifndef _AIX # ifdef _AIX
#pragma alloca
# else
# ifndef alloca /* predefined by HP cc +Olibcalls */ # ifndef alloca /* predefined by HP cc +Olibcalls */
void *alloca (); void *alloca ();
# endif # endif
@ -69,15 +71,115 @@ void *alloca ();
static unsigned long malloc_increase = 0; static unsigned long malloc_increase = 0;
static unsigned long malloc_limit = GC_MALLOC_LIMIT; static unsigned long malloc_limit = GC_MALLOC_LIMIT;
static void run_final(VALUE obj);
static VALUE nomem_error; 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); static int garbage_collect(void);
void
rb_global_variable(VALUE *var)
{
rb_gc_register_address(var);
}
void void
rb_memerror(void) rb_memerror(void)
{ {
static int recurse = 0; static int recurse = 0;
if (!nomem_error || (recurse > 0 && rb_safe_level() < 4)) { if (!nomem_error || (recurse > 0 && rb_safe_level() < 4)) {
fprintf(stderr, "[FATAL] failed to allocate memory\n"); fprintf(stderr, "[FATAL] failed to allocate memory\n");
exit(1); exit(1);
@ -86,8 +188,6 @@ rb_memerror(void)
rb_exc_raise(nomem_error); rb_exc_raise(nomem_error);
} }
int gc_stress = 0;
/* /*
* call-seq: * call-seq:
* GC.stress => true or false * GC.stress => true or false
@ -211,11 +311,6 @@ ruby_xfree(void *x)
RUBY_CRITICAL(free(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: * call-seq:
@ -278,6 +373,13 @@ rb_gc_register_address(VALUE *addr)
global_List = tmp; global_List = tmp;
} }
void
rb_register_mark_object(VALUE obj)
{
VALUE ary = GET_THREAD()->vm->mark_object_ary;
rb_ary_push(ary, obj);
}
void void
rb_gc_unregister_address(VALUE *addr) 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 static void
add_heap(void) add_heap(void)
{ {
@ -396,13 +434,13 @@ add_heap(void)
heap_slots = HEAP_MIN_SLOTS; heap_slots = HEAP_MIN_SLOTS;
continue; continue;
} }
heaps[heaps_used].membase = p; heaps[heaps_used].membase = p;
if ((VALUE)p % sizeof(RVALUE) == 0) if ((VALUE)p % sizeof(RVALUE) == 0)
heap_slots += 1; heap_slots += 1;
else else
p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE))); p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
heaps[heaps_used].slot = p; heaps[heaps_used].slot = p;
heaps[heaps_used].limit = heap_slots; heaps[heaps_used].limit = heap_slots;
break; break;
} }
pend = p + heap_slots; pend = p + heap_slots;
@ -410,7 +448,6 @@ add_heap(void)
if (himem < pend) himem = pend; if (himem < pend) himem = pend;
heaps_used++; heaps_used++;
heap_slots *= 1.8; heap_slots *= 1.8;
if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS;
while (p < pend) { while (p < pend) {
p->as.free.flags = 0; p->as.free.flags = 0;
@ -421,16 +458,20 @@ add_heap(void)
} }
#define RANY(o) ((RVALUE*)(o)) #define RANY(o) ((RVALUE*)(o))
VALUE static VALUE
rb_newobj(void) rb_newobj_from_heap(void)
{ {
VALUE obj; VALUE obj;
if ((gc_stress || !freelist) && !garbage_collect()) if (gc_stress || !freelist) {
rb_memerror(); if(!garbage_collect()) {
rb_memerror();
}
}
obj = (VALUE)freelist; obj = (VALUE)freelist;
freelist = freelist->as.free.next; freelist = freelist->as.free.next;
MEMZERO((void*)obj, RVALUE, 1); MEMZERO((void*)obj, RVALUE, 1);
#ifdef GC_DEBUG #ifdef GC_DEBUG
RANY(obj)->file = ruby_sourcefile; RANY(obj)->file = ruby_sourcefile;
@ -439,6 +480,52 @@ rb_newobj(void)
return obj; 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 VALUE
rb_data_object_alloc(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree) 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; return (VALUE)data;
} }
extern st_table *rb_class_tbl; NOINLINE(void yarv_set_stack_end(VALUE **stack_end_p));
VALUE *rb_gc_stack_start = 0;
#ifdef __ia64
VALUE *rb_gc_register_stack_start = 0;
#endif
#define YARV_SET_STACK_END yarv_set_stack_end(&th->machine_stack_end)
#ifdef DJGPP #define STACK_START (th->machine_stack_start)
/* set stack size (http://www.delorie.com/djgpp/v2faq/faq15_9.html) */ #define STACK_END (th->machine_stack_end)
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)
#if defined(sparc) || defined(__sparc__) #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 #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 #elif STACK_GROW_DIRECTION > 0
# define STACK_LENGTH (STACK_END - rb_gc_stack_start + 1) # define STACK_LENGTH (STACK_END - STACK_START + 1)
#else #else
# define STACK_LENGTH ((STACK_END < rb_gc_stack_start) ? rb_gc_stack_start - STACK_END\ # define STACK_LENGTH ((STACK_END < STACK_START) ? STACK_START - STACK_END\
: STACK_END - rb_gc_stack_start + 1) : STACK_END - STACK_START + 1)
#endif #endif
#if STACK_GROW_DIRECTION > 0 #if STACK_GROW_DIRECTION > 0
# define STACK_UPPER(x, a, b) a # define STACK_UPPER(x, a, b) a
@ -506,10 +564,11 @@ static int grow_direction;
static int static int
stack_grow_direction(VALUE *addr) 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; if (STACK_END > addr) return grow_direction = 1;
return grow_direction = -1; return grow_direction = -1;
} }
# define stack_growup_p(x) ((grow_direction ? grow_direction : stack_grow_direction(x)) > 0) # 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) # 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 GC_WATER_MARK 512
#define CHECK_STACK(ret) do {\ #define CHECK_STACK(ret) do {\
SET_STACK_END;\ YARV_SET_STACK_END;\
(ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\ (ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\
} while (0) } while (0)
int int
ruby_stack_length(VALUE **p) ruby_stack_length(VALUE **p)
{ {
SET_STACK_END; yarv_thread_t *th = GET_THREAD();
if (p) *p = STACK_UPPER(STACK_END, rb_gc_stack_start, STACK_END); YARV_SET_STACK_END;
return STACK_LENGTH; if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END);
return STACK_LENGTH;
} }
int int
ruby_stack_check(void) ruby_stack_check(void)
{ {
int ret; int ret;
yarv_thread_t *th = GET_THREAD();
CHECK_STACK(ret); CHECK_STACK(ret);
return 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 static void
init_mark_stack(void) init_mark_stack(void)
{ {
@ -624,7 +679,7 @@ gc_mark_rest(void)
MEMCPY(tmp_arry, mark_stack, VALUE, MARK_STACK_MAX); MEMCPY(tmp_arry, mark_stack, VALUE, MARK_STACK_MAX);
init_mark_stack(); init_mark_stack();
while (p != tmp_arry){ while(p != tmp_arry){
p--; p--;
gc_mark_children(*p, 0); gc_mark_children(*p, 0);
} }
@ -644,7 +699,7 @@ is_pointer_to_heap(void *ptr)
for (i=0; i < heaps_used; i++) { for (i=0; i < heaps_used; i++) {
heap_org = heaps[i].slot; heap_org = heaps[i].slot;
if (heap_org <= p && p < heap_org + heaps[i].limit) if (heap_org <= p && p < heap_org + heaps[i].limit)
return Qtrue; return Qtrue;
} }
return Qfalse; return Qfalse;
} }
@ -785,6 +840,7 @@ gc_mark_children(VALUE ptr, int lev)
case NODE_IF: /* 1,2,3 */ case NODE_IF: /* 1,2,3 */
case NODE_FOR: case NODE_FOR:
case NODE_ITER: case NODE_ITER:
case NODE_CREF:
case NODE_WHEN: case NODE_WHEN:
case NODE_MASGN: case NODE_MASGN:
case NODE_RESCUE: case NODE_RESCUE:
@ -795,17 +851,16 @@ gc_mark_children(VALUE ptr, int lev)
gc_mark((VALUE)obj->as.node.u2.node, lev); gc_mark((VALUE)obj->as.node.u2.node, lev);
/* fall through */ /* fall through */
case NODE_BLOCK: /* 1,3 */ case NODE_BLOCK: /* 1,3 */
case NODE_OPTBLOCK:
case NODE_ARRAY: case NODE_ARRAY:
case NODE_DSTR: case NODE_DSTR:
case NODE_DXSTR: case NODE_DXSTR:
case NODE_DREGX: case NODE_DREGX:
case NODE_DREGX_ONCE: case NODE_DREGX_ONCE:
case NODE_FBODY:
case NODE_ENSURE: case NODE_ENSURE:
case NODE_CALL: case NODE_CALL:
case NODE_DEFS: case NODE_DEFS:
case NODE_OP_ASGN1: case NODE_OP_ASGN1:
case NODE_CREF:
gc_mark((VALUE)obj->as.node.u1.node, lev); gc_mark((VALUE)obj->as.node.u1.node, lev);
/* fall through */ /* fall through */
case NODE_SUPER: /* 3 */ case NODE_SUPER: /* 3 */
@ -814,7 +869,8 @@ gc_mark_children(VALUE ptr, int lev)
ptr = (VALUE)obj->as.node.u3.node; ptr = (VALUE)obj->as.node.u3.node;
goto again; goto again;
case NODE_WHILE: /* 1,2 */ case NODE_METHOD: /* 1,2 */
case NODE_WHILE:
case NODE_UNTIL: case NODE_UNTIL:
case NODE_AND: case NODE_AND:
case NODE_OR: case NODE_OR:
@ -831,10 +887,9 @@ gc_mark_children(VALUE ptr, int lev)
case NODE_MODULE: case NODE_MODULE:
case NODE_ALIAS: case NODE_ALIAS:
case NODE_VALIAS: case NODE_VALIAS:
case NODE_LAMBDA:
gc_mark((VALUE)obj->as.node.u1.node, lev); gc_mark((VALUE)obj->as.node.u1.node, lev);
/* fall through */ /* fall through */
case NODE_METHOD: /* 2 */ case NODE_FBODY: /* 2 */
case NODE_NOT: case NODE_NOT:
case NODE_GASGN: case NODE_GASGN:
case NODE_LASGN: case NODE_LASGN:
@ -932,7 +987,6 @@ gc_mark_children(VALUE ptr, int lev)
else { else {
long i, len = RARRAY_LEN(obj); long i, len = RARRAY_LEN(obj);
VALUE *ptr = RARRAY_PTR(obj); VALUE *ptr = RARRAY_PTR(obj);
for (i=0; i < len; i++) { for (i=0; i < len; i++) {
gc_mark(*ptr++, lev); gc_mark(*ptr++, lev);
} }
@ -968,29 +1022,13 @@ gc_mark_children(VALUE ptr, int lev)
break; break;
case T_MATCH: case T_MATCH:
gc_mark(obj->as.match.regexp, lev); gc_mark(obj->as.match.regexp, lev);
if (obj->as.match.str) { if (obj->as.match.str) {
ptr = obj->as.match.str; ptr = obj->as.match.str;
goto again; goto again;
} }
break; 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: case T_STRUCT:
{ {
long len = RSTRUCT_LEN(obj); long len = RSTRUCT_LEN(obj);
@ -1002,6 +1040,15 @@ gc_mark_children(VALUE ptr, int lev)
} }
break; break;
case T_VALUES:
{
rb_gc_mark(RVALUES(obj)->v1);
rb_gc_mark(RVALUES(obj)->v2);
ptr = RVALUES(obj)->v3;
goto again;
}
break;
default: default:
rb_bug("rb_gc_mark(): unknown data type 0x%lx(%p) %s", rb_bug("rb_gc_mark(): unknown data type 0x%lx(%p) %s",
obj->as.basic.flags & T_MASK, obj, obj->as.basic.flags & T_MASK, obj,
@ -1054,14 +1101,6 @@ gc_sweep(void)
int freed = 0; int freed = 0;
int i; int i;
unsigned long live = 0; 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); mark_source_filename(ruby_sourcefile);
if (source_filenames) { if (source_filenames) {
@ -1104,12 +1143,12 @@ gc_sweep(void)
} }
p++; p++;
} }
if (n == heaps[i].limit && freed > free_min) { if (n == heaps[i].limit && freed > FREE_MIN) {
RVALUE *pp; RVALUE *pp;
heaps[i].limit = 0; heaps[i].limit = 0;
for (pp = final_list; pp != final; pp = pp->as.free.next) { 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 */ 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; if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
} }
malloc_increase = 0; malloc_increase = 0;
if (freed < free_min) { if (freed < FREE_MIN) {
add_heap(); add_heap();
} }
during_gc = 0; during_gc = 0;
@ -1218,9 +1257,10 @@ obj_free(VALUE obj)
break; break;
case T_FLOAT: case T_FLOAT:
case T_VARMAP:
case T_BLOCK: case T_BLOCK:
break; break;
case T_VALUES:
break;
case T_BIGNUM: case T_BIGNUM:
if (RANY(obj)->as.bignum.digits) { if (RANY(obj)->as.bignum.digits) {
@ -1240,17 +1280,6 @@ obj_free(VALUE obj)
} }
return; /* no need to free iv_tbl */ 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: case T_STRUCT:
if (RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK == 0 && if (RBASIC(obj)->flags & RSTRUCT_EMBED_LEN_MASK == 0 &&
RANY(obj)->as.rstruct.as.heap.ptr) { 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__ #ifdef __GNUC__
#if defined(__human68k__) || defined(DJGPP) #if defined(__human68k__) || defined(DJGPP)
#if defined(__human68k__) #if defined(__human68k__)
@ -1308,20 +1331,21 @@ int rb_setjmp (rb_jmp_buf);
#endif /* __human68k__ or DJGPP */ #endif /* __human68k__ or DJGPP */
#endif /* __GNUC__ */ #endif /* __GNUC__ */
#define GC_NOTIFY 0
static int static int
garbage_collect(void) garbage_collect(void)
{ {
struct gc_list *list; struct gc_list *list;
struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */
jmp_buf save_regs_gc_mark; jmp_buf save_regs_gc_mark;
SET_STACK_END; yarv_thread_t *th = GET_THREAD();
if (!heaps) return Qfalse; if (GC_NOTIFY) printf("start garbage_collect()\n");
#ifdef HAVE_NATIVETHREAD
if (!is_ruby_native_thread()) { if (!heaps) {
rb_bug("cross-thread violation on rb_gc()"); return Qfalse;
} }
#endif
if (dont_gc || during_gc) { if (dont_gc || during_gc) {
if (!freelist) { if (!freelist) {
add_heap(); add_heap();
@ -1330,23 +1354,13 @@ garbage_collect(void)
} }
during_gc++; during_gc++;
YARV_SET_STACK_END;
init_mark_stack(); 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) { if (finalizer_table) {
mark_tbl(finalizer_table, 0); 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) */ /* This assumes that all registers are saved into the jmp_buf (and stack) */
setjmp(save_regs_gc_mark); setjmp(save_regs_gc_mark);
mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *)); mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
#if STACK_GROW_DIRECTION < 0 #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 #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 #else
if ((VALUE*)STACK_END < rb_gc_stack_start) if (th->machine_stack_end < th->machin_stack_start)
rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start); rb_gc_mark_locations(th->machine_stack_end, th->machin_stack_start);
else 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 #endif
#ifdef __ia64 #ifdef __ia64__
/* mark backing store (flushed register stack) */ /* mark backing store (flushed register window on the stack) */
/* the basic idea from guile GC code */ /* 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 #endif
#if defined(__human68k__) || defined(__mc68000__) #if defined(__human68k__) || defined(__mc68000__)
rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2), rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2),
(VALUE*)((char*)rb_gc_stack_start + 2)); (VALUE*)((char*)STACK_START + 2));
#endif #endif
rb_gc_mark_threads(); rb_gc_mark_threads();
rb_gc_mark_symbols(); rb_gc_mark_symbols();
@ -1393,23 +1428,38 @@ garbage_collect(void)
rb_gc_mark_parser(); rb_gc_mark_parser();
/* gc_mark objects whose marking are not completed*/ /* gc_mark objects whose marking are not completed*/
do { while (!MARK_STACK_EMPTY){
while (!MARK_STACK_EMPTY) { if (mark_stack_overflow){
if (mark_stack_overflow){ gc_mark_all();
gc_mark_all();
}
else {
gc_mark_rest();
}
} }
rb_gc_abort_threads(); else {
} while (!MARK_STACK_EMPTY); gc_mark_rest();
}
}
gc_sweep(); gc_sweep();
if (GC_NOTIFY) printf("end garbage_collect()\n");
return Qtrue; 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 void
rb_gc(void) rb_gc(void)
{ {
@ -1604,8 +1654,6 @@ os_live_obj(void)
if (p->as.basic.flags) { if (p->as.basic.flags) {
switch (TYPE(p)) { switch (TYPE(p)) {
case T_ICLASS: case T_ICLASS:
case T_VARMAP:
case T_SCOPE:
case T_NODE: case T_NODE:
continue; continue;
case T_CLASS: case T_CLASS:
@ -1636,8 +1684,6 @@ os_obj_of(VALUE of)
if (p->as.basic.flags) { if (p->as.basic.flags) {
switch (TYPE(p)) { switch (TYPE(p)) {
case T_ICLASS: case T_ICLASS:
case T_VARMAP:
case T_SCOPE:
case T_NODE: case T_NODE:
continue; continue;
case T_CLASS: case T_CLASS:
@ -1796,7 +1842,7 @@ define_final(int argc, VALUE *argv, VALUE os)
need_call_final = 1; need_call_final = 1;
FL_SET(obj, FL_FINALIZE); 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) { if (!finalizer_table) {
finalizer_table = st_init_numtable(); finalizer_table = st_init_numtable();
@ -1840,7 +1886,7 @@ run_final(VALUE obj)
objid = rb_obj_id(obj); /* make obj into id */ objid = rb_obj_id(obj); /* make obj into id */
rb_thread_critical = Qtrue; rb_thread_critical = Qtrue;
args[1] = 0; args[1] = 0;
args[2] = (VALUE)ruby_safe_level; args[2] = (VALUE)rb_safe_level();
for (i=0; i<RARRAY_LEN(finalizers); i++) { for (i=0; i<RARRAY_LEN(finalizers); i++) {
args[0] = RARRAY_PTR(finalizers)[i]; args[0] = RARRAY_PTR(finalizers)[i];
if (!args[1]) args[1] = rb_ary_new3(1, objid); 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)) { if ((ptr % sizeof(RVALUE)) == (4 << 2)) {
ID symid = ptr / sizeof(RVALUE); ID symid = ptr / sizeof(RVALUE);
if (rb_id2name(symid) == 0) if (rb_id2name(symid) == 0)
rb_raise(rb_eRangeError, "%p is not symbol id value", p0); rb_raise(rb_eRangeError, "%p is not symbol id value", p0);
return ID2SYM(symid); return ID2SYM(symid);
} }
if (!is_pointer_to_heap((void *)ptr)|| BUILTIN_TYPE(ptr) >= T_BLOCK) { if (!is_pointer_to_heap((void *)ptr)|| BUILTIN_TYPE(ptr) >= T_BLOCK) {
@ -2011,7 +2057,7 @@ rb_obj_id(VALUE obj)
* nil 00000000000000000000000000000100 * nil 00000000000000000000000000000100
* undef 00000000000000000000000000000110 * undef 00000000000000000000000000000110
* symbol ssssssssssssssssssssssss00001110 * symbol ssssssssssssssssssssssss00001110
* object oooooooooooooooooooooooooooooo00 = 0 (mod sizeof(RVALUE)) * object oooooooooooooooooooooooooooooo00 = 0 (mod sizeof(RVALUE)
* fixnum fffffffffffffffffffffffffffffff1 * fixnum fffffffffffffffffffffffffffffff1
* *
* object_id space * object_id space
@ -2020,7 +2066,7 @@ rb_obj_id(VALUE obj)
* true 00000000000000000000000000000010 * true 00000000000000000000000000000010
* nil 00000000000000000000000000000100 * nil 00000000000000000000000000000100
* undef 00000000000000000000000000000110 * 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 * object oooooooooooooooooooooooooooooo0 o...o % A = 0
* fixnum fffffffffffffffffffffffffffffff1 bignum if required * fixnum fffffffffffffffffffffffffffffff1 bignum if required
* *
@ -2031,6 +2077,9 @@ rb_obj_id(VALUE obj)
* 24 if 32-bit, double is 8-byte aligned * 24 if 32-bit, double is 8-byte aligned
* 40 if 64-bit * 40 if 64-bit
*/ */
if (TYPE(obj) == T_SYMBOL) {
return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG;
}
if (SPECIAL_CONST_P(obj)) { if (SPECIAL_CONST_P(obj)) {
return LONG2NUM((long)obj); return LONG2NUM((long)obj);
} }
@ -2079,7 +2128,7 @@ Init_GC(void)
rb_global_variable(&nomem_error); rb_global_variable(&nomem_error);
nomem_error = rb_exc_new2(rb_eNoMemError, "failed to allocate memory"); 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, "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