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:
parent
3e7566d8fb
commit
a3e1b1ce7e
233 changed files with 46004 additions and 13653 deletions
|
@ -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
69
array.c
|
@ -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]]
|
||||||
*/
|
*/
|
||||||
|
|
15
benchmark/bm_app_answer.rb
Normal file
15
benchmark/bm_app_answer.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
def ack(m, n)
|
||||||
|
if m == 0 then
|
||||||
|
n + 1
|
||||||
|
elsif n == 0 then
|
||||||
|
ack(m - 1, 1)
|
||||||
|
else
|
||||||
|
ack(m - 1, ack(m, n - 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def the_answer_to_life_the_universe_and_everything
|
||||||
|
(ack(3,7).to_s.split(//).inject(0){|s,x| s+x.to_i}.to_s + "2" ).to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
answer = the_answer_to_life_the_universe_and_everything
|
11
benchmark/bm_app_factorial.rb
Normal file
11
benchmark/bm_app_factorial.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
def fact(n)
|
||||||
|
if(n > 1)
|
||||||
|
n * fact(n-1)
|
||||||
|
else
|
||||||
|
1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
8.times{
|
||||||
|
fact(5000)
|
||||||
|
}
|
10
benchmark/bm_app_fib.rb
Normal file
10
benchmark/bm_app_fib.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
def fib n
|
||||||
|
if n < 3
|
||||||
|
1
|
||||||
|
else
|
||||||
|
fib(n-1) + fib(n-2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
fib(34)
|
||||||
|
|
23
benchmark/bm_app_mandelbrot.rb
Normal file
23
benchmark/bm_app_mandelbrot.rb
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
require 'complex'
|
||||||
|
|
||||||
|
def mandelbrot? z
|
||||||
|
i = 0
|
||||||
|
while i<100
|
||||||
|
i+=1
|
||||||
|
z = z * z
|
||||||
|
return false if z.abs > 2
|
||||||
|
end
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
ary = []
|
||||||
|
|
||||||
|
(0..100).each{|dx|
|
||||||
|
(0..100).each{|dy|
|
||||||
|
x = dx / 50.0
|
||||||
|
y = dy / 50.0
|
||||||
|
c = Complex(x, y)
|
||||||
|
ary << c if mandelbrot?(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
259
benchmark/bm_app_pentomino.rb
Normal file
259
benchmark/bm_app_pentomino.rb
Normal file
|
@ -0,0 +1,259 @@
|
||||||
|
#!/usr/local/bin/ruby
|
||||||
|
# This program is contributed by Shin Nishiyama
|
||||||
|
|
||||||
|
|
||||||
|
# modified by K.Sasada
|
||||||
|
|
||||||
|
NP = 5
|
||||||
|
ROW = 8 + NP
|
||||||
|
COL = 8
|
||||||
|
|
||||||
|
$p = []
|
||||||
|
$b = []
|
||||||
|
$no = 0
|
||||||
|
|
||||||
|
def piece(n, a, nb)
|
||||||
|
nb.each{|x|
|
||||||
|
a[n] = x
|
||||||
|
if n == NP-1
|
||||||
|
$p << [a.sort]
|
||||||
|
else
|
||||||
|
nbc=nb.clone
|
||||||
|
[-ROW, -1, 1, ROW].each{|d|
|
||||||
|
if x+d > 0 and not a.include?(x+d) and not nbc.include?(x+d)
|
||||||
|
nbc << x+d
|
||||||
|
end
|
||||||
|
}
|
||||||
|
nbc.delete x
|
||||||
|
piece(n+1,a[0..n],nbc)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def kikaku(a)
|
||||||
|
a.collect {|x| x - a[0]}
|
||||||
|
end
|
||||||
|
def ud(a)
|
||||||
|
kikaku(a.collect {|x| ((x+NP)%ROW)-ROW*((x+NP)/ROW) }.sort)
|
||||||
|
end
|
||||||
|
def rl(a)
|
||||||
|
kikaku(a.collect {|x| ROW*((x+NP)/ROW)+ROW-((x+NP)%ROW)}.sort)
|
||||||
|
end
|
||||||
|
def xy(a)
|
||||||
|
kikaku(a.collect {|x| ROW*((x+NP)%ROW) + (x+NP)/ROW }.sort)
|
||||||
|
end
|
||||||
|
|
||||||
|
def mkpieces
|
||||||
|
piece(0,[],[0])
|
||||||
|
$p.each do |a|
|
||||||
|
a0 = a[0]
|
||||||
|
a[1] = ud(a0)
|
||||||
|
a[2] = rl(a0)
|
||||||
|
a[3] = ud(rl(a0))
|
||||||
|
a[4] = xy(a0)
|
||||||
|
a[5] = ud(xy(a0))
|
||||||
|
a[6] = rl(xy(a0))
|
||||||
|
a[7] = ud(rl(xy(a0)))
|
||||||
|
a.sort!
|
||||||
|
a.uniq!
|
||||||
|
end
|
||||||
|
$p.uniq!.sort! {|x,y| x[0] <=> y[0] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def mkboard
|
||||||
|
(0...ROW*COL).each{|i|
|
||||||
|
if i % ROW >= ROW-NP
|
||||||
|
$b[i] = -2
|
||||||
|
else
|
||||||
|
$b[i] = -1
|
||||||
|
end
|
||||||
|
$b[3*ROW+3]=$b[3*ROW+4]=$b[4*ROW+3]=$b[4*ROW+4]=-2
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def pboard
|
||||||
|
return # skip print
|
||||||
|
print "No. #$no\n"
|
||||||
|
(0...COL).each{|i|
|
||||||
|
print "|"
|
||||||
|
(0...ROW-NP).each{|j|
|
||||||
|
x = $b[i*ROW+j]
|
||||||
|
if x < 0
|
||||||
|
print "..|"
|
||||||
|
else
|
||||||
|
printf "%2d|",x+1
|
||||||
|
end
|
||||||
|
}
|
||||||
|
print "\n"
|
||||||
|
}
|
||||||
|
print "\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
$pnum=[]
|
||||||
|
def setpiece(a,pos)
|
||||||
|
if a.length == $p.length then
|
||||||
|
$no += 1
|
||||||
|
pboard
|
||||||
|
return
|
||||||
|
end
|
||||||
|
while $b[pos] != -1
|
||||||
|
pos += 1
|
||||||
|
end
|
||||||
|
($pnum - a).each do |i|
|
||||||
|
$p[i].each do |x|
|
||||||
|
f = 0
|
||||||
|
x.each{|s|
|
||||||
|
if $b[pos+s] != -1
|
||||||
|
f=1
|
||||||
|
break
|
||||||
|
end
|
||||||
|
}
|
||||||
|
if f == 0 then
|
||||||
|
x.each{|s|
|
||||||
|
$b[pos+s] = i
|
||||||
|
}
|
||||||
|
a << i
|
||||||
|
setpiece(a.clone, pos)
|
||||||
|
a.pop
|
||||||
|
x.each{|s|
|
||||||
|
$b[pos+s] = -1
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mkpieces
|
||||||
|
mkboard
|
||||||
|
$p[4] = [$p[4][0]]
|
||||||
|
$pnum = (0...$p.length).to_a
|
||||||
|
setpiece([],0)
|
||||||
|
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
# original
|
||||||
|
|
||||||
|
NP = 5
|
||||||
|
ROW = 8 + NP
|
||||||
|
COL = 8
|
||||||
|
|
||||||
|
$p = []
|
||||||
|
$b = []
|
||||||
|
$no = 0
|
||||||
|
|
||||||
|
def piece(n,a,nb)
|
||||||
|
for x in nb
|
||||||
|
a[n] = x
|
||||||
|
if n == NP-1
|
||||||
|
$p << [a.sort]
|
||||||
|
else
|
||||||
|
nbc=nb.clone
|
||||||
|
for d in [-ROW, -1, 1, ROW]
|
||||||
|
if x+d > 0 and not a.include?(x+d) and not nbc.include?(x+d)
|
||||||
|
nbc << x+d
|
||||||
|
end
|
||||||
|
end
|
||||||
|
nbc.delete x
|
||||||
|
piece(n+1,a[0..n],nbc)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def kikaku(a)
|
||||||
|
a.collect {|x| x - a[0]}
|
||||||
|
end
|
||||||
|
def ud(a)
|
||||||
|
kikaku(a.collect {|x| ((x+NP)%ROW)-ROW*((x+NP)/ROW) }.sort)
|
||||||
|
end
|
||||||
|
def rl(a)
|
||||||
|
kikaku(a.collect {|x| ROW*((x+NP)/ROW)+ROW-((x+NP)%ROW)}.sort)
|
||||||
|
end
|
||||||
|
def xy(a)
|
||||||
|
kikaku(a.collect {|x| ROW*((x+NP)%ROW) + (x+NP)/ROW }.sort)
|
||||||
|
end
|
||||||
|
|
||||||
|
def mkpieces
|
||||||
|
piece(0,[],[0])
|
||||||
|
$p.each do |a|
|
||||||
|
a0 = a[0]
|
||||||
|
a[1] = ud(a0)
|
||||||
|
a[2] = rl(a0)
|
||||||
|
a[3] = ud(rl(a0))
|
||||||
|
a[4] = xy(a0)
|
||||||
|
a[5] = ud(xy(a0))
|
||||||
|
a[6] = rl(xy(a0))
|
||||||
|
a[7] = ud(rl(xy(a0)))
|
||||||
|
a.sort!
|
||||||
|
a.uniq!
|
||||||
|
end
|
||||||
|
$p.uniq!.sort! {|x,y| x[0] <=> y[0] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def mkboard
|
||||||
|
for i in 0...ROW*COL
|
||||||
|
if i % ROW >= ROW-NP
|
||||||
|
$b[i] = -2
|
||||||
|
else
|
||||||
|
$b[i] = -1
|
||||||
|
end
|
||||||
|
$b[3*ROW+3]=$b[3*ROW+4]=$b[4*ROW+3]=$b[4*ROW+4]=-2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pboard
|
||||||
|
print "No. #$no\n"
|
||||||
|
for i in 0...COL
|
||||||
|
print "|"
|
||||||
|
for j in 0...ROW-NP
|
||||||
|
x = $b[i*ROW+j]
|
||||||
|
if x < 0
|
||||||
|
print "..|"
|
||||||
|
else
|
||||||
|
printf "%2d|",x+1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print "\n"
|
||||||
|
end
|
||||||
|
print "\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
$pnum=[]
|
||||||
|
def setpiece(a,pos)
|
||||||
|
if a.length == $p.length then
|
||||||
|
$no += 1
|
||||||
|
pboard
|
||||||
|
return
|
||||||
|
end
|
||||||
|
while $b[pos] != -1
|
||||||
|
pos += 1
|
||||||
|
end
|
||||||
|
($pnum - a).each do |i|
|
||||||
|
$p[i].each do |x|
|
||||||
|
f = 0
|
||||||
|
for s in x do
|
||||||
|
if $b[pos+s] != -1
|
||||||
|
f=1
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if f == 0 then
|
||||||
|
for s in x do
|
||||||
|
$b[pos+s] = i
|
||||||
|
end
|
||||||
|
a << i
|
||||||
|
setpiece(a.clone, pos)
|
||||||
|
a.pop
|
||||||
|
for s in x do
|
||||||
|
$b[pos+s] = -1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mkpieces
|
||||||
|
mkboard
|
||||||
|
$p[4] = [$p[4][0]]
|
||||||
|
$pnum = (0...$p.length).to_a
|
||||||
|
setpiece([],0)
|
8
benchmark/bm_app_raise.rb
Normal file
8
benchmark/bm_app_raise.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
i=0
|
||||||
|
while i<300000
|
||||||
|
i+=1
|
||||||
|
begin
|
||||||
|
raise
|
||||||
|
rescue
|
||||||
|
end
|
||||||
|
end
|
5
benchmark/bm_app_strconcat.rb
Normal file
5
benchmark/bm_app_strconcat.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
i=0
|
||||||
|
while i<500000
|
||||||
|
"#{1+1} #{1+1} #{1+1}"
|
||||||
|
i+=1
|
||||||
|
end
|
13
benchmark/bm_app_tak.rb
Normal file
13
benchmark/bm_app_tak.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
def tak x, y, z
|
||||||
|
unless y < x
|
||||||
|
z
|
||||||
|
else
|
||||||
|
tak( tak(x-1, y, z),
|
||||||
|
tak(y-1, z, x),
|
||||||
|
tak(z-1, x, y))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tak(18, 9, 0)
|
||||||
|
|
10
benchmark/bm_app_tarai.rb
Normal file
10
benchmark/bm_app_tarai.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
def tarai( x, y, z )
|
||||||
|
if x <= y
|
||||||
|
then y
|
||||||
|
else tarai(tarai(x-1, y, z),
|
||||||
|
tarai(y-1, z, x),
|
||||||
|
tarai(z-1, x, y))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tarai(12, 6, 0)
|
1
benchmark/bm_loop_times.rb
Normal file
1
benchmark/bm_loop_times.rb
Normal file
|
@ -0,0 +1 @@
|
||||||
|
30000000.times{|e|}
|
4
benchmark/bm_loop_whileloop.rb
Normal file
4
benchmark/bm_loop_whileloop.rb
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
i = 0
|
||||||
|
while i<30000000 # benchmark loop 1
|
||||||
|
i+=1
|
||||||
|
end
|
5
benchmark/bm_loop_whileloop2.rb
Normal file
5
benchmark/bm_loop_whileloop2.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
i=0
|
||||||
|
while i<6000000 # benchmark loop 2
|
||||||
|
i+=1
|
||||||
|
end
|
||||||
|
|
19
benchmark/bm_so_ackermann.rb
Normal file
19
benchmark/bm_so_ackermann.rb
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/ruby
|
||||||
|
# -*- mode: ruby -*-
|
||||||
|
# $Id: ackermann-ruby.code,v 1.4 2004/11/13 07:40:41 bfulgham Exp $
|
||||||
|
# http://www.bagley.org/~doug/shootout/
|
||||||
|
|
||||||
|
def ack(m, n)
|
||||||
|
if m == 0 then
|
||||||
|
n + 1
|
||||||
|
elsif n == 0 then
|
||||||
|
ack(m - 1, 1)
|
||||||
|
else
|
||||||
|
ack(m - 1, ack(m, n - 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
NUM = 9
|
||||||
|
ack(3, NUM)
|
||||||
|
|
||||||
|
|
23
benchmark/bm_so_array.rb
Normal file
23
benchmark/bm_so_array.rb
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/ruby
|
||||||
|
# -*- mode: ruby -*-
|
||||||
|
# $Id: ary-ruby.code,v 1.4 2004/11/13 07:41:27 bfulgham Exp $
|
||||||
|
# http://www.bagley.org/~doug/shootout/
|
||||||
|
# with help from Paul Brannan and Mark Hubbart
|
||||||
|
|
||||||
|
n = 9000 # Integer(ARGV.shift || 1)
|
||||||
|
|
||||||
|
x = Array.new(n)
|
||||||
|
y = Array.new(n, 0)
|
||||||
|
|
||||||
|
n.times{|bi|
|
||||||
|
x[bi] = bi + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
(0 .. 999).each do |e|
|
||||||
|
(n-1).step(0,-1) do |bi|
|
||||||
|
y[bi] += x.at(bi)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# puts "#{y.first} #{y.last}"
|
||||||
|
|
||||||
|
|
18
benchmark/bm_so_concatenate.rb
Normal file
18
benchmark/bm_so_concatenate.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/ruby
|
||||||
|
# -*- mode: ruby -*-
|
||||||
|
# $Id: strcat-ruby.code,v 1.4 2004/11/13 07:43:28 bfulgham Exp $
|
||||||
|
# http://www.bagley.org/~doug/shootout/
|
||||||
|
# based on code from Aristarkh A Zagorodnikov and Dat Nguyen
|
||||||
|
|
||||||
|
STUFF = "hello\n"
|
||||||
|
i=0
|
||||||
|
while i<10
|
||||||
|
i+=1
|
||||||
|
hello = ''
|
||||||
|
400000.times do |e|
|
||||||
|
hello << STUFF
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# puts hello.length
|
||||||
|
|
||||||
|
|
18
benchmark/bm_so_count_words.rb
Normal file
18
benchmark/bm_so_count_words.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/ruby
|
||||||
|
# -*- mode: ruby -*-
|
||||||
|
# $Id: wc-ruby.code,v 1.4 2004/11/13 07:43:32 bfulgham Exp $
|
||||||
|
# http://www.bagley.org/~doug/shootout/
|
||||||
|
# with help from Paul Brannan
|
||||||
|
|
||||||
|
input = open(File.join(File.dirname($0), 'wc.input'), 'rb')
|
||||||
|
|
||||||
|
nl = nw = nc = 0
|
||||||
|
while true
|
||||||
|
data = (input.read(4096) or break) << (input.gets || "")
|
||||||
|
nc += data.length
|
||||||
|
nl += data.count("\n")
|
||||||
|
((data.strip! || data).tr!("\n", " ") || data).squeeze!
|
||||||
|
#nw += data.count(" ") + 1
|
||||||
|
end
|
||||||
|
# STDERR.puts "#{nl} #{nw} #{nc}"
|
||||||
|
|
61
benchmark/bm_so_exception.rb
Normal file
61
benchmark/bm_so_exception.rb
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#!/usr/bin/ruby
|
||||||
|
# -*- mode: ruby -*-
|
||||||
|
# $Id: except-ruby.code,v 1.4 2004/11/13 07:41:33 bfulgham Exp $
|
||||||
|
# http://www.bagley.org/~doug/shootout/
|
||||||
|
|
||||||
|
$HI = 0
|
||||||
|
$LO = 0
|
||||||
|
NUM = 250000 # Integer(ARGV[0] || 1)
|
||||||
|
|
||||||
|
|
||||||
|
class Lo_Exception < Exception
|
||||||
|
def initialize(num)
|
||||||
|
@value = num
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Hi_Exception < Exception
|
||||||
|
def initialize(num)
|
||||||
|
@value = num
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def some_function(num)
|
||||||
|
begin
|
||||||
|
hi_function(num)
|
||||||
|
rescue
|
||||||
|
print "We shouldn't get here, exception is: #{$!.type}\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def hi_function(num)
|
||||||
|
begin
|
||||||
|
lo_function(num)
|
||||||
|
rescue Hi_Exception
|
||||||
|
$HI = $HI + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def lo_function(num)
|
||||||
|
begin
|
||||||
|
blowup(num)
|
||||||
|
rescue Lo_Exception
|
||||||
|
$LO = $LO + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def blowup(num)
|
||||||
|
if num % 2 == 0
|
||||||
|
raise Lo_Exception.new(num)
|
||||||
|
else
|
||||||
|
raise Hi_Exception.new(num)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
i = 1
|
||||||
|
max = NUM+1
|
||||||
|
while i < max
|
||||||
|
i+=1
|
||||||
|
some_function(i+1)
|
||||||
|
end
|
47
benchmark/bm_so_lists.rb
Normal file
47
benchmark/bm_so_lists.rb
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#from http://www.bagley.org/~doug/shootout/bench/lists/lists.ruby
|
||||||
|
|
||||||
|
NUM = 100
|
||||||
|
SIZE = 10000
|
||||||
|
|
||||||
|
def test_lists()
|
||||||
|
# create a list of integers (Li1) from 1 to SIZE
|
||||||
|
li1 = (1..SIZE).to_a
|
||||||
|
# copy the list to li2 (not by individual items)
|
||||||
|
li2 = li1.dup
|
||||||
|
# remove each individual item from left side of li2 and
|
||||||
|
# append to right side of li3 (preserving order)
|
||||||
|
li3 = Array.new
|
||||||
|
while (not li2.empty?)
|
||||||
|
li3.push(li2.shift)
|
||||||
|
end
|
||||||
|
# li2 must now be empty
|
||||||
|
# remove each individual item from right side of li3 and
|
||||||
|
# append to right side of li2 (reversing list)
|
||||||
|
while (not li3.empty?)
|
||||||
|
li2.push(li3.pop)
|
||||||
|
end
|
||||||
|
# li3 must now be empty
|
||||||
|
# reverse li1 in place
|
||||||
|
li1.reverse!
|
||||||
|
# check that first item is now SIZE
|
||||||
|
if li1[0] != SIZE then
|
||||||
|
p "not SIZE"
|
||||||
|
0
|
||||||
|
else
|
||||||
|
# compare li1 and li2 for equality
|
||||||
|
if li1 != li2 then
|
||||||
|
return(0)
|
||||||
|
else
|
||||||
|
# return the length of the list
|
||||||
|
li1.length
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i<NUM
|
||||||
|
i+=1
|
||||||
|
result = test_lists()
|
||||||
|
end
|
||||||
|
|
||||||
|
result
|
48
benchmark/bm_so_matrix.rb
Normal file
48
benchmark/bm_so_matrix.rb
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#!/usr/bin/ruby
|
||||||
|
# -*- mode: ruby -*-
|
||||||
|
# $Id: matrix-ruby.code,v 1.4 2004/11/13 07:42:14 bfulgham Exp $
|
||||||
|
# http://www.bagley.org/~doug/shootout/
|
||||||
|
|
||||||
|
n = 60 #Integer(ARGV.shift || 1)
|
||||||
|
|
||||||
|
size = 30
|
||||||
|
|
||||||
|
def mkmatrix(rows, cols)
|
||||||
|
count = 1
|
||||||
|
mx = Array.new(rows)
|
||||||
|
(0 .. (rows - 1)).each do |bi|
|
||||||
|
row = Array.new(cols, 0)
|
||||||
|
(0 .. (cols - 1)).each do |j|
|
||||||
|
row[j] = count
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
mx[bi] = row
|
||||||
|
end
|
||||||
|
mx
|
||||||
|
end
|
||||||
|
|
||||||
|
def mmult(rows, cols, m1, m2)
|
||||||
|
m3 = Array.new(rows)
|
||||||
|
(0 .. (rows - 1)).each do |bi|
|
||||||
|
row = Array.new(cols, 0)
|
||||||
|
(0 .. (cols - 1)).each do |j|
|
||||||
|
val = 0
|
||||||
|
(0 .. (cols - 1)).each do |k|
|
||||||
|
val += m1.at(bi).at(k) * m2.at(k).at(j)
|
||||||
|
end
|
||||||
|
row[j] = val
|
||||||
|
end
|
||||||
|
m3[bi] = row
|
||||||
|
end
|
||||||
|
m3
|
||||||
|
end
|
||||||
|
|
||||||
|
m1 = mkmatrix(size, size)
|
||||||
|
m2 = mkmatrix(size, size)
|
||||||
|
mm = Array.new
|
||||||
|
n.times do
|
||||||
|
mm = mmult(size, size, m1, m2)
|
||||||
|
end
|
||||||
|
# puts "#{mm[0][0]} #{mm[2][3]} #{mm[3][2]} #{mm[4][4]}"
|
||||||
|
|
||||||
|
|
24
benchmark/bm_so_nested_loop.rb
Normal file
24
benchmark/bm_so_nested_loop.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/ruby
|
||||||
|
# -*- mode: ruby -*-
|
||||||
|
# $Id: nestedloop-ruby.code,v 1.4 2004/11/13 07:42:22 bfulgham Exp $
|
||||||
|
# http://www.bagley.org/~doug/shootout/
|
||||||
|
# from Avi Bryant
|
||||||
|
|
||||||
|
n = 16 # Integer(ARGV.shift || 1)
|
||||||
|
x = 0
|
||||||
|
n.times do
|
||||||
|
n.times do
|
||||||
|
n.times do
|
||||||
|
n.times do
|
||||||
|
n.times do
|
||||||
|
n.times do
|
||||||
|
x += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# puts x
|
||||||
|
|
||||||
|
|
56
benchmark/bm_so_object.rb
Normal file
56
benchmark/bm_so_object.rb
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#!/usr/bin/ruby
|
||||||
|
# -*- mode: ruby -*-
|
||||||
|
# $Id: objinst-ruby.code,v 1.4 2004/11/13 07:42:25 bfulgham Exp $
|
||||||
|
# http://www.bagley.org/~doug/shootout/
|
||||||
|
# with help from Aristarkh Zagorodnikov
|
||||||
|
|
||||||
|
class Toggle
|
||||||
|
def initialize(start_state)
|
||||||
|
@bool = start_state
|
||||||
|
end
|
||||||
|
|
||||||
|
def value
|
||||||
|
@bool
|
||||||
|
end
|
||||||
|
|
||||||
|
def activate
|
||||||
|
@bool = !@bool
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class NthToggle < Toggle
|
||||||
|
def initialize(start_state, max_counter)
|
||||||
|
super start_state
|
||||||
|
@count_max = max_counter
|
||||||
|
@counter = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def activate
|
||||||
|
@counter += 1
|
||||||
|
if @counter >= @count_max
|
||||||
|
@bool = !@bool
|
||||||
|
@counter = 0
|
||||||
|
end
|
||||||
|
self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
n = 1500000 # (ARGV.shift || 1).to_i
|
||||||
|
|
||||||
|
toggle = Toggle.new 1
|
||||||
|
5.times do
|
||||||
|
toggle.activate.value ? 'true' : 'false'
|
||||||
|
end
|
||||||
|
n.times do
|
||||||
|
toggle = Toggle.new 1
|
||||||
|
end
|
||||||
|
|
||||||
|
ntoggle = NthToggle.new 1, 3
|
||||||
|
8.times do
|
||||||
|
ntoggle.activate.value ? 'true' : 'false'
|
||||||
|
end
|
||||||
|
n.times do
|
||||||
|
ntoggle = NthToggle.new 1, 3
|
||||||
|
end
|
||||||
|
|
20
benchmark/bm_so_random.rb
Normal file
20
benchmark/bm_so_random.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# from http://www.bagley.org/~doug/shootout/bench/random/random.ruby
|
||||||
|
|
||||||
|
IM = 139968.0
|
||||||
|
IA = 3877.0
|
||||||
|
IC = 29573.0
|
||||||
|
|
||||||
|
$last = 42.0
|
||||||
|
|
||||||
|
def gen_random(max)
|
||||||
|
(max * ($last = ($last * IA + IC) % IM)) / IM
|
||||||
|
end
|
||||||
|
|
||||||
|
N = 1000000
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i<N
|
||||||
|
i+=1
|
||||||
|
gen_random(100.0)
|
||||||
|
end
|
||||||
|
# "%.9f" % gen_random(100.0)
|
24
benchmark/bm_so_sieve.rb
Normal file
24
benchmark/bm_so_sieve.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# from http://www.bagley.org/~doug/shootout/bench/sieve/sieve.ruby
|
||||||
|
num = 40
|
||||||
|
count = i = j = 0
|
||||||
|
flags0 = Array.new(8192,1)
|
||||||
|
k = 0
|
||||||
|
while k < num
|
||||||
|
k+=1
|
||||||
|
count = 0
|
||||||
|
flags = flags0.dup
|
||||||
|
i = 2
|
||||||
|
while i<8192
|
||||||
|
i+=1
|
||||||
|
if flags[i]
|
||||||
|
# remove all multiples of prime: i
|
||||||
|
j = i*i
|
||||||
|
while j < 8192
|
||||||
|
j += i
|
||||||
|
flags[j] = nil
|
||||||
|
end
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
count
|
10
benchmark/bm_vm1_block.rb
Normal file
10
benchmark/bm_vm1_block.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
def m
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i<30000000 # while loop 1
|
||||||
|
i+=1
|
||||||
|
m{
|
||||||
|
}
|
||||||
|
end
|
8
benchmark/bm_vm1_const.rb
Normal file
8
benchmark/bm_vm1_const.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Const = 1
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i<30000000 # while loop 1
|
||||||
|
i+= 1
|
||||||
|
j = Const
|
||||||
|
k = Const
|
||||||
|
end
|
11
benchmark/bm_vm1_ensure.rb
Normal file
11
benchmark/bm_vm1_ensure.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
i=0
|
||||||
|
while i<30000000 # benchmark loop 1
|
||||||
|
i+=1
|
||||||
|
begin
|
||||||
|
begin
|
||||||
|
ensure
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
9
benchmark/bm_vm1_length.rb
Normal file
9
benchmark/bm_vm1_length.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
a = 'abc'
|
||||||
|
b = [1, 2, 3]
|
||||||
|
i=0
|
||||||
|
while i<30000000 # while loop 1
|
||||||
|
i+=1
|
||||||
|
a.length
|
||||||
|
b.length
|
||||||
|
end
|
||||||
|
|
7
benchmark/bm_vm1_rescue.rb
Normal file
7
benchmark/bm_vm1_rescue.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
i=0
|
||||||
|
while i<30000000 # while loop 1
|
||||||
|
i+=1
|
||||||
|
begin
|
||||||
|
rescue
|
||||||
|
end
|
||||||
|
end
|
9
benchmark/bm_vm1_simplereturn.rb
Normal file
9
benchmark/bm_vm1_simplereturn.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
def m
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
i=0
|
||||||
|
while i<30000000 # while loop 1
|
||||||
|
i+=1
|
||||||
|
m
|
||||||
|
end
|
||||||
|
|
8
benchmark/bm_vm1_swap.rb
Normal file
8
benchmark/bm_vm1_swap.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
a = 1
|
||||||
|
b = 2
|
||||||
|
i=0
|
||||||
|
while i<30000000 # while loop 1
|
||||||
|
i+=1
|
||||||
|
a, b = b, a
|
||||||
|
end
|
||||||
|
|
5
benchmark/bm_vm2_array.rb
Normal file
5
benchmark/bm_vm2_array.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
i=0
|
||||||
|
while i<6000000 # benchmark loop 2
|
||||||
|
i+=1
|
||||||
|
a = [1,2,3,4,5,6,7,8,9,10]
|
||||||
|
end
|
9
benchmark/bm_vm2_method.rb
Normal file
9
benchmark/bm_vm2_method.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
def m
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i<6000000 # benchmark loop 2
|
||||||
|
i+=1
|
||||||
|
m; m; m; m; m; m; m; m;
|
||||||
|
end
|
20
benchmark/bm_vm2_poly_method.rb
Normal file
20
benchmark/bm_vm2_poly_method.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
class C1
|
||||||
|
def m
|
||||||
|
1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
class C2
|
||||||
|
def m
|
||||||
|
2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
o1 = C1.new
|
||||||
|
o2 = C2.new
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i<6000000 # benchmark loop 2
|
||||||
|
o = (i % 2 == 0) ? o1 : o2
|
||||||
|
o.m; o.m; o.m; o.m; o.m; o.m; o.m; o.m
|
||||||
|
i+=1
|
||||||
|
end
|
20
benchmark/bm_vm2_poly_method_ov.rb
Normal file
20
benchmark/bm_vm2_poly_method_ov.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
class C1
|
||||||
|
def m
|
||||||
|
1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
class C2
|
||||||
|
def m
|
||||||
|
2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
o1 = C1.new
|
||||||
|
o2 = C2.new
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i<6000000 # benchmark loop 2
|
||||||
|
o = (i % 2 == 0) ? o1 : o2
|
||||||
|
# o.m; o.m; o.m; o.m; o.m; o.m; o.m; o.m
|
||||||
|
i+=1
|
||||||
|
end
|
14
benchmark/bm_vm2_proc.rb
Normal file
14
benchmark/bm_vm2_proc.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
def m &b
|
||||||
|
b
|
||||||
|
end
|
||||||
|
|
||||||
|
pr = m{
|
||||||
|
a = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i<6000000 # benchmark loop 2
|
||||||
|
i+=1
|
||||||
|
pr.call
|
||||||
|
end
|
||||||
|
|
6
benchmark/bm_vm2_regexp.rb
Normal file
6
benchmark/bm_vm2_regexp.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
i=0
|
||||||
|
str = 'xxxhogexxx'
|
||||||
|
while i<6000000 # benchmark loop 2
|
||||||
|
/hoge/ =~ str
|
||||||
|
i+=1
|
||||||
|
end
|
12
benchmark/bm_vm2_send.rb
Normal file
12
benchmark/bm_vm2_send.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
class C
|
||||||
|
def m
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
o = C.new
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i<6000000 # benchmark loop 2
|
||||||
|
i+=1
|
||||||
|
o.__send__ :m
|
||||||
|
end
|
20
benchmark/bm_vm2_super.rb
Normal file
20
benchmark/bm_vm2_super.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
class C
|
||||||
|
def m
|
||||||
|
1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class CC < C
|
||||||
|
def m
|
||||||
|
super()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
obj = CC.new
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i<6000000 # benchmark loop 2
|
||||||
|
obj.m
|
||||||
|
i+=1
|
||||||
|
end
|
8
benchmark/bm_vm2_unif1.rb
Normal file
8
benchmark/bm_vm2_unif1.rb
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
i = 0
|
||||||
|
def m a, b
|
||||||
|
end
|
||||||
|
|
||||||
|
while i<6000000 # benchmark loop 2
|
||||||
|
i+=1
|
||||||
|
m 100, 200
|
||||||
|
end
|
20
benchmark/bm_vm2_zsuper.rb
Normal file
20
benchmark/bm_vm2_zsuper.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
class C
|
||||||
|
def m a
|
||||||
|
1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class CC < C
|
||||||
|
def m a
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
obj = CC.new
|
||||||
|
|
||||||
|
while i<6000000 # benchmark loop 2
|
||||||
|
obj.m 10
|
||||||
|
i+=1
|
||||||
|
end
|
6
benchmark/bm_vm3_thread_create_join.rb
Normal file
6
benchmark/bm_vm3_thread_create_join.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
i=0
|
||||||
|
while i<1000 # benchmark loop 3
|
||||||
|
i+=1
|
||||||
|
Thread.new{
|
||||||
|
}.join
|
||||||
|
end
|
57
benchmark/bmx_temp.rb
Normal file
57
benchmark/bmx_temp.rb
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i<20000000
|
||||||
|
x = 1 # "foo"
|
||||||
|
i+=1
|
||||||
|
end
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
class Range
|
||||||
|
def each
|
||||||
|
f = self.first
|
||||||
|
l = self.last
|
||||||
|
while f < l
|
||||||
|
yield
|
||||||
|
f = f.succ
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
(0..10000000).each{
|
||||||
|
}
|
||||||
|
|
||||||
|
__END__
|
||||||
|
class Fixnum_
|
||||||
|
def times
|
||||||
|
i = 0
|
||||||
|
while i<self
|
||||||
|
yield(i)
|
||||||
|
i+=1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
10000000.times{
|
||||||
|
}
|
||||||
|
__END__
|
||||||
|
|
||||||
|
ths = (1..10).map{
|
||||||
|
Thread.new{
|
||||||
|
1000000.times{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ths.each{|e|
|
||||||
|
e.join
|
||||||
|
}
|
||||||
|
|
||||||
|
__END__
|
||||||
|
$pr = proc{}
|
||||||
|
def m
|
||||||
|
$pr.call
|
||||||
|
end
|
||||||
|
|
||||||
|
1000000.times{|e|
|
||||||
|
m
|
||||||
|
}
|
11
benchmark/other-lang/ack.pl
Normal file
11
benchmark/other-lang/ack.pl
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use integer;
|
||||||
|
|
||||||
|
sub Ack {
|
||||||
|
return $_[0] ? ($_[1] ? Ack($_[0]-1, Ack($_[0], $_[1]-1))
|
||||||
|
: Ack($_[0]-1, 1))
|
||||||
|
: $_[1]+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $NUM = 9;
|
||||||
|
$NUM = 1 if ($NUM < 1);
|
||||||
|
my $ack = Ack(3, $NUM);
|
16
benchmark/other-lang/ack.py
Normal file
16
benchmark/other-lang/ack.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import sys
|
||||||
|
sys.setrecursionlimit(5000000)
|
||||||
|
|
||||||
|
def Ack(M, N):
|
||||||
|
if (not M):
|
||||||
|
return( N + 1 )
|
||||||
|
if (not N):
|
||||||
|
return( Ack(M-1, 1) )
|
||||||
|
return( Ack(M-1, Ack(M, N-1)) )
|
||||||
|
|
||||||
|
def main():
|
||||||
|
NUM = 9
|
||||||
|
sys.setrecursionlimit(10000)
|
||||||
|
Ack(3, NUM)
|
||||||
|
|
||||||
|
main()
|
12
benchmark/other-lang/ack.rb
Normal file
12
benchmark/other-lang/ack.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
def ack(m, n)
|
||||||
|
if m == 0 then
|
||||||
|
n + 1
|
||||||
|
elsif n == 0 then
|
||||||
|
ack(m - 1, 1)
|
||||||
|
else
|
||||||
|
ack(m - 1, ack(m, n - 1))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
NUM = 9
|
||||||
|
ack(3, NUM)
|
7
benchmark/other-lang/ack.scm
Normal file
7
benchmark/other-lang/ack.scm
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
(define (ack m n)
|
||||||
|
(cond ((zero? m) (+ n 1))
|
||||||
|
((zero? n) (ack (- m 1) 1))
|
||||||
|
(else (ack (- m 1) (ack m (- n 1))))))
|
||||||
|
|
||||||
|
(ack 3 9)
|
||||||
|
|
66
benchmark/other-lang/eval.rb
Normal file
66
benchmark/other-lang/eval.rb
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
|
||||||
|
Bench = %w(
|
||||||
|
loop
|
||||||
|
ack
|
||||||
|
fib
|
||||||
|
tak
|
||||||
|
fact
|
||||||
|
)
|
||||||
|
|
||||||
|
Lang = <<EOP.map{|l| l.strip}
|
||||||
|
ruby-cyg
|
||||||
|
../../../test6/miniruby
|
||||||
|
perl
|
||||||
|
python
|
||||||
|
gosh
|
||||||
|
EOP
|
||||||
|
|
||||||
|
Bench.replace ['loop2']
|
||||||
|
Lang.replace ['ruby-cyg']
|
||||||
|
|
||||||
|
Ext = %w(
|
||||||
|
.rb
|
||||||
|
.rb
|
||||||
|
.pl
|
||||||
|
.py
|
||||||
|
.scm
|
||||||
|
)
|
||||||
|
|
||||||
|
p Bench
|
||||||
|
p Lang
|
||||||
|
|
||||||
|
require 'benchmark'
|
||||||
|
|
||||||
|
def bench cmd
|
||||||
|
m = Benchmark.measure{
|
||||||
|
#p cmd
|
||||||
|
system(cmd)
|
||||||
|
}
|
||||||
|
[m.utime, m.real]
|
||||||
|
end
|
||||||
|
|
||||||
|
Result = []
|
||||||
|
Bench.each{|b|
|
||||||
|
r = []
|
||||||
|
Lang.each_with_index{|l, idx|
|
||||||
|
cmd = "#{l} #{b}#{Ext[idx]}"
|
||||||
|
r << bench(cmd)
|
||||||
|
}
|
||||||
|
Result << r
|
||||||
|
}
|
||||||
|
|
||||||
|
require 'pp'
|
||||||
|
# utime
|
||||||
|
puts Lang.join("\t")
|
||||||
|
Bench.each_with_index{|b, bi|
|
||||||
|
print b, "\t"
|
||||||
|
puts Result[bi].map{|e| e[0]}.join("\t")
|
||||||
|
}
|
||||||
|
|
||||||
|
# rtime
|
||||||
|
puts Lang.join("\t")
|
||||||
|
Bench.each_with_index{|b, bi|
|
||||||
|
print b, "\t"
|
||||||
|
puts Result[bi].map{|e| e[1]}.join("\t")
|
||||||
|
}
|
||||||
|
|
13
benchmark/other-lang/fact.pl
Normal file
13
benchmark/other-lang/fact.pl
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
sub fact{
|
||||||
|
my $n = @_[0];
|
||||||
|
if($n < 2){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return $n * fact($n-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for($i=0; $i<10000; $i++){
|
||||||
|
&fact(100);
|
||||||
|
}
|
18
benchmark/other-lang/fact.py
Normal file
18
benchmark/other-lang/fact.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#import sys
|
||||||
|
#sys.setrecursionlimit(1000)
|
||||||
|
|
||||||
|
def factL(n):
|
||||||
|
r = 1
|
||||||
|
for x in range(2, n):
|
||||||
|
r *= x
|
||||||
|
return r
|
||||||
|
|
||||||
|
def factR(n):
|
||||||
|
if n < 2:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return n * factR(n-1)
|
||||||
|
|
||||||
|
for i in range(10000):
|
||||||
|
factR(100)
|
||||||
|
|
13
benchmark/other-lang/fact.rb
Normal file
13
benchmark/other-lang/fact.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
def fact(n)
|
||||||
|
if n < 2
|
||||||
|
1
|
||||||
|
else
|
||||||
|
n * fact(n-1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
i=0
|
||||||
|
while i<10000
|
||||||
|
i+=1
|
||||||
|
fact(100)
|
||||||
|
end
|
8
benchmark/other-lang/fact.scm
Normal file
8
benchmark/other-lang/fact.scm
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
(define (fact n)
|
||||||
|
(if (< n 2)
|
||||||
|
1
|
||||||
|
(* n (fact (- n 1)))))
|
||||||
|
|
||||||
|
(dotimes (i 10000)
|
||||||
|
(fact 100))
|
||||||
|
|
11
benchmark/other-lang/fib.pl
Normal file
11
benchmark/other-lang/fib.pl
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
sub fib{
|
||||||
|
my $n = $_[0];
|
||||||
|
if($n < 3){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return fib($n-1) + fib($n-2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
&fib(34);
|
7
benchmark/other-lang/fib.py
Normal file
7
benchmark/other-lang/fib.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
def fib(n):
|
||||||
|
if n < 3:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return fib(n-1) + fib(n-2)
|
||||||
|
|
||||||
|
fib(34)
|
9
benchmark/other-lang/fib.rb
Normal file
9
benchmark/other-lang/fib.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
def fib n
|
||||||
|
if n < 3
|
||||||
|
1
|
||||||
|
else
|
||||||
|
fib(n-1) + fib(n-2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
fib(34)
|
7
benchmark/other-lang/fib.scm
Normal file
7
benchmark/other-lang/fib.scm
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
(define (fib n)
|
||||||
|
(if (< n 3)
|
||||||
|
1
|
||||||
|
(+ (fib (- n 1)) (fib (- n 2)))))
|
||||||
|
|
||||||
|
(fib 34)
|
||||||
|
|
3
benchmark/other-lang/loop.pl
Normal file
3
benchmark/other-lang/loop.pl
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
for($i=0; $i<30000000; $i++){
|
||||||
|
}
|
||||||
|
|
2
benchmark/other-lang/loop.py
Normal file
2
benchmark/other-lang/loop.py
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
for i in xrange(30000000):
|
||||||
|
pass
|
4
benchmark/other-lang/loop.rb
Normal file
4
benchmark/other-lang/loop.rb
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
i=0
|
||||||
|
while i<30000000
|
||||||
|
i+=1
|
||||||
|
end
|
1
benchmark/other-lang/loop.scm
Normal file
1
benchmark/other-lang/loop.scm
Normal file
|
@ -0,0 +1 @@
|
||||||
|
(dotimes (x 30000000))
|
1
benchmark/other-lang/loop2.rb
Normal file
1
benchmark/other-lang/loop2.rb
Normal file
|
@ -0,0 +1 @@
|
||||||
|
30000000.times{}
|
11
benchmark/other-lang/tak.pl
Normal file
11
benchmark/other-lang/tak.pl
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
sub tak {
|
||||||
|
local($x, $y, $z) = @_;
|
||||||
|
if (!($y < $x)) {
|
||||||
|
return $z;
|
||||||
|
} else {
|
||||||
|
return &tak(&tak($x - 1, $y, $z),
|
||||||
|
&tak($y - 1, $z, $x),
|
||||||
|
&tak($z - 1, $x, $y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&tak(18, 9, 0);
|
8
benchmark/other-lang/tak.py
Normal file
8
benchmark/other-lang/tak.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
def tak(x, y, z):
|
||||||
|
if not(y<x):
|
||||||
|
return z
|
||||||
|
else:
|
||||||
|
return tak(tak(x-1, y, z),
|
||||||
|
tak(y-1, z, x),
|
||||||
|
tak(z-1, x, y))
|
||||||
|
tak(18, 9, 0)
|
13
benchmark/other-lang/tak.rb
Normal file
13
benchmark/other-lang/tak.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
def tak x, y, z
|
||||||
|
unless y < x
|
||||||
|
z
|
||||||
|
else
|
||||||
|
tak( tak(x-1, y, z),
|
||||||
|
tak(y-1, z, x),
|
||||||
|
tak(z-1, x, y))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tak(18, 9, 0)
|
||||||
|
|
10
benchmark/other-lang/tak.scm
Normal file
10
benchmark/other-lang/tak.scm
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
(define (tak x y z)
|
||||||
|
(if (not (< y x))
|
||||||
|
z
|
||||||
|
(tak (tak (- x 1) y z)
|
||||||
|
(tak (- y 1) z x)
|
||||||
|
(tak (- z 1) x y))))
|
||||||
|
|
||||||
|
(tak 18 9 0)
|
||||||
|
|
||||||
|
|
81
benchmark/report.rb
Normal file
81
benchmark/report.rb
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#
|
||||||
|
# YARV benchmark driver
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'yarvutil'
|
||||||
|
require 'benchmark'
|
||||||
|
require 'rbconfig'
|
||||||
|
|
||||||
|
def exec_command type, file, w
|
||||||
|
<<-EOP
|
||||||
|
$DRIVER_PATH = '#{File.dirname($0)}'
|
||||||
|
$LOAD_PATH.replace $LOAD_PATH | #{$LOAD_PATH.inspect}
|
||||||
|
require 'benchmark'
|
||||||
|
require 'yarvutil'
|
||||||
|
# print '#{type}'
|
||||||
|
begin
|
||||||
|
puts Benchmark.measure{
|
||||||
|
#{w}('#{file}')
|
||||||
|
}.utime
|
||||||
|
rescue Exception => exec_command_error_variable
|
||||||
|
puts "\t" + exec_command_error_variable.message
|
||||||
|
end
|
||||||
|
EOP
|
||||||
|
end
|
||||||
|
|
||||||
|
def benchmark cmd
|
||||||
|
rubybin = ENV['RUBY'] || File.join(
|
||||||
|
Config::CONFIG["bindir"],
|
||||||
|
Config::CONFIG["ruby_install_name"] + Config::CONFIG["EXEEXT"])
|
||||||
|
|
||||||
|
IO.popen(rubybin, 'r+'){|io|
|
||||||
|
io.write cmd
|
||||||
|
io.close_write
|
||||||
|
return io.gets
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def ruby_exec file
|
||||||
|
prog = exec_command 'ruby', file, 'load'
|
||||||
|
benchmark prog
|
||||||
|
end
|
||||||
|
|
||||||
|
def yarv_exec file
|
||||||
|
prog = exec_command 'yarv', file, 'YARVUtil.load_bm'
|
||||||
|
benchmark prog
|
||||||
|
end
|
||||||
|
|
||||||
|
$wr = $wy = nil
|
||||||
|
|
||||||
|
def measure bench
|
||||||
|
file = File.dirname($0) + "/bm_#{bench}.rb"
|
||||||
|
r = ruby_exec(file).to_f
|
||||||
|
y = yarv_exec(file).to_f
|
||||||
|
puts "#{bench}\t#{r}\t#{y}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def measure2
|
||||||
|
r = ruby_exec.to_f
|
||||||
|
y = yarv_exec.to_f
|
||||||
|
puts r/y
|
||||||
|
end
|
||||||
|
|
||||||
|
if $0 == __FILE__
|
||||||
|
%w{
|
||||||
|
whileloop
|
||||||
|
whileloop2
|
||||||
|
times
|
||||||
|
const
|
||||||
|
method
|
||||||
|
poly_method
|
||||||
|
block
|
||||||
|
rescue
|
||||||
|
rescue2
|
||||||
|
}.each{|bench|
|
||||||
|
measure bench
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
137
benchmark/run.rb
Normal file
137
benchmark/run.rb
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
#
|
||||||
|
# YARV benchmark driver
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'yarvutil'
|
||||||
|
require 'benchmark'
|
||||||
|
require 'rbconfig'
|
||||||
|
|
||||||
|
$yarvonly = false
|
||||||
|
$rubyonly = false
|
||||||
|
|
||||||
|
$results = []
|
||||||
|
|
||||||
|
puts "ruby #{RUBY_VERSION} #{RUBY_PLATFORM}(#{RUBY_RELEASE_DATE})"
|
||||||
|
puts YARVCore::VERSION + " rev: #{YARVCore::REV} (#{YARVCore::DATE})"
|
||||||
|
puts YARVCore::OPTS
|
||||||
|
puts
|
||||||
|
|
||||||
|
def bm file
|
||||||
|
prog = File.read(file).map{|e| e.rstrip}.join("\n")
|
||||||
|
return if prog.empty?
|
||||||
|
|
||||||
|
/[a-z]+_(.+)\.rb/ =~ file
|
||||||
|
bm_name = $1
|
||||||
|
puts '-----------------------------------------------------------' unless $yarvonly || $rubyonly
|
||||||
|
puts "#{bm_name}: "
|
||||||
|
|
||||||
|
|
||||||
|
puts <<EOS unless $yarvonly || $rubyonly
|
||||||
|
#{prog}
|
||||||
|
--
|
||||||
|
EOS
|
||||||
|
#iseq = YARVUtil.parse(File.read(file))
|
||||||
|
#vm = YARVCore::VM.new
|
||||||
|
begin
|
||||||
|
Benchmark.bm{|x|
|
||||||
|
# x.report("yarv"){ YARVUtil.load_bm(file) }
|
||||||
|
} unless $yarvonly || $rubyonly
|
||||||
|
|
||||||
|
result = [bm_name]
|
||||||
|
result << ruby_exec(file) unless $yarvonly
|
||||||
|
result << yarv_exec(file) unless $rubyonly
|
||||||
|
$results << result
|
||||||
|
|
||||||
|
# puts YARVUtil.parse(File.read(file), file, 1).disasm
|
||||||
|
|
||||||
|
# x.report("ruby"){ load(file, false) }
|
||||||
|
# x.report("yarv"){ vm.eval iseq }
|
||||||
|
rescue Exception => e
|
||||||
|
puts
|
||||||
|
puts "** benchmark failure: #{e}"
|
||||||
|
puts e.backtrace
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exec_command type, file, w
|
||||||
|
<<-EOP
|
||||||
|
$DRIVER_PATH = '#{File.dirname($0)}'
|
||||||
|
$LOAD_PATH.replace $LOAD_PATH | #{$LOAD_PATH.inspect}
|
||||||
|
require 'benchmark'
|
||||||
|
require 'yarvutil'
|
||||||
|
print '#{type}'
|
||||||
|
begin
|
||||||
|
puts Benchmark.measure{
|
||||||
|
#{w}('#{file}')
|
||||||
|
}
|
||||||
|
rescue Exception => exec_command_error_variable
|
||||||
|
puts "\t" + exec_command_error_variable.message
|
||||||
|
end
|
||||||
|
EOP
|
||||||
|
end
|
||||||
|
|
||||||
|
def benchmark prog
|
||||||
|
rubybin = ENV['RUBY'] || File.join(
|
||||||
|
Config::CONFIG["bindir"],
|
||||||
|
Config::CONFIG["ruby_install_name"] + Config::CONFIG["EXEEXT"])
|
||||||
|
|
||||||
|
#
|
||||||
|
tmpfile = Tempfile.new('yarvbench')
|
||||||
|
tmpfile.write(prog)
|
||||||
|
tmpfile.close
|
||||||
|
|
||||||
|
cmd = "#{rubybin} #{tmpfile.path}"
|
||||||
|
result = `#{cmd}`
|
||||||
|
puts result
|
||||||
|
tmpfile.close(true)
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def ruby_exec file
|
||||||
|
prog = exec_command 'ruby', file, 'load'
|
||||||
|
benchmark prog
|
||||||
|
end
|
||||||
|
|
||||||
|
def yarv_exec file
|
||||||
|
prog = exec_command 'yarv', file, 'YARVUtil.load_bm'
|
||||||
|
benchmark prog
|
||||||
|
end
|
||||||
|
|
||||||
|
if $0 == __FILE__
|
||||||
|
ARGV.each{|arg|
|
||||||
|
if /\A(--yarv)|(-y)/ =~ arg
|
||||||
|
$yarvonly = true
|
||||||
|
elsif /\A(--ruby)|(-r)/ =~ arg
|
||||||
|
$rubyonly = true
|
||||||
|
end
|
||||||
|
}
|
||||||
|
ARGV.delete_if{|arg|
|
||||||
|
/\A-/ =~ arg
|
||||||
|
}
|
||||||
|
|
||||||
|
if ARGV.empty?
|
||||||
|
Dir.glob(File.dirname(__FILE__) + '/bm_*.rb').sort.each{|file|
|
||||||
|
bm file
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ARGV.each{|file|
|
||||||
|
Dir.glob(File.join(File.dirname(__FILE__), file + '*')){|ef|
|
||||||
|
# file = "#{File.dirname(__FILE__)}/#{file}.rb"
|
||||||
|
bm ef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
puts
|
||||||
|
puts "-- benchmark summary ---------------------------"
|
||||||
|
$results.each{|res|
|
||||||
|
print res.shift, "\t"
|
||||||
|
(res||[]).each{|result|
|
||||||
|
/([\d\.]+)/ =~ result
|
||||||
|
print $1 + "\t" if $1
|
||||||
|
}
|
||||||
|
puts
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
129
benchmark/run_rite.rb
Normal file
129
benchmark/run_rite.rb
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
#
|
||||||
|
# YARV benchmark driver
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'benchmark'
|
||||||
|
require 'rbconfig'
|
||||||
|
|
||||||
|
$yarvonly = false
|
||||||
|
$rubyonly = false
|
||||||
|
|
||||||
|
$results = []
|
||||||
|
|
||||||
|
# prepare 'wc.input'
|
||||||
|
def prepare_wc_input
|
||||||
|
wcinput = File.join(File.dirname($0), 'wc.input')
|
||||||
|
wcbase = File.join(File.dirname($0), 'wc.input.base')
|
||||||
|
unless FileTest.exist?(wcinput)
|
||||||
|
data = File.read(wcbase)
|
||||||
|
13.times{
|
||||||
|
data << data
|
||||||
|
}
|
||||||
|
open(wcinput, 'w'){|f| f.write data}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
prepare_wc_input
|
||||||
|
|
||||||
|
def bm file
|
||||||
|
prog = File.read(file).map{|e| e.rstrip}.join("\n")
|
||||||
|
return if prog.empty?
|
||||||
|
|
||||||
|
/[a-z]+_(.+)\.rb/ =~ file
|
||||||
|
bm_name = $1
|
||||||
|
puts '-----------------------------------------------------------' unless $yarvonly || $rubyonly
|
||||||
|
puts "#{bm_name}: "
|
||||||
|
|
||||||
|
|
||||||
|
puts <<EOS unless $yarvonly || $rubyonly
|
||||||
|
#{prog}
|
||||||
|
--
|
||||||
|
EOS
|
||||||
|
#iseq = YARVUtil.parse(File.read(file))
|
||||||
|
#vm = YARVCore::VM.new
|
||||||
|
begin
|
||||||
|
result = [bm_name]
|
||||||
|
result << ruby_exec(file) unless $yarvonly
|
||||||
|
result << yarv_exec(file) unless $rubyonly
|
||||||
|
$results << result
|
||||||
|
|
||||||
|
# puts YARVUtil.parse(File.read(file), file, 1).disasm
|
||||||
|
|
||||||
|
# x.report("ruby"){ load(file, false) }
|
||||||
|
# x.report("yarv"){ vm.eval iseq }
|
||||||
|
rescue Exception => e
|
||||||
|
puts
|
||||||
|
puts "** benchmark failure: #{e}"
|
||||||
|
puts e.backtrace
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def benchmark file, bin
|
||||||
|
m = Benchmark.measure{
|
||||||
|
`#{bin} #{$opts} #{file}`
|
||||||
|
}
|
||||||
|
sec = '%.3f' % m.real
|
||||||
|
puts " #{sec}"
|
||||||
|
sec
|
||||||
|
end
|
||||||
|
|
||||||
|
def ruby_exec file
|
||||||
|
print 'ruby'
|
||||||
|
benchmark file, $ruby_program
|
||||||
|
end
|
||||||
|
|
||||||
|
def yarv_exec file
|
||||||
|
print 'yarv'
|
||||||
|
benchmark file, $yarv_program
|
||||||
|
end
|
||||||
|
|
||||||
|
if $0 == __FILE__
|
||||||
|
ARGV.each{|arg|
|
||||||
|
case arg
|
||||||
|
when /\A--yarv-program=(.+)/
|
||||||
|
$yarv_program = $1
|
||||||
|
when /\A--ruby-program=(.+)/
|
||||||
|
$ruby_program = $1
|
||||||
|
when /\A--opts=(.+)/
|
||||||
|
$opts = $1
|
||||||
|
when /\A(--yarv)|(-y)/
|
||||||
|
$yarvonly = true
|
||||||
|
when /\A(--ruby)|(-r)/
|
||||||
|
$rubyonly = true
|
||||||
|
end
|
||||||
|
}
|
||||||
|
ARGV.delete_if{|arg|
|
||||||
|
/\A-/ =~ arg
|
||||||
|
}
|
||||||
|
|
||||||
|
puts "Ruby:"
|
||||||
|
system("#{$ruby_program} -v")
|
||||||
|
puts
|
||||||
|
puts "YARV:"
|
||||||
|
system("#{$yarv_program} -v")
|
||||||
|
|
||||||
|
if ARGV.empty?
|
||||||
|
Dir.glob(File.dirname(__FILE__) + '/bm_*.rb').sort.each{|file|
|
||||||
|
bm file
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ARGV.each{|file|
|
||||||
|
Dir.glob(File.join(File.dirname(__FILE__), file + '*')){|ef|
|
||||||
|
# file = "#{File.dirname(__FILE__)}/#{file}.rb"
|
||||||
|
bm ef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
puts
|
||||||
|
puts "-- benchmark summary ---------------------------"
|
||||||
|
$results.each{|res|
|
||||||
|
print res.shift, "\t"
|
||||||
|
(res||[]).each{|result|
|
||||||
|
/([\d\.]+)/ =~ result
|
||||||
|
print $1 + "\t" if $1
|
||||||
|
}
|
||||||
|
puts
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
29
benchmark/runc.rb
Normal file
29
benchmark/runc.rb
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'benchmark'
|
||||||
|
require 'rbconfig'
|
||||||
|
|
||||||
|
$rubybin = ENV['RUBY'] || File.join(
|
||||||
|
Config::CONFIG["bindir"],
|
||||||
|
Config::CONFIG["ruby_install_name"] + Config::CONFIG["EXEEXT"])
|
||||||
|
|
||||||
|
def runfile file
|
||||||
|
puts file
|
||||||
|
file = File.join(File.dirname($0), 'contrib', file)
|
||||||
|
Benchmark.bm{|x|
|
||||||
|
x.report('ruby'){
|
||||||
|
system("#{$rubybin} #{file}")
|
||||||
|
}
|
||||||
|
x.report('yarv'){
|
||||||
|
system("#{$rubybin} -rite -I.. #{file}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
ARGV.each{|file|
|
||||||
|
runfile file
|
||||||
|
}
|
||||||
|
|
||||||
|
|
25
benchmark/wc.input.base
Normal file
25
benchmark/wc.input.base
Normal file
File diff suppressed because one or more lines are too long
461
blockinlining.c
Normal file
461
blockinlining.c
Normal file
|
@ -0,0 +1,461 @@
|
||||||
|
/**********************************************************************
|
||||||
|
|
||||||
|
blockinlining.c -
|
||||||
|
|
||||||
|
$Author$
|
||||||
|
$Date$
|
||||||
|
|
||||||
|
Copyright (C) 2004-2006 Koichi Sasada
|
||||||
|
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include "ruby.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "yarvcore.h"
|
||||||
|
|
||||||
|
VALUE yarv_new_iseqval(VALUE node, VALUE name, VALUE file,
|
||||||
|
VALUE parent, VALUE type, VALUE block_opt, VALUE opt);
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
yarv_iseq_special_block(yarv_iseq_t *iseq, void *builder)
|
||||||
|
{
|
||||||
|
#if OPT_BLOCKINLINING
|
||||||
|
VALUE parent = Qfalse;
|
||||||
|
VALUE iseqval;
|
||||||
|
|
||||||
|
if (iseq->argc > 1 || iseq->arg_simple == 0) {
|
||||||
|
/* argument check */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iseq->cached_special_block_builder) {
|
||||||
|
if (iseq->cached_special_block_builder == builder) {
|
||||||
|
return iseq->cached_special_block;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
iseq->cached_special_block_builder = (void *)1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iseq->parent_iseq) {
|
||||||
|
parent = iseq->parent_iseq->self;
|
||||||
|
}
|
||||||
|
iseqval = yarv_iseq_new_with_bopt(iseq->node, iseq->name, iseq->file_name,
|
||||||
|
parent, iseq->type,
|
||||||
|
GC_GUARDED_PTR(builder));
|
||||||
|
if (0) {
|
||||||
|
printf("%s\n", RSTRING_PTR(iseq_disasm(iseqval)));
|
||||||
|
}
|
||||||
|
iseq->cached_special_block = iseqval;
|
||||||
|
iseq->cached_special_block_builder = builder;
|
||||||
|
return iseqval;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static NODE *
|
||||||
|
new_block(NODE * head, NODE * tail)
|
||||||
|
{
|
||||||
|
head = NEW_BLOCK(head);
|
||||||
|
tail = NEW_BLOCK(tail);
|
||||||
|
head->nd_next = tail;
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NODE *
|
||||||
|
new_ary(NODE * head, NODE * tail)
|
||||||
|
{
|
||||||
|
head = NEW_ARRAY(head);
|
||||||
|
head->nd_next = tail;
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NODE *
|
||||||
|
new_assign(NODE * lnode, NODE * rhs)
|
||||||
|
{
|
||||||
|
switch (nd_type(lnode)) {
|
||||||
|
case NODE_LASGN:{
|
||||||
|
return NEW_NODE(NODE_LASGN, lnode->nd_vid, rhs, lnode->nd_cnt);
|
||||||
|
/* NEW_LASGN(lnode->nd_vid, rhs); */
|
||||||
|
}
|
||||||
|
case NODE_GASGN:{
|
||||||
|
return NEW_GASGN(lnode->nd_vid, rhs);
|
||||||
|
}
|
||||||
|
case NODE_DASGN:{
|
||||||
|
return NEW_DASGN(lnode->nd_vid, rhs);
|
||||||
|
}
|
||||||
|
case NODE_ATTRASGN:{
|
||||||
|
NODE *args = 0;
|
||||||
|
if (lnode->nd_args) {
|
||||||
|
args = NEW_ARRAY(lnode->nd_args->nd_head);
|
||||||
|
args->nd_next = NEW_ARRAY(rhs);
|
||||||
|
args->nd_alen = 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
args = NEW_ARRAY(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NEW_ATTRASGN(lnode->nd_recv,
|
||||||
|
lnode->nd_mid,
|
||||||
|
args);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
rb_bug("unimplemented (block inlining): %s", node_name(nd_type(lnode)));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NODE *
|
||||||
|
build_Integer_times_node(yarv_iseq_t *iseq, NODE * node, NODE * lnode,
|
||||||
|
VALUE param_vars, VALUE local_vars)
|
||||||
|
{
|
||||||
|
/* Special Block for Integer#times
|
||||||
|
{|e, _self|
|
||||||
|
_e = e
|
||||||
|
while(e < _self)
|
||||||
|
e = _e
|
||||||
|
redo_point:
|
||||||
|
BODY
|
||||||
|
next_point:
|
||||||
|
_e = _e.succ
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
{|e, _self|
|
||||||
|
while(e < _self)
|
||||||
|
BODY
|
||||||
|
next_point:
|
||||||
|
e = e.succ
|
||||||
|
end
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
ID _self = rb_intern("#_self");
|
||||||
|
if (iseq->argc == 0) {
|
||||||
|
ID e = rb_intern("#e");
|
||||||
|
rb_ary_push(param_vars, ID2SYM(e));
|
||||||
|
rb_ary_push(param_vars, ID2SYM(_self));
|
||||||
|
iseq->argc += 2;
|
||||||
|
|
||||||
|
node =
|
||||||
|
NEW_WHILE(NEW_CALL
|
||||||
|
(NEW_DVAR(e), idLT, new_ary(NEW_DVAR(_self), 0)),
|
||||||
|
new_block(NEW_OPTBLOCK(node),
|
||||||
|
NEW_DASGN(e,
|
||||||
|
NEW_CALL(NEW_DVAR(e), idSucc, 0))),
|
||||||
|
Qundef);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ID _e = rb_intern("#_e");
|
||||||
|
ID e = SYM2ID(rb_ary_entry(param_vars, 0));
|
||||||
|
NODE *assign;
|
||||||
|
|
||||||
|
rb_ary_push(param_vars, ID2SYM(_self));
|
||||||
|
rb_ary_push(local_vars, ID2SYM(_e));
|
||||||
|
iseq->argc++;
|
||||||
|
|
||||||
|
if (nd_type(lnode) == NODE_DASGN_CURR) {
|
||||||
|
assign = NEW_DASGN(e, NEW_DVAR(_e));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assign = new_assign(lnode, NEW_DVAR(_e));
|
||||||
|
}
|
||||||
|
|
||||||
|
node =
|
||||||
|
new_block(NEW_DASGN(_e, NEW_DVAR(e)),
|
||||||
|
NEW_WHILE(NEW_CALL
|
||||||
|
(NEW_DVAR(_e), idLT,
|
||||||
|
new_ary(NEW_DVAR(_self), 0)),
|
||||||
|
new_block(assign,
|
||||||
|
new_block(NEW_OPTBLOCK(node),
|
||||||
|
NEW_DASGN(_e,
|
||||||
|
NEW_CALL
|
||||||
|
(NEW_DVAR(_e),
|
||||||
|
idSucc, 0)))),
|
||||||
|
Qundef));
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
yarv_invoke_Integer_times_special_block(VALUE num)
|
||||||
|
{
|
||||||
|
yarv_thread_t *th = GET_THREAD();
|
||||||
|
yarv_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
|
||||||
|
|
||||||
|
if (orig_block && BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
|
||||||
|
VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq,
|
||||||
|
build_Integer_times_node);
|
||||||
|
yarv_iseq_t *tsiseq;
|
||||||
|
VALUE argv[2], val;
|
||||||
|
|
||||||
|
if (tsiseqval) {
|
||||||
|
yarv_block_t block = *orig_block;
|
||||||
|
GetISeqPtr(tsiseqval, tsiseq);
|
||||||
|
block.iseq = tsiseq;
|
||||||
|
th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
|
||||||
|
argv[0] = INT2FIX(0);
|
||||||
|
argv[1] = num;
|
||||||
|
val = th_invoke_yield(th, 2, argv);
|
||||||
|
if (val == Qundef) {
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Qundef;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NODE *
|
||||||
|
build_Range_each_node(yarv_iseq_t *iseq, NODE * node, NODE * lnode,
|
||||||
|
VALUE param_vars, VALUE local_vars, ID mid)
|
||||||
|
{
|
||||||
|
/* Special Block for Range#each
|
||||||
|
{|e, _last|
|
||||||
|
_e = e
|
||||||
|
while _e < _last
|
||||||
|
e = _e
|
||||||
|
next_point:
|
||||||
|
BODY
|
||||||
|
redo_point:
|
||||||
|
_e = _e.succ
|
||||||
|
end
|
||||||
|
}
|
||||||
|
{|e, _last|
|
||||||
|
while e < _last
|
||||||
|
BODY
|
||||||
|
redo_point:
|
||||||
|
e = e.succ
|
||||||
|
end
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
ID _last = rb_intern("#_last");
|
||||||
|
if (iseq->argc == 0) {
|
||||||
|
ID e = rb_intern("#e");
|
||||||
|
rb_ary_push(param_vars, ID2SYM(e));
|
||||||
|
rb_ary_push(param_vars, ID2SYM(_last));
|
||||||
|
iseq->argc += 2;
|
||||||
|
|
||||||
|
node =
|
||||||
|
NEW_WHILE(NEW_CALL(NEW_DVAR(e), mid, new_ary(NEW_DVAR(_last), 0)),
|
||||||
|
new_block(NEW_OPTBLOCK(node),
|
||||||
|
NEW_DASGN(e,
|
||||||
|
NEW_CALL(NEW_DVAR(e), idSucc, 0))),
|
||||||
|
Qundef);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ID _e = rb_intern("#_e");
|
||||||
|
ID e = SYM2ID(rb_ary_entry(param_vars, 0));
|
||||||
|
NODE *assign;
|
||||||
|
|
||||||
|
rb_ary_push(param_vars, ID2SYM(_last));
|
||||||
|
rb_ary_push(local_vars, ID2SYM(_e));
|
||||||
|
iseq->argc++;
|
||||||
|
|
||||||
|
if (nd_type(lnode) == NODE_DASGN_CURR) {
|
||||||
|
assign = NEW_DASGN(e, NEW_DVAR(_e));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assign = new_assign(lnode, NEW_DVAR(_e));
|
||||||
|
}
|
||||||
|
|
||||||
|
node =
|
||||||
|
new_block(NEW_DASGN(_e, NEW_DVAR(e)),
|
||||||
|
NEW_WHILE(NEW_CALL
|
||||||
|
(NEW_DVAR(_e), mid,
|
||||||
|
new_ary(NEW_DVAR(_last), 0)),
|
||||||
|
new_block(assign,
|
||||||
|
new_block(NEW_OPTBLOCK(node),
|
||||||
|
NEW_DASGN(_e,
|
||||||
|
NEW_CALL
|
||||||
|
(NEW_DVAR(_e),
|
||||||
|
idSucc, 0)))),
|
||||||
|
Qundef));
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NODE *
|
||||||
|
build_Range_each_node_LE(yarv_iseq_t *iseq, NODE * node, NODE * lnode,
|
||||||
|
VALUE param_vars, VALUE local_vars)
|
||||||
|
{
|
||||||
|
return build_Range_each_node(iseq, node, lnode,
|
||||||
|
param_vars, local_vars, idLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NODE *
|
||||||
|
build_Range_each_node_LT(yarv_iseq_t *iseq, NODE * node, NODE * lnode,
|
||||||
|
VALUE param_vars, VALUE local_vars)
|
||||||
|
{
|
||||||
|
return build_Range_each_node(iseq, node, lnode,
|
||||||
|
param_vars, local_vars, idLT);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
yarv_invoke_Range_each_special_block(VALUE range,
|
||||||
|
VALUE beg, VALUE end, int excl)
|
||||||
|
{
|
||||||
|
yarv_thread_t *th = GET_THREAD();
|
||||||
|
yarv_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
|
||||||
|
|
||||||
|
if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
|
||||||
|
void *builder =
|
||||||
|
excl ? build_Range_each_node_LT : build_Range_each_node_LE;
|
||||||
|
VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq, builder);
|
||||||
|
yarv_iseq_t *tsiseq;
|
||||||
|
VALUE argv[2];
|
||||||
|
|
||||||
|
if (tsiseqval) {
|
||||||
|
VALUE val;
|
||||||
|
yarv_block_t block = *orig_block;
|
||||||
|
GetISeqPtr(tsiseqval, tsiseq);
|
||||||
|
block.iseq = tsiseq;
|
||||||
|
th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
|
||||||
|
argv[0] = beg;
|
||||||
|
argv[1] = end;
|
||||||
|
val = th_invoke_yield(th, 2, argv);
|
||||||
|
if (val == Qundef) {
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Qundef;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static NODE *
|
||||||
|
build_Array_each_node(yarv_iseq_t *iseq, NODE * node, NODE * lnode,
|
||||||
|
VALUE param_vars, VALUE local_vars)
|
||||||
|
{
|
||||||
|
/* Special block for Array#each
|
||||||
|
ary.each{|e|
|
||||||
|
BODY
|
||||||
|
}
|
||||||
|
=>
|
||||||
|
{|e, _self|
|
||||||
|
_i = 0
|
||||||
|
while _i < _self.length
|
||||||
|
e = _self[_i]
|
||||||
|
redo_point:
|
||||||
|
BODY
|
||||||
|
next_point:
|
||||||
|
_i = _i.succ
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
ary.each{
|
||||||
|
BODY
|
||||||
|
}
|
||||||
|
=>
|
||||||
|
{|_i, _self|
|
||||||
|
_i = 0
|
||||||
|
while _i < _self.length
|
||||||
|
redo_point:
|
||||||
|
BODY
|
||||||
|
next_point:
|
||||||
|
_i = _i.succ
|
||||||
|
end
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
ID _self = rb_intern("#_self");
|
||||||
|
ID _i = rb_intern("#_i");
|
||||||
|
|
||||||
|
if (iseq->argc == 0) {
|
||||||
|
ID _e = rb_intern("#_e");
|
||||||
|
rb_ary_push(param_vars, ID2SYM(_e));
|
||||||
|
rb_ary_push(param_vars, ID2SYM(_self));
|
||||||
|
iseq->argc += 2;
|
||||||
|
rb_ary_push(local_vars, ID2SYM(_i));
|
||||||
|
|
||||||
|
node =
|
||||||
|
new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))),
|
||||||
|
NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT,
|
||||||
|
new_ary(NEW_CALL
|
||||||
|
(NEW_DVAR(_self), idLength,
|
||||||
|
0), 0)),
|
||||||
|
new_block(NEW_OPTBLOCK(node),
|
||||||
|
NEW_DASGN(_i,
|
||||||
|
NEW_CALL(NEW_DVAR(_i),
|
||||||
|
idSucc, 0))),
|
||||||
|
Qundef));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ID e = SYM2ID(rb_ary_entry(param_vars, 0));
|
||||||
|
NODE *assign;
|
||||||
|
|
||||||
|
rb_ary_push(param_vars, ID2SYM(_self));
|
||||||
|
iseq->argc++;
|
||||||
|
rb_ary_push(local_vars, ID2SYM(_i));
|
||||||
|
|
||||||
|
if (nd_type(lnode) == NODE_DASGN_CURR) {
|
||||||
|
assign = NEW_DASGN(e,
|
||||||
|
NEW_CALL(NEW_DVAR(_self), idAREF,
|
||||||
|
new_ary(NEW_DVAR(_i), 0)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assign = new_assign(lnode,
|
||||||
|
NEW_CALL(NEW_DVAR(_self), idAREF,
|
||||||
|
new_ary(NEW_DVAR(_i), 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
node =
|
||||||
|
new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))),
|
||||||
|
NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT,
|
||||||
|
new_ary(NEW_CALL
|
||||||
|
(NEW_DVAR(_self), idLength,
|
||||||
|
0), 0)), new_block(assign,
|
||||||
|
new_block
|
||||||
|
(NEW_OPTBLOCK
|
||||||
|
(node),
|
||||||
|
NEW_DASGN
|
||||||
|
(_i,
|
||||||
|
NEW_CALL
|
||||||
|
(NEW_DVAR
|
||||||
|
(_i),
|
||||||
|
idSucc,
|
||||||
|
0)))),
|
||||||
|
Qundef));
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
yarv_invoke_Array_each_special_block(VALUE ary)
|
||||||
|
{
|
||||||
|
yarv_thread_t *th = GET_THREAD();
|
||||||
|
yarv_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
|
||||||
|
|
||||||
|
if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
|
||||||
|
VALUE tsiseqval = yarv_iseq_special_block(orig_block->iseq,
|
||||||
|
build_Array_each_node);
|
||||||
|
yarv_iseq_t *tsiseq;
|
||||||
|
VALUE argv[2];
|
||||||
|
|
||||||
|
if (tsiseqval) {
|
||||||
|
VALUE val;
|
||||||
|
yarv_block_t block = *orig_block;
|
||||||
|
GetISeqPtr(tsiseqval, tsiseq);
|
||||||
|
block.iseq = tsiseq;
|
||||||
|
th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
|
||||||
|
argv[0] = 0;
|
||||||
|
argv[1] = ary;
|
||||||
|
val = th_invoke_yield(th, 2, argv);
|
||||||
|
if (val == Qundef) {
|
||||||
|
return ary;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Qundef;
|
||||||
|
}
|
94
call_cfunc.ci
Normal file
94
call_cfunc.ci
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/* -*-c-*- */
|
||||||
|
|
||||||
|
/* from ruby1.9/eval.c */
|
||||||
|
|
||||||
|
static inline VALUE
|
||||||
|
call_cfunc(func, recv, len, argc, argv)
|
||||||
|
VALUE (*func) ();
|
||||||
|
VALUE recv;
|
||||||
|
int len, argc;
|
||||||
|
const VALUE *argv;
|
||||||
|
{
|
||||||
|
// printf("len: %d, argc: %d\n", len, argc);
|
||||||
|
|
||||||
|
if (len >= 0 && argc != len) {
|
||||||
|
rb_raise(rb_eArgError, "wrong number of arguments(%d for %d)",
|
||||||
|
argc, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case -2:
|
||||||
|
return (*func) (recv, rb_ary_new4(argc, argv));
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
return (*func) (argc, argv, recv);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
return (*func) (recv);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
return (*func) (recv, argv[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
return (*func) (recv, argv[0], argv[1]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3]);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4]);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||||
|
argv[5]);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||||
|
argv[5], argv[6]);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||||
|
argv[5], argv[6], argv[7]);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||||
|
argv[5], argv[6], argv[7], argv[8]);
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||||
|
argv[5], argv[6], argv[7], argv[8], argv[9]);
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||||
|
argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||||
|
argv[10]);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||||
|
argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||||
|
argv[10], argv[11]);
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||||
|
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||||
|
argv[11], argv[12]);
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||||
|
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||||
|
argv[11], argv[12], argv[13]);
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
return (*func) (recv, argv[0], argv[1], argv[2], argv[3], argv[4],
|
||||||
|
argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||||
|
argv[11], argv[12], argv[13], argv[14]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rb_raise(rb_eArgError, "too many arguments(%d)", len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Qnil; /* not reached */
|
||||||
|
}
|
81
class.c
81
class.c
|
@ -56,10 +56,26 @@ rb_class_new(VALUE super)
|
||||||
return rb_class_boot(super);
|
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
403
common.mk
|
@ -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
|
||||||
|
|
||||||
|
|
210
compile.h
Normal file
210
compile.h
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/**********************************************************************
|
||||||
|
|
||||||
|
compile.h -
|
||||||
|
|
||||||
|
$Author$
|
||||||
|
$Date$
|
||||||
|
created at: 04/01/01 23:36:57 JST
|
||||||
|
|
||||||
|
Copyright (C) 2004-2006 Koichi Sasada
|
||||||
|
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _COMPILER_H_INCLUDED_
|
||||||
|
#define _COMPILER_H_INCLUDED_
|
||||||
|
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#if YARVDEBUG > CPDEBUG
|
||||||
|
#undef CPDEBUG
|
||||||
|
#define CPDEBUG YARVDEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* */
|
||||||
|
/**
|
||||||
|
* debug function(macro) interface depend on CPDEBUG
|
||||||
|
*
|
||||||
|
* debug level:
|
||||||
|
* 0: no debug output
|
||||||
|
* 1: show node type
|
||||||
|
* 2: show node important parameters
|
||||||
|
* ...
|
||||||
|
* 5: show other parameters
|
||||||
|
* 10: show every AST array
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#undef CPDEBUG
|
||||||
|
#define CPDEBUG 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CPDEBUG > 0
|
||||||
|
|
||||||
|
#define debugp(header, value) \
|
||||||
|
(debug_indent(0, CPDEBUG, gl_node_level * 2), \
|
||||||
|
debug_value(0, CPDEBUG, header, value))
|
||||||
|
|
||||||
|
#define debugi(header, id) \
|
||||||
|
(debug_indent(0, CPDEBUG, gl_node_level * 2), \
|
||||||
|
debug_id(0, CPDEBUG, header, id))
|
||||||
|
|
||||||
|
#define debugp_param(header, value) \
|
||||||
|
(debug_indent(1, CPDEBUG, gl_node_level * 2), \
|
||||||
|
debug_value(1, CPDEBUG, header, value))
|
||||||
|
|
||||||
|
#define debugp_verbose(header, value) \
|
||||||
|
(debug_indent(2, CPDEBUG, gl_node_level * 2), \
|
||||||
|
debug_value(2, CPDEBUG, header, value))
|
||||||
|
|
||||||
|
#define debugp_verbose_node(header, value) \
|
||||||
|
(debug_indent(10, CPDEBUG, gl_node_level * 2), \
|
||||||
|
debug_value(10, CPDEBUG, header, value))
|
||||||
|
|
||||||
|
#define debug_nodeprint(node) \
|
||||||
|
debug_indent(-1, CPDEBUG, gl_node_level*2); \
|
||||||
|
printf("node: %s (%d)\n", node_name(nd_type(node)), nd_line(node)); \
|
||||||
|
gl_node_level ++;
|
||||||
|
|
||||||
|
#define debug_nodeprint_close() gl_node_level --;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline ID
|
||||||
|
r_id(ID id)
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline VALUE
|
||||||
|
r_value(VALUE value)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define debugi(header, id) r_id(id)
|
||||||
|
#define debugp(header, value) r_value(value)
|
||||||
|
#define debugp_verbose(header, value) r_value(value)
|
||||||
|
#define debugp_verbose_node(header, value) r_value(value)
|
||||||
|
#define debugp_param(header, value) r_value(value)
|
||||||
|
#define debug_nodeprint(node)
|
||||||
|
#define debug_nodeprint_close()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CPDEBUG > 1
|
||||||
|
#define debugs debug_indent(-1, CPDEBUG, gl_node_level*2), printf
|
||||||
|
#define debug_compile(msg, v) (debug_indent(-1, CPDEBUG, gl_node_level*2), printf("%s", msg), (v))
|
||||||
|
#else
|
||||||
|
#define debugs if(0)printf
|
||||||
|
#define debug_compile(msg, v) (v)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* create new label */
|
||||||
|
#define NEW_LABEL(l) new_label_body(iseq, l)
|
||||||
|
|
||||||
|
#define iseq_filename(iseq) \
|
||||||
|
(((yarv_iseq_t*)DATA_PTR(iseq))->file_name)
|
||||||
|
|
||||||
|
#define NEW_ISEQVAL(node, name, type) \
|
||||||
|
new_child_iseq(iseq, node, name, 0, type)
|
||||||
|
|
||||||
|
#define NEW_CHILD_ISEQVAL(node, name, type) \
|
||||||
|
new_child_iseq(iseq, node, name, iseq->self, type)
|
||||||
|
|
||||||
|
#define NEW_SPECIAQL_BLOCK_ISEQVAL(iseq, sym) \
|
||||||
|
new_child_iseq(iseq, iseq->node, iseq->name, iseq->parent_iseq, iseq->type, sym)
|
||||||
|
|
||||||
|
/* add instructions */
|
||||||
|
#define ADD_SEQ(seq1, seq2) \
|
||||||
|
APPEND_LIST(seq1, seq2)
|
||||||
|
|
||||||
|
/* add an instruction */
|
||||||
|
#define ADD_INSN(seq, line, insn) \
|
||||||
|
ADD_ELEM(seq, (LINK_ELEMENT *) new_insn_body(iseq, line, BIN(insn), 0))
|
||||||
|
|
||||||
|
/* add an instruction with label operand */
|
||||||
|
#define ADD_INSNL(seq, line, insn, label) \
|
||||||
|
ADD_ELEM(seq, (LINK_ELEMENT *) \
|
||||||
|
new_insn_body(iseq, line, BIN(insn), 1, (VALUE)label))
|
||||||
|
|
||||||
|
/* add an instruction with some operands (1, 2, 3, 5) */
|
||||||
|
#define ADD_INSN1(seq, line, insn, op1) \
|
||||||
|
ADD_ELEM(seq, (LINK_ELEMENT *) \
|
||||||
|
new_insn_body(iseq, line, BIN(insn), 1, (VALUE)op1))
|
||||||
|
|
||||||
|
#define ADD_INSN2(seq, line, insn, op1, op2) \
|
||||||
|
ADD_ELEM(seq, (LINK_ELEMENT *) \
|
||||||
|
new_insn_body(iseq, line, BIN(insn), 2, (VALUE)op1, (VALUE)op2))
|
||||||
|
|
||||||
|
#define ADD_INSN3(seq, line, insn, op1, op2, op3) \
|
||||||
|
ADD_ELEM(seq, (LINK_ELEMENT *) \
|
||||||
|
new_insn_body(iseq, line, BIN(insn), 3, (VALUE)op1, (VALUE)op2, (VALUE)op3))
|
||||||
|
|
||||||
|
/* Specific Insn factory */
|
||||||
|
#define ADD_SEND(seq, line, id, argc) \
|
||||||
|
ADD_SEND_R(seq, line, id, argc, (VALUE)Qfalse, (VALUE)INT2FIX(0))
|
||||||
|
|
||||||
|
#define ADD_CALL(seq, line, id, argc) \
|
||||||
|
ADD_SEND_R(seq, line, id, argc, (VALUE)Qfalse, (VALUE)INT2FIX(VM_CALL_FCALL_BIT))
|
||||||
|
|
||||||
|
#define ADD_SEND_R(seq, line, id, argc, block, flag) \
|
||||||
|
ADD_ELEM(seq, (LINK_ELEMENT *) \
|
||||||
|
new_insn_send(iseq, line, \
|
||||||
|
(VALUE)id, (VALUE)argc, (VALUE)block, (VALUE)flag))
|
||||||
|
|
||||||
|
/* add label */
|
||||||
|
#define ADD_LABEL(seq, label) \
|
||||||
|
ADD_ELEM(seq, (LINK_ELEMENT *)label)
|
||||||
|
|
||||||
|
#define ADD_CATCH_ENTRY(type, ls, le, iseqv, lc) \
|
||||||
|
(tmp = rb_ary_new(), \
|
||||||
|
rb_ary_push(tmp, type), \
|
||||||
|
rb_ary_push(tmp, (VALUE) ls | 1), \
|
||||||
|
rb_ary_push(tmp, (VALUE) le | 1), \
|
||||||
|
rb_ary_push(tmp, iseqv), \
|
||||||
|
rb_ary_push(tmp, (VALUE) lc | 1), \
|
||||||
|
rb_ary_push(iseq->compile_data->catch_table_ary, tmp))
|
||||||
|
|
||||||
|
/* compile node */
|
||||||
|
#define COMPILE(anchor, desc, node) \
|
||||||
|
(debug_compile("== " desc "\n", \
|
||||||
|
iseq_compile_each(iseq, anchor, node, 0)))
|
||||||
|
|
||||||
|
/* compile node, this node's value will be poped */
|
||||||
|
#define COMPILE_POPED(anchor, desc, node) \
|
||||||
|
(debug_compile("== " desc "\n", \
|
||||||
|
iseq_compile_each(iseq, anchor, node, 1)))
|
||||||
|
|
||||||
|
/* compile node, which is poped when 'poped' is true */
|
||||||
|
#define COMPILE_(anchor, desc, node, poped) \
|
||||||
|
(debug_compile("== " desc "\n", \
|
||||||
|
iseq_compile_each(iseq, anchor, node, poped)))
|
||||||
|
|
||||||
|
#define OPERAND_AT(insn, idx) \
|
||||||
|
(((INSN*)(insn))->operands[idx])
|
||||||
|
|
||||||
|
#define INSN_OF(insn) \
|
||||||
|
(((INSN*)(insn))->insn_id)
|
||||||
|
|
||||||
|
/* error */
|
||||||
|
#define COMPILE_ERROR(strs) \
|
||||||
|
{ \
|
||||||
|
VALUE tmp = GET_THREAD()->errinfo; \
|
||||||
|
if(CPDEBUG)rb_bug strs; \
|
||||||
|
GET_THREAD()->errinfo = iseq->compile_data->err_info; \
|
||||||
|
rb_compile_error strs; \
|
||||||
|
iseq->compile_data->err_info = GET_THREAD()->errinfo; \
|
||||||
|
GET_THREAD()->errinfo = tmp; \
|
||||||
|
ret = 0; \
|
||||||
|
break; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define COMPILE_OK 1
|
||||||
|
#define COMPILE_NG 0
|
||||||
|
|
||||||
|
#define DECL_ANCHOR(name) \
|
||||||
|
LINK_ANCHOR name##_body__ = {{0,}, &name##_body__.anchor}; \
|
||||||
|
LINK_ANCHOR *name = & name##_body__
|
||||||
|
|
||||||
|
#endif // _COMPILER_H_INCLUDED_
|
15
configure.in
15
configure.in
|
@ -71,6 +71,7 @@ fi
|
||||||
if test "$program_prefix" = NONE; then
|
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
71
debug.c
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/**********************************************************************
|
||||||
|
|
||||||
|
debug.c -
|
||||||
|
|
||||||
|
$Author$
|
||||||
|
$Date$
|
||||||
|
created at: 04/08/25 02:31:54 JST
|
||||||
|
|
||||||
|
Copyright (C) 2004-2006 Koichi Sasada
|
||||||
|
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#include "ruby.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
debug_indent(int level, int debug_level, int indent_level)
|
||||||
|
{
|
||||||
|
if (level < debug_level) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < indent_level; i++) {
|
||||||
|
fprintf(stderr, " ");
|
||||||
|
}
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
debug_value(int level, int debug_level, char *header, VALUE obj)
|
||||||
|
{
|
||||||
|
if (level < debug_level) {
|
||||||
|
VALUE str;
|
||||||
|
str = rb_inspect(obj);
|
||||||
|
fprintf(stderr, "DBG> %s: %s\n", header,
|
||||||
|
obj == -1 ? "" : StringValueCStr(str));
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
debug_v(VALUE v)
|
||||||
|
{
|
||||||
|
debug_value(0, 1, "", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
ID
|
||||||
|
debug_id(int level, int debug_level, char *header, ID id)
|
||||||
|
{
|
||||||
|
if (level < debug_level) {
|
||||||
|
fprintf(stderr, "DBG> %s: %s\n", header, rb_id2name(id));
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gc_check_func(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
#define GCMKMAX 0x10
|
||||||
|
for (i = 0; i < GCMKMAX; i++) {
|
||||||
|
rb_ary_new2(1000);
|
||||||
|
}
|
||||||
|
rb_gc();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
debug_breakpoint(void)
|
||||||
|
{
|
||||||
|
/* */
|
||||||
|
}
|
47
debug.h
Normal file
47
debug.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/**********************************************************************
|
||||||
|
|
||||||
|
debug.h - YARV Debug function interface
|
||||||
|
|
||||||
|
$Author$
|
||||||
|
$Date$
|
||||||
|
created at: 04/08/25 02:33:49 JST
|
||||||
|
|
||||||
|
Copyright (C) 2004-2006 Koichi Sasada
|
||||||
|
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _DEBUG_H_INCLUDED_
|
||||||
|
#define _DEBUG_H_INCLUDED_
|
||||||
|
|
||||||
|
#include <ruby.h>
|
||||||
|
|
||||||
|
VALUE debug_value(int level, int debug_level, char *header, VALUE v);
|
||||||
|
ID debug_id(int level, int debug_level, char *header, ID id);
|
||||||
|
void debug_indent(int level, int debug_level, int indent_level);
|
||||||
|
|
||||||
|
#define dpv(h,v) debug_value(-1, 0, h, v)
|
||||||
|
#define dp(v) debug_value(-1, 0, "", v)
|
||||||
|
#define dpi(i) debug_id (-1, 0, "", i)
|
||||||
|
#define bp() debug_breakpoint()
|
||||||
|
|
||||||
|
void gc_check_func();
|
||||||
|
|
||||||
|
#if GCDEBUG == 1
|
||||||
|
|
||||||
|
#define GC_CHECK() \
|
||||||
|
gc_check_func()
|
||||||
|
|
||||||
|
#elif GCDEBUG == 2
|
||||||
|
|
||||||
|
#define GC_CHECK() \
|
||||||
|
(printf("** %s:%d gc start\n", __FILE__, __LINE__), \
|
||||||
|
gc_check_func(), \
|
||||||
|
printf("** end\n"))
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define GC_CHECK()
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _DEBUG_H_INCLUDED_
|
6917
doc/ChangeLog-YARV
Normal file
6917
doc/ChangeLog-YARV
Normal file
File diff suppressed because it is too large
Load diff
57
error.c
57
error.c
|
@ -11,8 +11,8 @@
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
#include "ruby.h"
|
#include "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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
250
eval_error.h
Normal file
250
eval_error.h
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
/*
|
||||||
|
* included by eval.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SET_CURRENT_SOURCE() ((void)0)
|
||||||
|
|
||||||
|
void
|
||||||
|
ruby_set_current_source(void)
|
||||||
|
{
|
||||||
|
if (ruby_current_node) {
|
||||||
|
ruby_sourcefile = ruby_current_node->nd_file;
|
||||||
|
ruby_sourceline = nd_line(ruby_current_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
warn_printf(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_init_list(args, fmt);
|
||||||
|
vsnprintf(buf, BUFSIZ, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
rb_write_error(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define warn_print(x) rb_write_error(x)
|
||||||
|
#define warn_print2(x,l) rb_write_error2(x,l)
|
||||||
|
|
||||||
|
static void
|
||||||
|
error_pos(void)
|
||||||
|
{
|
||||||
|
ruby_set_current_source();
|
||||||
|
if (ruby_sourcefile) {
|
||||||
|
if (ruby_sourceline == 0) {
|
||||||
|
warn_printf("%s", ruby_sourcefile);
|
||||||
|
}
|
||||||
|
else if (rb_frame_callee()) {
|
||||||
|
warn_printf("%s:%d:in `%s'", ruby_sourcefile, ruby_sourceline,
|
||||||
|
rb_id2name(rb_frame_callee()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
warn_printf("%s:%d", ruby_sourcefile, ruby_sourceline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
get_backtrace(VALUE info)
|
||||||
|
{
|
||||||
|
if (NIL_P(info))
|
||||||
|
return Qnil;
|
||||||
|
info = rb_funcall(info, rb_intern("backtrace"), 0);
|
||||||
|
if (NIL_P(info))
|
||||||
|
return Qnil;
|
||||||
|
return rb_check_array_type(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_backtrace(VALUE info, VALUE bt)
|
||||||
|
{
|
||||||
|
rb_funcall(info, rb_intern("set_backtrace"), 1, bt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
error_print(void)
|
||||||
|
{
|
||||||
|
VALUE errat = Qnil; /* OK */
|
||||||
|
volatile VALUE eclass, e;
|
||||||
|
char *einfo;
|
||||||
|
long elen;
|
||||||
|
|
||||||
|
if (NIL_P(GET_THREAD()->errinfo))
|
||||||
|
return;
|
||||||
|
|
||||||
|
PUSH_TAG(PROT_NONE);
|
||||||
|
if (EXEC_TAG() == 0) {
|
||||||
|
errat = get_backtrace(GET_THREAD()->errinfo);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errat = Qnil;
|
||||||
|
}
|
||||||
|
if (EXEC_TAG())
|
||||||
|
goto error;
|
||||||
|
if (NIL_P(errat)) {
|
||||||
|
ruby_set_current_source();
|
||||||
|
if (ruby_sourcefile)
|
||||||
|
warn_printf("%s:%d", ruby_sourcefile, ruby_sourceline);
|
||||||
|
else
|
||||||
|
warn_printf("%d", ruby_sourceline);
|
||||||
|
}
|
||||||
|
else if (RARRAY_LEN(errat) == 0) {
|
||||||
|
error_pos();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VALUE mesg = RARRAY_PTR(errat)[0];
|
||||||
|
|
||||||
|
if (NIL_P(mesg))
|
||||||
|
error_pos();
|
||||||
|
else {
|
||||||
|
warn_print2(RSTRING_PTR(mesg), RSTRING_LEN(mesg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eclass = CLASS_OF(GET_THREAD()->errinfo);
|
||||||
|
if (EXEC_TAG() == 0) {
|
||||||
|
e = rb_funcall(GET_THREAD()->errinfo, rb_intern("message"), 0, 0);
|
||||||
|
StringValue(e);
|
||||||
|
einfo = RSTRING_PTR(e);
|
||||||
|
elen = RSTRING_LEN(e);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
einfo = "";
|
||||||
|
elen = 0;
|
||||||
|
}
|
||||||
|
if (EXEC_TAG())
|
||||||
|
goto error;
|
||||||
|
if (eclass == rb_eRuntimeError && elen == 0) {
|
||||||
|
warn_print(": unhandled exception\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VALUE epath;
|
||||||
|
|
||||||
|
epath = rb_class_name(eclass);
|
||||||
|
if (elen == 0) {
|
||||||
|
warn_print(": ");
|
||||||
|
warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
|
||||||
|
warn_print("\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char *tail = 0;
|
||||||
|
long len = elen;
|
||||||
|
|
||||||
|
if (RSTRING_PTR(epath)[0] == '#')
|
||||||
|
epath = 0;
|
||||||
|
if (tail = memchr(einfo, '\n', elen)) {
|
||||||
|
len = tail - einfo;
|
||||||
|
tail++; /* skip newline */
|
||||||
|
}
|
||||||
|
warn_print(": ");
|
||||||
|
warn_print2(einfo, len);
|
||||||
|
if (epath) {
|
||||||
|
warn_print(" (");
|
||||||
|
warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath));
|
||||||
|
warn_print(")\n");
|
||||||
|
}
|
||||||
|
if (tail) {
|
||||||
|
warn_print2(tail, elen - len - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NIL_P(errat)) {
|
||||||
|
long i;
|
||||||
|
long len = RARRAY_LEN(errat);
|
||||||
|
VALUE *ptr = RARRAY_PTR(errat);
|
||||||
|
|
||||||
|
#define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
|
||||||
|
#define TRACE_HEAD 8
|
||||||
|
#define TRACE_TAIL 5
|
||||||
|
|
||||||
|
for (i = 1; i < len; i++) {
|
||||||
|
if (TYPE(ptr[i]) == T_STRING) {
|
||||||
|
warn_printf("\tfrom %s\n", RSTRING_PTR(ptr[i]));
|
||||||
|
}
|
||||||
|
if (i == TRACE_HEAD && len > TRACE_MAX) {
|
||||||
|
warn_printf("\t ... %ld levels...\n",
|
||||||
|
len - TRACE_HEAD - TRACE_TAIL);
|
||||||
|
i = len - TRACE_TAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error:
|
||||||
|
POP_TAG();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_undef(VALUE klass, ID id)
|
||||||
|
{
|
||||||
|
rb_name_error(id, "undefined method `%s' for %s `%s'",
|
||||||
|
rb_id2name(id),
|
||||||
|
(TYPE(klass) == T_MODULE) ? "module" : "class",
|
||||||
|
rb_class2name(klass));
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE exception_error;
|
||||||
|
VALUE sysstack_error;
|
||||||
|
|
||||||
|
static int
|
||||||
|
sysexit_status(VALUE err)
|
||||||
|
{
|
||||||
|
VALUE st = rb_iv_get(err, "status");
|
||||||
|
return NUM2INT(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
error_handle(int ex)
|
||||||
|
{
|
||||||
|
int status = EXIT_FAILURE;
|
||||||
|
yarv_thread_t *th = GET_THREAD();
|
||||||
|
|
||||||
|
if (thread_set_raised(th))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
switch (ex & TAG_MASK) {
|
||||||
|
case 0:
|
||||||
|
status = EXIT_SUCCESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TAG_RETURN:
|
||||||
|
error_pos();
|
||||||
|
warn_print(": unexpected return\n");
|
||||||
|
break;
|
||||||
|
case TAG_NEXT:
|
||||||
|
error_pos();
|
||||||
|
warn_print(": unexpected next\n");
|
||||||
|
break;
|
||||||
|
case TAG_BREAK:
|
||||||
|
error_pos();
|
||||||
|
warn_print(": unexpected break\n");
|
||||||
|
break;
|
||||||
|
case TAG_REDO:
|
||||||
|
error_pos();
|
||||||
|
warn_print(": unexpected redo\n");
|
||||||
|
break;
|
||||||
|
case TAG_RETRY:
|
||||||
|
error_pos();
|
||||||
|
warn_print(": retry outside of rescue clause\n");
|
||||||
|
break;
|
||||||
|
case TAG_THROW:
|
||||||
|
// TODO: fix me
|
||||||
|
error_pos();
|
||||||
|
warn_printf(": unexpected throw\n");
|
||||||
|
break;
|
||||||
|
case TAG_RAISE:
|
||||||
|
case TAG_FATAL:
|
||||||
|
if (rb_obj_is_kind_of(GET_THREAD()->errinfo, rb_eSystemExit)) {
|
||||||
|
status = sysexit_status(GET_THREAD()->errinfo);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
error_print();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rb_bug("Unknown longjmp status %d", ex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
thread_reset_raised(th);
|
||||||
|
return status;
|
||||||
|
}
|
328
eval_intern.h
Normal file
328
eval_intern.h
Normal file
|
@ -0,0 +1,328 @@
|
||||||
|
|
||||||
|
#ifndef EVAL_INTERN_H_INCLUDED
|
||||||
|
#define EVAL_INTERN_H_INCLUDED
|
||||||
|
|
||||||
|
#define PASS_PASSED_BLOCK() \
|
||||||
|
(GET_THREAD()->passed_block = \
|
||||||
|
GC_GUARDED_PTR_REF((yarv_block_t *)GET_THREAD()->cfp->lfp[0]))
|
||||||
|
|
||||||
|
|
||||||
|
#define UNSUPPORTED(func) \
|
||||||
|
{ \
|
||||||
|
int *a = 0; \
|
||||||
|
fprintf(stderr, "%s", "-- unsupported: " #func "\n"); fflush(stderr); \
|
||||||
|
*a = 0; \
|
||||||
|
rb_bug("unsupported: " #func); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "ruby.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "rubysig.h"
|
||||||
|
#include "yarv.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_STDLIB_H
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
#ifndef EXIT_SUCCESS
|
||||||
|
#define EXIT_SUCCESS 0
|
||||||
|
#endif
|
||||||
|
#ifndef EXIT_FAILURE
|
||||||
|
#define EXIT_FAILURE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
#include "st.h"
|
||||||
|
#include "dln.h"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <crt_externs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Make alloca work the best possible way. */
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# ifndef atarist
|
||||||
|
# ifndef alloca
|
||||||
|
# define alloca __builtin_alloca
|
||||||
|
# endif
|
||||||
|
# endif /* atarist */
|
||||||
|
#else
|
||||||
|
# ifdef HAVE_ALLOCA_H
|
||||||
|
# include <alloca.h>
|
||||||
|
# else
|
||||||
|
# ifdef _AIX
|
||||||
|
#pragma alloca
|
||||||
|
# else
|
||||||
|
# ifndef alloca /* predefined by HP cc +Olibcalls */
|
||||||
|
void *alloca();
|
||||||
|
# endif
|
||||||
|
# endif /* AIX */
|
||||||
|
# endif /* HAVE_ALLOCA_H */
|
||||||
|
#endif /* __GNUC__ */
|
||||||
|
|
||||||
|
#ifdef HAVE_STDARG_PROTOTYPES
|
||||||
|
#include <stdarg.h>
|
||||||
|
#define va_init_list(a,b) va_start(a,b)
|
||||||
|
#else
|
||||||
|
#include <varargs.h>
|
||||||
|
#define va_init_list(a,b) va_start(a)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_STRING_H
|
||||||
|
char *strrchr _((const char *, const char));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __BEOS__
|
||||||
|
#include <net/socket.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __MACOS__
|
||||||
|
#include "macruby_private.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __VMS
|
||||||
|
#include "vmsruby_private.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_CONTEXT
|
||||||
|
|
||||||
|
NORETURN(static void rb_jump_context(rb_jmpbuf_t, int));
|
||||||
|
static inline void
|
||||||
|
rb_jump_context(rb_jmpbuf_t env, int val)
|
||||||
|
{
|
||||||
|
env->status = val;
|
||||||
|
setcontext(&env->context);
|
||||||
|
abort(); /* ensure noreturn */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FUNCTION_CALL_MAY_RETURN_TWICE is a magic for getcontext, gcc,
|
||||||
|
* IA64 register stack and SPARC register window combination problem.
|
||||||
|
*
|
||||||
|
* Assume following code sequence.
|
||||||
|
*
|
||||||
|
* 1. set a register in the register stack/window such as r32/l0.
|
||||||
|
* 2. call getcontext.
|
||||||
|
* 3. use the register.
|
||||||
|
* 4. update the register for other use.
|
||||||
|
* 5. call setcontext indirectly (or directly).
|
||||||
|
*
|
||||||
|
* This code should be run as 1->2->3->4->5->3->4.
|
||||||
|
* But after second getcontext return (second 3),
|
||||||
|
* the register is broken (updated).
|
||||||
|
* It's because getcontext/setcontext doesn't preserve the content of the
|
||||||
|
* register stack/window.
|
||||||
|
*
|
||||||
|
* setjmp also doesn't preserve the content of the register stack/window.
|
||||||
|
* But it has not the problem because gcc knows setjmp may return twice.
|
||||||
|
* gcc detects setjmp and generates setjmp safe code.
|
||||||
|
*
|
||||||
|
* So setjmp call before getcontext call makes the code somewhat safe.
|
||||||
|
* It fix the problem on IA64.
|
||||||
|
* It is not required that setjmp is called at run time, since the problem is
|
||||||
|
* register usage.
|
||||||
|
*
|
||||||
|
* Since the magic setjmp is not enough for SPARC,
|
||||||
|
* inline asm is used to prohibit registers in register windows.
|
||||||
|
*/
|
||||||
|
#if defined (__GNUC__) && (defined(sparc) || defined(__sparc__))
|
||||||
|
#define FUNCTION_CALL_MAY_RETURN_TWICE \
|
||||||
|
({ __asm__ volatile ("" : : : \
|
||||||
|
"%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%o7", \
|
||||||
|
"%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", \
|
||||||
|
"%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%i7"); })
|
||||||
|
#else
|
||||||
|
extern jmp_buf function_call_may_return_twice_jmp_buf;
|
||||||
|
extern int function_call_may_return_twice_false;
|
||||||
|
#define FUNCTION_CALL_MAY_RETURN_TWICE \
|
||||||
|
(function_call_may_return_twice_false ? \
|
||||||
|
setjmp(function_call_may_return_twice_jmp_buf) : \
|
||||||
|
0)
|
||||||
|
#endif
|
||||||
|
#define ruby_longjmp(env, val) rb_jump_context(env, val)
|
||||||
|
#define ruby_setjmp(j) ((j)->status = 0, \
|
||||||
|
FUNCTION_CALL_MAY_RETURN_TWICE, \
|
||||||
|
getcontext(&(j)->context), \
|
||||||
|
(j)->status)
|
||||||
|
#else
|
||||||
|
#if !defined(setjmp) && defined(HAVE__SETJMP)
|
||||||
|
#define ruby_setjmp(env) _setjmp(env)
|
||||||
|
#define ruby_longjmp(env,val) _longjmp(env,val)
|
||||||
|
#else
|
||||||
|
#define ruby_setjmp(env) setjmp(env)
|
||||||
|
#define ruby_longjmp(env,val) longjmp(env,val)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#if defined(__VMS)
|
||||||
|
#pragma nostandard
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_SELECT_H
|
||||||
|
#include <sys/select.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
Solaris sys/select.h switches select to select_large_fdset to support larger
|
||||||
|
file descriptors if FD_SETSIZE is larger than 1024 on 32bit environment.
|
||||||
|
But Ruby doesn't change FD_SETSIZE because fd_set is allocated dynamically.
|
||||||
|
So following definition is required to use select_large_fdset.
|
||||||
|
*/
|
||||||
|
#ifdef HAVE_SELECT_LARGE_FDSET
|
||||||
|
#define select(n, r, w, e, t) select_large_fdset(n, r, w, e, t)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_PARAM_H
|
||||||
|
#include <sys/param.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#define TH_PUSH_TAG(th) do { \
|
||||||
|
yarv_thread_t * const _th = th; \
|
||||||
|
struct yarv_tag _tag; \
|
||||||
|
_tag.tag = 0; \
|
||||||
|
_tag.prev = _th->tag; \
|
||||||
|
_th->tag = &_tag;
|
||||||
|
|
||||||
|
#define TH_POP_TAG() \
|
||||||
|
_th->tag = _tag.prev; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define TH_POP_TAG2() \
|
||||||
|
_th->tag = _tag.prev
|
||||||
|
|
||||||
|
#define PUSH_TAG(ptag) TH_PUSH_TAG(GET_THREAD())
|
||||||
|
#define POP_TAG() TH_POP_TAG()
|
||||||
|
#define POP_TAG_INIT() } while (0)
|
||||||
|
|
||||||
|
#define PUSH_THREAD_TAG() \
|
||||||
|
PUSH_TAG(PROT_THREAD)
|
||||||
|
|
||||||
|
#define POP_THREAD_TAG() \
|
||||||
|
POP_TAG()
|
||||||
|
|
||||||
|
#define PROT_NONE Qfalse /* 0 */
|
||||||
|
#define PROT_THREAD Qtrue /* 2 */
|
||||||
|
#define PROT_FUNC INT2FIX(0) /* 1 */
|
||||||
|
#define PROT_LOOP INT2FIX(1) /* 3 */
|
||||||
|
#define PROT_LAMBDA INT2FIX(2) /* 5 */
|
||||||
|
#define PROT_YIELD INT2FIX(3) /* 7 */
|
||||||
|
#define PROT_TOP INT2FIX(4) /* 9 */
|
||||||
|
|
||||||
|
#define TH_EXEC_TAG() \
|
||||||
|
(FLUSH_REGISTER_WINDOWS, ruby_setjmp(_th->tag->buf))
|
||||||
|
|
||||||
|
#define EXEC_TAG() \
|
||||||
|
TH_EXEC_TAG()
|
||||||
|
|
||||||
|
#define TH_JUMP_TAG(th, st) do { \
|
||||||
|
ruby_longjmp(th->tag->buf,(st)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define JUMP_TAG(st) TH_JUMP_TAG(GET_THREAD(), st)
|
||||||
|
|
||||||
|
#define TAG_RETURN 0x1
|
||||||
|
#define TAG_BREAK 0x2
|
||||||
|
#define TAG_NEXT 0x3
|
||||||
|
#define TAG_RETRY 0x4
|
||||||
|
#define TAG_REDO 0x5
|
||||||
|
#define TAG_RAISE 0x6
|
||||||
|
#define TAG_THROW 0x7
|
||||||
|
#define TAG_FATAL 0x8
|
||||||
|
#define TAG_CONTCALL 0x9
|
||||||
|
#define TAG_THREAD 0xa
|
||||||
|
#define TAG_MASK 0xf
|
||||||
|
|
||||||
|
#define SCOPE_TEST(f) \
|
||||||
|
(ruby_cref()->nd_visi & (f))
|
||||||
|
|
||||||
|
#define SCOPE_CHECK(f) \
|
||||||
|
(ruby_cref()->nd_visi == (f))
|
||||||
|
|
||||||
|
#define SCOPE_SET(f) \
|
||||||
|
{ \
|
||||||
|
ruby_cref()->nd_visi = (f); \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ruby_env {
|
||||||
|
struct ruby_env *prev;
|
||||||
|
struct FRAME *frame;
|
||||||
|
struct SCOPE *scope;
|
||||||
|
struct BLOCK *block;
|
||||||
|
struct iter *iter;
|
||||||
|
struct tag *tag;
|
||||||
|
NODE *cref;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct thread *rb_thread_t;
|
||||||
|
|
||||||
|
extern VALUE rb_cBinding;
|
||||||
|
extern VALUE rb_eThreadError;
|
||||||
|
extern VALUE rb_eLocalJumpError;
|
||||||
|
extern VALUE rb_eSysStackError;
|
||||||
|
extern VALUE exception_error;
|
||||||
|
extern VALUE sysstack_error;
|
||||||
|
|
||||||
|
|
||||||
|
void rb_thread_cleanup _((void));
|
||||||
|
void rb_thread_wait_other_threads _((void));
|
||||||
|
|
||||||
|
int thread_set_raised(yarv_thread_t *th);
|
||||||
|
int thread_reset_raised(yarv_thread_t *th);
|
||||||
|
|
||||||
|
VALUE rb_f_eval(int argc, VALUE *argv, VALUE self);
|
||||||
|
VALUE rb_make_exception _((int argc, VALUE *argv));
|
||||||
|
|
||||||
|
NORETURN(void rb_raise_jump _((VALUE)));
|
||||||
|
NORETURN(void print_undef _((VALUE, ID)));
|
||||||
|
NORETURN(void th_localjump_error(const char *, VALUE, int));
|
||||||
|
NORETURN(void th_jump_tag_but_local_jump(int, VALUE));
|
||||||
|
|
||||||
|
rb_thread_t rb_vm_curr_thread();
|
||||||
|
VALUE th_compile(yarv_thread_t *th, VALUE str, VALUE file, VALUE line);
|
||||||
|
|
||||||
|
NODE *th_get_cref(yarv_thread_t *th, yarv_iseq_t *iseq, yarv_control_frame_t *cfp);
|
||||||
|
NODE *th_cref_push(yarv_thread_t *th, VALUE, int);
|
||||||
|
NODE *th_set_special_cref(yarv_thread_t *th, VALUE *lfp, NODE * cref_stack);
|
||||||
|
|
||||||
|
static yarv_control_frame_t *
|
||||||
|
th_get_ruby_level_cfp(yarv_thread_t *th, yarv_control_frame_t *cfp)
|
||||||
|
{
|
||||||
|
yarv_iseq_t *iseq = 0;
|
||||||
|
while (!YARV_CONTROL_FRAME_STACK_OVERFLOW_P(th, cfp)) {
|
||||||
|
if (YARV_NORMAL_ISEQ_P(cfp->iseq)) {
|
||||||
|
iseq = cfp->iseq;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cfp = YARV_PREVIOUS_CONTROL_FRAME(cfp);
|
||||||
|
}
|
||||||
|
if (!iseq) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return cfp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NODE *
|
||||||
|
ruby_cref()
|
||||||
|
{
|
||||||
|
yarv_thread_t *th = GET_THREAD();
|
||||||
|
yarv_control_frame_t *cfp = th_get_ruby_level_cfp(th, th->cfp);
|
||||||
|
return th_get_cref(th, cfp->iseq, cfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE th_get_cbase(yarv_thread_t *th);
|
||||||
|
|
||||||
|
#define ruby_cbase() th_get_cbase(GET_THREAD())
|
||||||
|
|
||||||
|
#endif /* EVAL_INTERN_H_INCLUDED */
|
411
eval_jump.h
Normal file
411
eval_jump.h
Normal file
|
@ -0,0 +1,411 @@
|
||||||
|
/*
|
||||||
|
* from eval.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "eval_intern.h"
|
||||||
|
|
||||||
|
NORETURN(static VALUE rb_f_throw _((int, VALUE *)));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* throw(symbol [, obj])
|
||||||
|
*
|
||||||
|
* Transfers control to the end of the active +catch+ block
|
||||||
|
* waiting for _symbol_. Raises +NameError+ if there
|
||||||
|
* is no +catch+ block for the symbol. The optional second
|
||||||
|
* parameter supplies a return value for the +catch+ block,
|
||||||
|
* which otherwise defaults to +nil+. For examples, see
|
||||||
|
* <code>Kernel::catch</code>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_f_throw(int argc, VALUE *argv)
|
||||||
|
{
|
||||||
|
VALUE tag, value;
|
||||||
|
yarv_thread_t *th = GET_THREAD();
|
||||||
|
struct yarv_tag *tt = th->tag;
|
||||||
|
|
||||||
|
rb_scan_args(argc, argv, "11", &tag, &value);
|
||||||
|
tag = ID2SYM(rb_to_id(tag));
|
||||||
|
|
||||||
|
while (tt) {
|
||||||
|
if (tt->tag == tag) {
|
||||||
|
tt->retval = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tt = tt->prev;
|
||||||
|
}
|
||||||
|
if (!tt) {
|
||||||
|
rb_name_error(SYM2ID(tag), "uncaught throw `%s'",
|
||||||
|
rb_id2name(SYM2ID(tag)));
|
||||||
|
}
|
||||||
|
rb_trap_restore_mask();
|
||||||
|
th->errinfo = tag;
|
||||||
|
|
||||||
|
JUMP_TAG(TAG_THROW);
|
||||||
|
#ifndef __GNUC__
|
||||||
|
return Qnil; /* not reached */
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_throw(const char *tag, VALUE val)
|
||||||
|
{
|
||||||
|
VALUE argv[2];
|
||||||
|
|
||||||
|
argv[0] = ID2SYM(rb_intern(tag));
|
||||||
|
argv[1] = val;
|
||||||
|
rb_f_throw(2, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* catch(symbol) {| | block } > obj
|
||||||
|
*
|
||||||
|
* +catch+ executes its block. If a +throw+ is
|
||||||
|
* executed, Ruby searches up its stack for a +catch+ block
|
||||||
|
* with a tag corresponding to the +throw+'s
|
||||||
|
* _symbol_. If found, that block is terminated, and
|
||||||
|
* +catch+ returns the value given to +throw+. If
|
||||||
|
* +throw+ is not called, the block terminates normally, and
|
||||||
|
* the value of +catch+ is the value of the last expression
|
||||||
|
* evaluated. +catch+ expressions may be nested, and the
|
||||||
|
* +throw+ call need not be in lexical scope.
|
||||||
|
*
|
||||||
|
* def routine(n)
|
||||||
|
* puts n
|
||||||
|
* throw :done if n <= 0
|
||||||
|
* routine(n-1)
|
||||||
|
* end
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* catch(:done) { routine(3) }
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* 3
|
||||||
|
* 2
|
||||||
|
* 1
|
||||||
|
* 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_f_catch(VALUE dmy, VALUE tag)
|
||||||
|
{
|
||||||
|
int state;
|
||||||
|
VALUE val = Qnil; /* OK */
|
||||||
|
yarv_thread_t *th = GET_THREAD();
|
||||||
|
|
||||||
|
tag = ID2SYM(rb_to_id(tag));
|
||||||
|
PUSH_TAG(tag);
|
||||||
|
|
||||||
|
th->tag->tag = tag;
|
||||||
|
|
||||||
|
if ((state = EXEC_TAG()) == 0) {
|
||||||
|
val = rb_yield_0(tag, 0, 0, 0, Qfalse);
|
||||||
|
}
|
||||||
|
else if (state == TAG_THROW && th->errinfo == tag) {
|
||||||
|
val = th->tag->retval;
|
||||||
|
th->errinfo = 0;
|
||||||
|
state = 0;
|
||||||
|
}
|
||||||
|
POP_TAG();
|
||||||
|
if (state)
|
||||||
|
JUMP_TAG(state);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
catch_i(VALUE tag)
|
||||||
|
{
|
||||||
|
return rb_funcall(Qnil, rb_intern("catch"), 1, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_catch(const char *tag, VALUE (*func)(), VALUE data)
|
||||||
|
{
|
||||||
|
return rb_iterate((VALUE (*)_((VALUE)))catch_i, ID2SYM(rb_intern(tag)),
|
||||||
|
func, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* exit */
|
||||||
|
|
||||||
|
NORETURN(static VALUE terminate_process _((int, const char *, long)));
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
terminate_process(int status, const char *mesg, long mlen)
|
||||||
|
{
|
||||||
|
VALUE args[2];
|
||||||
|
yarv_vm_t *vm = GET_THREAD()->vm;
|
||||||
|
|
||||||
|
args[0] = INT2NUM(status);
|
||||||
|
args[1] = rb_str_new(mesg, mlen);
|
||||||
|
|
||||||
|
vm->exit_code = status;
|
||||||
|
rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_exit(int status)
|
||||||
|
{
|
||||||
|
if (GET_THREAD()->tag) {
|
||||||
|
terminate_process(status, "exit", 4);
|
||||||
|
}
|
||||||
|
ruby_finalize();
|
||||||
|
exit(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* exit(integer=0)
|
||||||
|
* Kernel::exit(integer=0)
|
||||||
|
* Process::exit(integer=0)
|
||||||
|
*
|
||||||
|
* Initiates the termination of the Ruby script by raising the
|
||||||
|
* <code>SystemExit</code> exception. This exception may be caught. The
|
||||||
|
* optional parameter is used to return a status code to the invoking
|
||||||
|
* environment.
|
||||||
|
*
|
||||||
|
* begin
|
||||||
|
* exit
|
||||||
|
* puts "never get here"
|
||||||
|
* rescue SystemExit
|
||||||
|
* puts "rescued a SystemExit exception"
|
||||||
|
* end
|
||||||
|
* puts "after begin block"
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* rescued a SystemExit exception
|
||||||
|
* after begin block
|
||||||
|
*
|
||||||
|
* Just prior to termination, Ruby executes any <code>at_exit</code> functions
|
||||||
|
* (see Kernel::at_exit) and runs any object finalizers (see
|
||||||
|
* ObjectSpace::define_finalizer).
|
||||||
|
*
|
||||||
|
* at_exit { puts "at_exit function" }
|
||||||
|
* ObjectSpace.define_finalizer("string", proc { puts "in finalizer" })
|
||||||
|
* exit
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* at_exit function
|
||||||
|
* in finalizer
|
||||||
|
*/
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_f_exit(int argc, VALUE *argv)
|
||||||
|
{
|
||||||
|
VALUE status;
|
||||||
|
int istatus;
|
||||||
|
|
||||||
|
rb_secure(4);
|
||||||
|
if (rb_scan_args(argc, argv, "01", &status) == 1) {
|
||||||
|
switch (status) {
|
||||||
|
case Qtrue:
|
||||||
|
istatus = EXIT_SUCCESS;
|
||||||
|
break;
|
||||||
|
case Qfalse:
|
||||||
|
istatus = EXIT_FAILURE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
istatus = NUM2INT(status);
|
||||||
|
#if EXIT_SUCCESS != 0
|
||||||
|
if (istatus == 0)
|
||||||
|
istatus = EXIT_SUCCESS;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
istatus = EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
rb_exit(istatus);
|
||||||
|
return Qnil; /* not reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* abort
|
||||||
|
* Kernel::abort
|
||||||
|
* Process::abort
|
||||||
|
*
|
||||||
|
* Terminate execution immediately, effectively by calling
|
||||||
|
* <code>Kernel.exit(1)</code>. If _msg_ is given, it is written
|
||||||
|
* to STDERR prior to terminating.
|
||||||
|
*/
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_f_abort(int argc, VALUE *argv)
|
||||||
|
{
|
||||||
|
rb_secure(4);
|
||||||
|
if (argc == 0) {
|
||||||
|
if (!NIL_P(GET_THREAD()->errinfo)) {
|
||||||
|
error_print();
|
||||||
|
}
|
||||||
|
rb_exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VALUE mesg;
|
||||||
|
|
||||||
|
rb_scan_args(argc, argv, "1", &mesg);
|
||||||
|
StringValue(argv[0]);
|
||||||
|
rb_io_puts(argc, argv, rb_stderr);
|
||||||
|
terminate_process(EXIT_FAILURE, RSTRING_PTR(argv[0]),
|
||||||
|
RSTRING_LEN(argv[0]));
|
||||||
|
}
|
||||||
|
return Qnil; /* not reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void call_end_proc _((VALUE data));
|
||||||
|
|
||||||
|
static void
|
||||||
|
call_end_proc(VALUE data)
|
||||||
|
{
|
||||||
|
// TODO: fix me
|
||||||
|
proc_invoke(data, rb_ary_new2(0), Qundef, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* at_exit { block } -> proc
|
||||||
|
*
|
||||||
|
* Converts _block_ to a +Proc+ object (and therefore
|
||||||
|
* binds it at the point of call) and registers it for execution when
|
||||||
|
* the program exits. If multiple handlers are registered, they are
|
||||||
|
* executed in reverse order of registration.
|
||||||
|
*
|
||||||
|
* def do_at_exit(str1)
|
||||||
|
* at_exit { print str1 }
|
||||||
|
* end
|
||||||
|
* at_exit { puts "cruel world" }
|
||||||
|
* do_at_exit("goodbye ")
|
||||||
|
* exit
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* goodbye cruel world
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_f_at_exit(void)
|
||||||
|
{
|
||||||
|
VALUE proc;
|
||||||
|
|
||||||
|
if (!rb_block_given_p()) {
|
||||||
|
rb_raise(rb_eArgError, "called without a block");
|
||||||
|
}
|
||||||
|
proc = rb_block_proc();
|
||||||
|
rb_set_end_proc(call_end_proc, proc);
|
||||||
|
return proc;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct end_proc_data {
|
||||||
|
void (*func) ();
|
||||||
|
VALUE data;
|
||||||
|
int safe;
|
||||||
|
struct end_proc_data *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct end_proc_data *end_procs, *ephemeral_end_procs, *tmp_end_procs;
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_set_end_proc(void (*func)(VALUE), VALUE data)
|
||||||
|
{
|
||||||
|
struct end_proc_data *link = ALLOC(struct end_proc_data);
|
||||||
|
struct end_proc_data **list;
|
||||||
|
|
||||||
|
if (ruby_wrapper) {
|
||||||
|
list = &ephemeral_end_procs;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
list = &end_procs;
|
||||||
|
}
|
||||||
|
link->next = *list;
|
||||||
|
link->func = func;
|
||||||
|
link->data = data;
|
||||||
|
link->safe = rb_safe_level();
|
||||||
|
*list = link;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_mark_end_proc(void)
|
||||||
|
{
|
||||||
|
struct end_proc_data *link;
|
||||||
|
|
||||||
|
link = end_procs;
|
||||||
|
while (link) {
|
||||||
|
rb_gc_mark(link->data);
|
||||||
|
link = link->next;
|
||||||
|
}
|
||||||
|
link = ephemeral_end_procs;
|
||||||
|
while (link) {
|
||||||
|
rb_gc_mark(link->data);
|
||||||
|
link = link->next;
|
||||||
|
}
|
||||||
|
link = tmp_end_procs;
|
||||||
|
while (link) {
|
||||||
|
rb_gc_mark(link->data);
|
||||||
|
link = link->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_exec_end_proc(void)
|
||||||
|
{
|
||||||
|
struct end_proc_data *link, *tmp;
|
||||||
|
int status;
|
||||||
|
volatile int safe = rb_safe_level();
|
||||||
|
|
||||||
|
while (ephemeral_end_procs) {
|
||||||
|
tmp_end_procs = link = ephemeral_end_procs;
|
||||||
|
ephemeral_end_procs = 0;
|
||||||
|
while (link) {
|
||||||
|
PUSH_TAG(PROT_NONE);
|
||||||
|
if ((status = EXEC_TAG()) == 0) {
|
||||||
|
rb_set_safe_level_force(link->safe);
|
||||||
|
(*link->func) (link->data);
|
||||||
|
}
|
||||||
|
POP_TAG();
|
||||||
|
if (status) {
|
||||||
|
error_handle(status);
|
||||||
|
}
|
||||||
|
tmp = link;
|
||||||
|
tmp_end_procs = link = link->next;
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (end_procs) {
|
||||||
|
tmp_end_procs = link = end_procs;
|
||||||
|
end_procs = 0;
|
||||||
|
while (link) {
|
||||||
|
PUSH_TAG(PROT_NONE);
|
||||||
|
if ((status = EXEC_TAG()) == 0) {
|
||||||
|
rb_set_safe_level_force(link->safe);
|
||||||
|
(*link->func) (link->data);
|
||||||
|
}
|
||||||
|
POP_TAG();
|
||||||
|
if (status) {
|
||||||
|
error_handle(status);
|
||||||
|
}
|
||||||
|
tmp = link;
|
||||||
|
tmp_end_procs = link = link->next;
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rb_set_safe_level_force(safe);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Init_jump()
|
||||||
|
{
|
||||||
|
rb_define_global_function("catch", rb_f_catch, 1);
|
||||||
|
rb_define_global_function("throw", rb_f_throw, -1);
|
||||||
|
rb_define_global_function("exit", rb_f_exit, -1);
|
||||||
|
rb_define_global_function("abort", rb_f_abort, -1);
|
||||||
|
rb_define_global_function("at_exit", rb_f_at_exit, 0);
|
||||||
|
}
|
508
eval_load.c
Normal file
508
eval_load.c
Normal file
|
@ -0,0 +1,508 @@
|
||||||
|
/*
|
||||||
|
* load methods from eval.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "eval_intern.h"
|
||||||
|
|
||||||
|
extern VALUE ruby_top_self;
|
||||||
|
|
||||||
|
VALUE ruby_dln_librefs;
|
||||||
|
static VALUE rb_features;
|
||||||
|
static st_table *loading_tbl;
|
||||||
|
|
||||||
|
NORETURN(void jump_tag_but_local_jump(int, VALUE));
|
||||||
|
|
||||||
|
#define IS_SOEXT(e) (strcmp(e, ".so") == 0 || strcmp(e, ".o") == 0)
|
||||||
|
#ifdef DLEXT2
|
||||||
|
#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0 || strcmp(e, DLEXT2) == 0)
|
||||||
|
#else
|
||||||
|
#define IS_DLEXT(e) (strcmp(e, DLEXT) == 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int
|
||||||
|
rb_feature_p(const char *feature, const char *ext, int rb)
|
||||||
|
{
|
||||||
|
VALUE v;
|
||||||
|
char *f, *e;
|
||||||
|
long i, len, elen;
|
||||||
|
|
||||||
|
if (ext) {
|
||||||
|
len = ext - feature;
|
||||||
|
elen = strlen(ext);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
len = strlen(feature);
|
||||||
|
elen = 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < RARRAY_LEN(rb_features); ++i) {
|
||||||
|
v = RARRAY_PTR(rb_features)[i];
|
||||||
|
f = StringValuePtr(v);
|
||||||
|
if (strncmp(f, feature, len) != 0)
|
||||||
|
continue;
|
||||||
|
if (!*(e = f + len)) {
|
||||||
|
if (ext)
|
||||||
|
continue;
|
||||||
|
return 'u';
|
||||||
|
}
|
||||||
|
if (*e != '.')
|
||||||
|
continue;
|
||||||
|
if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
|
||||||
|
return 's';
|
||||||
|
}
|
||||||
|
if ((rb || !ext) && (strcmp(e, ".rb") == 0)) {
|
||||||
|
return 'r';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *const loadable_ext[] = {
|
||||||
|
".rb", DLEXT,
|
||||||
|
#ifdef DLEXT2
|
||||||
|
DLEXT2,
|
||||||
|
#endif
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static int search_required _((VALUE, VALUE *));
|
||||||
|
|
||||||
|
int
|
||||||
|
rb_provided(const char *feature)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *buf;
|
||||||
|
VALUE fname;
|
||||||
|
|
||||||
|
if (rb_feature_p(feature, 0, Qfalse))
|
||||||
|
return Qtrue;
|
||||||
|
if (loading_tbl) {
|
||||||
|
if (st_lookup(loading_tbl, (st_data_t) feature, 0))
|
||||||
|
return Qtrue;
|
||||||
|
buf = ALLOCA_N(char, strlen(feature) + 8);
|
||||||
|
strcpy(buf, feature);
|
||||||
|
for (i = 0; loadable_ext[i]; i++) {
|
||||||
|
strcpy(buf + strlen(feature), loadable_ext[i]);
|
||||||
|
if (st_lookup(loading_tbl, (st_data_t) buf, 0))
|
||||||
|
return Qtrue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (search_required(rb_str_new2(feature), &fname)) {
|
||||||
|
feature = RSTRING_PTR(fname);
|
||||||
|
if (rb_feature_p(feature, 0, Qfalse))
|
||||||
|
return Qtrue;
|
||||||
|
if (loading_tbl && st_lookup(loading_tbl, (st_data_t) feature, 0))
|
||||||
|
return Qtrue;
|
||||||
|
}
|
||||||
|
return Qfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_provide_feature(VALUE feature)
|
||||||
|
{
|
||||||
|
rb_ary_push(rb_features, feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_provide(const char *feature)
|
||||||
|
{
|
||||||
|
rb_provide_feature(rb_str_new2(feature));
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE rb_load_path;
|
||||||
|
|
||||||
|
NORETURN(static void load_failed _((VALUE)));
|
||||||
|
void th_klass_init(yarv_thread_t *);
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_load(VALUE fname, int wrap)
|
||||||
|
{
|
||||||
|
VALUE tmp;
|
||||||
|
int state;
|
||||||
|
volatile VALUE self = ruby_top_self;
|
||||||
|
|
||||||
|
FilePathValue(fname);
|
||||||
|
fname = rb_str_new4(fname);
|
||||||
|
tmp = rb_find_file(fname);
|
||||||
|
if (!tmp) {
|
||||||
|
load_failed(fname);
|
||||||
|
}
|
||||||
|
fname = tmp;
|
||||||
|
|
||||||
|
GET_THREAD()->errinfo = Qnil; /* ensure */
|
||||||
|
|
||||||
|
if (!wrap) {
|
||||||
|
rb_secure(4); /* should alter global state */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* load in anonymous module as toplevel */
|
||||||
|
self = rb_obj_clone(ruby_top_self);
|
||||||
|
}
|
||||||
|
|
||||||
|
PUSH_TAG(PROT_NONE);
|
||||||
|
state = EXEC_TAG();
|
||||||
|
if (state == 0) {
|
||||||
|
yarv_load(RSTRING_PTR(fname));
|
||||||
|
}
|
||||||
|
POP_TAG();
|
||||||
|
|
||||||
|
if (ruby_nerrs > 0) {
|
||||||
|
ruby_nerrs = 0;
|
||||||
|
rb_exc_raise(GET_THREAD()->errinfo);
|
||||||
|
}
|
||||||
|
if (state) {
|
||||||
|
th_jump_tag_but_local_jump(state, Qundef);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NIL_P(GET_THREAD()->errinfo)) {
|
||||||
|
/* exception during load */
|
||||||
|
rb_exc_raise(GET_THREAD()->errinfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_load_protect(VALUE fname, int wrap, int *state)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
PUSH_THREAD_TAG();
|
||||||
|
if ((status = EXEC_TAG()) == 0) {
|
||||||
|
rb_load(fname, wrap);
|
||||||
|
}
|
||||||
|
POP_THREAD_TAG();
|
||||||
|
if (state)
|
||||||
|
*state = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* load(filename, wrap=false) => true
|
||||||
|
*
|
||||||
|
* Loads and executes the Ruby
|
||||||
|
* program in the file _filename_. If the filename does not
|
||||||
|
* resolve to an absolute path, the file is searched for in the library
|
||||||
|
* directories listed in <code>$:</code>. If the optional _wrap_
|
||||||
|
* parameter is +true+, the loaded script will be executed
|
||||||
|
* under an anonymous module, protecting the calling program's global
|
||||||
|
* namespace. In no circumstance will any local variables in the loaded
|
||||||
|
* file be propagated to the loading environment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_f_load(argc, argv)
|
||||||
|
int argc;
|
||||||
|
VALUE *argv;
|
||||||
|
{
|
||||||
|
VALUE fname, wrap;
|
||||||
|
|
||||||
|
rb_scan_args(argc, argv, "11", &fname, &wrap);
|
||||||
|
rb_load(fname, RTEST(wrap));
|
||||||
|
return Qtrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
load_wait(char *ftptr)
|
||||||
|
{
|
||||||
|
st_data_t th;
|
||||||
|
if (!loading_tbl) {
|
||||||
|
return Qfalse;
|
||||||
|
}
|
||||||
|
if (!st_lookup(loading_tbl, (st_data_t) ftptr, &th)) {
|
||||||
|
return Qfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: write wait routine
|
||||||
|
return Qtrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* require(string) => true or false
|
||||||
|
*
|
||||||
|
* Ruby tries to load the library named _string_, returning
|
||||||
|
* +true+ if successful. If the filename does not resolve to
|
||||||
|
* an absolute path, it will be searched for in the directories listed
|
||||||
|
* in <code>$:</code>. If the file has the extension ``.rb'', it is
|
||||||
|
* loaded as a source file; if the extension is ``.so'', ``.o'', or
|
||||||
|
* ``.dll'', or whatever the default shared library extension is on
|
||||||
|
* the current platform, Ruby loads the shared library as a Ruby
|
||||||
|
* extension. Otherwise, Ruby tries adding ``.rb'', ``.so'', and so on
|
||||||
|
* to the name. The name of the loaded feature is added to the array in
|
||||||
|
* <code>$"</code>. A feature will not be loaded if it's name already
|
||||||
|
* appears in <code>$"</code>. However, the file name is not converted
|
||||||
|
* to an absolute path, so that ``<code>require 'a';require
|
||||||
|
* './a'</code>'' will load <code>a.rb</code> twice.
|
||||||
|
*
|
||||||
|
* require "my-library.rb"
|
||||||
|
* require "db-driver"
|
||||||
|
*/
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_f_require(VALUE obj, VALUE fname)
|
||||||
|
{
|
||||||
|
return rb_require_safe(fname, rb_safe_level());
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
search_required(VALUE fname, VALUE *path)
|
||||||
|
{
|
||||||
|
VALUE tmp;
|
||||||
|
char *ext, *ftptr;
|
||||||
|
int type, ft = 0;
|
||||||
|
|
||||||
|
*path = 0;
|
||||||
|
ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
|
||||||
|
if (ext && !strchr(ext, '/')) {
|
||||||
|
if (strcmp(".rb", ext) == 0) {
|
||||||
|
if (rb_feature_p(ftptr, ext, Qtrue))
|
||||||
|
return 'r';
|
||||||
|
if (tmp = rb_find_file(fname)) {
|
||||||
|
tmp = rb_file_expand_path(tmp, Qnil);
|
||||||
|
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||||
|
if (!rb_feature_p(ftptr, ext, Qtrue))
|
||||||
|
*path = tmp;
|
||||||
|
return 'r';
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (IS_SOEXT(ext)) {
|
||||||
|
if (rb_feature_p(ftptr, ext, Qfalse))
|
||||||
|
return 's';
|
||||||
|
tmp = rb_str_new(RSTRING_PTR(fname), ext - RSTRING_PTR(fname));
|
||||||
|
#ifdef DLEXT2
|
||||||
|
OBJ_FREEZE(tmp);
|
||||||
|
if (rb_find_file_ext(&tmp, loadable_ext + 1)) {
|
||||||
|
tmp = rb_file_expand_path(tmp, Qnil);
|
||||||
|
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||||
|
if (!rb_feature_p(ftptr, ext, Qfalse))
|
||||||
|
*path = tmp;
|
||||||
|
return 's';
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
rb_str_cat2(tmp, DLEXT);
|
||||||
|
OBJ_FREEZE(tmp);
|
||||||
|
if (tmp = rb_find_file(tmp)) {
|
||||||
|
tmp = rb_file_expand_path(tmp, Qnil);
|
||||||
|
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||||
|
if (!rb_feature_p(ftptr, ext, Qfalse))
|
||||||
|
*path = tmp;
|
||||||
|
return 's';
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (IS_DLEXT(ext)) {
|
||||||
|
if (rb_feature_p(ftptr, ext, Qfalse))
|
||||||
|
return 's';
|
||||||
|
if (tmp = rb_find_file(fname)) {
|
||||||
|
tmp = rb_file_expand_path(tmp, Qnil);
|
||||||
|
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||||
|
if (!rb_feature_p(ftptr, ext, Qfalse))
|
||||||
|
*path = tmp;
|
||||||
|
return 's';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((ft = rb_feature_p(ftptr, 0, Qfalse)) == 'r') {
|
||||||
|
return 'r';
|
||||||
|
}
|
||||||
|
tmp = fname;
|
||||||
|
type = rb_find_file_ext(&tmp, loadable_ext);
|
||||||
|
tmp = rb_file_expand_path(tmp, Qnil);
|
||||||
|
switch (type) {
|
||||||
|
case 0:
|
||||||
|
ftptr = RSTRING_PTR(tmp);
|
||||||
|
if (ft)
|
||||||
|
break;
|
||||||
|
return rb_feature_p(ftptr, 0, Qfalse);
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (ft)
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
|
||||||
|
if (rb_feature_p(ftptr, ext, !--type))
|
||||||
|
break;
|
||||||
|
*path = tmp;
|
||||||
|
}
|
||||||
|
return type ? 's' : 'r';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_failed(VALUE fname)
|
||||||
|
{
|
||||||
|
rb_raise(rb_eLoadError, "no such file to load -- %s",
|
||||||
|
RSTRING_PTR(fname));
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_require_safe(VALUE fname, int safe)
|
||||||
|
{
|
||||||
|
VALUE result = Qnil;
|
||||||
|
volatile VALUE errinfo = GET_THREAD()->errinfo;
|
||||||
|
yarv_thread_t *th = GET_THREAD();
|
||||||
|
int state;
|
||||||
|
char *volatile ftptr = 0;
|
||||||
|
|
||||||
|
PUSH_TAG(PROT_NONE);
|
||||||
|
if ((state = EXEC_TAG()) == 0) {
|
||||||
|
VALUE path;
|
||||||
|
long handle;
|
||||||
|
int found;
|
||||||
|
|
||||||
|
rb_set_safe_level_force(safe);
|
||||||
|
FilePathValue(fname);
|
||||||
|
*(volatile VALUE *)&fname = rb_str_new4(fname);
|
||||||
|
found = search_required(fname, &path);
|
||||||
|
if (found) {
|
||||||
|
if (!path || load_wait(RSTRING_PTR(path))) {
|
||||||
|
result = Qfalse;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_set_safe_level_force(0);
|
||||||
|
switch (found) {
|
||||||
|
case 'r':
|
||||||
|
/* loading ruby library should be serialized. */
|
||||||
|
if (!loading_tbl) {
|
||||||
|
loading_tbl = st_init_strtable();
|
||||||
|
}
|
||||||
|
/* partial state */
|
||||||
|
ftptr = ruby_strdup(RSTRING_PTR(path));
|
||||||
|
st_insert(loading_tbl, (st_data_t) ftptr,
|
||||||
|
(st_data_t) GET_THREAD()->self);
|
||||||
|
rb_load(path, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
ruby_current_node = 0;
|
||||||
|
ruby_sourcefile = rb_source_filename(RSTRING_PTR(path));
|
||||||
|
ruby_sourceline = 0;
|
||||||
|
//SCOPE_SET(NOEX_PUBLIC);
|
||||||
|
handle = (long)dln_load(RSTRING_PTR(path));
|
||||||
|
rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rb_provide_feature(path);
|
||||||
|
result = Qtrue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
POP_TAG();
|
||||||
|
|
||||||
|
if (ftptr) {
|
||||||
|
if (st_delete(loading_tbl, (st_data_t *) & ftptr, 0)) { /* loading done */
|
||||||
|
free(ftptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state) {
|
||||||
|
JUMP_TAG(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NIL_P(result)) {
|
||||||
|
load_failed(fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
th->errinfo = errinfo;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_require(const char *fname)
|
||||||
|
{
|
||||||
|
VALUE fn = rb_str_new2(fname);
|
||||||
|
OBJ_FREEZE(fn);
|
||||||
|
return rb_require_safe(fn, rb_safe_level());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* mod.autoload(name, filename) => nil
|
||||||
|
*
|
||||||
|
* Registers _filename_ to be loaded (using <code>Kernel::require</code>)
|
||||||
|
* the first time that _module_ (which may be a <code>String</code> or
|
||||||
|
* a symbol) is accessed in the namespace of _mod_.
|
||||||
|
*
|
||||||
|
* module A
|
||||||
|
* end
|
||||||
|
* A.autoload(:B, "b")
|
||||||
|
* A::B.doit # autoloads "b"
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
|
||||||
|
{
|
||||||
|
ID id = rb_to_id(sym);
|
||||||
|
|
||||||
|
Check_SafeStr(file);
|
||||||
|
rb_autoload(mod, id, RSTRING_PTR(file));
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MISSING: documentation
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_mod_autoload_p(VALUE mod, VALUE sym)
|
||||||
|
{
|
||||||
|
return rb_autoload_p(mod, rb_to_id(sym));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* autoload(module, filename) => nil
|
||||||
|
*
|
||||||
|
* Registers _filename_ to be loaded (using <code>Kernel::require</code>)
|
||||||
|
* the first time that _module_ (which may be a <code>String</code> or
|
||||||
|
* a symbol) is accessed.
|
||||||
|
*
|
||||||
|
* autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
|
||||||
|
{
|
||||||
|
VALUE klass = ruby_cbase();
|
||||||
|
if (NIL_P(klass)) {
|
||||||
|
rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
|
||||||
|
}
|
||||||
|
return rb_mod_autoload(klass, sym, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MISSING: documentation
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_f_autoload_p(VALUE obj, VALUE sym)
|
||||||
|
{
|
||||||
|
/* use ruby_cbase() as same as rb_f_autoload. */
|
||||||
|
VALUE klass = ruby_cbase();
|
||||||
|
if (NIL_P(klass)) {
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
return rb_mod_autoload_p(klass, sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Init_load()
|
||||||
|
{
|
||||||
|
rb_load_path = rb_ary_new();
|
||||||
|
rb_define_readonly_variable("$:", &rb_load_path);
|
||||||
|
rb_define_readonly_variable("$-I", &rb_load_path);
|
||||||
|
rb_define_readonly_variable("$LOAD_PATH", &rb_load_path);
|
||||||
|
|
||||||
|
rb_features = rb_ary_new();
|
||||||
|
rb_define_readonly_variable("$\"", &rb_features);
|
||||||
|
rb_define_readonly_variable("$LOADED_FEATURES", &rb_features);
|
||||||
|
|
||||||
|
rb_define_global_function("load", rb_f_load, -1);
|
||||||
|
rb_define_global_function("require", rb_f_require, 1);
|
||||||
|
rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
|
||||||
|
rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1);
|
||||||
|
rb_define_global_function("autoload", rb_f_autoload, 2);
|
||||||
|
rb_define_global_function("autoload?", rb_f_autoload_p, 1);
|
||||||
|
|
||||||
|
ruby_dln_librefs = rb_ary_new();
|
||||||
|
rb_register_mark_object(ruby_dln_librefs);
|
||||||
|
}
|
612
eval_method.h
Normal file
612
eval_method.h
Normal file
|
@ -0,0 +1,612 @@
|
||||||
|
/*
|
||||||
|
* This file is included by eval.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CACHE_SIZE 0x800
|
||||||
|
#define CACHE_MASK 0x7ff
|
||||||
|
#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
|
||||||
|
|
||||||
|
struct cache_entry { /* method hash table. */
|
||||||
|
ID mid; /* method's id */
|
||||||
|
ID mid0; /* method's original id */
|
||||||
|
VALUE klass; /* receiver's class */
|
||||||
|
NODE *method;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cache_entry cache[CACHE_SIZE];
|
||||||
|
static int ruby_running = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_clear_cache(void)
|
||||||
|
{
|
||||||
|
struct cache_entry *ent, *end;
|
||||||
|
|
||||||
|
rb_vm_change_state();
|
||||||
|
|
||||||
|
if (!ruby_running)
|
||||||
|
return;
|
||||||
|
ent = cache;
|
||||||
|
end = ent + CACHE_SIZE;
|
||||||
|
while (ent < end) {
|
||||||
|
ent->mid = 0;
|
||||||
|
ent++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_clear_cache_for_undef(VALUE klass, ID id)
|
||||||
|
{
|
||||||
|
struct cache_entry *ent, *end;
|
||||||
|
|
||||||
|
rb_vm_change_state();
|
||||||
|
|
||||||
|
if (!ruby_running)
|
||||||
|
return;
|
||||||
|
ent = cache;
|
||||||
|
end = ent + CACHE_SIZE;
|
||||||
|
while (ent < end) {
|
||||||
|
if (ent->method && ent->method->nd_clss == klass && ent->mid == id) {
|
||||||
|
ent->mid = 0;
|
||||||
|
}
|
||||||
|
ent++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_clear_cache_by_id(ID id)
|
||||||
|
{
|
||||||
|
struct cache_entry *ent, *end;
|
||||||
|
|
||||||
|
rb_vm_change_state();
|
||||||
|
|
||||||
|
if (!ruby_running)
|
||||||
|
return;
|
||||||
|
ent = cache;
|
||||||
|
end = ent + CACHE_SIZE;
|
||||||
|
while (ent < end) {
|
||||||
|
if (ent->mid == id) {
|
||||||
|
ent->mid = 0;
|
||||||
|
}
|
||||||
|
ent++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_clear_cache_by_class(VALUE klass)
|
||||||
|
{
|
||||||
|
struct cache_entry *ent, *end;
|
||||||
|
|
||||||
|
rb_vm_change_state();
|
||||||
|
|
||||||
|
if (!ruby_running)
|
||||||
|
return;
|
||||||
|
ent = cache;
|
||||||
|
end = ent + CACHE_SIZE;
|
||||||
|
while (ent < end) {
|
||||||
|
if ((ent->klass == klass) ||
|
||||||
|
(ent->method && ent->method->nd_clss == klass)) {
|
||||||
|
ent->mid = 0;
|
||||||
|
}
|
||||||
|
ent++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_add_method(VALUE klass, ID mid, NODE * node, int noex)
|
||||||
|
{
|
||||||
|
NODE *body;
|
||||||
|
|
||||||
|
if (NIL_P(klass)) {
|
||||||
|
klass = rb_cObject;
|
||||||
|
}
|
||||||
|
if (rb_safe_level() >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) {
|
||||||
|
rb_raise(rb_eSecurityError, "Insecure: can't define method");
|
||||||
|
}
|
||||||
|
if (!FL_TEST(klass, FL_SINGLETON) &&
|
||||||
|
node && nd_type(node) != NODE_ZSUPER &&
|
||||||
|
(mid == rb_intern("initialize") || mid == rb_intern("initialize_copy"))) {
|
||||||
|
noex = NOEX_PRIVATE | noex;
|
||||||
|
}
|
||||||
|
else if (FL_TEST(klass, FL_SINGLETON) && node
|
||||||
|
&& nd_type(node) == NODE_CFUNC && mid == rb_intern("allocate")) {
|
||||||
|
rb_warn
|
||||||
|
("defining %s.allocate is deprecated; use rb_define_alloc_func()",
|
||||||
|
rb_class2name(rb_iv_get(klass, "__attached__")));
|
||||||
|
mid = ID_ALLOCATOR;
|
||||||
|
}
|
||||||
|
if (OBJ_FROZEN(klass)) {
|
||||||
|
rb_error_frozen("class/module");
|
||||||
|
}
|
||||||
|
rb_clear_cache_by_id(mid);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NODE_METHOD (NEW_METHOD(body, klass, vis)):
|
||||||
|
* nd_body : method body // (2) // mark
|
||||||
|
* nd_clss : klass // (1) // mark
|
||||||
|
* nd_noex : visibility // (3)
|
||||||
|
*
|
||||||
|
* NODE_FBODY (NEW_FBODY(method, alias)):
|
||||||
|
* nd_body : method (NODE_METHOD) // (2) // mark
|
||||||
|
* nd_oid : original id // (1)
|
||||||
|
* nd_cnt : alias count // (3)
|
||||||
|
*/
|
||||||
|
if (node) {
|
||||||
|
body = NEW_FBODY(NEW_METHOD(node, klass, noex), 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
body = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/* check re-definition */
|
||||||
|
NODE *old_node;
|
||||||
|
|
||||||
|
if (st_lookup(RCLASS(klass)->m_tbl, mid, (st_data_t *)&old_node)) {
|
||||||
|
if (old_node) {
|
||||||
|
if (nd_type(old_node->nd_body->nd_body) == NODE_CFUNC) {
|
||||||
|
yarv_check_redefinition_opt_method(old_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (klass == rb_cObject && node->nd_mid == init) {
|
||||||
|
rb_warn("redefining Object#initialize may cause infinite loop");
|
||||||
|
}
|
||||||
|
if (RTEST(ruby_verbose) && old_node->nd_cnt == 0 && old_node->nd_body) {
|
||||||
|
rb_warning("method redefined; discarding old %s", rb_id2name(mid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mid == object_id || mid == __send || mid == __send_bang) {
|
||||||
|
if (node && nd_type(node) == YARV_METHOD_NODE) {
|
||||||
|
rb_warn("redefining `%s' may cause serious problem",
|
||||||
|
rb_id2name(mid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
st_insert(RCLASS(klass)->m_tbl, mid, (st_data_t) body);
|
||||||
|
|
||||||
|
if (node && mid != ID_ALLOCATOR && ruby_running) {
|
||||||
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||||
|
rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1,
|
||||||
|
ID2SYM(mid));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_funcall(klass, added, 1, ID2SYM(mid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_define_alloc_func(VALUE klass, VALUE (*func) _((VALUE)))
|
||||||
|
{
|
||||||
|
Check_Type(klass, T_CLASS);
|
||||||
|
rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, NEW_CFUNC(func, 0),
|
||||||
|
NOEX_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_undef_alloc_func(VALUE klass)
|
||||||
|
{
|
||||||
|
Check_Type(klass, T_CLASS);
|
||||||
|
rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, 0, NOEX_UNDEF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NODE *
|
||||||
|
search_method(VALUE klass, ID id, VALUE *klassp)
|
||||||
|
{
|
||||||
|
NODE *body;
|
||||||
|
|
||||||
|
if (!klass) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!st_lookup(RCLASS(klass)->m_tbl, id, (st_data_t *) & body)) {
|
||||||
|
klass = RCLASS(klass)->super;
|
||||||
|
if (!klass)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (klassp) {
|
||||||
|
*klassp = klass;
|
||||||
|
}
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* search method body (NODE_METHOD)
|
||||||
|
* with : klass and id
|
||||||
|
* without : method cache
|
||||||
|
*
|
||||||
|
* if you need method node with method cache, use
|
||||||
|
* rb_method_node()
|
||||||
|
*/
|
||||||
|
NODE *
|
||||||
|
rb_get_method_body(VALUE klass, ID id, ID *idp)
|
||||||
|
{
|
||||||
|
NODE *volatile fbody, *body;
|
||||||
|
NODE *method;
|
||||||
|
|
||||||
|
if ((fbody = search_method(klass, id, 0)) == 0 || !fbody->nd_body) {
|
||||||
|
/* store empty info in cache */
|
||||||
|
struct cache_entry *ent;
|
||||||
|
ent = cache + EXPR1(klass, id);
|
||||||
|
ent->klass = klass;
|
||||||
|
ent->mid = ent->mid0 = id;
|
||||||
|
ent->method = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
method = fbody->nd_body;
|
||||||
|
|
||||||
|
if (ruby_running) {
|
||||||
|
/* store in cache */
|
||||||
|
struct cache_entry *ent;
|
||||||
|
ent = cache + EXPR1(klass, id);
|
||||||
|
ent->klass = klass;
|
||||||
|
ent->mid = id;
|
||||||
|
ent->mid0 = fbody->nd_oid;
|
||||||
|
ent->method = body = method;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
body = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idp) {
|
||||||
|
*idp = fbody->nd_oid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE *
|
||||||
|
rb_method_node(VALUE klass, ID id)
|
||||||
|
{
|
||||||
|
struct cache_entry *ent;
|
||||||
|
|
||||||
|
ent = cache + EXPR1(klass, id);
|
||||||
|
if (ent->mid == id && ent->klass == klass && ent->method) {
|
||||||
|
return ent->method;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rb_get_method_body(klass, id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_method(VALUE klass, ID mid)
|
||||||
|
{
|
||||||
|
NODE *body;
|
||||||
|
|
||||||
|
if (klass == rb_cObject) {
|
||||||
|
rb_secure(4);
|
||||||
|
}
|
||||||
|
if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
|
||||||
|
rb_raise(rb_eSecurityError, "Insecure: can't remove method");
|
||||||
|
}
|
||||||
|
if (OBJ_FROZEN(klass))
|
||||||
|
rb_error_frozen("class/module");
|
||||||
|
if (mid == object_id || mid == __send || mid == __send_bang || mid == init) {
|
||||||
|
rb_warn("removing `%s' may cause serious problem", rb_id2name(mid));
|
||||||
|
}
|
||||||
|
if (!st_delete(RCLASS(klass)->m_tbl, &mid, (st_data_t *) & body) ||
|
||||||
|
!body->nd_body) {
|
||||||
|
rb_name_error(mid, "method `%s' not defined in %s",
|
||||||
|
rb_id2name(mid), rb_class2name(klass));
|
||||||
|
}
|
||||||
|
rb_clear_cache_for_undef(klass, mid);
|
||||||
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||||
|
rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1,
|
||||||
|
ID2SYM(mid));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_funcall(klass, removed, 1, ID2SYM(mid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_remove_method(VALUE klass, const char *name)
|
||||||
|
{
|
||||||
|
remove_method(klass, rb_intern(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* remove_method(symbol) => self
|
||||||
|
*
|
||||||
|
* Removes the method identified by _symbol_ from the current
|
||||||
|
* class. For an example, see <code>Module.undef_method</code>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_mod_remove_method(int argc, VALUE *argv, VALUE mod)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
remove_method(mod, rb_to_id(argv[i]));
|
||||||
|
}
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef rb_disable_super
|
||||||
|
#undef rb_enable_super
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_disable_super(VALUE klass, const char *name)
|
||||||
|
{
|
||||||
|
/* obsolete - no use */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_enable_super(VALUE klass, const char *name)
|
||||||
|
{
|
||||||
|
rb_warning("rb_enable_super() is obsolete");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_export_method(VALUE klass, ID name, ID noex)
|
||||||
|
{
|
||||||
|
NODE *fbody;
|
||||||
|
VALUE origin;
|
||||||
|
|
||||||
|
if (klass == rb_cObject) {
|
||||||
|
rb_secure(4);
|
||||||
|
}
|
||||||
|
fbody = search_method(klass, name, &origin);
|
||||||
|
if (!fbody && TYPE(klass) == T_MODULE) {
|
||||||
|
fbody = search_method(rb_cObject, name, &origin);
|
||||||
|
}
|
||||||
|
if (!fbody || !fbody->nd_body) {
|
||||||
|
print_undef(klass, name);
|
||||||
|
}
|
||||||
|
if (fbody->nd_body->nd_noex != noex) {
|
||||||
|
if (klass == origin) {
|
||||||
|
fbody->nd_body->nd_noex = noex;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_add_method(klass, name, NEW_ZSUPER(), noex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rb_method_boundp(VALUE klass, ID id, int ex)
|
||||||
|
{
|
||||||
|
NODE *method;
|
||||||
|
|
||||||
|
if ((method = rb_method_node(klass, id)) != 0) {
|
||||||
|
if (ex && (method->nd_noex & NOEX_PRIVATE)) {
|
||||||
|
return Qfalse;
|
||||||
|
}
|
||||||
|
return Qtrue;
|
||||||
|
}
|
||||||
|
return Qfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_attr(VALUE klass, ID id, int read, int write, int ex)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
char *buf;
|
||||||
|
ID attriv;
|
||||||
|
int noex;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (!ex) {
|
||||||
|
noex = NOEX_PUBLIC;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (SCOPE_TEST(NOEX_PRIVATE)) {
|
||||||
|
noex = NOEX_PRIVATE;
|
||||||
|
rb_warning((SCOPE_CHECK(NOEX_MODFUNC)) ?
|
||||||
|
"attribute accessor as module_function" :
|
||||||
|
"private attribute?");
|
||||||
|
}
|
||||||
|
else if (SCOPE_TEST(NOEX_PROTECTED)) {
|
||||||
|
noex = NOEX_PROTECTED;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
noex = NOEX_PUBLIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rb_is_local_id(id) && !rb_is_const_id(id)) {
|
||||||
|
rb_name_error(id, "invalid attribute name `%s'", rb_id2name(id));
|
||||||
|
}
|
||||||
|
name = rb_id2name(id);
|
||||||
|
if (!name) {
|
||||||
|
rb_raise(rb_eArgError, "argument needs to be symbol or string");
|
||||||
|
}
|
||||||
|
len = strlen(name) + 2;
|
||||||
|
buf = ALLOCA_N(char, len);
|
||||||
|
snprintf(buf, len, "@%s", name);
|
||||||
|
attriv = rb_intern(buf);
|
||||||
|
if (read) {
|
||||||
|
rb_add_method(klass, id, NEW_IVAR(attriv), noex);
|
||||||
|
}
|
||||||
|
if (write) {
|
||||||
|
rb_add_method(klass, rb_id_attrset(id), NEW_ATTRSET(attriv), noex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_undef(VALUE klass, ID id)
|
||||||
|
{
|
||||||
|
VALUE origin;
|
||||||
|
NODE *body;
|
||||||
|
|
||||||
|
if (ruby_cbase() == rb_cObject && klass == rb_cObject) {
|
||||||
|
rb_secure(4);
|
||||||
|
}
|
||||||
|
if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
|
||||||
|
rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'",
|
||||||
|
rb_id2name(id));
|
||||||
|
}
|
||||||
|
rb_frozen_class_p(klass);
|
||||||
|
if (id == object_id || id == __send || id == __send_bang || id == init) {
|
||||||
|
rb_warn("undefining `%s' may cause serious problem", rb_id2name(id));
|
||||||
|
}
|
||||||
|
body = search_method(klass, id, &origin);
|
||||||
|
if (!body || !body->nd_body) {
|
||||||
|
char *s0 = " class";
|
||||||
|
VALUE c = klass;
|
||||||
|
|
||||||
|
if (FL_TEST(c, FL_SINGLETON)) {
|
||||||
|
VALUE obj = rb_iv_get(klass, "__attached__");
|
||||||
|
|
||||||
|
switch (TYPE(obj)) {
|
||||||
|
case T_MODULE:
|
||||||
|
case T_CLASS:
|
||||||
|
c = obj;
|
||||||
|
s0 = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (TYPE(c) == T_MODULE) {
|
||||||
|
s0 = " module";
|
||||||
|
}
|
||||||
|
rb_name_error(id, "undefined method `%s' for%s `%s'",
|
||||||
|
rb_id2name(id), s0, rb_class2name(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_add_method(klass, id, 0, NOEX_PUBLIC);
|
||||||
|
|
||||||
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||||
|
rb_funcall(rb_iv_get(klass, "__attached__"),
|
||||||
|
singleton_undefined, 1, ID2SYM(id));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_funcall(klass, undefined, 1, ID2SYM(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* undef_method(symbol) => self
|
||||||
|
*
|
||||||
|
* Prevents the current class from responding to calls to the named
|
||||||
|
* method. Contrast this with <code>remove_method</code>, which deletes
|
||||||
|
* the method from the particular class; Ruby will still search
|
||||||
|
* superclasses and mixed-in modules for a possible receiver.
|
||||||
|
*
|
||||||
|
* class Parent
|
||||||
|
* def hello
|
||||||
|
* puts "In parent"
|
||||||
|
* end
|
||||||
|
* end
|
||||||
|
* class Child < Parent
|
||||||
|
* def hello
|
||||||
|
* puts "In child"
|
||||||
|
* end
|
||||||
|
* end
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* c = Child.new
|
||||||
|
* c.hello
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* class Child
|
||||||
|
* remove_method :hello # remove from child, still in parent
|
||||||
|
* end
|
||||||
|
* c.hello
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* class Child
|
||||||
|
* undef_method :hello # prevent any calls to 'hello'
|
||||||
|
* end
|
||||||
|
* c.hello
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* In child
|
||||||
|
* In parent
|
||||||
|
* prog.rb:23: undefined method `hello' for #<Child:0x401b3bb4> (NoMethodError)
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < argc; i++) {
|
||||||
|
rb_undef(mod, rb_to_id(argv[i]));
|
||||||
|
}
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_alias(VALUE klass, ID name, ID def)
|
||||||
|
{
|
||||||
|
NODE *orig_fbody, *node;
|
||||||
|
VALUE singleton = 0;
|
||||||
|
|
||||||
|
rb_frozen_class_p(klass);
|
||||||
|
if (name == def)
|
||||||
|
return;
|
||||||
|
if (klass == rb_cObject) {
|
||||||
|
rb_secure(4);
|
||||||
|
}
|
||||||
|
orig_fbody = search_method(klass, def, 0);
|
||||||
|
if (!orig_fbody || !orig_fbody->nd_body) {
|
||||||
|
if (TYPE(klass) == T_MODULE) {
|
||||||
|
orig_fbody = search_method(rb_cObject, def, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!orig_fbody || !orig_fbody->nd_body) {
|
||||||
|
print_undef(klass, def);
|
||||||
|
}
|
||||||
|
if (FL_TEST(klass, FL_SINGLETON)) {
|
||||||
|
singleton = rb_iv_get(klass, "__attached__");
|
||||||
|
}
|
||||||
|
|
||||||
|
orig_fbody->nd_cnt++;
|
||||||
|
|
||||||
|
if (RTEST(ruby_verbose) &&
|
||||||
|
st_lookup(RCLASS(klass)->m_tbl, name, (st_data_t *) & node)) {
|
||||||
|
if (node->nd_cnt == 0 && node->nd_body) {
|
||||||
|
rb_warning("discarding old %s", rb_id2name(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
st_insert(RCLASS(klass)->m_tbl, name,
|
||||||
|
(st_data_t) NEW_FBODY(
|
||||||
|
NEW_METHOD(orig_fbody->nd_body->nd_body,
|
||||||
|
orig_fbody->nd_body->nd_clss,
|
||||||
|
orig_fbody->nd_body->nd_noex), def));
|
||||||
|
|
||||||
|
rb_clear_cache_by_id(name);
|
||||||
|
|
||||||
|
if (singleton) {
|
||||||
|
rb_funcall(singleton, singleton_added, 1, ID2SYM(name));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_funcall(klass, added, 1, ID2SYM(name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* alias_method(new_name, old_name) => self
|
||||||
|
*
|
||||||
|
* Makes <i>new_name</i> a new copy of the method <i>old_name</i>. This can
|
||||||
|
* be used to retain access to methods that are overridden.
|
||||||
|
*
|
||||||
|
* module Mod
|
||||||
|
* alias_method :orig_exit, :exit
|
||||||
|
* def exit(code=0)
|
||||||
|
* puts "Exiting with code #{code}"
|
||||||
|
* orig_exit(code)
|
||||||
|
* end
|
||||||
|
* end
|
||||||
|
* include Mod
|
||||||
|
* exit(99)
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* Exiting with code 99
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_mod_alias_method(VALUE mod, VALUE newname, VALUE oldname)
|
||||||
|
{
|
||||||
|
rb_alias(mod, rb_to_id(newname), rb_to_id(oldname));
|
||||||
|
return mod;
|
||||||
|
}
|
1195
eval_proc.c
Normal file
1195
eval_proc.c
Normal file
File diff suppressed because it is too large
Load diff
117
eval_safe.h
Normal file
117
eval_safe.h
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* This file is included by eval.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* safe-level:
|
||||||
|
0 - strings from streams/environment/ARGV are tainted (default)
|
||||||
|
1 - no dangerous operation by tainted value
|
||||||
|
2 - process/file operations prohibited
|
||||||
|
3 - all generated objects are tainted
|
||||||
|
4 - no global (non-tainted) variable modification/no direct output
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
rb_safe_level(void)
|
||||||
|
{
|
||||||
|
return GET_THREAD()->safe_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_set_safe_level_force(int safe)
|
||||||
|
{
|
||||||
|
GET_THREAD()->safe_level = safe;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE safe_getter _((void));
|
||||||
|
static void safe_setter _((VALUE val));
|
||||||
|
|
||||||
|
#define PROC_TSHIFT (FL_USHIFT+1)
|
||||||
|
#define PROC_TMASK (FL_USER1|FL_USER2|FL_USER3)
|
||||||
|
#define PROC_TMAX (PROC_TMASK >> PROC_TSHIFT)
|
||||||
|
#define PROC_NOSAFE FL_USER4
|
||||||
|
|
||||||
|
#define SAFE_LEVEL_MAX PROC_TMASK
|
||||||
|
|
||||||
|
/* $SAFE accessor */
|
||||||
|
void
|
||||||
|
rb_set_safe_level(int level)
|
||||||
|
{
|
||||||
|
yarv_thread_t *th = GET_THREAD();
|
||||||
|
|
||||||
|
if (level > th->safe_level) {
|
||||||
|
if (level > SAFE_LEVEL_MAX) {
|
||||||
|
level = SAFE_LEVEL_MAX;
|
||||||
|
}
|
||||||
|
th->safe_level = level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
safe_getter(void)
|
||||||
|
{
|
||||||
|
return INT2NUM(rb_safe_level());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
safe_setter(VALUE val)
|
||||||
|
{
|
||||||
|
int level = NUM2INT(val);
|
||||||
|
yarv_thread_t *th = GET_THREAD();
|
||||||
|
|
||||||
|
if (level < th->safe_level) {
|
||||||
|
rb_raise(rb_eSecurityError,
|
||||||
|
"tried to downgrade safe level from %d to %d",
|
||||||
|
th->safe_level, level);
|
||||||
|
}
|
||||||
|
if (level > SAFE_LEVEL_MAX) {
|
||||||
|
level = SAFE_LEVEL_MAX;
|
||||||
|
}
|
||||||
|
th->safe_level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_secure(int level)
|
||||||
|
{
|
||||||
|
if (level <= rb_safe_level()) {
|
||||||
|
if (rb_frame_callee()) {
|
||||||
|
rb_raise(rb_eSecurityError, "Insecure operation `%s' at level %d",
|
||||||
|
rb_id2name(rb_frame_callee()), rb_safe_level());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_raise(rb_eSecurityError, "Insecure operation at level %d",
|
||||||
|
rb_safe_level());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_secure_update(VALUE obj)
|
||||||
|
{
|
||||||
|
if (!OBJ_TAINTED(obj))
|
||||||
|
rb_secure(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_check_safe_obj(VALUE x)
|
||||||
|
{
|
||||||
|
if (rb_safe_level() > 0 && OBJ_TAINTED(x)) {
|
||||||
|
if (rb_frame_callee()) {
|
||||||
|
rb_raise(rb_eSecurityError, "Insecure operation - %s",
|
||||||
|
rb_id2name(rb_frame_callee()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rb_raise(rb_eSecurityError, "Insecure operation: -r");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rb_secure(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_check_safe_str(VALUE x)
|
||||||
|
{
|
||||||
|
rb_check_safe_obj(x);
|
||||||
|
if (TYPE(x) != T_STRING) {
|
||||||
|
rb_raise(rb_eTypeError, "wrong argument type %s (expected String)",
|
||||||
|
rb_obj_classname(x));
|
||||||
|
}
|
||||||
|
}
|
683
eval_thread.c
Normal file
683
eval_thread.c
Normal file
|
@ -0,0 +1,683 @@
|
||||||
|
/*
|
||||||
|
* Thread from eval.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "eval_intern.h"
|
||||||
|
|
||||||
|
#ifdef __ia64__
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
/*
|
||||||
|
* FreeBSD/ia64 currently does not have a way for a process to get the
|
||||||
|
* base address for the RSE backing store, so hardcode it.
|
||||||
|
*/
|
||||||
|
#define __libc_ia64_register_backing_store_base (4ULL<<61)
|
||||||
|
#else
|
||||||
|
#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF)
|
||||||
|
#include <unwind.h>
|
||||||
|
#else
|
||||||
|
#pragma weak __libc_ia64_register_backing_store_base
|
||||||
|
extern unsigned long __libc_ia64_register_backing_store_base;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Windows SEH refers data on the stack. */
|
||||||
|
#undef SAVE_WIN32_EXCEPTION_LIST
|
||||||
|
#if defined _WIN32 || defined __CYGWIN__
|
||||||
|
#if defined __CYGWIN__
|
||||||
|
typedef unsigned long DWORD;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline DWORD
|
||||||
|
win32_get_exception_list()
|
||||||
|
{
|
||||||
|
DWORD p;
|
||||||
|
# if defined _MSC_VER
|
||||||
|
# ifdef _M_IX86
|
||||||
|
# define SAVE_WIN32_EXCEPTION_LIST
|
||||||
|
# if _MSC_VER >= 1310
|
||||||
|
/* warning: unsafe assignment to fs:0 ... this is ok */
|
||||||
|
# pragma warning(disable: 4733)
|
||||||
|
# endif
|
||||||
|
__asm mov eax, fs:[0];
|
||||||
|
__asm mov p, eax;
|
||||||
|
# endif
|
||||||
|
# elif defined __GNUC__
|
||||||
|
# ifdef __i386__
|
||||||
|
# define SAVE_WIN32_EXCEPTION_LIST
|
||||||
|
__asm__("movl %%fs:0,%0":"=r"(p));
|
||||||
|
# endif
|
||||||
|
# elif defined __BORLANDC__
|
||||||
|
# define SAVE_WIN32_EXCEPTION_LIST
|
||||||
|
__emit__(0x64, 0xA1, 0, 0, 0, 0); /* mov eax, fs:[0] */
|
||||||
|
p = _EAX;
|
||||||
|
# endif
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
win32_set_exception_list(p)
|
||||||
|
DWORD p;
|
||||||
|
{
|
||||||
|
# if defined _MSC_VER
|
||||||
|
# ifdef _M_IX86
|
||||||
|
__asm mov eax, p;
|
||||||
|
__asm mov fs:[0], eax;
|
||||||
|
# endif
|
||||||
|
# elif defined __GNUC__
|
||||||
|
# ifdef __i386__
|
||||||
|
__asm__("movl %0,%%fs:0"::"r"(p));
|
||||||
|
# endif
|
||||||
|
# elif defined __BORLANDC__
|
||||||
|
_EAX = p;
|
||||||
|
__emit__(0x64, 0xA3, 0, 0, 0, 0); /* mov fs:[0], eax */
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined SAVE_WIN32_EXCEPTION_LIST && !defined _WIN32_WCE
|
||||||
|
# error unsupported platform
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int rb_thread_pending = 0;
|
||||||
|
|
||||||
|
VALUE rb_cThread;
|
||||||
|
|
||||||
|
extern VALUE rb_last_status;
|
||||||
|
|
||||||
|
#define WAIT_FD (1<<0)
|
||||||
|
#define WAIT_SELECT (1<<1)
|
||||||
|
#define WAIT_TIME (1<<2)
|
||||||
|
#define WAIT_JOIN (1<<3)
|
||||||
|
#define WAIT_PID (1<<4)
|
||||||
|
|
||||||
|
/* +infty, for this purpose */
|
||||||
|
#define DELAY_INFTY 1E30
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef NFDBITS
|
||||||
|
void
|
||||||
|
rb_fd_init(fds)
|
||||||
|
volatile rb_fdset_t *fds;
|
||||||
|
{
|
||||||
|
fds->maxfd = 0;
|
||||||
|
fds->fdset = ALLOC(fd_set);
|
||||||
|
FD_ZERO(fds->fdset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_fd_term(fds)
|
||||||
|
rb_fdset_t *fds;
|
||||||
|
{
|
||||||
|
if (fds->fdset)
|
||||||
|
free(fds->fdset);
|
||||||
|
fds->maxfd = 0;
|
||||||
|
fds->fdset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_fd_zero(fds)
|
||||||
|
rb_fdset_t *fds;
|
||||||
|
{
|
||||||
|
if (fds->fdset) {
|
||||||
|
MEMZERO(fds->fdset, fd_mask, howmany(fds->maxfd, NFDBITS));
|
||||||
|
FD_ZERO(fds->fdset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_fd_resize(n, fds)
|
||||||
|
int n;
|
||||||
|
rb_fdset_t *fds;
|
||||||
|
{
|
||||||
|
int m = howmany(n + 1, NFDBITS) * sizeof(fd_mask);
|
||||||
|
int o = howmany(fds->maxfd, NFDBITS) * sizeof(fd_mask);
|
||||||
|
|
||||||
|
if (m < sizeof(fd_set))
|
||||||
|
m = sizeof(fd_set);
|
||||||
|
if (o < sizeof(fd_set))
|
||||||
|
o = sizeof(fd_set);
|
||||||
|
|
||||||
|
if (m > o) {
|
||||||
|
fds->fdset = realloc(fds->fdset, m);
|
||||||
|
memset((char *)fds->fdset + o, 0, m - o);
|
||||||
|
}
|
||||||
|
if (n >= fds->maxfd)
|
||||||
|
fds->maxfd = n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_fd_set(n, fds)
|
||||||
|
int n;
|
||||||
|
rb_fdset_t *fds;
|
||||||
|
{
|
||||||
|
rb_fd_resize(n, fds);
|
||||||
|
FD_SET(n, fds->fdset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_fd_clr(n, fds)
|
||||||
|
int n;
|
||||||
|
rb_fdset_t *fds;
|
||||||
|
{
|
||||||
|
if (n >= fds->maxfd)
|
||||||
|
return;
|
||||||
|
FD_CLR(n, fds->fdset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rb_fd_isset(n, fds)
|
||||||
|
int n;
|
||||||
|
const rb_fdset_t *fds;
|
||||||
|
{
|
||||||
|
if (n >= fds->maxfd)
|
||||||
|
return 0;
|
||||||
|
return FD_ISSET(n, fds->fdset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_fd_copy(dst, src, max)
|
||||||
|
rb_fdset_t *dst;
|
||||||
|
const fd_set *src;
|
||||||
|
int max;
|
||||||
|
{
|
||||||
|
int size = howmany(max, NFDBITS) * sizeof(fd_mask);
|
||||||
|
|
||||||
|
if (size < sizeof(fd_set))
|
||||||
|
size = sizeof(fd_set);
|
||||||
|
dst->maxfd = max;
|
||||||
|
dst->fdset = realloc(dst->fdset, size);
|
||||||
|
memcpy(dst->fdset, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rb_fd_select(n, readfds, writefds, exceptfds, timeout)
|
||||||
|
int n;
|
||||||
|
rb_fdset_t *readfds, *writefds, *exceptfds;
|
||||||
|
struct timeval *timeout;
|
||||||
|
{
|
||||||
|
rb_fd_resize(n - 1, readfds);
|
||||||
|
rb_fd_resize(n - 1, writefds);
|
||||||
|
rb_fd_resize(n - 1, exceptfds);
|
||||||
|
return select(n, rb_fd_ptr(readfds), rb_fd_ptr(writefds),
|
||||||
|
rb_fd_ptr(exceptfds), timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef FD_ZERO
|
||||||
|
#undef FD_SET
|
||||||
|
#undef FD_CLR
|
||||||
|
#undef FD_ISSET
|
||||||
|
|
||||||
|
#define FD_ZERO(f) rb_fd_zero(f)
|
||||||
|
#define FD_SET(i, f) rb_fd_set(i, f)
|
||||||
|
#define FD_CLR(i, f) rb_fd_clr(i, f)
|
||||||
|
#define FD_ISSET(i, f) rb_fd_isset(i, f)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* typedef struct thread * rb_thread_t; */
|
||||||
|
|
||||||
|
struct thread {
|
||||||
|
/* obsolete */
|
||||||
|
struct thread *next, *prev;
|
||||||
|
rb_jmpbuf_t context;
|
||||||
|
#ifdef SAVE_WIN32_EXCEPTION_LIST
|
||||||
|
DWORD win32_exception_list;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
VALUE result;
|
||||||
|
|
||||||
|
long stk_len;
|
||||||
|
long stk_max;
|
||||||
|
VALUE *stk_ptr;
|
||||||
|
VALUE *stk_pos;
|
||||||
|
#ifdef __ia64__
|
||||||
|
VALUE *bstr_ptr;
|
||||||
|
long bstr_len;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct FRAME *frame;
|
||||||
|
struct SCOPE *scope;
|
||||||
|
struct RVarmap *dyna_vars;
|
||||||
|
struct BLOCK *block;
|
||||||
|
struct iter *iter;
|
||||||
|
struct tag *tag;
|
||||||
|
VALUE klass;
|
||||||
|
VALUE wrapper;
|
||||||
|
NODE *cref;
|
||||||
|
struct ruby_env *anchor;
|
||||||
|
|
||||||
|
int flags; /* misc. states (vmode/rb_trap_immediate/raised) */
|
||||||
|
|
||||||
|
NODE *node;
|
||||||
|
|
||||||
|
int tracing;
|
||||||
|
VALUE errinfo;
|
||||||
|
VALUE last_status;
|
||||||
|
VALUE last_line;
|
||||||
|
VALUE last_match;
|
||||||
|
|
||||||
|
int safe;
|
||||||
|
|
||||||
|
enum yarv_thread_status status;
|
||||||
|
int wait_for;
|
||||||
|
int fd;
|
||||||
|
rb_fdset_t readfds;
|
||||||
|
rb_fdset_t writefds;
|
||||||
|
rb_fdset_t exceptfds;
|
||||||
|
int select_value;
|
||||||
|
double delay;
|
||||||
|
rb_thread_t join;
|
||||||
|
|
||||||
|
int abort;
|
||||||
|
int priority;
|
||||||
|
VALUE thgroup;
|
||||||
|
|
||||||
|
st_table *locals;
|
||||||
|
|
||||||
|
VALUE thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define THREAD_RAISED 0x200 /* temporary flag */
|
||||||
|
#define THREAD_TERMINATING 0x400 /* persistent flag */
|
||||||
|
#define THREAD_FLAGS_MASK 0x400 /* mask for persistent flags */
|
||||||
|
|
||||||
|
#define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next;
|
||||||
|
#define END_FOREACH_FROM(f,x) } while (x != f)
|
||||||
|
|
||||||
|
#define FOREACH_THREAD(x) FOREACH_THREAD_FROM(curr_thread,x)
|
||||||
|
#define END_FOREACH(x) END_FOREACH_FROM(curr_thread,x)
|
||||||
|
|
||||||
|
struct thread_status_t {
|
||||||
|
NODE *node;
|
||||||
|
|
||||||
|
int tracing;
|
||||||
|
VALUE errinfo;
|
||||||
|
VALUE last_status;
|
||||||
|
VALUE last_line;
|
||||||
|
VALUE last_match;
|
||||||
|
|
||||||
|
int safe;
|
||||||
|
|
||||||
|
enum yarv_thread_status status;
|
||||||
|
int wait_for;
|
||||||
|
int fd;
|
||||||
|
rb_fdset_t readfds;
|
||||||
|
rb_fdset_t writefds;
|
||||||
|
rb_fdset_t exceptfds;
|
||||||
|
int select_value;
|
||||||
|
double delay;
|
||||||
|
rb_thread_t join;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define THREAD_COPY_STATUS(src, dst) (void)( \
|
||||||
|
(dst)->node = (src)->node, \
|
||||||
|
\
|
||||||
|
(dst)->tracing = (src)->tracing, \
|
||||||
|
(dst)->errinfo = (src)->errinfo, \
|
||||||
|
(dst)->last_status = (src)->last_status, \
|
||||||
|
(dst)->last_line = (src)->last_line, \
|
||||||
|
(dst)->last_match = (src)->last_match, \
|
||||||
|
\
|
||||||
|
(dst)->safe = (src)->safe, \
|
||||||
|
\
|
||||||
|
(dst)->status = (src)->status, \
|
||||||
|
(dst)->wait_for = (src)->wait_for, \
|
||||||
|
(dst)->fd = (src)->fd, \
|
||||||
|
(dst)->readfds = (src)->readfds, \
|
||||||
|
(dst)->writefds = (src)->writefds, \
|
||||||
|
(dst)->exceptfds = (src)->exceptfds, \
|
||||||
|
rb_fd_init(&(src)->readfds), \
|
||||||
|
rb_fd_init(&(src)->writefds), \
|
||||||
|
rb_fd_init(&(src)->exceptfds), \
|
||||||
|
(dst)->select_value = (src)->select_value, \
|
||||||
|
(dst)->delay = (src)->delay, \
|
||||||
|
(dst)->join = (src)->join, \
|
||||||
|
0)
|
||||||
|
|
||||||
|
int
|
||||||
|
thread_set_raised(yarv_thread_t *th)
|
||||||
|
{
|
||||||
|
if (th->raised_flag) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
th->raised_flag = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
thread_reset_raised(yarv_thread_t *th)
|
||||||
|
{
|
||||||
|
if (th->raised_flag == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
th->raised_flag = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_thread_fd_close(fd)
|
||||||
|
int fd;
|
||||||
|
{
|
||||||
|
// TODO: fix me
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_thread_current()
|
||||||
|
{
|
||||||
|
return GET_THREAD()->self;
|
||||||
|
}
|
||||||
|
|
||||||
|
static rb_thread_t
|
||||||
|
rb_thread_alloc(klass)
|
||||||
|
VALUE klass;
|
||||||
|
{
|
||||||
|
UNSUPPORTED(rb_thread_alloc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_thread_start_0(fn, arg, th)
|
||||||
|
VALUE (*fn) ();
|
||||||
|
void *arg;
|
||||||
|
rb_thread_t th;
|
||||||
|
{
|
||||||
|
rb_bug("unsupported: rb_thread_start_0");
|
||||||
|
return 0; /* not reached */
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_thread_create(VALUE (*fn) (), void *arg)
|
||||||
|
{
|
||||||
|
Init_stack((VALUE *)&arg);
|
||||||
|
return rb_thread_start_0(fn, arg, rb_thread_alloc(rb_cThread));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* Thread.new([arg]*) {|args| block } => thread
|
||||||
|
*
|
||||||
|
* Creates and runs a new thread to execute the instructions given in
|
||||||
|
* <i>block</i>. Any arguments passed to <code>Thread::new</code> are passed
|
||||||
|
* into the block.
|
||||||
|
*
|
||||||
|
* x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
|
||||||
|
* a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
|
||||||
|
* x.join # Let the threads finish before
|
||||||
|
* a.join # main thread exits...
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* abxyzc
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* Thread.new([arg]*) {|args| block } => thread
|
||||||
|
*
|
||||||
|
* Creates and runs a new thread to execute the instructions given in
|
||||||
|
* <i>block</i>. Any arguments passed to <code>Thread::new</code> are passed
|
||||||
|
* into the block.
|
||||||
|
*
|
||||||
|
* x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
|
||||||
|
* a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
|
||||||
|
* x.join # Let the threads finish before
|
||||||
|
* a.join # main thread exits...
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* abxyzc
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* Thread.start([args]*) {|args| block } => thread
|
||||||
|
* Thread.fork([args]*) {|args| block } => thread
|
||||||
|
*
|
||||||
|
* Basically the same as <code>Thread::new</code>. However, if class
|
||||||
|
* <code>Thread</code> is subclassed, then calling <code>start</code> in that
|
||||||
|
* subclass will not invoke the subclass's <code>initialize</code> method.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int rb_thread_critical;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* Thread.critical => true or false
|
||||||
|
*
|
||||||
|
* Returns the status of the global ``thread critical'' condition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* Thread.critical= boolean => true or false
|
||||||
|
*
|
||||||
|
* Sets the status of the global ``thread critical'' condition and returns
|
||||||
|
* it. When set to <code>true</code>, prohibits scheduling of any existing
|
||||||
|
* thread. Does not block new threads from being created and run. Certain
|
||||||
|
* thread operations (such as stopping or killing a thread, sleeping in the
|
||||||
|
* current thread, and raising an exception) may cause a thread to be scheduled
|
||||||
|
* even when in a critical section. <code>Thread::critical</code> is not
|
||||||
|
* intended for daily use: it is primarily there to support folks writing
|
||||||
|
* threading libraries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Document-class: Continuation
|
||||||
|
*
|
||||||
|
* Continuation objects are generated by
|
||||||
|
* <code>Kernel#callcc</code>. They hold a return address and execution
|
||||||
|
* context, allowing a nonlocal return to the end of the
|
||||||
|
* <code>callcc</code> block from anywhere within a program.
|
||||||
|
* Continuations are somewhat analogous to a structured version of C's
|
||||||
|
* <code>setjmp/longjmp</code> (although they contain more state, so
|
||||||
|
* you might consider them closer to threads).
|
||||||
|
*
|
||||||
|
* For instance:
|
||||||
|
*
|
||||||
|
* arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
|
||||||
|
* callcc{|$cc|}
|
||||||
|
* puts(message = arr.shift)
|
||||||
|
* $cc.call unless message =~ /Max/
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* Freddie
|
||||||
|
* Herbie
|
||||||
|
* Ron
|
||||||
|
* Max
|
||||||
|
*
|
||||||
|
* This (somewhat contrived) example allows the inner loop to abandon
|
||||||
|
* processing early:
|
||||||
|
*
|
||||||
|
* callcc {|cont|
|
||||||
|
* for i in 0..4
|
||||||
|
* print "\n#{i}: "
|
||||||
|
* for j in i*5...(i+1)*5
|
||||||
|
* cont.call() if j == 17
|
||||||
|
* printf "%3d", j
|
||||||
|
* end
|
||||||
|
* end
|
||||||
|
* }
|
||||||
|
* print "\n"
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* 0: 0 1 2 3 4
|
||||||
|
* 1: 5 6 7 8 9
|
||||||
|
* 2: 10 11 12 13 14
|
||||||
|
* 3: 15 16
|
||||||
|
*/
|
||||||
|
|
||||||
|
VALUE rb_cCont;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* callcc {|cont| block } => obj
|
||||||
|
*
|
||||||
|
* Generates a <code>Continuation</code> object, which it passes to the
|
||||||
|
* associated block. Performing a <em>cont</em><code>.call</code> will
|
||||||
|
* cause the <code>callcc</code> to return (as will falling through the
|
||||||
|
* end of the block). The value returned by the <code>callcc</code> is
|
||||||
|
* the value of the block, or the value passed to
|
||||||
|
* <em>cont</em><code>.call</code>. See class <code>Continuation</code>
|
||||||
|
* for more details. Also see <code>Kernel::throw</code> for
|
||||||
|
* an alternative mechanism for unwinding a call stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_callcc(self)
|
||||||
|
VALUE self;
|
||||||
|
{
|
||||||
|
UNSUPPORTED(rb_callcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* cont.call(args, ...)
|
||||||
|
* cont[args, ...]
|
||||||
|
*
|
||||||
|
* Invokes the continuation. The program continues from the end of the
|
||||||
|
* <code>callcc</code> block. If no arguments are given, the original
|
||||||
|
* <code>callcc</code> returns <code>nil</code>. If one argument is
|
||||||
|
* given, <code>callcc</code> returns it. Otherwise, an array
|
||||||
|
* containing <i>args</i> is returned.
|
||||||
|
*
|
||||||
|
* callcc {|cont| cont.call } #=> nil
|
||||||
|
* callcc {|cont| cont.call 1 } #=> 1
|
||||||
|
* callcc {|cont| cont.call 1, 2, 3 } #=> [1, 2, 3]
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_cont_call(argc, argv, cont)
|
||||||
|
int argc;
|
||||||
|
VALUE *argv;
|
||||||
|
VALUE cont;
|
||||||
|
{
|
||||||
|
UNSUPPORTED(rb_cont_call);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* variables for recursive traversals */
|
||||||
|
static ID recursive_key;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* +Thread+ encapsulates the behavior of a thread of
|
||||||
|
* execution, including the main thread of the Ruby script.
|
||||||
|
*
|
||||||
|
* In the descriptions of the methods in this class, the parameter _sym_
|
||||||
|
* refers to a symbol, which is either a quoted string or a
|
||||||
|
* +Symbol+ (such as <code>:name</code>).
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
Init_Thread()
|
||||||
|
{
|
||||||
|
recursive_key = rb_intern("__recursive_key__");
|
||||||
|
rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
|
||||||
|
rb_cCont = rb_define_class("Continuation", rb_cObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
recursive_check(obj)
|
||||||
|
VALUE obj;
|
||||||
|
{
|
||||||
|
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
||||||
|
|
||||||
|
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
||||||
|
return Qfalse;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VALUE list = rb_hash_aref(hash, ID2SYM(rb_frame_this_func()));
|
||||||
|
|
||||||
|
if (NIL_P(list) || TYPE(list) != T_ARRAY)
|
||||||
|
return Qfalse;
|
||||||
|
return rb_ary_includes(list, rb_obj_id(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
recursive_push(obj)
|
||||||
|
VALUE obj;
|
||||||
|
{
|
||||||
|
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
||||||
|
VALUE list, sym;
|
||||||
|
|
||||||
|
sym = ID2SYM(rb_frame_this_func());
|
||||||
|
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
||||||
|
hash = rb_hash_new();
|
||||||
|
rb_thread_local_aset(rb_thread_current(), recursive_key, hash);
|
||||||
|
list = Qnil;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
list = rb_hash_aref(hash, sym);
|
||||||
|
}
|
||||||
|
if (NIL_P(list) || TYPE(list) != T_ARRAY) {
|
||||||
|
list = rb_ary_new();
|
||||||
|
rb_hash_aset(hash, sym, list);
|
||||||
|
}
|
||||||
|
rb_ary_push(list, rb_obj_id(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
recursive_pop()
|
||||||
|
{
|
||||||
|
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
||||||
|
VALUE list, sym;
|
||||||
|
|
||||||
|
sym = ID2SYM(rb_frame_this_func());
|
||||||
|
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
||||||
|
VALUE symname;
|
||||||
|
VALUE thrname;
|
||||||
|
symname = rb_inspect(sym);
|
||||||
|
thrname = rb_inspect(rb_thread_current());
|
||||||
|
|
||||||
|
rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s",
|
||||||
|
StringValuePtr(symname), StringValuePtr(thrname));
|
||||||
|
}
|
||||||
|
list = rb_hash_aref(hash, sym);
|
||||||
|
if (NIL_P(list) || TYPE(list) != T_ARRAY) {
|
||||||
|
VALUE symname = rb_inspect(sym);
|
||||||
|
VALUE thrname = rb_inspect(rb_thread_current());
|
||||||
|
rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s",
|
||||||
|
StringValuePtr(symname), StringValuePtr(thrname));
|
||||||
|
}
|
||||||
|
rb_ary_pop(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
|
||||||
|
{
|
||||||
|
if (recursive_check(obj)) {
|
||||||
|
return (*func) (obj, arg, Qtrue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VALUE result = Qundef;
|
||||||
|
int state;
|
||||||
|
|
||||||
|
recursive_push(obj);
|
||||||
|
PUSH_TAG(PROT_NONE);
|
||||||
|
if ((state = EXEC_TAG()) == 0) {
|
||||||
|
result = (*func) (obj, arg, Qfalse);
|
||||||
|
}
|
||||||
|
POP_TAG();
|
||||||
|
recursive_pop();
|
||||||
|
if (state)
|
||||||
|
JUMP_TAG(state);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush_register_windows must not be inlined because flushrs doesn't flush
|
||||||
|
* current frame in register stack. */
|
||||||
|
#ifdef __ia64__
|
||||||
|
void
|
||||||
|
flush_register_windows(void)
|
||||||
|
{
|
||||||
|
__asm__("flushrs");
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -118,12 +118,12 @@ module DL
|
||||||
f = import_function(symname, ctype, argtype, opt[:call_type])
|
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
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
Makefile
|
Makefile
|
||||||
mkmf.log
|
mkmf.log
|
||||||
*.def
|
*.def
|
||||||
extconf.h
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
547
gc.c
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue