ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download mbox.gz: |
* [ruby-core:104916] [Ruby master Bug#18075] Crasher using ripper + yydebug
@ 2021-08-14  4:20  6% ryand-ruby
  0 siblings, 0 replies; 71+ results
From: ryand-ruby @ 2021-08-14  4:20 UTC (permalink / raw)
  To: ruby-core

Issue #18075 has been reported by zenspider (Ryan Davis).

----------------------------------------
Bug #18075: Crasher using ripper + yydebug
https://bugs.ruby-lang.org/issues/18075

* Author: zenspider (Ryan Davis)
* Status: Open
* Priority: Normal
* Backport: 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN
----------------------------------------
`method `inspect' called on unexpected T_NODE object` via the following with `-d` (see output at end):

```
#!/usr/bin/env ruby -wvs

$d ||= false

require "ripper/sexp"

src = "'woot'"

rip = Ripper::SexpBuilderPP.new src
rip.yydebug = $d

p rip.parse # boom

__END__
############################################################
% % multiruby ./ripper_bug.rb
...
Passed: 2.3.8, 2.4.9, 2.5.8, 2.6.6, 2.7.3, 3.0.1 master
Failed:

############################################################
% multiruby ./ripper_bug.rb -d
...
Entering state 299
./ripper_bug.rb:11:in `parse': method `inspect' called on unexpected T_NODE object (0x000000012f8db898 flags=0x1e1b) (NotImplementedError)
        from ./ripper_bug.rb:11:in `<main>'

RESULT = pid 24703 exit 1

TOTAL RESULT = 3 failures out of 6

Passed: 2.3.8, 2.4.9, 2.5.8
Failed: 2.6.6, 2.7.3, 3.0.1, master
```

Exists on 2.6 and up



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 6%]

* [ruby-core:92065] [Ruby trunk Bug#15650] Segmentation fault when accessing $! in at_exit within a forked process
       [not found]     <redmine.issue-15650.20190309221037@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2019-03-12 21:06  5% ` [ruby-core:91792] " nagachika00
@ 2019-03-31 15:01  5% ` usa
  3 siblings, 0 replies; 71+ results
From: usa @ 2019-03-31 15:01 UTC (permalink / raw)
  To: ruby-core

Issue #15650 has been updated by usa (Usaku NAKAMURA).

Backport changed from 2.4: REQUIRED, 2.5: DONE, 2.6: DONE to 2.4: DONE, 2.5: DONE, 2.6: DONE

ruby_2_4 r67392 merged revision(s) 67201.

----------------------------------------
Bug #15650: Segmentation fault when accessing $! in at_exit within a forked process
https://bugs.ruby-lang.org/issues/15650#change-77390

* Author: vincentvanbush (Michał Buszkiewicz)
* Status: Closed
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-linux]
* Backport: 2.4: DONE, 2.5: DONE, 2.6: DONE
----------------------------------------
In the following piece of code, `break` is erroneously used inside a block passed to `Process.fork`, which would normally result in a ``fork': unexpected break` message.
It is not entirely clear to me whether this should be accessible as an exception object or not - if not, I would expect this code to just print the error out and terminate, so $! would just contain `nil` in the `at_exit` block.
```ruby
fork do
  at_exit do
    puts $!
  end

  break
end
```
However, what occurs is a segmentation fault, which can be found in an attachment to this issue.

Historical behavior:

* `ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]`:
```
nil
foo.rb:7:in `fork': unexpected break
```
* `ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-linux]`:

```
foo.rb:3:in `block (2 levels) in <main>': method `method_missing' called on unexpected T_NODE object (0x0055a2323cfc88 flags=0x381c klass=0x0) (NotImplementedError)
        from foo.rb:1:in `fork'
        from foo.rb:1:in `<main>'
foo.rb:1:in `fork': unexpected break
```

* `ruby 2.0.0p648 (2015-12-16 revision 53162) [x86_64-linux]`:

```
foo.rb:3:in `puts': method `to_ary' called on unexpected T_NODE object (0x00565176a0f820 flags=0x391c) (NotImplementedError)
	from foo.rb:3:in `puts'
	from foo.rb:3:in `block (2 levels) in <main>'
	from foo.rb:1:in `fork'
	from foo.rb:1:in `<main>'
foo.rb:1: unexpected break
```

* `ruby 2.1.9p490 (2016-03-30 revision 54437) [x86_64-linux]` - segmentation fault
* `ruby 2.2.10p489 (2018-03-28 revision 63023) [x86_64-linux]` - ditto
* `ruby 2.3.8p459 (2018-10-18 revision 65136) [x86_64-linux]` - ditto
* `ruby 2.4.5p335 (2018-10-18 revision 65137) [x86_64-linux]` - ditto
* `ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux]` - ditto

There is clearly something funny going on since 1.9, and 2.1 goes totally nuts.

When `break` is replaced with `raise 'foo'`, all of these versions catch the exception under `$!` correctly.

Tried compiling 2.6.1 under Ubuntu with GCC 4, 5, 6, 7 and 8, and Clang and the exception is not different. Also tried one of the rubies (2.3.8) compiled in CentOS 7 - no difference in result.

---Files--------------------------------
backtrace.txt (17.3 KB)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 5%]

* [ruby-core:91792] [Ruby trunk Bug#15650] Segmentation fault when accessing $! in at_exit within a forked process
       [not found]     <redmine.issue-15650.20190309221037@ruby-lang.org>
  2019-03-09 22:11  4% ` [ruby-core:91731] [Ruby trunk Bug#15650] Segmentation fault when accessing $! in at_exit within a forked process buszkiewiczm
  2019-03-11  7:03  5% ` [ruby-core:91762] " naruse
@ 2019-03-12 21:06  5% ` nagachika00
  2019-03-31 15:01  5% ` [ruby-core:92065] " usa
  3 siblings, 0 replies; 71+ results
From: nagachika00 @ 2019-03-12 21:06 UTC (permalink / raw)
  To: ruby-core

Issue #15650 has been updated by nagachika (Tomoyuki Chikanaga).

Backport changed from 2.4: REQUIRED, 2.5: REQUIRED, 2.6: DONE to 2.4: REQUIRED, 2.5: DONE, 2.6: DONE

ruby_2_5 r67233 merged revision(s) 67201.

----------------------------------------
Bug #15650: Segmentation fault when accessing $! in at_exit within a forked process
https://bugs.ruby-lang.org/issues/15650#change-77066

* Author: vincentvanbush (Michał Buszkiewicz)
* Status: Closed
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-linux]
* Backport: 2.4: REQUIRED, 2.5: DONE, 2.6: DONE
----------------------------------------
In the following piece of code, `break` is erroneously used inside a block passed to `Process.fork`, which would normally result in a ``fork': unexpected break` message.
It is not entirely clear to me whether this should be accessible as an exception object or not - if not, I would expect this code to just print the error out and terminate, so $! would just contain `nil` in the `at_exit` block.
```ruby
fork do
  at_exit do
    puts $!
  end

  break
end
```
However, what occurs is a segmentation fault, which can be found in an attachment to this issue.

Historical behavior:

* `ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]`:
```
nil
foo.rb:7:in `fork': unexpected break
```
* `ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-linux]`:

```
foo.rb:3:in `block (2 levels) in <main>': method `method_missing' called on unexpected T_NODE object (0x0055a2323cfc88 flags=0x381c klass=0x0) (NotImplementedError)
        from foo.rb:1:in `fork'
        from foo.rb:1:in `<main>'
foo.rb:1:in `fork': unexpected break
```

* `ruby 2.0.0p648 (2015-12-16 revision 53162) [x86_64-linux]`:

```
foo.rb:3:in `puts': method `to_ary' called on unexpected T_NODE object (0x00565176a0f820 flags=0x391c) (NotImplementedError)
	from foo.rb:3:in `puts'
	from foo.rb:3:in `block (2 levels) in <main>'
	from foo.rb:1:in `fork'
	from foo.rb:1:in `<main>'
foo.rb:1: unexpected break
```

* `ruby 2.1.9p490 (2016-03-30 revision 54437) [x86_64-linux]` - segmentation fault
* `ruby 2.2.10p489 (2018-03-28 revision 63023) [x86_64-linux]` - ditto
* `ruby 2.3.8p459 (2018-10-18 revision 65136) [x86_64-linux]` - ditto
* `ruby 2.4.5p335 (2018-10-18 revision 65137) [x86_64-linux]` - ditto
* `ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux]` - ditto

There is clearly something funny going on since 1.9, and 2.1 goes totally nuts.

When `break` is replaced with `raise 'foo'`, all of these versions catch the exception under `$!` correctly.

Tried compiling 2.6.1 under Ubuntu with GCC 4, 5, 6, 7 and 8, and Clang and the exception is not different. Also tried one of the rubies (2.3.8) compiled in CentOS 7 - no difference in result.

---Files--------------------------------
backtrace.txt (17.3 KB)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 5%]

* [ruby-core:91762] [Ruby trunk Bug#15650] Segmentation fault when accessing $! in at_exit within a forked process
       [not found]     <redmine.issue-15650.20190309221037@ruby-lang.org>
  2019-03-09 22:11  4% ` [ruby-core:91731] [Ruby trunk Bug#15650] Segmentation fault when accessing $! in at_exit within a forked process buszkiewiczm
@ 2019-03-11  7:03  5% ` naruse
  2019-03-12 21:06  5% ` [ruby-core:91792] " nagachika00
  2019-03-31 15:01  5% ` [ruby-core:92065] " usa
  3 siblings, 0 replies; 71+ results
From: naruse @ 2019-03-11  7:03 UTC (permalink / raw)
  To: ruby-core

Issue #15650 has been updated by naruse (Yui NARUSE).

Backport changed from 2.4: REQUIRED, 2.5: REQUIRED, 2.6: REQUIRED to 2.4: REQUIRED, 2.5: REQUIRED, 2.6: DONE

ruby_2_6 r67209 merged revision(s) 67201.

----------------------------------------
Bug #15650: Segmentation fault when accessing $! in at_exit within a forked process
https://bugs.ruby-lang.org/issues/15650#change-77037

* Author: vincentvanbush (Michał Buszkiewicz)
* Status: Closed
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-linux]
* Backport: 2.4: REQUIRED, 2.5: REQUIRED, 2.6: DONE
----------------------------------------
In the following piece of code, `break` is erroneously used inside a block passed to `Process.fork`, which would normally result in a ``fork': unexpected break` message.
It is not entirely clear to me whether this should be accessible as an exception object or not - if not, I would expect this code to just print the error out and terminate, so $! would just contain `nil` in the `at_exit` block.
```ruby
fork do
  at_exit do
    puts $!
  end

  break
end
```
However, what occurs is a segmentation fault, which can be found in an attachment to this issue.

Historical behavior:

* `ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]`:
```
nil
foo.rb:7:in `fork': unexpected break
```
* `ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-linux]`:

```
foo.rb:3:in `block (2 levels) in <main>': method `method_missing' called on unexpected T_NODE object (0x0055a2323cfc88 flags=0x381c klass=0x0) (NotImplementedError)
        from foo.rb:1:in `fork'
        from foo.rb:1:in `<main>'
foo.rb:1:in `fork': unexpected break
```

* `ruby 2.0.0p648 (2015-12-16 revision 53162) [x86_64-linux]`:

```
foo.rb:3:in `puts': method `to_ary' called on unexpected T_NODE object (0x00565176a0f820 flags=0x391c) (NotImplementedError)
	from foo.rb:3:in `puts'
	from foo.rb:3:in `block (2 levels) in <main>'
	from foo.rb:1:in `fork'
	from foo.rb:1:in `<main>'
foo.rb:1: unexpected break
```

* `ruby 2.1.9p490 (2016-03-30 revision 54437) [x86_64-linux]` - segmentation fault
* `ruby 2.2.10p489 (2018-03-28 revision 63023) [x86_64-linux]` - ditto
* `ruby 2.3.8p459 (2018-10-18 revision 65136) [x86_64-linux]` - ditto
* `ruby 2.4.5p335 (2018-10-18 revision 65137) [x86_64-linux]` - ditto
* `ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux]` - ditto

There is clearly something funny going on since 1.9, and 2.1 goes totally nuts.

When `break` is replaced with `raise 'foo'`, all of these versions catch the exception under `$!` correctly.

Tried compiling 2.6.1 under Ubuntu with GCC 4, 5, 6, 7 and 8, and Clang and the exception is not different. Also tried one of the rubies (2.3.8) compiled in CentOS 7 - no difference in result.

---Files--------------------------------
backtrace.txt (17.3 KB)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 5%]

* [ruby-core:91731] [Ruby trunk Bug#15650] Segmentation fault when accessing $! in at_exit within a forked process
       [not found]     <redmine.issue-15650.20190309221037@ruby-lang.org>
@ 2019-03-09 22:11  4% ` buszkiewiczm
  2019-03-11  7:03  5% ` [ruby-core:91762] " naruse
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 71+ results
From: buszkiewiczm @ 2019-03-09 22:11 UTC (permalink / raw)
  To: ruby-core

Issue #15650 has been reported by vincentvanbush (Michał Buszkiewicz).

----------------------------------------
Bug #15650: Segmentation fault when accessing $! in at_exit within a forked process
https://bugs.ruby-lang.org/issues/15650

* Author: vincentvanbush (Michał Buszkiewicz)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
* ruby -v: ruby 2.6.1p33 (2019-01-30 revision 66950) [x86_64-linux]
* Backport: 2.4: UNKNOWN, 2.5: UNKNOWN, 2.6: UNKNOWN
----------------------------------------
In the following piece of code, `break` is erroneously used inside a block passed to `Process.fork`, which would normally result in a ``fork': unexpected break` message.
It is not entirely clear to me whether this should be accessible as an exception object or not - if not, I would expect this code to just print the error out and terminate, so $! would just contain `nil` in the `at_exit` block.
```
fork do
  at_exit do
    puts $!
  end

  break
end
```
However, what occurs is a segmentation fault, which can be found in an attachment to this issue.

Historical behavior:

* `ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]`:
```
nil
foo.rb:7:in `fork': unexpected break
```
* `ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-linux]`:
```
foo.rb:3:in `block (2 levels) in <main>': method `method_missing' called on unexpected T_NODE object (0x0055a2323cfc88 flags=0x381c klass=0x0) (NotImplementedError)
        from foo.rb:1:in `fork'
        from foo.rb:1:in `<main>'
foo.rb:1:in `fork': unexpected break
```
* `ruby 2.0.0p648 (2015-12-16 revision 53162) [x86_64-linux]`:
foo.rb:3:in `block (2 levels) in <main>': undefined method `inspect' for #<Object:0x005648577df7f8> (NoMethodError)
        from foo.rb:1:in `fork'
        from foo.rb:1:in `<main>'
foo.rb:1: unexpected break
* `ruby 2.1.9p490 (2016-03-30 revision 54437) [x86_64-linux]` - segmentation fault
* `ruby 2.2.10p489 (2018-03-28 revision 63023) [x86_64-linux]` - ditto
* `ruby 2.3.8p459 (2018-10-18 revision 65136) [x86_64-linux]` - ditto
* `ruby 2.4.5p335 (2018-10-18 revision 65137) [x86_64-linux]` - ditto
* `ruby 2.5.3p105 (2018-10-18 revision 65156) [x86_64-linux]` - ditto

There is clearly something funny going on since 1.9, and 2.1 goes totally nuts.

When `break` is replaced with `raise 'foo'`, all of these versions catch the exception under `$!` correctly.

Tried compiling 2.6.1 under Ubuntu with GCC 4, 5, 6, 7 and 8, and Clang and the exception is not different. Also tried one of the rubies (2.3.8) compiled in CentOS 7 - no difference in result.

---Files--------------------------------
backtrace.txt (17.3 KB)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 4%]

* [ruby-core:87076] Re: [Ruby trunk Misc#14762] [PATCH] gc.c: use ccan/list
  @ 2018-05-16  9:38  5%   ` Eric Wong
  0 siblings, 0 replies; 71+ results
From: Eric Wong @ 2018-05-16  9:38 UTC (permalink / raw)
  To: ruby-core

ko1@atdot.net wrote:
> No strong opinion.
> 
> They are memo:
> 
> I tried to reorder sweeping list by (a) "full page (all slots are living)" and (b)"can sweep page (there are some free-able slots)" and sweep only (b).
> No big improvement though :p
> 
> I think using ccan we can move the order, so we can try it later?

Yes, ccan/list should make reordering and experimentation
simpler.

> If we have any trouble to modify them using more complex strategy, we can revert it.
> 
> 
> Trivial comments:

> * The field name `sweep_pos` seems index for me. Maybe
> `sweeping_page` or something is fine for me.

Right, I think of it as an index to the main ->pages list; so I
used '_pos' suffix.  I guess `sweeping_page` along with comment
clarifying it is a pointer inside ->pages is OK.

> * Every time I feel magical for the name `node` (for CCAN
> list). Should I endure? (page_node or something is clear, but
> verbose I agree).

I only wondered about confusion with T_NODE type.
I suppose `page_node` is OK, but I prefer shorter names
(since I need big fonts)

^ permalink raw reply	[relevance 5%]

* [ruby-core:79444] [Ruby trunk Bug#10232][Rejected] Trivial change of IMMEDIATE VALUE bits layout
       [not found]     <redmine.issue-10232.20140912012732@ruby-lang.org>
                   ` (3 preceding siblings ...)
  2014-11-27 11:28  4% ` [ruby-core:66522] " ko1
@ 2017-02-06  2:55  4% ` ko1
  4 siblings, 0 replies; 71+ results
From: ko1 @ 2017-02-06  2:55 UTC (permalink / raw)
  To: ruby-core

Issue #10232 has been updated by Koichi Sasada.

Status changed from Open to Rejected

Reject it and revisit sometime.

----------------------------------------
Bug #10232: Trivial change of IMMEDIATE VALUE bits layout
https://bugs.ruby-lang.org/issues/10232#change-62875

* Author: Koichi Sasada
* Status: Rejected
* Priority: Normal
* Assignee: Koichi Sasada
* Target version: next minor
* ruby -v: 2.2
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN
----------------------------------------

The following patch improves performance a bit.

```
!USE_FLONUM
-------------------------
...xxxx xxx1 Fixnum
...0000 1110 Symbol
...0000 0000 Qfalse
...0000 0010 Qtrue
...0000 0100 Qnil
...0000 0110 Qundef

USE_FLONUM
-------------------------
...xxxx xxx1 Fixnum
...xxxx xx10 Flonum
...0000 1100 Symbol
...0000 0000 Qfalse  0x00 =  0
...0000 1000 Qnil    0x08 =  8
...0001 0100 Qtrue   0x14 = 20
...0011 0100 Qundef  0x34 = 52

#=>

!USE_FLONUM
-------------------------
xxxx xxxx xxx1 Fixnum  0x01
xxxx 0011 0010 Symbol  0x32 = 50
0000 0000 0000 Qfalse  0x00
0000 0000 0010 Qnil    0x02
0000 0001 0010 Qtrue   0x12 = 18
0000 0010 0010 Qundef  0x22 = 32

USE_FLONUM
-------------------------
xxxx xxxx xxx1 Fixnum  0x01
xxxx xxxx xx10 Flonum  0x02
xxxx 0011 0100 Symbol  0x34 = 52
0000 0000 0000 Qfalse  0x00 =  0
0000 0000 0100 Qnil    0x04 =  4
0000 0001 0100 Qtrue   0x14 = 20
0000 0010 0100 Qundef  0x24 = 36
```

```patch
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 47531)
+++ include/ruby/ruby.h	(working copy)
@@ -395,6 +395,27 @@ USE_FLONUM
 ...0000 1000 Qnil    0x08 =  8
 ...0001 0100 Qtrue   0x14 = 20
 ...0011 0100 Qundef  0x34 = 52
+
+#=>
+
+!USE_FLONUM
+-------------------------
+xxxx xxxx xxx1 Fixnum  0x01
+xxxx 0011 0010 Symbol  0x32 = 50
+0000 0000 0000 Qfalse  0x00
+0000 0000 0010 Qnil    0x02
+0000 0001 0010 Qtrue   0x12 = 18
+0000 0010 0010 Qundef  0x22 = 32
+
+USE_FLONUM
+-------------------------
+xxxx xxxx xxx1 Fixnum  0x01
+xxxx xxxx xx10 Flonum  0x02
+xxxx 0011 0100 Symbol  0x34 = 52
+0000 0000 0000 Qfalse  0x00 =  0
+0000 0000 0100 Qnil    0x04 =  4
+0000 0001 0100 Qtrue   0x14 = 20
+0000 0010 0100 Qundef  0x24 = 36
  */
 
 /* special constants - i.e. non-zero and non-fixnum constants */
@@ -402,26 +423,26 @@ enum ruby_special_consts {
 #if USE_FLONUM
     RUBY_Qfalse = 0x00,
     RUBY_Qtrue  = 0x14,
-    RUBY_Qnil   = 0x08,
-    RUBY_Qundef = 0x34,
+    RUBY_Qnil   = 0x04,
+    RUBY_Qundef = 0x24,
 
     RUBY_IMMEDIATE_MASK = 0x07,
     RUBY_FIXNUM_FLAG    = 0x01,
     RUBY_FLONUM_MASK    = 0x03,
     RUBY_FLONUM_FLAG    = 0x02,
-    RUBY_SYMBOL_FLAG    = 0x0c,
+    RUBY_SYMBOL_FLAG    = 0x34,
     RUBY_SPECIAL_SHIFT  = 8
 #else
-    RUBY_Qfalse = 0,
-    RUBY_Qtrue  = 2,
-    RUBY_Qnil   = 4,
-    RUBY_Qundef = 6,
+    RUBY_Qfalse = 0x00,
+    RUBY_Qtrue  = 0x12,
+    RUBY_Qnil   = 0x02,
+    RUBY_Qundef = 0x22,
 
     RUBY_IMMEDIATE_MASK = 0x03,
     RUBY_FIXNUM_FLAG    = 0x01,
     RUBY_FLONUM_MASK    = 0x00,	/* any values ANDed with FLONUM_MASK cannot be FLONUM_FLAG */
     RUBY_FLONUM_FLAG    = 0x02,
-    RUBY_SYMBOL_FLAG    = 0x0e,
+    RUBY_SYMBOL_FLAG    = 0x32,
     RUBY_SPECIAL_SHIFT  = 8
 #endif
 };
@@ -1106,7 +1127,7 @@ struct RStruct {
 #define FL_USER18    (((VALUE)1)<<(FL_USHIFT+18))
 #define FL_USER19    (((VALUE)1)<<(FL_USHIFT+19))
 
-#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !RTEST(x))
+#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !(x))
 
 #define FL_ABLE(x) (!SPECIAL_CONST_P(x) && BUILTIN_TYPE(x) != T_NODE)
 #define FL_TEST_RAW(x,f) (RBASIC(x)->flags&(f))
@@ -1583,11 +1604,9 @@ rb_class_of(VALUE obj)
 	if (FLONUM_P(obj)) return rb_cFloat;
 	if (obj == Qtrue)  return rb_cTrueClass;
 	if (STATIC_SYM_P(obj)) return rb_cSymbol;
-    }
-    else if (!RTEST(obj)) {
 	if (obj == Qnil)   return rb_cNilClass;
-	if (obj == Qfalse) return rb_cFalseClass;
     }
+    else if (obj == Qfalse) return rb_cFalseClass;
     return RBASIC(obj)->klass;
 }
 
@@ -1600,11 +1619,9 @@ rb_type(VALUE obj)
         if (obj == Qtrue)  return T_TRUE;
 	if (STATIC_SYM_P(obj)) return T_SYMBOL;
 	if (obj == Qundef) return T_UNDEF;
-    }
-    else if (!RTEST(obj)) {
 	if (obj == Qnil)   return T_NIL;
-	if (obj == Qfalse) return T_FALSE;
     }
+    else if (obj == Qfalse) return T_FALSE;
     return BUILTIN_TYPE(obj);
 }
 
```

The change is:

(1) IMMEDIATE_P(Qnil) => TRUE
(2) SPECIAL_CONST_P(x) becomes a bit simple -> (IMMEDIATE_P(x) || !(x))

(1) can be incompatibility issue so that I don't propose this fix strongly.
Interpreter core doesn't depends on this spec, but C-exts can be affected.


Benchmark result is: http://www.atdot.net/sp/raw/stirbn (gitruby is modified version)

Strange thing is: vm1_const

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
end

trunk	1.057002067565918
trunk	1.07387113571167
trunk	1.3638195991516113
trunk	1.076874017715454
trunk	1.0717082023620605
gitruby	0.7370171546936035
gitruby	0.7366814613342285
gitruby	0.7377498149871826
gitruby	0.7381434440612793
gitruby	0.7375714778900146
```

vm1_const only repeats `getinlinecache' instruction. I'm not sure why it has impact.

Change this program to repeat accessing constant more:

```
Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
    k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const

end

trunk   2.2485034465789795
trunk   2.2310359477996826
trunk   2.2247872352600098
trunk   2.2434682846069336
trunk   2.225156307220459
gitruby 2.2048048973083496
gitruby 2.2114696502685547
gitruby 2.2110848426818848
gitruby 2.208353042602539
gitruby 2.2142462730407715
```

It can be accidentally.

Other variations:

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  k = Const
end

trunk   0.6202449798583984
trunk   0.8297767639160156
trunk   0.6203830242156982
trunk   0.6206128597259521
trunk   0.6202561855316162
gitruby 0.6209316253662109
gitruby 0.6197938919067383
gitruby 0.6191442012786865
gitruby 0.6194281578063965
gitruby 0.6211118698120117
```

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
  l = Const
end

trunk   1.195659875869751
trunk   1.1864018440246582
trunk   1.1857333183288574
trunk   1.17852783203125
trunk   1.177058458328247
gitruby 1.1888437271118164
gitruby 1.1901893615722656
gitruby 1.1873669624328613
gitruby 1.187666893005371
gitruby 1.182875156402588
```

It seems that such strange behaviour only on two Const accessing.





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 4%]

* [ruby-core:72425] [Ruby trunk - Bug #11740] ObjectSpace.each_object exposes internal metaclasses
       [not found]     <redmine.issue-11740.20151125102527@ruby-lang.org>
  2015-12-16  8:06  5% ` [ruby-core:72180] [Ruby trunk - Bug #11740] ObjectSpace.each_object exposes internal metaclasses ko1
@ 2015-12-22  2:36  5% ` shugo
  1 sibling, 0 replies; 71+ results
From: shugo @ 2015-12-22  2:36 UTC (permalink / raw)
  To: ruby-core

Issue #11740 has been updated by Shugo Maeda.


Koichi Sasada wrote:
> Maybe I missed some points.
> Any idea?

You shouldn't hide singleton classes of non-class objects.

```diff
diff --git a/gc.c b/gc.c
index 12be1ea..a574656 100644
--- a/gc.c
+++ b/gc.c
@@ -2400,6 +2400,14 @@ internal_object_p(VALUE obj)
 	  case T_NODE:
 	  case T_ZOMBIE:
 	    break;
+	  case T_CLASS:
+	    {
+		if (FL_TEST(obj, FL_SINGLETON)) {
+		    int rb_singleton_class_has_metaclass_p(VALUE sklass);
+		    return RB_TYPE_P(rb_attr_get(obj, id__attached__), T_CLASS) &&
+			rb_singleton_class_has_metaclass_p(obj) == 0;
+		}
+	    }
 	  default:
 	    if (!p->as.basic.klass) break;
 	    return 0;
```



----------------------------------------
Bug #11740: ObjectSpace.each_object exposes internal metaclasses
https://bugs.ruby-lang.org/issues/11740#change-55718

* Author: Benoit Daloze
* Status: Assigned
* Priority: Normal
* Assignee: Koichi Sasada
* ruby -v: ruby 2.3.0dev (2015-11-19 trunk 52672) [x86_64-linux]
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
ObjectSpace.each_object exposes internal metaclasses and
this might result in assumptions being violated since the metaclass structure is not well preserved.

See the attached script for an example.
The #bla method should always be defined on the metaclass of "klass".

See https://bugs.ruby-lang.org/issues/11360#note-2 as well in which I warned against this problem ;)

---Files--------------------------------
objspace_expose_intern_meta.rb (413 Bytes)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply related	[relevance 5%]

* [ruby-core:72180] [Ruby trunk - Bug #11740] ObjectSpace.each_object exposes internal metaclasses
       [not found]     <redmine.issue-11740.20151125102527@ruby-lang.org>
@ 2015-12-16  8:06  5% ` ko1
  2015-12-22  2:36  5% ` [ruby-core:72425] " shugo
  1 sibling, 0 replies; 71+ results
From: ko1 @ 2015-12-16  8:06 UTC (permalink / raw)
  To: ruby-core

Issue #11740 has been updated by Koichi Sasada.


```diff
Index: class.c
===================================================================
--- class.c	(revision 53150)
+++ class.c	(working copy)
@@ -442,6 +442,12 @@ rb_singleton_class_attached(VALUE klass,
  */
 #define META_CLASS_OF_CLASS_CLASS_P(k)  (METACLASS_OF(k) == (k))
 
+int
+rb_singleton_class_has_metaclass_p(VALUE sklass)
+{
+    return rb_ivar_get(METACLASS_OF(sklass), id_attached) == sklass;
+}
+
 /*!
  * whether k has a metaclass
  * @retval 1 if \a k has a metaclass
@@ -449,7 +455,13 @@ rb_singleton_class_attached(VALUE klass,
  */
 #define HAVE_METACLASS_P(k) \
     (FL_TEST(METACLASS_OF(k), FL_SINGLETON) && \
-     rb_ivar_get(METACLASS_OF(k), id_attached) == (k))
+     rb_singleton_class_has_metaclass_p(k))
+
+int
+rb_class_has_metaclass_p(VALUE klass)
+{
+    return HAVE_METACLASS_P(klass);
+}
 
 /*!
  * ensures \a klass belongs to its own eigenclass.
Index: gc.c
===================================================================
--- gc.c	(revision 53150)
+++ gc.c	(working copy)
@@ -2400,6 +2400,13 @@ internal_object_p(VALUE obj)
 	  case T_NODE:
 	  case T_ZOMBIE:
 	    break;
+	  case T_CLASS:
+	    {
+		if (FL_TEST(obj, FL_SINGLETON)) {
+		    int rb_singleton_class_has_metaclass_p(VALUE sklass);
+		    return rb_singleton_class_has_metaclass_p(obj) == 0;
+		}
+	    }
 	  default:
 	    if (!p->as.basic.klass) break;
 	    return 0;
```

This patch solves this problem.
Could you check it?


----------------------------------------
Bug #11740: ObjectSpace.each_object exposes internal metaclasses
https://bugs.ruby-lang.org/issues/11740#change-55594

* Author: Benoit Daloze
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
* ruby -v: ruby 2.3.0dev (2015-11-19 trunk 52672) [x86_64-linux]
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
ObjectSpace.each_object exposes internal metaclasses and
this might result in assumptions being violated since the metaclass structure is not well preserved.

See the attached script for an example.
The #bla method should always be defined on the metaclass of "klass".

See https://bugs.ruby-lang.org/issues/11360#note-2 as well in which I warned against this problem ;)

---Files--------------------------------
objspace_expose_intern_meta.rb (413 Bytes)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 5%]

* [ruby-core:70071] [Ruby trunk - Bug #11360] Singleton class doesn't appear by ObjectSpace.each_object
       [not found]     <redmine.issue-11360.20150717052032@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2015-07-17  9:43  4% ` [ruby-core:70010] " eregontp
@ 2015-07-21 15:04  4% ` matz
  3 siblings, 0 replies; 71+ results
From: matz @ 2015-07-21 15:04 UTC (permalink / raw)
  To: ruby-core

Issue #11360 has been updated by Yukihiro Matsumoto.


It was intentional, since in the old days singleton classes are merely internal data structure.  After intoduction of #singleton_class method, singleton classes are objects visible to Ruby world.  In that sense, now it's natural for them to be visible from #each_object.

Matz.
 

----------------------------------------
Bug #11360: Singleton class doesn't appear by ObjectSpace.each_object
https://bugs.ruby-lang.org/issues/11360#change-53486

* Author: Koichi Sasada
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
* ruby -v: 2.3dev
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
Singleton class doesn't appear by ObjectSpace.each_object.

The following is reproducible code.

```ruby
class C
  class << self
    p [self, self.class]
    $c = self
  end
end

ObjectSpace.each_object(Class){|o|
  exit if $c == o
}
raise "#{$c} is not found!"
```

This is because internal_object_p in gc.c skips singleton classes.

```C
static int
internal_object_p(VALUE obj)
{
    RVALUE *p = (RVALUE *)obj;

    if (p->as.basic.flags) {
	switch (BUILTIN_TYPE(p)) {
	  case T_NONE:
	  case T_IMEMO:
	  case T_ICLASS:
	  case T_NODE:
	  case T_ZOMBIE:
	    break;
	  case T_CLASS:
	    if (FL_TEST(p, FL_SINGLETON))
	      break;
	  default:
	    if (!p->as.basic.klass) break;
	    return 0;
	}
    }
    return 1;
}
```




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 4%]

* [ruby-core:70010] [Ruby trunk - Bug #11360] Singleton class doesn't appear by ObjectSpace.each_object
       [not found]     <redmine.issue-11360.20150717052032@ruby-lang.org>
  2015-07-17  5:20  5% ` [ruby-core:70006] [Ruby trunk - Bug #11360] [Open] Singleton class doesn't appear by ObjectSpace.each_object ko1
  2015-07-17  5:45  5% ` [ruby-core:70007] [Ruby trunk - Bug #11360] " ko1
@ 2015-07-17  9:43  4% ` eregontp
  2015-07-21 15:04  4% ` [ruby-core:70071] " matz
  3 siblings, 0 replies; 71+ results
From: eregontp @ 2015-07-17  9:43 UTC (permalink / raw)
  To: ruby-core

Issue #11360 has been updated by Benoit Daloze.


Koichi Sasada wrote:
> From Ruby 1.6, singleton classes are not appeared.
> Is it intentional?

I guess the reason is exposing the last layer of singleton classes would expose "VM-internal singleton classes/metaclasses".
The documentation of `rb_singleton_class` explains it a bit.
But basically the VM needs the metaclass of any class exposed to the user, and exposing them would require another layer, which if exposed as well would need another, etc.
Singleton classes which already have a metaclass could be iterated though.

----------------------------------------
Bug #11360: Singleton class doesn't appear by ObjectSpace.each_object
https://bugs.ruby-lang.org/issues/11360#change-53443

* Author: Koichi Sasada
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
* ruby -v: 2.3dev
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
Singleton class doesn't appear by ObjectSpace.each_object.

The following is reproducible code.

```ruby
class C
  class << self
    p [self, self.class]
    $c = self
  end
end

ObjectSpace.each_object(Class){|o|
  exit if $c == o
}
raise "#{$c} is not found!"
```

This is because internal_object_p in gc.c skips singleton classes.

```C
static int
internal_object_p(VALUE obj)
{
    RVALUE *p = (RVALUE *)obj;

    if (p->as.basic.flags) {
	switch (BUILTIN_TYPE(p)) {
	  case T_NONE:
	  case T_IMEMO:
	  case T_ICLASS:
	  case T_NODE:
	  case T_ZOMBIE:
	    break;
	  case T_CLASS:
	    if (FL_TEST(p, FL_SINGLETON))
	      break;
	  default:
	    if (!p->as.basic.klass) break;
	    return 0;
	}
    }
    return 1;
}
```




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 4%]

* [ruby-core:70007] [Ruby trunk - Bug #11360] Singleton class doesn't appear by ObjectSpace.each_object
       [not found]     <redmine.issue-11360.20150717052032@ruby-lang.org>
  2015-07-17  5:20  5% ` [ruby-core:70006] [Ruby trunk - Bug #11360] [Open] Singleton class doesn't appear by ObjectSpace.each_object ko1
@ 2015-07-17  5:45  5% ` ko1
  2015-07-17  9:43  4% ` [ruby-core:70010] " eregontp
  2015-07-21 15:04  4% ` [ruby-core:70071] " matz
  3 siblings, 0 replies; 71+ results
From: ko1 @ 2015-07-17  5:45 UTC (permalink / raw)
  To: ruby-core

Issue #11360 has been updated by Koichi Sasada.


From Ruby 1.6, singleton classes are not appeared.
Is it intentional?


----------------------------------------
Bug #11360: Singleton class doesn't appear by ObjectSpace.each_object
https://bugs.ruby-lang.org/issues/11360#change-53441

* Author: Koichi Sasada
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
* ruby -v: 2.3dev
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
Singleton class doesn't appear by ObjectSpace.each_object.

The following is reproducible code.

```ruby
class C
  class << self
    p [self, self.class]
    $c = self
  end
end

ObjectSpace.each_object(Class){|o|
  exit if $c == o
}
raise "#{$c} is not found!"
```

This is because internal_object_p in gc.c skips singleton classes.

```C
static int
internal_object_p(VALUE obj)
{
    RVALUE *p = (RVALUE *)obj;

    if (p->as.basic.flags) {
	switch (BUILTIN_TYPE(p)) {
	  case T_NONE:
	  case T_IMEMO:
	  case T_ICLASS:
	  case T_NODE:
	  case T_ZOMBIE:
	    break;
	  case T_CLASS:
	    if (FL_TEST(p, FL_SINGLETON))
	      break;
	  default:
	    if (!p->as.basic.klass) break;
	    return 0;
	}
    }
    return 1;
}
```




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 5%]

* [ruby-core:70006] [Ruby trunk - Bug #11360] [Open] Singleton class doesn't appear by ObjectSpace.each_object
       [not found]     <redmine.issue-11360.20150717052032@ruby-lang.org>
@ 2015-07-17  5:20  5% ` ko1
  2015-07-17  5:45  5% ` [ruby-core:70007] [Ruby trunk - Bug #11360] " ko1
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 71+ results
From: ko1 @ 2015-07-17  5:20 UTC (permalink / raw)
  To: ruby-core

Issue #11360 has been reported by Koichi Sasada.

----------------------------------------
Bug #11360: Singleton class doesn't appear by ObjectSpace.each_object
https://bugs.ruby-lang.org/issues/11360

* Author: Koichi Sasada
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
* ruby -v: 2.3dev
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN
----------------------------------------
Singleton class doesn't appear by ObjectSpace.each_object.

The following is reproducible code.

```ruby
class C
  class << self
    p [self, self.class]
    $c = self
  end
end

ObjectSpace.each_object(Class){|o|
  exit if $c == o
}
raise "#{$c} is not found!"
```

This is because internal_object_p in gc.c skips singleton classes.

```C
static int
internal_object_p(VALUE obj)
{
    RVALUE *p = (RVALUE *)obj;

    if (p->as.basic.flags) {
	switch (BUILTIN_TYPE(p)) {
	  case T_NONE:
	  case T_IMEMO:
	  case T_ICLASS:
	  case T_NODE:
	  case T_ZOMBIE:
	    break;
	  case T_CLASS:
	    if (FL_TEST(p, FL_SINGLETON))
	      break;
	  default:
	    if (!p->as.basic.klass) break;
	    return 0;
	}
    }
    return 1;
}
```




-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 5%]

* [ruby-core:66522] [ruby-trunk - Bug #10232] Trivial change of IMMEDIATE VALUE bits layout
       [not found]     <redmine.issue-10232.20140912012732@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2014-09-12  3:31  4% ` [ruby-core:64987] " ko1
@ 2014-11-27 11:28  4% ` ko1
  2017-02-06  2:55  4% ` [ruby-core:79444] [Ruby trunk Bug#10232][Rejected] " ko1
  4 siblings, 0 replies; 71+ results
From: ko1 @ 2014-11-27 11:28 UTC (permalink / raw)
  To: ruby-core

Issue #10232 has been updated by Koichi Sasada.

Target version changed from current: 2.2.0 to next minor

----------------------------------------
Bug #10232: Trivial change of IMMEDIATE VALUE bits layout
https://bugs.ruby-lang.org/issues/10232#change-50137

* Author: Koichi Sasada
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
* Category: core
* Target version: next minor
* ruby -v: 2.2
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN
----------------------------------------

The following patch improves performance a bit.

```
!USE_FLONUM
-------------------------
...xxxx xxx1 Fixnum
...0000 1110 Symbol
...0000 0000 Qfalse
...0000 0010 Qtrue
...0000 0100 Qnil
...0000 0110 Qundef

USE_FLONUM
-------------------------
...xxxx xxx1 Fixnum
...xxxx xx10 Flonum
...0000 1100 Symbol
...0000 0000 Qfalse  0x00 =  0
...0000 1000 Qnil    0x08 =  8
...0001 0100 Qtrue   0x14 = 20
...0011 0100 Qundef  0x34 = 52

#=>

!USE_FLONUM
-------------------------
xxxx xxxx xxx1 Fixnum  0x01
xxxx 0011 0010 Symbol  0x32 = 50
0000 0000 0000 Qfalse  0x00
0000 0000 0010 Qnil    0x02
0000 0001 0010 Qtrue   0x12 = 18
0000 0010 0010 Qundef  0x22 = 32

USE_FLONUM
-------------------------
xxxx xxxx xxx1 Fixnum  0x01
xxxx xxxx xx10 Flonum  0x02
xxxx 0011 0100 Symbol  0x34 = 52
0000 0000 0000 Qfalse  0x00 =  0
0000 0000 0100 Qnil    0x04 =  4
0000 0001 0100 Qtrue   0x14 = 20
0000 0010 0100 Qundef  0x24 = 36
```

```patch
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 47531)
+++ include/ruby/ruby.h	(working copy)
@@ -395,6 +395,27 @@ USE_FLONUM
 ...0000 1000 Qnil    0x08 =  8
 ...0001 0100 Qtrue   0x14 = 20
 ...0011 0100 Qundef  0x34 = 52
+
+#=>
+
+!USE_FLONUM
+-------------------------
+xxxx xxxx xxx1 Fixnum  0x01
+xxxx 0011 0010 Symbol  0x32 = 50
+0000 0000 0000 Qfalse  0x00
+0000 0000 0010 Qnil    0x02
+0000 0001 0010 Qtrue   0x12 = 18
+0000 0010 0010 Qundef  0x22 = 32
+
+USE_FLONUM
+-------------------------
+xxxx xxxx xxx1 Fixnum  0x01
+xxxx xxxx xx10 Flonum  0x02
+xxxx 0011 0100 Symbol  0x34 = 52
+0000 0000 0000 Qfalse  0x00 =  0
+0000 0000 0100 Qnil    0x04 =  4
+0000 0001 0100 Qtrue   0x14 = 20
+0000 0010 0100 Qundef  0x24 = 36
  */
 
 /* special constants - i.e. non-zero and non-fixnum constants */
@@ -402,26 +423,26 @@ enum ruby_special_consts {
 #if USE_FLONUM
     RUBY_Qfalse = 0x00,
     RUBY_Qtrue  = 0x14,
-    RUBY_Qnil   = 0x08,
-    RUBY_Qundef = 0x34,
+    RUBY_Qnil   = 0x04,
+    RUBY_Qundef = 0x24,
 
     RUBY_IMMEDIATE_MASK = 0x07,
     RUBY_FIXNUM_FLAG    = 0x01,
     RUBY_FLONUM_MASK    = 0x03,
     RUBY_FLONUM_FLAG    = 0x02,
-    RUBY_SYMBOL_FLAG    = 0x0c,
+    RUBY_SYMBOL_FLAG    = 0x34,
     RUBY_SPECIAL_SHIFT  = 8
 #else
-    RUBY_Qfalse = 0,
-    RUBY_Qtrue  = 2,
-    RUBY_Qnil   = 4,
-    RUBY_Qundef = 6,
+    RUBY_Qfalse = 0x00,
+    RUBY_Qtrue  = 0x12,
+    RUBY_Qnil   = 0x02,
+    RUBY_Qundef = 0x22,
 
     RUBY_IMMEDIATE_MASK = 0x03,
     RUBY_FIXNUM_FLAG    = 0x01,
     RUBY_FLONUM_MASK    = 0x00,	/* any values ANDed with FLONUM_MASK cannot be FLONUM_FLAG */
     RUBY_FLONUM_FLAG    = 0x02,
-    RUBY_SYMBOL_FLAG    = 0x0e,
+    RUBY_SYMBOL_FLAG    = 0x32,
     RUBY_SPECIAL_SHIFT  = 8
 #endif
 };
@@ -1106,7 +1127,7 @@ struct RStruct {
 #define FL_USER18    (((VALUE)1)<<(FL_USHIFT+18))
 #define FL_USER19    (((VALUE)1)<<(FL_USHIFT+19))
 
-#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !RTEST(x))
+#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !(x))
 
 #define FL_ABLE(x) (!SPECIAL_CONST_P(x) && BUILTIN_TYPE(x) != T_NODE)
 #define FL_TEST_RAW(x,f) (RBASIC(x)->flags&(f))
@@ -1583,11 +1604,9 @@ rb_class_of(VALUE obj)
 	if (FLONUM_P(obj)) return rb_cFloat;
 	if (obj == Qtrue)  return rb_cTrueClass;
 	if (STATIC_SYM_P(obj)) return rb_cSymbol;
-    }
-    else if (!RTEST(obj)) {
 	if (obj == Qnil)   return rb_cNilClass;
-	if (obj == Qfalse) return rb_cFalseClass;
     }
+    else if (obj == Qfalse) return rb_cFalseClass;
     return RBASIC(obj)->klass;
 }
 
@@ -1600,11 +1619,9 @@ rb_type(VALUE obj)
         if (obj == Qtrue)  return T_TRUE;
 	if (STATIC_SYM_P(obj)) return T_SYMBOL;
 	if (obj == Qundef) return T_UNDEF;
-    }
-    else if (!RTEST(obj)) {
 	if (obj == Qnil)   return T_NIL;
-	if (obj == Qfalse) return T_FALSE;
     }
+    else if (obj == Qfalse) return T_FALSE;
     return BUILTIN_TYPE(obj);
 }
 
```

The change is:

(1) IMMEDIATE_P(Qnil) => TRUE
(2) SPECIAL_CONST_P(x) becomes a bit simple -> (IMMEDIATE_P(x) || !(x))

(1) can be incompatibility issue so that I don't propose this fix strongly.
Interpreter core doesn't depends on this spec, but C-exts can be affected.


Benchmark result is: http://www.atdot.net/sp/raw/stirbn (gitruby is modified version)

Strange thing is: vm1_const

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
end

trunk	1.057002067565918
trunk	1.07387113571167
trunk	1.3638195991516113
trunk	1.076874017715454
trunk	1.0717082023620605
gitruby	0.7370171546936035
gitruby	0.7366814613342285
gitruby	0.7377498149871826
gitruby	0.7381434440612793
gitruby	0.7375714778900146
```

vm1_const only repeats `getinlinecache' instruction. I'm not sure why it has impact.

Change this program to repeat accessing constant more:

```
Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
    k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const

end

trunk   2.2485034465789795
trunk   2.2310359477996826
trunk   2.2247872352600098
trunk   2.2434682846069336
trunk   2.225156307220459
gitruby 2.2048048973083496
gitruby 2.2114696502685547
gitruby 2.2110848426818848
gitruby 2.208353042602539
gitruby 2.2142462730407715
```

It can be accidentally.

Other variations:

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  k = Const
end

trunk   0.6202449798583984
trunk   0.8297767639160156
trunk   0.6203830242156982
trunk   0.6206128597259521
trunk   0.6202561855316162
gitruby 0.6209316253662109
gitruby 0.6197938919067383
gitruby 0.6191442012786865
gitruby 0.6194281578063965
gitruby 0.6211118698120117
```

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
  l = Const
end

trunk   1.195659875869751
trunk   1.1864018440246582
trunk   1.1857333183288574
trunk   1.17852783203125
trunk   1.177058458328247
gitruby 1.1888437271118164
gitruby 1.1901893615722656
gitruby 1.1873669624328613
gitruby 1.187666893005371
gitruby 1.182875156402588
```

It seems that such strange behaviour only on two Const accessing.





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 4%]

* [ruby-core:64987] [ruby-trunk - Bug #10232] Trivial change of IMMEDIATE VALUE bits layout
       [not found]     <redmine.issue-10232.20140912012732@ruby-lang.org>
  2014-09-12  1:27  4% ` [ruby-core:64979] [ruby-trunk - Bug #10232] [Open] Trivial change of IMMEDIATE VALUE bits layout ko1
  2014-09-12  3:10  4% ` [ruby-core:64986] [ruby-trunk - Bug #10232] " normalperson
@ 2014-09-12  3:31  4% ` ko1
  2014-11-27 11:28  4% ` [ruby-core:66522] " ko1
  2017-02-06  2:55  4% ` [ruby-core:79444] [Ruby trunk Bug#10232][Rejected] " ko1
  4 siblings, 0 replies; 71+ results
From: ko1 @ 2014-09-12  3:31 UTC (permalink / raw)
  To: ruby-core

Issue #10232 has been updated by Koichi Sasada.


Eric Wong wrote:
>  > Strange thing is: vm1_const
>  
>  I suspect this is CPU-specific behaviors.  I cannot see the difference
>  on my AMD FX-8320 (on vm1_const, haven't tested others)

I agree.




----------------------------------------
Bug #10232: Trivial change of IMMEDIATE VALUE bits layout
https://bugs.ruby-lang.org/issues/10232#change-48862

* Author: Koichi Sasada
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
* Category: core
* Target version: current: 2.2.0
* ruby -v: 2.2
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN
----------------------------------------

The following patch improves performance a bit.

```
!USE_FLONUM
-------------------------
...xxxx xxx1 Fixnum
...0000 1110 Symbol
...0000 0000 Qfalse
...0000 0010 Qtrue
...0000 0100 Qnil
...0000 0110 Qundef

USE_FLONUM
-------------------------
...xxxx xxx1 Fixnum
...xxxx xx10 Flonum
...0000 1100 Symbol
...0000 0000 Qfalse  0x00 =  0
...0000 1000 Qnil    0x08 =  8
...0001 0100 Qtrue   0x14 = 20
...0011 0100 Qundef  0x34 = 52

#=>

!USE_FLONUM
-------------------------
xxxx xxxx xxx1 Fixnum  0x01
xxxx 0011 0010 Symbol  0x32 = 50
0000 0000 0000 Qfalse  0x00
0000 0000 0010 Qnil    0x02
0000 0001 0010 Qtrue   0x12 = 18
0000 0010 0010 Qundef  0x22 = 32

USE_FLONUM
-------------------------
xxxx xxxx xxx1 Fixnum  0x01
xxxx xxxx xx10 Flonum  0x02
xxxx 0011 0100 Symbol  0x34 = 52
0000 0000 0000 Qfalse  0x00 =  0
0000 0000 0100 Qnil    0x04 =  4
0000 0001 0100 Qtrue   0x14 = 20
0000 0010 0100 Qundef  0x24 = 36
```

```patch
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 47531)
+++ include/ruby/ruby.h	(working copy)
@@ -395,6 +395,27 @@ USE_FLONUM
 ...0000 1000 Qnil    0x08 =  8
 ...0001 0100 Qtrue   0x14 = 20
 ...0011 0100 Qundef  0x34 = 52
+
+#=>
+
+!USE_FLONUM
+-------------------------
+xxxx xxxx xxx1 Fixnum  0x01
+xxxx 0011 0010 Symbol  0x32 = 50
+0000 0000 0000 Qfalse  0x00
+0000 0000 0010 Qnil    0x02
+0000 0001 0010 Qtrue   0x12 = 18
+0000 0010 0010 Qundef  0x22 = 32
+
+USE_FLONUM
+-------------------------
+xxxx xxxx xxx1 Fixnum  0x01
+xxxx xxxx xx10 Flonum  0x02
+xxxx 0011 0100 Symbol  0x34 = 52
+0000 0000 0000 Qfalse  0x00 =  0
+0000 0000 0100 Qnil    0x04 =  4
+0000 0001 0100 Qtrue   0x14 = 20
+0000 0010 0100 Qundef  0x24 = 36
  */
 
 /* special constants - i.e. non-zero and non-fixnum constants */
@@ -402,26 +423,26 @@ enum ruby_special_consts {
 #if USE_FLONUM
     RUBY_Qfalse = 0x00,
     RUBY_Qtrue  = 0x14,
-    RUBY_Qnil   = 0x08,
-    RUBY_Qundef = 0x34,
+    RUBY_Qnil   = 0x04,
+    RUBY_Qundef = 0x24,
 
     RUBY_IMMEDIATE_MASK = 0x07,
     RUBY_FIXNUM_FLAG    = 0x01,
     RUBY_FLONUM_MASK    = 0x03,
     RUBY_FLONUM_FLAG    = 0x02,
-    RUBY_SYMBOL_FLAG    = 0x0c,
+    RUBY_SYMBOL_FLAG    = 0x34,
     RUBY_SPECIAL_SHIFT  = 8
 #else
-    RUBY_Qfalse = 0,
-    RUBY_Qtrue  = 2,
-    RUBY_Qnil   = 4,
-    RUBY_Qundef = 6,
+    RUBY_Qfalse = 0x00,
+    RUBY_Qtrue  = 0x12,
+    RUBY_Qnil   = 0x02,
+    RUBY_Qundef = 0x22,
 
     RUBY_IMMEDIATE_MASK = 0x03,
     RUBY_FIXNUM_FLAG    = 0x01,
     RUBY_FLONUM_MASK    = 0x00,	/* any values ANDed with FLONUM_MASK cannot be FLONUM_FLAG */
     RUBY_FLONUM_FLAG    = 0x02,
-    RUBY_SYMBOL_FLAG    = 0x0e,
+    RUBY_SYMBOL_FLAG    = 0x32,
     RUBY_SPECIAL_SHIFT  = 8
 #endif
 };
@@ -1106,7 +1127,7 @@ struct RStruct {
 #define FL_USER18    (((VALUE)1)<<(FL_USHIFT+18))
 #define FL_USER19    (((VALUE)1)<<(FL_USHIFT+19))
 
-#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !RTEST(x))
+#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !(x))
 
 #define FL_ABLE(x) (!SPECIAL_CONST_P(x) && BUILTIN_TYPE(x) != T_NODE)
 #define FL_TEST_RAW(x,f) (RBASIC(x)->flags&(f))
@@ -1583,11 +1604,9 @@ rb_class_of(VALUE obj)
 	if (FLONUM_P(obj)) return rb_cFloat;
 	if (obj == Qtrue)  return rb_cTrueClass;
 	if (STATIC_SYM_P(obj)) return rb_cSymbol;
-    }
-    else if (!RTEST(obj)) {
 	if (obj == Qnil)   return rb_cNilClass;
-	if (obj == Qfalse) return rb_cFalseClass;
     }
+    else if (obj == Qfalse) return rb_cFalseClass;
     return RBASIC(obj)->klass;
 }
 
@@ -1600,11 +1619,9 @@ rb_type(VALUE obj)
         if (obj == Qtrue)  return T_TRUE;
 	if (STATIC_SYM_P(obj)) return T_SYMBOL;
 	if (obj == Qundef) return T_UNDEF;
-    }
-    else if (!RTEST(obj)) {
 	if (obj == Qnil)   return T_NIL;
-	if (obj == Qfalse) return T_FALSE;
     }
+    else if (obj == Qfalse) return T_FALSE;
     return BUILTIN_TYPE(obj);
 }
 
```

The change is:

(1) IMMEDIATE_P(Qnil) => TRUE
(2) SPECIAL_CONST_P(x) becomes a bit simple -> (IMMEDIATE_P(x) || !(x))

(1) can be incompatibility issue so that I don't propose this fix strongly.
Interpreter core doesn't depends on this spec, but C-exts can be affected.


Benchmark result is: http://www.atdot.net/sp/raw/stirbn (gitruby is modified version)

Strange thing is: vm1_const

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
end

trunk	1.057002067565918
trunk	1.07387113571167
trunk	1.3638195991516113
trunk	1.076874017715454
trunk	1.0717082023620605
gitruby	0.7370171546936035
gitruby	0.7366814613342285
gitruby	0.7377498149871826
gitruby	0.7381434440612793
gitruby	0.7375714778900146
```

vm1_const only repeats `getinlinecache' instruction. I'm not sure why it has impact.

Change this program to repeat accessing constant more:

```
Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
    k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const

end

trunk   2.2485034465789795
trunk   2.2310359477996826
trunk   2.2247872352600098
trunk   2.2434682846069336
trunk   2.225156307220459
gitruby 2.2048048973083496
gitruby 2.2114696502685547
gitruby 2.2110848426818848
gitruby 2.208353042602539
gitruby 2.2142462730407715
```

It can be accidentally.

Other variations:

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  k = Const
end

trunk   0.6202449798583984
trunk   0.8297767639160156
trunk   0.6203830242156982
trunk   0.6206128597259521
trunk   0.6202561855316162
gitruby 0.6209316253662109
gitruby 0.6197938919067383
gitruby 0.6191442012786865
gitruby 0.6194281578063965
gitruby 0.6211118698120117
```

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
  l = Const
end

trunk   1.195659875869751
trunk   1.1864018440246582
trunk   1.1857333183288574
trunk   1.17852783203125
trunk   1.177058458328247
gitruby 1.1888437271118164
gitruby 1.1901893615722656
gitruby 1.1873669624328613
gitruby 1.187666893005371
gitruby 1.182875156402588
```

It seems that such strange behaviour only on two Const accessing.





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 4%]

* [ruby-core:64986] [ruby-trunk - Bug #10232] Trivial change of IMMEDIATE VALUE bits layout
       [not found]     <redmine.issue-10232.20140912012732@ruby-lang.org>
  2014-09-12  1:27  4% ` [ruby-core:64979] [ruby-trunk - Bug #10232] [Open] Trivial change of IMMEDIATE VALUE bits layout ko1
@ 2014-09-12  3:10  4% ` normalperson
  2014-09-12  3:31  4% ` [ruby-core:64987] " ko1
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 71+ results
From: normalperson @ 2014-09-12  3:10 UTC (permalink / raw)
  To: ruby-core

Issue #10232 has been updated by Eric Wong.


 ko1@atdot.net wrote:
 > (1) can be incompatibility issue so that I don't propose this fix strongly.
 > Interpreter core doesn't depends on this spec, but C-exts can be affected.
 
 I think the only thing I've seen C-exts depend on is Qfalse == 0
 (which this preserves)
 
 > Strange thing is: vm1_const
 
 I suspect this is CPU-specific behaviors.  I cannot see the difference
 on my AMD FX-8320 (on vm1_const, haven't tested others)

----------------------------------------
Bug #10232: Trivial change of IMMEDIATE VALUE bits layout
https://bugs.ruby-lang.org/issues/10232#change-48861

* Author: Koichi Sasada
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
* Category: core
* Target version: current: 2.2.0
* ruby -v: 2.2
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN
----------------------------------------

The following patch improves performance a bit.

```
!USE_FLONUM
-------------------------
...xxxx xxx1 Fixnum
...0000 1110 Symbol
...0000 0000 Qfalse
...0000 0010 Qtrue
...0000 0100 Qnil
...0000 0110 Qundef

USE_FLONUM
-------------------------
...xxxx xxx1 Fixnum
...xxxx xx10 Flonum
...0000 1100 Symbol
...0000 0000 Qfalse  0x00 =  0
...0000 1000 Qnil    0x08 =  8
...0001 0100 Qtrue   0x14 = 20
...0011 0100 Qundef  0x34 = 52

#=>

!USE_FLONUM
-------------------------
xxxx xxxx xxx1 Fixnum  0x01
xxxx 0011 0010 Symbol  0x32 = 50
0000 0000 0000 Qfalse  0x00
0000 0000 0010 Qnil    0x02
0000 0001 0010 Qtrue   0x12 = 18
0000 0010 0010 Qundef  0x22 = 32

USE_FLONUM
-------------------------
xxxx xxxx xxx1 Fixnum  0x01
xxxx xxxx xx10 Flonum  0x02
xxxx 0011 0100 Symbol  0x34 = 52
0000 0000 0000 Qfalse  0x00 =  0
0000 0000 0100 Qnil    0x04 =  4
0000 0001 0100 Qtrue   0x14 = 20
0000 0010 0100 Qundef  0x24 = 36
```

```patch
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 47531)
+++ include/ruby/ruby.h	(working copy)
@@ -395,6 +395,27 @@ USE_FLONUM
 ...0000 1000 Qnil    0x08 =  8
 ...0001 0100 Qtrue   0x14 = 20
 ...0011 0100 Qundef  0x34 = 52
+
+#=>
+
+!USE_FLONUM
+-------------------------
+xxxx xxxx xxx1 Fixnum  0x01
+xxxx 0011 0010 Symbol  0x32 = 50
+0000 0000 0000 Qfalse  0x00
+0000 0000 0010 Qnil    0x02
+0000 0001 0010 Qtrue   0x12 = 18
+0000 0010 0010 Qundef  0x22 = 32
+
+USE_FLONUM
+-------------------------
+xxxx xxxx xxx1 Fixnum  0x01
+xxxx xxxx xx10 Flonum  0x02
+xxxx 0011 0100 Symbol  0x34 = 52
+0000 0000 0000 Qfalse  0x00 =  0
+0000 0000 0100 Qnil    0x04 =  4
+0000 0001 0100 Qtrue   0x14 = 20
+0000 0010 0100 Qundef  0x24 = 36
  */
 
 /* special constants - i.e. non-zero and non-fixnum constants */
@@ -402,26 +423,26 @@ enum ruby_special_consts {
 #if USE_FLONUM
     RUBY_Qfalse = 0x00,
     RUBY_Qtrue  = 0x14,
-    RUBY_Qnil   = 0x08,
-    RUBY_Qundef = 0x34,
+    RUBY_Qnil   = 0x04,
+    RUBY_Qundef = 0x24,
 
     RUBY_IMMEDIATE_MASK = 0x07,
     RUBY_FIXNUM_FLAG    = 0x01,
     RUBY_FLONUM_MASK    = 0x03,
     RUBY_FLONUM_FLAG    = 0x02,
-    RUBY_SYMBOL_FLAG    = 0x0c,
+    RUBY_SYMBOL_FLAG    = 0x34,
     RUBY_SPECIAL_SHIFT  = 8
 #else
-    RUBY_Qfalse = 0,
-    RUBY_Qtrue  = 2,
-    RUBY_Qnil   = 4,
-    RUBY_Qundef = 6,
+    RUBY_Qfalse = 0x00,
+    RUBY_Qtrue  = 0x12,
+    RUBY_Qnil   = 0x02,
+    RUBY_Qundef = 0x22,
 
     RUBY_IMMEDIATE_MASK = 0x03,
     RUBY_FIXNUM_FLAG    = 0x01,
     RUBY_FLONUM_MASK    = 0x00,	/* any values ANDed with FLONUM_MASK cannot be FLONUM_FLAG */
     RUBY_FLONUM_FLAG    = 0x02,
-    RUBY_SYMBOL_FLAG    = 0x0e,
+    RUBY_SYMBOL_FLAG    = 0x32,
     RUBY_SPECIAL_SHIFT  = 8
 #endif
 };
@@ -1106,7 +1127,7 @@ struct RStruct {
 #define FL_USER18    (((VALUE)1)<<(FL_USHIFT+18))
 #define FL_USER19    (((VALUE)1)<<(FL_USHIFT+19))
 
-#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !RTEST(x))
+#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !(x))
 
 #define FL_ABLE(x) (!SPECIAL_CONST_P(x) && BUILTIN_TYPE(x) != T_NODE)
 #define FL_TEST_RAW(x,f) (RBASIC(x)->flags&(f))
@@ -1583,11 +1604,9 @@ rb_class_of(VALUE obj)
 	if (FLONUM_P(obj)) return rb_cFloat;
 	if (obj == Qtrue)  return rb_cTrueClass;
 	if (STATIC_SYM_P(obj)) return rb_cSymbol;
-    }
-    else if (!RTEST(obj)) {
 	if (obj == Qnil)   return rb_cNilClass;
-	if (obj == Qfalse) return rb_cFalseClass;
     }
+    else if (obj == Qfalse) return rb_cFalseClass;
     return RBASIC(obj)->klass;
 }
 
@@ -1600,11 +1619,9 @@ rb_type(VALUE obj)
         if (obj == Qtrue)  return T_TRUE;
 	if (STATIC_SYM_P(obj)) return T_SYMBOL;
 	if (obj == Qundef) return T_UNDEF;
-    }
-    else if (!RTEST(obj)) {
 	if (obj == Qnil)   return T_NIL;
-	if (obj == Qfalse) return T_FALSE;
     }
+    else if (obj == Qfalse) return T_FALSE;
     return BUILTIN_TYPE(obj);
 }
 
```

The change is:

(1) IMMEDIATE_P(Qnil) => TRUE
(2) SPECIAL_CONST_P(x) becomes a bit simple -> (IMMEDIATE_P(x) || !(x))

(1) can be incompatibility issue so that I don't propose this fix strongly.
Interpreter core doesn't depends on this spec, but C-exts can be affected.


Benchmark result is: http://www.atdot.net/sp/raw/stirbn (gitruby is modified version)

Strange thing is: vm1_const

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
end

trunk	1.057002067565918
trunk	1.07387113571167
trunk	1.3638195991516113
trunk	1.076874017715454
trunk	1.0717082023620605
gitruby	0.7370171546936035
gitruby	0.7366814613342285
gitruby	0.7377498149871826
gitruby	0.7381434440612793
gitruby	0.7375714778900146
```

vm1_const only repeats `getinlinecache' instruction. I'm not sure why it has impact.

Change this program to repeat accessing constant more:

```
Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
    k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const

end

trunk   2.2485034465789795
trunk   2.2310359477996826
trunk   2.2247872352600098
trunk   2.2434682846069336
trunk   2.225156307220459
gitruby 2.2048048973083496
gitruby 2.2114696502685547
gitruby 2.2110848426818848
gitruby 2.208353042602539
gitruby 2.2142462730407715
```

It can be accidentally.

Other variations:

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  k = Const
end

trunk   0.6202449798583984
trunk   0.8297767639160156
trunk   0.6203830242156982
trunk   0.6206128597259521
trunk   0.6202561855316162
gitruby 0.6209316253662109
gitruby 0.6197938919067383
gitruby 0.6191442012786865
gitruby 0.6194281578063965
gitruby 0.6211118698120117
```

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
  l = Const
end

trunk   1.195659875869751
trunk   1.1864018440246582
trunk   1.1857333183288574
trunk   1.17852783203125
trunk   1.177058458328247
gitruby 1.1888437271118164
gitruby 1.1901893615722656
gitruby 1.1873669624328613
gitruby 1.187666893005371
gitruby 1.182875156402588
```

It seems that such strange behaviour only on two Const accessing.





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 4%]

* [ruby-core:64979] [ruby-trunk - Bug #10232] [Open] Trivial change of IMMEDIATE VALUE bits layout
       [not found]     <redmine.issue-10232.20140912012732@ruby-lang.org>
@ 2014-09-12  1:27  4% ` ko1
  2014-09-12  3:10  4% ` [ruby-core:64986] [ruby-trunk - Bug #10232] " normalperson
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 71+ results
From: ko1 @ 2014-09-12  1:27 UTC (permalink / raw)
  To: ruby-core

Issue #10232 has been reported by Koichi Sasada.

----------------------------------------
Bug #10232: Trivial change of IMMEDIATE VALUE bits layout
https://bugs.ruby-lang.org/issues/10232

* Author: Koichi Sasada
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
* Category: core
* Target version: current: 2.2.0
* ruby -v: 2.2
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN
----------------------------------------

The following patch improves performance a bit.

```
!USE_FLONUM
-------------------------
...xxxx xxx1 Fixnum
...0000 1110 Symbol
...0000 0000 Qfalse
...0000 0010 Qtrue
...0000 0100 Qnil
...0000 0110 Qundef

USE_FLONUM
-------------------------
...xxxx xxx1 Fixnum
...xxxx xx10 Flonum
...0000 1100 Symbol
...0000 0000 Qfalse  0x00 =  0
...0000 1000 Qnil    0x08 =  8
...0001 0100 Qtrue   0x14 = 20
...0011 0100 Qundef  0x34 = 52

#=>

!USE_FLONUM
-------------------------
xxxx xxxx xxx1 Fixnum  0x01
xxxx 0011 0010 Symbol  0x32 = 50
0000 0000 0000 Qfalse  0x00
0000 0000 0010 Qnil    0x02
0000 0001 0010 Qtrue   0x12 = 18
0000 0010 0010 Qundef  0x22 = 32

USE_FLONUM
-------------------------
xxxx xxxx xxx1 Fixnum  0x01
xxxx xxxx xx10 Flonum  0x02
xxxx 0011 0100 Symbol  0x34 = 52
0000 0000 0000 Qfalse  0x00 =  0
0000 0000 0100 Qnil    0x04 =  4
0000 0001 0100 Qtrue   0x14 = 20
0000 0010 0100 Qundef  0x24 = 36
```

```patch
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 47531)
+++ include/ruby/ruby.h	(working copy)
@@ -395,6 +395,27 @@ USE_FLONUM
 ...0000 1000 Qnil    0x08 =  8
 ...0001 0100 Qtrue   0x14 = 20
 ...0011 0100 Qundef  0x34 = 52
+
+#=>
+
+!USE_FLONUM
+-------------------------
+xxxx xxxx xxx1 Fixnum  0x01
+xxxx 0011 0010 Symbol  0x32 = 50
+0000 0000 0000 Qfalse  0x00
+0000 0000 0010 Qnil    0x02
+0000 0001 0010 Qtrue   0x12 = 18
+0000 0010 0010 Qundef  0x22 = 32
+
+USE_FLONUM
+-------------------------
+xxxx xxxx xxx1 Fixnum  0x01
+xxxx xxxx xx10 Flonum  0x02
+xxxx 0011 0100 Symbol  0x34 = 52
+0000 0000 0000 Qfalse  0x00 =  0
+0000 0000 0100 Qnil    0x04 =  4
+0000 0001 0100 Qtrue   0x14 = 20
+0000 0010 0100 Qundef  0x24 = 36
  */
 
 /* special constants - i.e. non-zero and non-fixnum constants */
@@ -402,26 +423,26 @@ enum ruby_special_consts {
 #if USE_FLONUM
     RUBY_Qfalse = 0x00,
     RUBY_Qtrue  = 0x14,
-    RUBY_Qnil   = 0x08,
-    RUBY_Qundef = 0x34,
+    RUBY_Qnil   = 0x04,
+    RUBY_Qundef = 0x24,
 
     RUBY_IMMEDIATE_MASK = 0x07,
     RUBY_FIXNUM_FLAG    = 0x01,
     RUBY_FLONUM_MASK    = 0x03,
     RUBY_FLONUM_FLAG    = 0x02,
-    RUBY_SYMBOL_FLAG    = 0x0c,
+    RUBY_SYMBOL_FLAG    = 0x34,
     RUBY_SPECIAL_SHIFT  = 8
 #else
-    RUBY_Qfalse = 0,
-    RUBY_Qtrue  = 2,
-    RUBY_Qnil   = 4,
-    RUBY_Qundef = 6,
+    RUBY_Qfalse = 0x00,
+    RUBY_Qtrue  = 0x12,
+    RUBY_Qnil   = 0x02,
+    RUBY_Qundef = 0x22,
 
     RUBY_IMMEDIATE_MASK = 0x03,
     RUBY_FIXNUM_FLAG    = 0x01,
     RUBY_FLONUM_MASK    = 0x00,	/* any values ANDed with FLONUM_MASK cannot be FLONUM_FLAG */
     RUBY_FLONUM_FLAG    = 0x02,
-    RUBY_SYMBOL_FLAG    = 0x0e,
+    RUBY_SYMBOL_FLAG    = 0x32,
     RUBY_SPECIAL_SHIFT  = 8
 #endif
 };
@@ -1106,7 +1127,7 @@ struct RStruct {
 #define FL_USER18    (((VALUE)1)<<(FL_USHIFT+18))
 #define FL_USER19    (((VALUE)1)<<(FL_USHIFT+19))
 
-#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !RTEST(x))
+#define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !(x))
 
 #define FL_ABLE(x) (!SPECIAL_CONST_P(x) && BUILTIN_TYPE(x) != T_NODE)
 #define FL_TEST_RAW(x,f) (RBASIC(x)->flags&(f))
@@ -1583,11 +1604,9 @@ rb_class_of(VALUE obj)
 	if (FLONUM_P(obj)) return rb_cFloat;
 	if (obj == Qtrue)  return rb_cTrueClass;
 	if (STATIC_SYM_P(obj)) return rb_cSymbol;
-    }
-    else if (!RTEST(obj)) {
 	if (obj == Qnil)   return rb_cNilClass;
-	if (obj == Qfalse) return rb_cFalseClass;
     }
+    else if (obj == Qfalse) return rb_cFalseClass;
     return RBASIC(obj)->klass;
 }
 
@@ -1600,11 +1619,9 @@ rb_type(VALUE obj)
         if (obj == Qtrue)  return T_TRUE;
 	if (STATIC_SYM_P(obj)) return T_SYMBOL;
 	if (obj == Qundef) return T_UNDEF;
-    }
-    else if (!RTEST(obj)) {
 	if (obj == Qnil)   return T_NIL;
-	if (obj == Qfalse) return T_FALSE;
     }
+    else if (obj == Qfalse) return T_FALSE;
     return BUILTIN_TYPE(obj);
 }
 
```

The change is:

(1) IMMEDIATE_P(Qnil) => TRUE
(2) SPECIAL_CONST_P(x) becomes a bit simple -> (IMMEDIATE_P(x) || !(x))

(1) can be incompatibility issue so that I don't propose this fix strongly.
Interpreter core doesn't depends on this spec, but C-exts can be affected.


Benchmark result is: http://www.atdot.net/sp/raw/stirbn (gitruby is modified version)

Strange thing is: vm1_const

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
end

trunk	1.057002067565918
trunk	1.07387113571167
trunk	1.3638195991516113
trunk	1.076874017715454
trunk	1.0717082023620605
gitruby	0.7370171546936035
gitruby	0.7366814613342285
gitruby	0.7377498149871826
gitruby	0.7381434440612793
gitruby	0.7375714778900146
```

vm1_const only repeats `getinlinecache' instruction. I'm not sure why it has impact.

Change this program to repeat accessing constant more:

```
Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
    k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const
  k = Const

end

trunk   2.2485034465789795
trunk   2.2310359477996826
trunk   2.2247872352600098
trunk   2.2434682846069336
trunk   2.225156307220459
gitruby 2.2048048973083496
gitruby 2.2114696502685547
gitruby 2.2110848426818848
gitruby 2.208353042602539
gitruby 2.2142462730407715
```

It can be accidentally.

Other variations:

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  k = Const
end

trunk   0.6202449798583984
trunk   0.8297767639160156
trunk   0.6203830242156982
trunk   0.6206128597259521
trunk   0.6202561855316162
gitruby 0.6209316253662109
gitruby 0.6197938919067383
gitruby 0.6191442012786865
gitruby 0.6194281578063965
gitruby 0.6211118698120117
```

```
vm1_const

Const = 1

i = 0
while i<30_000_000 # while loop 1
  i += 1
  j = Const
  k = Const
  l = Const
end

trunk   1.195659875869751
trunk   1.1864018440246582
trunk   1.1857333183288574
trunk   1.17852783203125
trunk   1.177058458328247
gitruby 1.1888437271118164
gitruby 1.1901893615722656
gitruby 1.1873669624328613
gitruby 1.187666893005371
gitruby 1.182875156402588
```

It seems that such strange behaviour only on two Const accessing.





-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 4%]

* [ruby-core:63729] [ruby-trunk - Bug #10037] Since r46798 on Solaris, "[BUG] rb_vm_get_cref: unreachable" during make
       [not found]     <redmine.issue-10037.20140715053007@ruby-lang.org>
@ 2014-07-15  9:51  9% ` ko1
  0 siblings, 0 replies; 71+ results
From: ko1 @ 2014-07-15  9:51 UTC (permalink / raw)
  To: ruby-core

Issue #10037 has been updated by Koichi Sasada.



```c
    enum iseq_type {
	ISEQ_TYPE_TOP,
	ISEQ_TYPE_METHOD,
	ISEQ_TYPE_BLOCK,
	ISEQ_TYPE_CLASS,
	ISEQ_TYPE_RESCUE,
	ISEQ_TYPE_ENSURE,
	ISEQ_TYPE_EVAL,
	ISEQ_TYPE_MAIN,
	ISEQ_TYPE_DEFINED_GUARD
    } type;              /* instruction sequence type */
    uint32_t stack_max; /* for stack overflow check */

...

#define RUBY_VM_IFUNC_P(ptr)        (BUILTIN_TYPE(ptr) == T_NODE)
#define RUBY_VM_NORMAL_ISEQ_P(ptr) \
  ((ptr) && !RUBY_VM_IFUNC_P(ptr))
```

On little endian, first 8 bytes (corresponds to RBasic::flags) of rb_iseq_t can not become T_NODE bit pattern. However, big endian can become.

Goto-san, could you check it?
Like that:

```diff
Index: iseq.c
===================================================================
--- iseq.c	(revision 46821)
+++ iseq.c	(working copy)
@@ -450,6 +450,8 @@
     prepare_iseq_build(iseq, name, path, absolute_path, first_lineno, parent, type, bopt, option);
     rb_iseq_compile_node(self, node);
     cleanup_iseq_build(iseq);
+
+    if (BUILTIN_TYPE((VALUE)iseq) == T_NODE) rb_bug("unreachable");
     return self;
 }
 
```


----------------------------------------
Bug #10037: Since r46798 on Solaris, "[BUG] rb_vm_get_cref: unreachable" during make
https://bugs.ruby-lang.org/issues/10037#change-47773

* Author: Naohisa Goto
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
* Category: 
* Target version: 
* ruby -v: ruby 2.2.0dev (2014-07-13) [sparc64-solaris2.10]
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN
----------------------------------------
Since r46798, failed to build on Solaris 10 running on SPARC64.

~~~
(snip)
converter from WINDOWS-874 to UTF-8
converter from UTF-8 to WINDOWS-874
enc/trans/single_byte.trans:22: [BUG] rb_vm_get_cref: unreachable
ruby 2.2.0dev (2014-07-13) [sparc64-solaris2.10]

-- Control frame information -----------------------------------------------
c:0008 p:---- s:0056 e:000053 TOP    [FINISH]
c:0007 p:---- s:0052 e:000051 CFUNC  :require
c:0006 p:0015 s:0048 e:000047 METHOD enc/trans/single_byte.trans:22
c:0005 p:0244 s:0041 E:0011d8 EVAL   enc/trans/single_byte.trans:48 [FINISH]
c:0004 p:---- s:0037 e:000036 CFUNC  :eval
c:0003 p:0045 s:0030 e:000029 METHOD /XXXXXXXXXX/lib/erb.rb:850
c:0002 p:1228 s:0026 E:000cf8 EVAL   ./tool/transcode-tblgen.rb:1043 [FINISH]
c:0001 p:0000 s:0002 E:001d68 TOP    [FINISH]

-- Ruby level backtrace information ----------------------------------------
./tool/transcode-tblgen.rb:1043:in `<main>'
/XXXXXXXXXX/lib/erb.rb:850:in `result'
/XXXXXXXXXX/lib/erb.rb:850:in `eval'
enc/trans/single_byte.trans:48:in `<main>'
enc/trans/single_byte.trans:22:in `transcode_tblgen_singlebyte'
enc/trans/single_byte.trans:22:in `require'
/XXXXXXXXXX/enc/trans/windows-1250-tbl.rb:1:in `<top (required)>'

-- Other runtime information -----------------------------------------------

* Loaded script: ./tool/transcode-tblgen.rb

* Loaded features:

    0 enumerator.so
    1 /XXXXXXXXXX/lib/optparse.rb
    2 /XXXXXXXXXX/lib/cgi/util.rb
    3 /XXXXXXXXXX/lib/erb.rb
    4 /XXXXXXXXXX/lib/fileutils.rb
    5 /XXXXXXXXXX/lib/prettyprint.rb
    6 /XXXXXXXXXX/lib/pp.rb
    7 /XXXXXXXXXX/enc/trans/iso-8859-1-tbl.rb
    8 /XXXXXXXXXX/enc/trans/iso-8859-2-tbl.rb
    9 /XXXXXXXXXX/enc/trans/iso-8859-3-tbl.rb
   10 /XXXXXXXXXX/enc/trans/iso-8859-4-tbl.rb
   11 /XXXXXXXXXX/enc/trans/iso-8859-5-tbl.rb
   12 /XXXXXXXXXX/enc/trans/iso-8859-6-tbl.rb
   13 /XXXXXXXXXX/enc/trans/iso-8859-7-tbl.rb
   14 /XXXXXXXXXX/enc/trans/iso-8859-8-tbl.rb
   15 /XXXXXXXXXX/enc/trans/iso-8859-9-tbl.rb
   16 /XXXXXXXXXX/enc/trans/iso-8859-10-tbl.rb
   17 /XXXXXXXXXX/enc/trans/iso-8859-11-tbl.rb
   18 /XXXXXXXXXX/enc/trans/iso-8859-13-tbl.rb
   19 /XXXXXXXXXX/enc/trans/iso-8859-14-tbl.rb
   20 /XXXXXXXXXX/enc/trans/iso-8859-15-tbl.rb
   21 /XXXXXXXXXX/enc/trans/iso-8859-16-tbl.rb
   22 /XXXXXXXXXX/enc/trans/windows-874-tbl.rb

[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html

Abort
make[1]: *** [enc/trans/single_byte.c] Error 134
make[1]: Leaving directory `/XXXXXXXXXX'
make: *** [srcs-enc] Error 2

~~~

The following patch fixed the problem (tested with r46821), but this completely breaks the benefit of r46798.

~~~
Index: vm_core.h
===================================================================
--- vm_core.h   (revision 46821)
+++ vm_core.h   (working copy)
@@ -205,6 +205,7 @@
        ISEQ_TYPE_MAIN,
        ISEQ_TYPE_DEFINED_GUARD
     } type;              /* instruction sequence type */
+    uint32_t dummy;
     uint32_t stack_max; /* for stack overflow check */
 
     rb_iseq_location_t location;
~~~

I think it is possbile that the first 8 byte (in 64-bit architecture) of "struct rb_iseq_struct" is sometimes used for some other purposes (maybe VALUE ?), and on big-endian 64-bit architecture (including SPARC64), it is frequently misunderstood as the other type.

By the way, I think "int stack_max" is better than "uint32_t stack_max" because it seems that all calculations of stack_max in compile.c(iseq_set_sequence) and vm_insnhelper.c(vm_push_frame) are conducted using int.



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 9%]

* [ruby-core:59018] [ruby-trunk - Bug #9226] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
  2013-12-07 16:17 10% [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect myronmarston (Myron Marston)
                   ` (8 preceding siblings ...)
  2013-12-10  4:13 10% ` [ruby-core:59016] " tmm1 (Aman Gupta)
@ 2013-12-10  5:48 10% ` tmm1 (Aman Gupta)
  9 siblings, 0 replies; 71+ results
From: tmm1 (Aman Gupta) @ 2013-12-10  5:48 UTC (permalink / raw)
  To: ruby-core


Issue #9226 has been updated by tmm1 (Aman Gupta).


After r44109, RGENGC_CHECK_MODE is able to detect the original Hash#replace miss issue:

$ ./miniruby test1.rb
gc_marks_check_i: WB miss 0x7fb33b053bb0 (T_HASH) -> 0x7fb33b033f90 (T_STRING)
test1.rb:15: [BUG] before_marks: GC has problem.

----------------------------------------
Bug #9226: Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
https://bugs.ruby-lang.org/issues/9226#change-43569

Author: myronmarston (Myron Marston)
Status: Closed
Priority: High
Assignee: ko1 (Koichi Sasada)
Category: core
Target version: current: 2.1.0
ruby -v: 2.1.0.preview2
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


We're trying to get a green RSpec build against ruby 2.1.0.preview2, and we're getting this very odd failure on travis:

https://travis-ci.org/rspec/rspec-core/jobs/15066502#L122

The line where it's failing is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/lib/rspec/core/filter_manager.rb#L75

It's calling `inspect` on a Hash and blowing up with that confusing error.  The hash that's causing this failure (if that helps) is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/spec/spec_helper.rb#L149-L158

It's the `{ :ruby => lambda { } }` hash being passed to `filter_run_excluding`.


-- 
http://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 10%]

* [ruby-core:59016] [ruby-trunk - Bug #9226] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
  2013-12-07 16:17 10% [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect myronmarston (Myron Marston)
                   ` (7 preceding siblings ...)
  2013-12-08  8:32 10% ` [ruby-core:58965] " myronmarston (Myron Marston)
@ 2013-12-10  4:13 10% ` tmm1 (Aman Gupta)
  2013-12-10  5:48 10% ` [ruby-core:59018] " tmm1 (Aman Gupta)
  9 siblings, 0 replies; 71+ results
From: tmm1 (Aman Gupta) @ 2013-12-10  4:13 UTC (permalink / raw)
  To: ruby-core


Issue #9226 has been updated by tmm1 (Aman Gupta).


With r44059, I can reproduce this issue with the following ruby code. I confirmed RGENGC_CHECK=2 does not complain.

def create_oldgen_hash
  @h1 = {}
  GC.start
end

def replace_with_young_hash
  h2 = {"a"=>"b"}
  @h1.replace(h2)
  h2 = nil
end

create_oldgen_hash
replace_with_young_hash
GC.start(full_mark:false,immediate_sweep:false)
p @h1


----------------------------------------
Bug #9226: Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
https://bugs.ruby-lang.org/issues/9226#change-43566

Author: myronmarston (Myron Marston)
Status: Open
Priority: High
Assignee: ko1 (Koichi Sasada)
Category: core
Target version: current: 2.1.0
ruby -v: 2.1.0.preview2
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


We're trying to get a green RSpec build against ruby 2.1.0.preview2, and we're getting this very odd failure on travis:

https://travis-ci.org/rspec/rspec-core/jobs/15066502#L122

The line where it's failing is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/lib/rspec/core/filter_manager.rb#L75

It's calling `inspect` on a Hash and blowing up with that confusing error.  The hash that's causing this failure (if that helps) is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/spec/spec_helper.rb#L149-L158

It's the `{ :ruby => lambda { } }` hash being passed to `filter_run_excluding`.


-- 
http://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 10%]

* [ruby-core:58965] [ruby-trunk - Bug #9226] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
  2013-12-07 16:17 10% [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect myronmarston (Myron Marston)
                   ` (6 preceding siblings ...)
  2013-12-08  8:32 10% ` [ruby-core:58964] [ruby-trunk - Bug #9226] " myronmarston (Myron Marston)
@ 2013-12-08  8:32 10% ` myronmarston (Myron Marston)
  2013-12-10  4:13 10% ` [ruby-core:59016] " tmm1 (Aman Gupta)
  2013-12-10  5:48 10% ` [ruby-core:59018] " tmm1 (Aman Gupta)
  9 siblings, 0 replies; 71+ results
From: myronmarston (Myron Marston) @ 2013-12-08  8:32 UTC (permalink / raw)
  To: ruby-core


Issue #9226 has been updated by myronmarston (Myron Marston).


Wow, thanks for the quick fix :).
----------------------------------------
Bug #9226: Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
https://bugs.ruby-lang.org/issues/9226#change-43515

Author: myronmarston (Myron Marston)
Status: Open
Priority: High
Assignee: ko1 (Koichi Sasada)
Category: core
Target version: current: 2.1.0
ruby -v: 2.1.0.preview2
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


We're trying to get a green RSpec build against ruby 2.1.0.preview2, and we're getting this very odd failure on travis:

https://travis-ci.org/rspec/rspec-core/jobs/15066502#L122

The line where it's failing is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/lib/rspec/core/filter_manager.rb#L75

It's calling `inspect` on a Hash and blowing up with that confusing error.  The hash that's causing this failure (if that helps) is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/spec/spec_helper.rb#L149-L158

It's the `{ :ruby => lambda { } }` hash being passed to `filter_run_excluding`.


-- 
http://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 10%]

* [ruby-core:58964] [ruby-trunk - Bug #9226] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
  2013-12-07 16:17 10% [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect myronmarston (Myron Marston)
                   ` (5 preceding siblings ...)
  2013-12-08  6:27 10% ` [ruby-core:58960] [ruby-trunk - Bug #9226][Open] " ko1 (Koichi Sasada)
@ 2013-12-08  8:32 10% ` myronmarston (Myron Marston)
  2013-12-08  8:32 10% ` [ruby-core:58965] " myronmarston (Myron Marston)
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 71+ results
From: myronmarston (Myron Marston) @ 2013-12-08  8:32 UTC (permalink / raw)
  To: ruby-core


Issue #9226 has been updated by myronmarston (Myron Marston).


Wow, thanks for the quick fix :).
----------------------------------------
Bug #9226: Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
https://bugs.ruby-lang.org/issues/9226#change-43514

Author: myronmarston (Myron Marston)
Status: Open
Priority: High
Assignee: ko1 (Koichi Sasada)
Category: core
Target version: current: 2.1.0
ruby -v: 2.1.0.preview2
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


We're trying to get a green RSpec build against ruby 2.1.0.preview2, and we're getting this very odd failure on travis:

https://travis-ci.org/rspec/rspec-core/jobs/15066502#L122

The line where it's failing is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/lib/rspec/core/filter_manager.rb#L75

It's calling `inspect` on a Hash and blowing up with that confusing error.  The hash that's causing this failure (if that helps) is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/spec/spec_helper.rb#L149-L158

It's the `{ :ruby => lambda { } }` hash being passed to `filter_run_excluding`.


-- 
http://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 10%]

* [ruby-core:58960] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
  2013-12-07 16:17 10% [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect myronmarston (Myron Marston)
                   ` (4 preceding siblings ...)
  2013-12-08  3:06 10% ` [ruby-core:58959] " tmm1 (Aman Gupta)
@ 2013-12-08  6:27 10% ` ko1 (Koichi Sasada)
  2013-12-08  8:32 10% ` [ruby-core:58964] [ruby-trunk - Bug #9226] " myronmarston (Myron Marston)
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 71+ results
From: ko1 (Koichi Sasada) @ 2013-12-08  6:27 UTC (permalink / raw)
  To: ruby-core


Issue #9226 has been updated by ko1 (Koichi Sasada).

Status changed from Closed to Open
% Done changed from 100 to 0

OMG That is another issue....

----------------------------------------
Bug #9226: Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
https://bugs.ruby-lang.org/issues/9226#change-43512

Author: myronmarston (Myron Marston)
Status: Open
Priority: High
Assignee: ko1 (Koichi Sasada)
Category: core
Target version: current: 2.1.0
ruby -v: 2.1.0.preview2
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


We're trying to get a green RSpec build against ruby 2.1.0.preview2, and we're getting this very odd failure on travis:

https://travis-ci.org/rspec/rspec-core/jobs/15066502#L122

The line where it's failing is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/lib/rspec/core/filter_manager.rb#L75

It's calling `inspect` on a Hash and blowing up with that confusing error.  The hash that's causing this failure (if that helps) is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/spec/spec_helper.rb#L149-L158

It's the `{ :ruby => lambda { } }` hash being passed to `filter_run_excluding`.


-- 
http://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 10%]

* [ruby-core:58959] [ruby-trunk - Bug #9226] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
  2013-12-07 16:17 10% [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect myronmarston (Myron Marston)
                   ` (3 preceding siblings ...)
  2013-12-08  2:51 10% ` [ruby-core:58958] " ko1 (Koichi Sasada)
@ 2013-12-08  3:06 10% ` tmm1 (Aman Gupta)
  2013-12-08  6:27 10% ` [ruby-core:58960] [ruby-trunk - Bug #9226][Open] " ko1 (Koichi Sasada)
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 71+ results
From: tmm1 (Aman Gupta) @ 2013-12-08  3:06 UTC (permalink / raw)
  To: ruby-core


Issue #9226 has been updated by tmm1 (Aman Gupta).


Committed.

I was surprised but RGENGC_CHECK did not find this issue.
----------------------------------------
Bug #9226: Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
https://bugs.ruby-lang.org/issues/9226#change-43510

Author: myronmarston (Myron Marston)
Status: Closed
Priority: High
Assignee: ko1 (Koichi Sasada)
Category: core
Target version: current: 2.1.0
ruby -v: 2.1.0.preview2
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


We're trying to get a green RSpec build against ruby 2.1.0.preview2, and we're getting this very odd failure on travis:

https://travis-ci.org/rspec/rspec-core/jobs/15066502#L122

The line where it's failing is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/lib/rspec/core/filter_manager.rb#L75

It's calling `inspect` on a Hash and blowing up with that confusing error.  The hash that's causing this failure (if that helps) is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/spec/spec_helper.rb#L149-L158

It's the `{ :ruby => lambda { } }` hash being passed to `filter_run_excluding`.


-- 
http://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 10%]

* [ruby-core:58958] [ruby-trunk - Bug #9226] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
  2013-12-07 16:17 10% [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect myronmarston (Myron Marston)
                   ` (2 preceding siblings ...)
  2013-12-08  0:11 10% ` [ruby-core:58952] " tmm1 (Aman Gupta)
@ 2013-12-08  2:51 10% ` ko1 (Koichi Sasada)
  2013-12-08  3:06 10% ` [ruby-core:58959] " tmm1 (Aman Gupta)
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 71+ results
From: ko1 (Koichi Sasada) @ 2013-12-08  2:51 UTC (permalink / raw)
  To: ruby-core


Issue #9226 has been updated by ko1 (Koichi Sasada).


I like charliesome's approach.
Could you commit it?

----------------------------------------
Bug #9226: Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
https://bugs.ruby-lang.org/issues/9226#change-43508

Author: myronmarston (Myron Marston)
Status: Open
Priority: High
Assignee: ko1 (Koichi Sasada)
Category: core
Target version: current: 2.1.0
ruby -v: 2.1.0.preview2
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


We're trying to get a green RSpec build against ruby 2.1.0.preview2, and we're getting this very odd failure on travis:

https://travis-ci.org/rspec/rspec-core/jobs/15066502#L122

The line where it's failing is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/lib/rspec/core/filter_manager.rb#L75

It's calling `inspect` on a Hash and blowing up with that confusing error.  The hash that's causing this failure (if that helps) is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/spec/spec_helper.rb#L149-L158

It's the `{ :ruby => lambda { } }` hash being passed to `filter_run_excluding`.


-- 
http://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 10%]

* [ruby-core:58952] [ruby-trunk - Bug #9226] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
  2013-12-07 16:17 10% [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect myronmarston (Myron Marston)
  2013-12-07 23:29 10% ` [ruby-core:58950] [ruby-trunk - Bug #9226] " tmm1 (Aman Gupta)
  2013-12-08  0:10 10% ` [ruby-core:58951] " charliesome (Charlie Somerville)
@ 2013-12-08  0:11 10% ` tmm1 (Aman Gupta)
  2013-12-08  2:51 10% ` [ruby-core:58958] " ko1 (Koichi Sasada)
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 71+ results
From: tmm1 (Aman Gupta) @ 2013-12-08  0:11 UTC (permalink / raw)
  To: ruby-core


Issue #9226 has been updated by tmm1 (Aman Gupta).

Category set to core
Assignee set to ko1 (Koichi Sasada)
Priority changed from Normal to High


----------------------------------------
Bug #9226: Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
https://bugs.ruby-lang.org/issues/9226#change-43500

Author: myronmarston (Myron Marston)
Status: Open
Priority: High
Assignee: ko1 (Koichi Sasada)
Category: core
Target version: current: 2.1.0
ruby -v: 2.1.0.preview2
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


We're trying to get a green RSpec build against ruby 2.1.0.preview2, and we're getting this very odd failure on travis:

https://travis-ci.org/rspec/rspec-core/jobs/15066502#L122

The line where it's failing is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/lib/rspec/core/filter_manager.rb#L75

It's calling `inspect` on a Hash and blowing up with that confusing error.  The hash that's causing this failure (if that helps) is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/spec/spec_helper.rb#L149-L158

It's the `{ :ruby => lambda { } }` hash being passed to `filter_run_excluding`.


-- 
http://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 10%]

* [ruby-core:58951] [ruby-trunk - Bug #9226] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
  2013-12-07 16:17 10% [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect myronmarston (Myron Marston)
  2013-12-07 23:29 10% ` [ruby-core:58950] [ruby-trunk - Bug #9226] " tmm1 (Aman Gupta)
@ 2013-12-08  0:10 10% ` charliesome (Charlie Somerville)
  2013-12-08  0:11 10% ` [ruby-core:58952] " tmm1 (Aman Gupta)
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 71+ results
From: charliesome (Charlie Somerville) @ 2013-12-08  0:10 UTC (permalink / raw)
  To: ruby-core


Issue #9226 has been updated by charliesome (Charlie Somerville).


Instead of shading the hash, we could probably do something like this:

diff --git hash.c hash.c
index a52e02f..e7a505e 100644
--- hash.c
+++ hash.c
@@ -1414,22 +1414,9 @@ rb_hash_replace(VALUE hash, VALUE hash2)
 
     table2 = RHASH(hash2)->ntbl;
 
-    if (RHASH_EMPTY_P(hash2)) {
-	rb_hash_clear(hash);
-	if (table2) hash_tbl(hash)->type = table2->type;
-	return hash;
-    }
-
-    if (RHASH_ITER_LEV(hash) > 0) {
-	rb_hash_clear(hash);
-	hash_tbl(hash)->type = table2->type;
-	rb_hash_foreach(hash2, replace_i, hash);
-    }
-    else {
-	st_table *old_table = RHASH(hash)->ntbl;
-	if (old_table) st_free_table(old_table);
-	RHASH(hash)->ntbl = st_copy(table2);
-    }
+    rb_hash_clear(hash);
+    hash_tbl(hash)->type = table2->type;
+    rb_hash_foreach(hash2, replace_i, hash);
 
     return hash;
 }

----------------------------------------
Bug #9226: Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
https://bugs.ruby-lang.org/issues/9226#change-43499

Author: myronmarston (Myron Marston)
Status: Open
Priority: Normal
Assignee: 
Category: 
Target version: current: 2.1.0
ruby -v: 2.1.0.preview2
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


We're trying to get a green RSpec build against ruby 2.1.0.preview2, and we're getting this very odd failure on travis:

https://travis-ci.org/rspec/rspec-core/jobs/15066502#L122

The line where it's failing is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/lib/rspec/core/filter_manager.rb#L75

It's calling `inspect` on a Hash and blowing up with that confusing error.  The hash that's causing this failure (if that helps) is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/spec/spec_helper.rb#L149-L158

It's the `{ :ruby => lambda { } }` hash being passed to `filter_run_excluding`.


-- 
http://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 10%]

* [ruby-core:58950] [ruby-trunk - Bug #9226] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
  2013-12-07 16:17 10% [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect myronmarston (Myron Marston)
@ 2013-12-07 23:29 10% ` tmm1 (Aman Gupta)
  2013-12-08  0:10 10% ` [ruby-core:58951] " charliesome (Charlie Somerville)
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 71+ results
From: tmm1 (Aman Gupta) @ 2013-12-07 23:29 UTC (permalink / raw)
  To: ruby-core


Issue #9226 has been updated by tmm1 (Aman Gupta).


I was able to reproduce this on trunk with the following patch to rspec:

--- a/lib/rspec/core/command_line.rb
+++ b/lib/rspec/core/command_line.rb
@@ -20,6 +20,7 @@ module RSpec
         @configuration.output_stream = out if @configuration.output_stream == $stdout
         @options.configure(@configuration)
         @configuration.load_spec_files
+        GC.stress=true
         @world.announce_filters

         @configuration.reporter.report(@world.example_count) do |reporter|

With the patch, you can see different results during `script/rspec_with_simplecov spec -b --format progress` boot due to object re-use:

  exclude {:ruby=>#<Proc:./spec/spec_helper.rb:149>}
  exclude {:ruby=>RSpec::ExampleGroups::RSpecCoreConfiguration::SeedUsed}
  exclude {:ruby=>#<RubyVM::Env:0x007ff5ec199198>}

I noticed that RSpec::Core::FilterManager was using Hash#merge, and after some debugging I confirmed that the following patch fixes this issue on trunk:

--- a/hash.c
+++ b/hash.c
@@ -1429,6 +1429,7 @@ rb_hash_replace(VALUE hash, VALUE hash2)
        st_table *old_table = RHASH(hash)->ntbl;
        if (old_table) st_free_table(old_table);
        RHASH(hash)->ntbl = st_copy(table2);
+       OBJ_WB_UNPROTECT(hash);
     }

     return hash;
----------------------------------------
Bug #9226: Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
https://bugs.ruby-lang.org/issues/9226#change-43498

Author: myronmarston (Myron Marston)
Status: Open
Priority: Normal
Assignee: 
Category: 
Target version: current: 2.1.0
ruby -v: 2.1.0.preview2
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


We're trying to get a green RSpec build against ruby 2.1.0.preview2, and we're getting this very odd failure on travis:

https://travis-ci.org/rspec/rspec-core/jobs/15066502#L122

The line where it's failing is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/lib/rspec/core/filter_manager.rb#L75

It's calling `inspect` on a Hash and blowing up with that confusing error.  The hash that's causing this failure (if that helps) is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/spec/spec_helper.rb#L149-L158

It's the `{ :ruby => lambda { } }` hash being passed to `filter_run_excluding`.


-- 
http://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 10%]

* [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
@ 2013-12-07 16:17 10% myronmarston (Myron Marston)
  2013-12-07 23:29 10% ` [ruby-core:58950] [ruby-trunk - Bug #9226] " tmm1 (Aman Gupta)
                   ` (9 more replies)
  0 siblings, 10 replies; 71+ results
From: myronmarston (Myron Marston) @ 2013-12-07 16:17 UTC (permalink / raw)
  To: ruby-core


Issue #9226 has been reported by myronmarston (Myron Marston).

----------------------------------------
Bug #9226: Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect
https://bugs.ruby-lang.org/issues/9226

Author: myronmarston (Myron Marston)
Status: Open
Priority: Normal
Assignee: 
Category: 
Target version: current: 2.1.0
ruby -v: 2.1.0.preview2
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN


We're trying to get a green RSpec build against ruby 2.1.0.preview2, and we're getting this very odd failure on travis:

https://travis-ci.org/rspec/rspec-core/jobs/15066502#L122

The line where it's failing is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/lib/rspec/core/filter_manager.rb#L75

It's calling `inspect` on a Hash and blowing up with that confusing error.  The hash that's causing this failure (if that helps) is here:

https://github.com/rspec/rspec-core/blob/2e77a83d92eb1e661398f00359fc784da019401a/spec/spec_helper.rb#L149-L158

It's the `{ :ruby => lambda { } }` hash being passed to `filter_run_excluding`.


-- 
http://bugs.ruby-lang.org/

^ permalink raw reply	[relevance 10%]

* [ruby-core:53504] [ruby-trunk - Bug #8092] [patch] gc: improve accuracy of objspace_live_num() and allocated/freed counters
    2013-03-18  8:32  4% ` [ruby-core:53496] [ruby-trunk - Bug #8092] " authorNari (Narihiro Nakamura)
@ 2013-03-18 13:27  4% ` tmm1 (Aman Gupta)
  1 sibling, 0 replies; 71+ results
From: tmm1 (Aman Gupta) @ 2013-03-18 13:27 UTC (permalink / raw)
  To: ruby-core


Issue #8092 has been updated by tmm1 (Aman Gupta).


This test is passing for me on trunk. Before r39811 it is failing.

[ 92/132] TestGc#test_stat                                                
{:count=>357, :heap_used=>421, :heap_length=>811, :heap_increment=>283, :heap_live_num=>14452, :heap_free_num=>156816, :heap_final_num=>0, :total_allocated_object=>389190, :total_freed_object=>374738}
{:TOTAL=>171268, :FREE=>156816, :T_OBJECT=>46, :T_CLASS=>655, :T_MODULE=>56, :T_FLOAT=>10, :T_STRING=>8268, :T_REGEXP=>145, :T_ARRAY=>1947, :T_HASH=>42, :T_STRUCT=>9, :T_BIGNUM=>25, :T_FILE=>3, :T_DATA=>2221, :T_MATCH=>21, :T_COMPLEX=>1, :T_NODE=>935, :T_ICLASS=>68}
Finished tests in 3.297242s, 40.0335 tests/s, 1313.5220 assertions/s.            
132 tests, 4331 assertions, 0 failures, 0 errors, 0 skips

ruby -v: ruby 2.1.0dev (2013-03-18 trunk 39811) [x86_64-linux]

----------------------------------------
Bug #8092: [patch] gc: improve accuracy of objspace_live_num() and allocated/freed counters
https://bugs.ruby-lang.org/issues/8092#change-37696

Author: tmm1 (Aman Gupta)
Status: Open
Priority: Normal
Assignee: authorNari (Narihiro Nakamura)
Category: core
Target version: 
ruby -v: ruby 2.1.0dev (2013-03-14 trunk 39748) [x86_64-darwin12.2.1]


Test with large rails app:

  ruby -e'
    require "./config/environment"

    stat, count = {}, {}
    GC.start
    GC.stat(stat)
    ObjectSpace.count_objects(count)

    printf "%d == %d\n", stat[:heap_live_num], count[:TOTAL]-count[:FREE]
  '

Without patch:

    632974 == 628506

With patch:

    628506 == 628506

diff --git a/gc.c b/gc.c
index bd95073..48f9470 100644
--- a/gc.c
+++ b/gc.c
@@ -1432,10 +1432,8 @@ finalize_list(rb_objspace_t *objspace, RVALUE *p)
 	run_final(objspace, (VALUE)p);
 	if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
             add_slot_local_freelist(objspace, p);
-            if (!is_lazy_sweeping(objspace)) {
-		objspace->total_freed_object_num++;
-		objspace->heap.free_num++;
-            }
+            objspace->total_freed_object_num++;
+            objspace->heap.free_num++;
 	}
 	else {
 	    struct heaps_slot *slot = (struct heaps_slot *)(VALUE)RDATA(p)->dmark;
@@ -1939,9 +1937,9 @@ slot_sweep(rb_objspace_t *objspace, struct heaps_slot *sweep_slot)
         else {
             sweep_slot->free_next = NULL;
         }
-	objspace->total_freed_object_num += freed_num;
 	objspace->heap.free_num += freed_num + empty_num;
     }
+    objspace->total_freed_object_num += freed_num;
     objspace->heap.final_num += final_num;
 
     if (deferred_final_list && !finalizing) {
@@ -2965,11 +2963,11 @@ rb_gc_force_recycle(VALUE p)
     rb_objspace_t *objspace = &rb_objspace;
     struct heaps_slot *slot;
 
+    objspace->total_freed_object_num++;
     if (MARKED_IN_BITMAP(GET_HEAP_BITMAP(p), p)) {
         add_slot_local_freelist(objspace, (RVALUE *)p);
     }
     else {
-	objspace->total_freed_object_num++;
 	objspace->heap.free_num++;
         slot = add_slot_local_freelist(objspace, (RVALUE *)p);
         if (slot->free_next == NULL) {



-- 
http://bugs.ruby-lang.org/

^ permalink raw reply related	[relevance 4%]

* [ruby-core:53496] [ruby-trunk - Bug #8092] [patch] gc: improve accuracy of objspace_live_num() and allocated/freed counters
  @ 2013-03-18  8:32  4% ` authorNari (Narihiro Nakamura)
  2013-03-18 13:27  4% ` [ruby-core:53504] " tmm1 (Aman Gupta)
  1 sibling, 0 replies; 71+ results
From: authorNari (Narihiro Nakamura) @ 2013-03-18  8:32 UTC (permalink / raw)
  To: ruby-core


Issue #8092 has been updated by authorNari (Narihiro Nakamura).


Thank you for bug report.

But, the following test case is failure.

I think ko1-san is the implementer of GC.stat.
ko1-san, what do you think?

=== start ===
$ git diff test
diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb
index bed58f3..8cb036a 100644
--- a/test/ruby/test_gc.rb
+++ b/test/ruby/test_gc.rb
@@ -64,6 +64,15 @@ class TestGc < Test::Unit::TestCase
     assert_equal(arg, res)
     assert_equal(false, res.empty?)
     assert_kind_of(Integer, res[:count])
+
+    stat, count = {}, {}
+    GC.start
+    GC.stat(stat)
+    ObjectSpace.count_objects(count)
+    puts ""
+    p stat
+    p count
+    assert_equal(stat[:heap_live_num], count[:TOTAL]-count[:FREE])
   end
 
   def test_singleton_method

$ % make test-all TESTS='ruby/test_defined.rb ruby/test_integer.rb ruby/test_objectspace.rb ruby/test_sprintf_comb.rb ruby/test_argf.rb ruby/test_fiber.rb ruby/test_gc.rb'
....
# Running tests:

[ 91/131] TestGc#test_stat
{:count=>351, :heap_used=>684, :heap_length=>1139, :heap_increment=>399, :heap_live_num=>46061, :heap_free_num=>152639, :heap_final_num=>0, :total_allocated_object=>402509, :total_freed_object=>356448}
{:TOTAL=>198553, :FREE=>152639, :T_OBJECT=>31312, :T_CLASS=>655, :T_MODULE=>56, :T_FLOAT=>10, :T_STRING=>8425, :T_REGEXP=>146, :T_ARRAY=>1966, :T_HASH=>49, :T_STRUCT=>10, :T_BIGNUM=>25, :T_FILE=>10, :T_DATA=>2225, :T_MATCH=>22, :T_COMPLEX=>1, :T_NODE=>934, :T_ICLASS=>68}
 = 0.01 s
  1) Failure:
test_stat(TestGc) [/home/nari/source/ruby/ruby-git/test/ruby/test_gc.rb:75]:
<46061> expected but was
<45914>.

Finished tests in 6.628281s, 19.7638 tests/s, 657.9383 assertions/s.
131 tests, 4361 assertions, 1 failures, 0 errors, 0 skips

ruby -v: ruby 2.1.0dev (2013-03-14 trunk 38552) [x86_64-linux]
make: *** [yes-test-all] Error 1
=== end ===

----------------------------------------
Bug #8092: [patch] gc: improve accuracy of objspace_live_num() and allocated/freed counters
https://bugs.ruby-lang.org/issues/8092#change-37690

Author: tmm1 (Aman Gupta)
Status: Open
Priority: Normal
Assignee: authorNari (Narihiro Nakamura)
Category: core
Target version: 
ruby -v: ruby 2.1.0dev (2013-03-14 trunk 39748) [x86_64-darwin12.2.1]


Test with large rails app:

  ruby -e'
    require "./config/environment"

    stat, count = {}, {}
    GC.start
    GC.stat(stat)
    ObjectSpace.count_objects(count)

    printf "%d == %d\n", stat[:heap_live_num], count[:TOTAL]-count[:FREE]
  '

Without patch:

    632974 == 628506

With patch:

    628506 == 628506

diff --git a/gc.c b/gc.c
index bd95073..48f9470 100644
--- a/gc.c
+++ b/gc.c
@@ -1432,10 +1432,8 @@ finalize_list(rb_objspace_t *objspace, RVALUE *p)
 	run_final(objspace, (VALUE)p);
 	if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
             add_slot_local_freelist(objspace, p);
-            if (!is_lazy_sweeping(objspace)) {
-		objspace->total_freed_object_num++;
-		objspace->heap.free_num++;
-            }
+            objspace->total_freed_object_num++;
+            objspace->heap.free_num++;
 	}
 	else {
 	    struct heaps_slot *slot = (struct heaps_slot *)(VALUE)RDATA(p)->dmark;
@@ -1939,9 +1937,9 @@ slot_sweep(rb_objspace_t *objspace, struct heaps_slot *sweep_slot)
         else {
             sweep_slot->free_next = NULL;
         }
-	objspace->total_freed_object_num += freed_num;
 	objspace->heap.free_num += freed_num + empty_num;
     }
+    objspace->total_freed_object_num += freed_num;
     objspace->heap.final_num += final_num;
 
     if (deferred_final_list && !finalizing) {
@@ -2965,11 +2963,11 @@ rb_gc_force_recycle(VALUE p)
     rb_objspace_t *objspace = &rb_objspace;
     struct heaps_slot *slot;
 
+    objspace->total_freed_object_num++;
     if (MARKED_IN_BITMAP(GET_HEAP_BITMAP(p), p)) {
         add_slot_local_freelist(objspace, (RVALUE *)p);
     }
     else {
-	objspace->total_freed_object_num++;
 	objspace->heap.free_num++;
         slot = add_slot_local_freelist(objspace, (RVALUE *)p);
         if (slot->free_next == NULL) {



-- 
http://bugs.ruby-lang.org/

^ permalink raw reply related	[relevance 4%]

* [ruby-core:41060] [ruby-trunk - Bug #5634] yield and binding
  @ 2011-11-15 10:37  1% ` Heesob Park
  0 siblings, 0 replies; 71+ results
From: Heesob Park @ 2011-11-15 10:37 UTC (permalink / raw)
  To: ruby-core


Issue #5634 has been updated by Heesob Park.


This segmentation fault occurs on the line #949 of vm_insnhelper.c(vm_invoke_block)
 if (BUILTIN_TYPE(iseq) != T_NODE) {

The variable iseq is NULL in this case.

----------------------------------------
Bug #5634: yield and binding
http://redmine.ruby-lang.org/issues/5634

Author: Thomas Sawyer
Status: Open
Priority: Normal
Assignee: 
Category: core
Target version: 2.0.0
ruby -v: ruby 1.9.3dev (2011-09-23 revision 33323) [x86_64-linux]


Per my recent question on ruby-core... "well there's your problem":

>> def x
>>   binding
>> end
=> nil
>> b = x{|a|a+a}
=> #<Binding:0x0000000103f1a0>
>> b.eval('yield(2)')

(irb):2: [BUG] Segmentation fault
ruby 1.9.3dev (2011-09-23 revision 33323) [x86_64-linux]

-- Control frame information -----------------------------------------------
c:0026 p:0007 s:0091 b:0090 l:001ff8 d:000089 EVAL   (irb):2
c:0025 p:---- s:0088 b:0088 l:000087 d:000087 FINISH
c:0024 p:---- s:0086 b:0086 l:000085 d:000085 CFUNC  :eval
c:0023 p:0013 s:0082 b:0082 l:0009a8 d:000081 EVAL   (irb):6
c:0022 p:---- s:0080 b:0080 l:000079 d:000079 FINISH
c:0021 p:---- s:0078 b:0078 l:000077 d:000077 CFUNC  :eval
c:0020 p:0028 s:0071 b:0071 l:000070 d:000070 METHOD /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/workspace.rb:80
c:0019 p:0033 s:0064 b:0063 l:000062 d:000062 METHOD /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/context.rb:254
c:0018 p:0031 s:0058 b:0058 l:000a28 d:000057 BLOCK  /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:159
c:0017 p:0042 s:0050 b:0050 l:000049 d:000049 METHOD /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:273
c:0016 p:0011 s:0045 b:0045 l:000a28 d:000044 BLOCK  /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:156
c:0015 p:0144 s:0041 b:0041 l:000024 d:000040 BLOCK  /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/ruby-lex.rb:243
c:0014 p:---- s:0038 b:0038 l:000037 d:000037 FINISH
c:0013 p:---- s:0036 b:0036 l:000035 d:000035 CFUNC  :loop
c:0012 p:0009 s:0033 b:0033 l:000024 d:000032 BLOCK  /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/ruby-lex.rb:229
c:0011 p:---- s:0031 b:0031 l:000030 d:000030 FINISH
c:0010 p:---- s:0029 b:0029 l:000028 d:000028 CFUNC  :catch
c:0009 p:0023 s:0025 b:0025 l:000024 d:000024 METHOD /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/ruby-lex.rb:228
c:0008 p:0046 s:0022 b:0022 l:000a28 d:000a28 METHOD /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:155
c:0007 p:0011 s:0019 b:0019 l:000658 d:000018 BLOCK  /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:70
c:0006 p:---- s:0017 b:0017 l:000016 d:000016 FINISH
c:0005 p:---- s:0015 b:0015 l:000014 d:000014 CFUNC  :catch
c:0004 p:0183 s:0011 b:0011 l:000658 d:000658 METHOD /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:69
c:0003 p:0039 s:0006 b:0006 l:0007a8 d:001e18 EVAL   /home/trans/.rbenv/versions/1.9.3-rc1/bin/irb:12
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH
c:0001 p:0000 s:0002 b:0002 l:0007a8 d:0007a8 TOP   

-- Ruby level backtrace information ----------------------------------------
/home/trans/.rbenv/versions/1.9.3-rc1/bin/irb:12:in `<main>'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:69:in `start'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:69:in `catch'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:70:in `block in start'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:155:in `eval_input'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `each_top_level_statement'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `catch'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `block in each_top_level_statement'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `loop'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/ruby-lex.rb:243:in `block (2 levels) in each_top_level_statement'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:156:in `block in eval_input'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:273:in `signal_status'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb:159:in `block (2 levels) in eval_input'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/context.rb:254:in `evaluate'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/workspace.rb:80:in `evaluate'
/home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/workspace.rb:80:in `eval'
(irb):6:in `irb_binding'
(irb):6:in `eval'
(irb):2:in `x'

-- C level backtrace information -------------------------------------------
irb() [0x526f18]
irb() [0x56ecb8]
irb(rb_bug+0xb3) [0x56ee53]
irb() [0x4b42b0]
/lib/libpthread.so.0(+0xf8f0) [0x7f8c9f5d38f0]
irb() [0x517a16]
irb() [0x51ba3b]
irb() [0x51c4da]
irb() [0x51ca86]
irb() [0x41ac06]
irb() [0x52072e]
irb() [0x5178d7]
irb() [0x51ba3b]
irb() [0x51c4da]
irb() [0x51ca86]
irb() [0x52072e]
irb() [0x5178d7]
irb() [0x51ba3b]
irb() [0x526259]
irb(rb_rescue2+0x15b) [0x417b9b]
irb() [0x5119c9]
irb() [0x52072e]
irb() [0x5178d7]
irb() [0x51ba3b]
irb() [0x51eb0e]
irb(rb_catch_obj+0xbe) [0x51082e]
irb() [0x51161a]
irb() [0x52072e]
irb() [0x5178d7]
irb() [0x51ba3b]
irb() [0x51eb0e]
irb(rb_catch_obj+0xbe) [0x51082e]
irb() [0x51161a]
irb() [0x52072e]
irb() [0x5178d7]
irb() [0x51ba3b]
irb(rb_iseq_eval_main+0x292) [0x51be72]
irb() [0x417f32]
irb(ruby_run_node+0x36) [0x419ff6]
irb() [0x4170d9]
/lib/libc.so.6(__libc_start_main+0xfd) [0x7f8c9e997c4d]
irb() [0x416fc9]

-- Other runtime information -----------------------------------------------

* Loaded script: irb

* Loaded features:

    0 enumerator.so
    1 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/enc/encdb.so
    2 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/enc/trans/transdb.so
    3 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/rubygems/defaults.rb
    4 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/rbconfig.rb
    5 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/rubygems/deprecate.rb
    6 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/rubygems/exceptions.rb
    7 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/rubygems/custom_require.rb
    8 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/rubygems.rb
    9 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/psych.so
   10 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/stringio.so
   11 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/nodes/node.rb
   12 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/nodes/stream.rb
   13 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/nodes/document.rb
   14 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/nodes/sequence.rb
   15 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/nodes/scalar.rb
   16 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/nodes/mapping.rb
   17 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/nodes/alias.rb
   18 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/nodes.rb
   19 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/streaming.rb
   20 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/visitors/visitor.rb
   21 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/strscan.so
   22 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/scalar_scanner.rb
   23 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/visitors/to_ruby.rb
   24 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/visitors/emitter.rb
   25 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/visitors/yaml_tree.rb
   26 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/json/ruby_events.rb
   27 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/visitors/json_tree.rb
   28 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/visitors/depth_first.rb
   29 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/visitors.rb
   30 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/handler.rb
   31 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/tree_builder.rb
   32 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/parser.rb
   33 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/omap.rb
   34 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/set.rb
   35 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/coder.rb
   36 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/core_ext.rb
   37 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/date_core.so
   38 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/date/format.rb
   39 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/date.rb
   40 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/deprecated.rb
   41 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych/json.rb
   42 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/psych.rb
   43 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/yaml.rb
   44 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/core_ext/rbconfig.rb
   45 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/xdg.rb
   46 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/control.rb
   47 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/command.rb
   48 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/original.rb
   49 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/core_ext/file.rb
   50 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/library/requirements.rb
   51 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/library/metadata.rb
   52 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/library/script.rb
   53 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/library/version.rb
   54 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/library.rb
   55 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/ruby.rb
   56 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll/kernel.rb
   57 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/roll.rb
   58 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/site_ruby/1.9.1/oll.rb
   59 ubygems.rb
   60 rubygems.rb
   61 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/ubygems.rb
   62 irb.rb
   63 e2mmap.rb
   64 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/e2mmap.rb
   65 irb/init.rb
   66 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/init.rb
   67 irb/context.rb
   68 irb/workspace.rb
   69 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/workspace.rb
   70 irb/inspector.rb
   71 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/inspector.rb
   72 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/context.rb
   73 irb/extend-command.rb
   74 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/extend-command.rb
   75 irb/ruby-lex.rb
   76 irb/slex.rb
   77 irb/notifier.rb
   78 irb/output-method.rb
   79 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/output-method.rb
   80 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/notifier.rb
   81 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/slex.rb
   82 irb/ruby-token.rb
   83 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/ruby-token.rb
   84 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/ruby-lex.rb
   85 irb/input-method.rb
   86 irb/src_encoding.rb
   87 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/src_encoding.rb
   88 irb/magic-file.rb
   89 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/magic-file.rb
   90 readline.so
   91 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/readline.so
   92 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/input-method.rb
   93 irb/locale.rb
   94 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/locale.rb
   95 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb.rb
   96 rubygems/version.rb
   97 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/rubygems/version.rb
   98 rubygems/requirement.rb
   99 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/rubygems/requirement.rb
  100 rubygems/platform.rb
  101 rubygems/deprecate.rb
  102 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/rubygems/platform.rb
  103 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/rubygems/specification.rb
  104 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/rubygems/path_support.rb
  105 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/rubygems/dependency.rb
  106 ostruct.rb
  107 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/ostruct.rb
  108 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/gems/1.9.1/gems/wirble-0.1.3/lib/wirble.rb
  109 pp.rb
  110 prettyprint.rb
  111 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/prettyprint.rb
  112 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/pp.rb
  113 irb/completion.rb
  114 /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/irb/completion.rb

* Process memory map:

00400000-00616000 r-xp 00000000 08:01 5575135                            /home/trans/.rbenv/versions/1.9.3-rc1/bin/ruby
00815000-00816000 r--p 00215000 08:01 5575135                            /home/trans/.rbenv/versions/1.9.3-rc1/bin/ruby
00816000-00818000 rw-p 00216000 08:01 5575135                            /home/trans/.rbenv/versions/1.9.3-rc1/bin/ruby
00818000-00834000 rw-p 00000000 00:00 0 
00a47000-012f9000 rw-p 00000000 00:00 0                                  [heap]
7f8c9d264000-7f8c9d27a000 r-xp 00000000 08:01 18972791                   /lib/libgcc_s.so.1
7f8c9d27a000-7f8c9d479000 ---p 00016000 08:01 18972791                   /lib/libgcc_s.so.1
7f8c9d479000-7f8c9d47a000 r--p 00015000 08:01 18972791                   /lib/libgcc_s.so.1
7f8c9d47a000-7f8c9d47b000 rw-p 00016000 08:01 18972791                   /lib/libgcc_s.so.1
7f8c9d47b000-7f8c9d4b9000 r-xp 00000000 08:01 18972805                   /lib/libncurses.so.5.7
7f8c9d4b9000-7f8c9d6b9000 ---p 0003e000 08:01 18972805                   /lib/libncurses.so.5.7
7f8c9d6b9000-7f8c9d6bd000 r--p 0003e000 08:01 18972805                   /lib/libncurses.so.5.7
7f8c9d6bd000-7f8c9d6be000 rw-p 00042000 08:01 18972805                   /lib/libncurses.so.5.7
7f8c9d6be000-7f8c9d6f7000 r-xp 00000000 08:01 18972819                   /lib/libreadline.so.6.1
7f8c9d6f7000-7f8c9d8f6000 ---p 00039000 08:01 18972819                   /lib/libreadline.so.6.1
7f8c9d8f6000-7f8c9d8f8000 r--p 00038000 08:01 18972819                   /lib/libreadline.so.6.1
7f8c9d8f8000-7f8c9d8fe000 rw-p 0003a000 08:01 18972819                   /lib/libreadline.so.6.1
7f8c9d8fe000-7f8c9d8ff000 rw-p 00000000 00:00 0 
7f8c9d8ff000-7f8c9d905000 r-xp 00000000 08:01 8702444                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/readline.so
7f8c9d905000-7f8c9db04000 ---p 00006000 08:01 8702444                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/readline.so
7f8c9db04000-7f8c9db05000 r--p 00005000 08:01 8702444                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/readline.so
7f8c9db05000-7f8c9db06000 rw-p 00006000 08:01 8702444                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/readline.so
7f8c9db06000-7f8c9db3a000 r-xp 00000000 08:01 8702448                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/date_core.so
7f8c9db3a000-7f8c9dd39000 ---p 00034000 08:01 8702448                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/date_core.so
7f8c9dd39000-7f8c9dd3a000 r--p 00033000 08:01 8702448                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/date_core.so
7f8c9dd3a000-7f8c9dd3b000 rw-p 00034000 08:01 8702448                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/date_core.so
7f8c9dd3b000-7f8c9dd3c000 rw-p 00000000 00:00 0 
7f8c9dd3c000-7f8c9dd41000 r-xp 00000000 08:01 8702451                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/strscan.so
7f8c9dd41000-7f8c9df41000 ---p 00005000 08:01 8702451                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/strscan.so
7f8c9df41000-7f8c9df42000 r--p 00005000 08:01 8702451                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/strscan.so
7f8c9df42000-7f8c9df43000 rw-p 00006000 08:01 8702451                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/strscan.so
7f8c9df43000-7f8c9df4a000 r-xp 00000000 08:01 8702446                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/stringio.so
7f8c9df4a000-7f8c9e149000 ---p 00007000 08:01 8702446                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/stringio.so
7f8c9e149000-7f8c9e14a000 r--p 00006000 08:01 8702446                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/stringio.so
7f8c9e14a000-7f8c9e14b000 rw-p 00007000 08:01 8702446                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/stringio.so
7f8c9e14b000-7f8c9e16a000 r-xp 00000000 08:01 39535253                   /home/trans/.rbenv/versions/1.9.3-rc1/lib/libyaml-0.so.2.0.2
7f8c9e16a000-7f8c9e369000 ---p 0001f000 08:01 39535253                   /home/trans/.rbenv/versions/1.9.3-rc1/lib/libyaml-0.so.2.0.2
7f8c9e369000-7f8c9e36a000 r--p 0001e000 08:01 39535253                   /home/trans/.rbenv/versions/1.9.3-rc1/lib/libyaml-0.so.2.0.2
7f8c9e36a000-7f8c9e36b000 rw-p 0001f000 08:01 39535253                   /home/trans/.rbenv/versions/1.9.3-rc1/lib/libyaml-0.so.2.0.2
7f8c9e36b000-7f8c9e370000 r-xp 00000000 08:01 8702452                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/psych.so
7f8c9e370000-7f8c9e570000 ---p 00005000 08:01 8702452                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/psych.so
7f8c9e570000-7f8c9e571000 r--p 00005000 08:01 8702452                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/psych.so
7f8c9e571000-7f8c9e572000 rw-p 00006000 08:01 8702452                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/psych.so
7f8c9e572000-7f8c9e574000 r-xp 00000000 08:01 9421126                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/enc/trans/transdb.so
7f8c9e574000-7f8c9e774000 ---p 00002000 08:01 9421126                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/enc/trans/transdb.so
7f8c9e774000-7f8c9e775000 r--p 00002000 08:01 9421126                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/enc/trans/transdb.so
7f8c9e775000-7f8c9e776000 rw-p 00003000 08:01 9421126                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/enc/trans/transdb.so
7f8c9e776000-7f8c9e778000 r-xp 00000000 08:01 9421099                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/enc/encdb.so
7f8c9e778000-7f8c9e977000 ---p 00002000 08:01 9421099                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/enc/encdb.so
7f8c9e977000-7f8c9e978000 r--p 00001000 08:01 9421099                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/enc/encdb.so
7f8c9e978000-7f8c9e979000 rw-p 00002000 08:01 9421099                    /home/trans/.rbenv/versions/1.9.3-rc1/lib/ruby/1.9.1/x86_64-linux/enc/encdb.so
7f8c9e979000-7f8c9eaf3000 r-xp 00000000 08:01 18972789                   /lib/libc-2.11.1.so
7f8c9eaf3000-7f8c9ecf2000 ---p 0017a000 08:01 18972789                   /lib/libc-2.11.1.so
7f8c9ecf2000-7f8c9ecf6000 r--p 00179000 08:01 18972789                   /lib/libc-2.11.1.so
7f8c9ecf6000-7f8c9ecf7000 rw-p 0017d000 08:01 18972789                   /lib/libc-2.11.1.so
7f8c9ecf7000-7f8c9ecfc000 rw-p 00000000 00:00 0 
7f8c9ecfc000-7f8c9ed7e000 r-xp 00000000 08:01 18972854                   /lib/libm-2.11.1.so
7f8c9ed7e000-7f8c9ef7d000 ---p 00082000 08:01 18972854                   /lib/libm-2.11.1.so
7f8c9ef7d000-7f8c9ef7e000 r--p 00081000 08:01 18972854                   /lib/libm-2.11.1.so
7f8c9ef7e000-7f8c9ef7f000 rw-p 00082000 08:01 18972854                   /lib/libm-2.11.1.so
7f8c9ef7f000-7f8c9ef88000 r-xp 00000000 08:01 18972806                   /lib/libcrypt-2.11.1.so
7f8c9ef88000-7f8c9f188000 ---p 00009000 08:01 18972806                   /lib/libcrypt-2.11.1.so
7f8c9f188000-7f8c9f189000 r--p 00009000 08:01 18972806                   /lib/libcrypt-2.11.1.so
7f8c9f189000-7f8c9f18a000 rw-p 0000a000 08:01 18972806                   /lib/libcrypt-2.11.1.so
7f8c9f18a000-7f8c9f1b8000 rw-p 00000000 00:00 0 
7f8c9f1b8000-7f8c9f1ba000 r-xp 00000000 08:01 18972823                   /lib/libdl-2.11.1.so
7f8c9f1ba000-7f8c9f3ba000 ---p 00002000 08:01 18972823                   /lib/libdl-2.11.1.so
7f8c9f3ba000-7f8c9f3bb000 r--p 00002000 08:01 18972823                   /lib/libdl-2.11.1.so
7f8c9f3bb000-7f8c9f3bc000 rw-p 00003000 08:01 18972823                   /lib/libdl-2.11.1.so
7f8c9f3bc000-7f8c9f3c3000 r-xp 00000000 08:01 18973094                   /lib/librt-2.11.1.so
7f8c9f3c3000-7f8c9f5c2000 ---p 00007000 08:01 18973094                   /lib/librt-2.11.1.so
7f8c9f5c2000-7f8c9f5c3000 r--p 00006000 08:01 18973094                   /lib/librt-2.11.1.so
7f8c9f5c3000-7f8c9f5c4000 rw-p 00007000 08:01 18973094                   /lib/librt-2.11.1.so
7f8c9f5c4000-7f8c9f5dc000 r-xp 00000000 08:01 18973092                   /lib/libpthread-2.11.1.so
7f8c9f5dc000-7f8c9f7db000 ---p 00018000 08:01 18973092                   /lib/libpthread-2.11.1.so
7f8c9f7db000-7f8c9f7dc000 r--p 00017000 08:01 18973092                   /lib/libpthread-2.11.1.so
7f8c9f7dc000-7f8c9f7dd000 rw-p 00018000 08:01 18973092                   /lib/libpthread-2.11.1.so
7f8c9f7dd000-7f8c9f7e1000 rw-p 00000000 00:00 0 
7f8c9f7e1000-7f8c9f801000 r-xp 00000000 08:01 18972752                   /lib/ld-2.11.1.so
7f8c9f894000-7f8c9f995000 rw-p 00000000 00:00 0 
7f8c9f995000-7f8c9f9d4000 r--p 00000000 08:01 10846233                   /usr/lib/locale/en_US.utf8/LC_CTYPE
7f8c9f9d4000-7f8c9f9d9000 rw-p 00000000 00:00 0 
7f8c9f9f1000-7f8c9f9f3000 rw-p 00000000 00:00 0 
7f8c9f9f3000-7f8c9f9f4000 ---p 00000000 00:00 0 
7f8c9f9f4000-7f8c9f9f7000 rw-p 00000000 00:00 0 
7f8c9f9f7000-7f8c9f9fe000 r--s 00000000 08:01 23150643                   /usr/lib/gconv/gconv-modules.cache
7f8c9f9fe000-7f8c9fa00000 rw-p 00000000 00:00 0 
7f8c9fa00000-7f8c9fa01000 r--p 0001f000 08:01 18972752                   /lib/ld-2.11.1.so
7f8c9fa01000-7f8c9fa02000 rw-p 00020000 08:01 18972752                   /lib/ld-2.11.1.so
7f8c9fa02000-7f8c9fa03000 rw-p 00000000 00:00 0 
7fffaa009000-7fffaa01f000 rw-p 00000000 00:00 0                          [stack]
7fffaa095000-7fffaa096000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]


[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html

Aborted



-- 
http://redmine.ruby-lang.org

^ permalink raw reply	[relevance 1%]

* [ruby-core:37835] Re: [Ruby 1.9 - Bug #4962] come back gem_prelude!
  @ 2011-07-06 22:26  4%     ` Eric Hodel
  0 siblings, 0 replies; 71+ results
From: Eric Hodel @ 2011-07-06 22:26 UTC (permalink / raw)
  To: ruby-core

On Jul 6, 2011, at 3:02 PM, Benoit Daloze wrote:

> On 6 July 2011 23:21, Eric Hodel <drbrain@segment7.net> wrote:
>> 
>> Please try r32429
> 
> I just tried, and here are some numbers.
> Surprising how such a change can move numbers.
> 
> $ time ruby -e ''
> before: 0.045
> no-gems: 0.013
> after: 0.024
> 
> $ ruby -e 'p ObjectSpace.count_objects[:TOTAL]'
> before: 20033
> no-gems: 9811
> after: 14308

I'm unsure if TOTAL is counting what we think it's counting.  It seems to be showing the size of the object space not the number of allocated objects.  If you add allocated and FREE from the output below you'll get TOTAL.

$ cat diffhash.rb 
gems    = eval `#{Gem.ruby} -e 'GC.start; p ObjectSpace.count_objects' | grep '{'`
no_gems = eval `#{Gem.ruby} --disable-gems -e 'GC.start; p ObjectSpace.count_objects' | grep '{'`

gems[:allocated]    =
  gems.select { |k,_| k.to_s.start_with? 'T_' }.values.inject :+

no_gems[:allocated] =
  no_gems.select { |k,_| k.to_s.start_with? 'T_' }.values.inject :+

puts "               gems  no_gems     diff"

gems.keys.sort.each do |key|
  a = gems[key].to_i
  b = no_gems[key].to_i

  puts "%-10s %8d %8d %8d" % [key, a, b, a - b]
end

$ ./ruby19 diffhash.rb 
               gems  no_gems     diff
FREE           6793     7357     -564
TOTAL         14309     9811     4498
T_ARRAY         226       20      206
T_BIGNUM          3        3        0
T_CLASS         474      425       49
T_COMPLEX         1        1        0
T_DATA          347      117      230
T_FILE            3        3        0
T_FLOAT           7        7        0
T_HASH            7        3        4
T_ICLASS         19       18        1
T_MODULE         21       18        3
T_NODE         3185       27     3158
T_OBJECT          7        6        1
T_REGEXP         24        8       16
T_STRING       3192     1798     1394
allocated      7516     2454     5062

Also, the GC runs once at ruby startup:

$ ruby19 --disable-gems -e 'GC::Profiler.enable; require "rubygems"; puts GC::Profiler.result'
GC 1 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC Time(ms)
    1               0.009               288200               409000                10225         0.41599999999999970335

Increasing HEAP_MIN_SLOTS to 20000 eliminates the initial garbage collection:

$ RUBY_HEAP_MIN_SLOTS=20000 ruby19 --disable-gems -e 'GC::Profiler.enable; require "rubygems"; puts GC::Profiler.result'
heap_min_slots=20000 (10000)

^ permalink raw reply	[relevance 4%]

* [ruby-core:25571] Implicit block argument in Procs
@ 2009-09-14  9:57  5% Cody Brocious
  0 siblings, 0 replies; 71+ results
From: Cody Brocious @ 2009-09-14  9:57 UTC (permalink / raw)
  To: ruby-core

I ran into some block behavior I thought was a bit odd.  Calling a
Proc (via .call or any other means) with a block causes the block to
be silently dropped unless the Proc has an explicit block argument.
This occurs even when taking a block as an explicit argument to
another method and then calling that Proc.  Below is a small bit of
code which shows the issue in two ways:

# Raw Proc
proc = Proc.new { |&block|
	block.yield
}
proc.call {
	puts 'test'
}

# 'Block' Proc
def set(&block)
	$block = block
end

set {
	yield
}

$block.call {
	puts 'test'
}

From a quick glance at the source (specifically proc.c), the issue
seems to be that in proc_call() there's the following line:
if (BUILTIN_TYPE(iseq) == T_NODE || iseq->arg_block != -1) {

Inside of that block the code that handles block passing.  The
iseq->arg_block != -1 check seems to prevent passing blocks unless
they're explicitly named.

Is this behavior intentional?  If not, is there a limitation in
rb_vm_invoke_proc() which makes passing an implicit block a problem?
It seems that killing the arg_block check would solve the issue if
there's no problem in rb_vm_invoke_proc().

Thanks,
- Cody Brocious

^ permalink raw reply	[relevance 5%]

* [ruby-core:24118] [Bug #1716] set_trace_func/raise related segfault, one line repro
@ 2009-07-02 17:11  4% Jedediah Smith
  0 siblings, 0 replies; 71+ results
From: Jedediah Smith @ 2009-07-02 17:11 UTC (permalink / raw)
  To: ruby-core

Bug #1716: set_trace_func/raise related segfault, one line repro
http://redmine.ruby-lang.org/issues/show/1716

Author: Jedediah Smith
Status: Open, Priority: Normal
Category: core
ruby -v: ruby 1.9.1p129 (2009-05-12 revision 23412) [x86_64-linux]

ruby -e 'set_trace_func proc{ begin; fail; rescue; end }; begin; fail; rescue; end'

-e: [BUG] Segmentation fault
ruby 1.9.1p129 (2009-05-12 revision 23412) [x86_64-linux]

-- control frame ----------
c:0004 p:0020 s:0009 b:0009 l:002588 d:000c70 BLOCK 
c:0003 p:0029 s:0006 b:0006 l:002588 d:002288 EVAL   -e:1
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH
c:0001 p:0000 s:0002 b:0002 l:002588 d:002588 TOP   
---------------------------
-- Ruby level backtrace information-----------------------------------------
-e:0:in `rescue in <main>'
-e:1:in `<main>'

-- C level backtrace information -------------------------------------------
0x7f6cc07d632b /usr/local/lib/libruby.so.1.9(rb_vm_bugreport+0x4b) [0x7f6cc07d632b]
0x7f6cc06f72be /usr/local/lib/libruby.so.1.9 [0x7f6cc06f72be]
0x7f6cc06f7433 /usr/local/lib/libruby.so.1.9(rb_bug+0xb3) [0x7f6cc06f7433]
0x7f6cc077e29c /usr/local/lib/libruby.so.1.9 [0x7f6cc077e29c]
0x7f6cc0498080 /lib/libpthread.so.0 [0x7f6cc0498080]
0x7f6cc07cbbb7 /usr/local/lib/libruby.so.1.9 [0x7f6cc07cbbb7]
0x7f6cc07cf684 /usr/local/lib/libruby.so.1.9 [0x7f6cc07cf684]
0x7f6cc07cf7d1 /usr/local/lib/libruby.so.1.9(rb_iseq_eval_main+0xb1) [0x7f6cc07cf7d1]
0x7f6cc06f9404 /usr/local/lib/libruby.so.1.9(ruby_exec_node+0xb4) [0x7f6cc06f9404]
0x7f6cc06fabd3 /usr/local/lib/libruby.so.1.9(ruby_run_node+0x33) [0x7f6cc06fabd3]
0x4009bf ruby(main+0x4f) [0x4009bf]
0x7f6cbf86c5a6 /lib/libc.so.6(__libc_start_main+0xe6) [0x7f6cbf86c5a6]
0x4008a9 ruby [0x4008a9]

[NOTE]
You may encounter a bug of Ruby interpreter. Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html

Aborted

... and in gdb ...

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7f71ee51a6f0 (LWP 23802)]
0x00007f71ee06ecde in vm_throw (th=0x6451c0, reg_cfp=0x7f71ee4d9e90, throw_state=0, throwobj=4) at vm_insnhelper.c:1389
1389		else if (BUILTIN_TYPE(err) == T_NODE) {
(gdb) backtrace
#0  0x00007f71ee06ecde in vm_throw (th=0x6451c0, reg_cfp=0x7f71ee4d9e90, throw_state=0, throwobj=4) at vm_insnhelper.c:1389
#1  0x00007f71ee0718c1 in vm_exec_core (th=0x6451c0, initial=0) at insns.def:1106
#2  0x00007f71ee07ed27 in vm_exec (th=0x6451c0) at vm.c:1078
#3  0x00007f71ee07f542 in rb_iseq_eval_main (iseqval=6645360) at vm.c:1294
#4  0x00007f71edf79c84 in ruby_exec_node (n=0x656670, file=<value optimized out>) at eval.c:206
#5  0x00007f71edf7b453 in ruby_run_node (n=0x656670) at eval.c:234
#6  0x00000000004009cf in main (argc=3, argv=0x7fff3df9bc08) at main.c:35


----------------------------------------
http://redmine.ruby-lang.org

^ permalink raw reply	[relevance 4%]

* [ruby-core:23263] Re: [Bug #1392] Object#extend leaks memory on  Ruby 1.9.1
  2009-04-20 13:23  0%   ` [ruby-core:23262] " Muhammad A. Ali
@ 2009-04-20 14:22  0%     ` Muhammad A. Ali
  0 siblings, 0 replies; 71+ results
From: Muhammad A. Ali @ 2009-04-20 14:22 UTC (permalink / raw)
  To: ruby-core

[-- Attachment #1: Type: text/plain, Size: 3063 bytes --]

On second thoughts, I still believe there is a leak. I modified the test as
follows:

@extend = ARGV[0]

module BetterHash
  def blabla
  end
end

unless @extend
  class Hash
  include BetterHash
  end
end

t = Time.now
100.times do #split the allocation process
  10000.times do
    s = {}
    s.extend BetterHash if @extend
  end
  GC.start # force a gc after each allocation batch
end

after = Time.now - t
puts "done with #{GC.count} gc runs after #{after} seconds"

This way the allocation is done in batches and the GC should be able to free
the objects after each batch.

After the first few batches the vm should have enough free space for any of
the next ones. Not what happens

though as it keeps growing till it reaches like ~18 MB on my machine. (the
include version maxes at 2.8).

If I add a delay between batches I could watch the process as it uses more
memory gradually.

To further prove I added the following code before the end:

@strings = []
10240.times do
 @strings << "a"*1024
end

This will alocate around 10MB worth of small strings (1K each). The include
version reports an increase of 10MB in its RAM usage.

The troubling thing is that the extend version also reports a 10MB increase
in its RAM usage (up to ~29) when it has supposedly

more than enough heap space to allocate those small strings.
thoughts?
oldmoe
oldmoe.blogspot.com
On Mon, Apr 20, 2009 at 3:23 PM, Muhammad A. Ali <oldmoe@gmail.com> wrote:

> Hi,
>
> Thanks for the clarification. The strange thing though (which lead me to
> this conclusion) is that 1.8 consistently maintains
>
> the same memory usage for both the include and the extend versions. Could
> this be attributed to the frequency of GC runs?
>
> Regards
>
> oldmoe
> oldmoe.blogspot.com
>
> On Mon, Apr 20, 2009 at 5:43 AM, Yukihiro Matsumoto <matz@ruby-lang.org>wrote:
>
>> Hi,
>>
>> In message "Re: [ruby-core:23252] [Bug #1392] Object#extend leaks memory
>> on Ruby 1.9.1"
>>     on Sun, 19 Apr 2009 07:18:18 +0900, Muhammad Ali <
>> redmine@ruby-lang.org> writes:
>> |
>> |Bug #1392: Object#extend leaks memory on Ruby 1.9.1
>> |http://redmine.ruby-lang.org/issues/show/1392
>>
>> |A few bytes are leaked every time Object#extend is called, here is a
>> sample 1.9.1 script
>>
>> It does not leak memory.  the version that use #extend allocates
>> internal class-like object for each hash object, so that it allocates
>> lot more objects than #include version, thus requires more heap space
>> to be allocated.  The GC does reclaim the unused objects, but it may
>> not be able to return heap space to the underlying OS.
>>
>> To confirm there's no memory leak, replace sleep with
>>
>>  GC.start
>>  p ObjectSpace.count_objects
>>
>> It prints the number of live objects, e.g.
>>
>> {:TOTAL=>17185, :FREE=>9590, :T_OBJECT=>5, :T_CLASS=>474, :T_MODULE=>20,
>> :T_FLOAT=>6, :T_STRING=>1551, :T_REGEXP=>10, :T_ARRAY=>23, :T_HASH=>3,
>> :T_BIGNUM=>2, :T_FILE=>3, :T_DATA=>28, :T_COMPLEX=>1, :T_NODE=>5451,
>> :T_ICLASS=>18}
>>
>>                                                        matz.
>>
>>
>

[-- Attachment #2: Type: text/html, Size: 4394 bytes --]

^ permalink raw reply	[relevance 0%]

* [ruby-core:23262] Re: [Bug #1392] Object#extend leaks memory on  Ruby 1.9.1
  2009-04-20  3:43  5% ` [ruby-core:23258] " Yukihiro Matsumoto
@ 2009-04-20 13:23  0%   ` Muhammad A. Ali
  2009-04-20 14:22  0%     ` [ruby-core:23263] " Muhammad A. Ali
  0 siblings, 1 reply; 71+ results
From: Muhammad A. Ali @ 2009-04-20 13:23 UTC (permalink / raw)
  To: ruby-core

[-- Attachment #1: Type: text/plain, Size: 1563 bytes --]

Hi,

Thanks for the clarification. The strange thing though (which lead me to
this conclusion) is that 1.8 consistently maintains

the same memory usage for both the include and the extend versions. Could
this be attributed to the frequency of GC runs?

Regards

oldmoe
oldmoe.blogspot.com

On Mon, Apr 20, 2009 at 5:43 AM, Yukihiro Matsumoto <matz@ruby-lang.org>wrote:

> Hi,
>
> In message "Re: [ruby-core:23252] [Bug #1392] Object#extend leaks memory on
> Ruby 1.9.1"
>     on Sun, 19 Apr 2009 07:18:18 +0900, Muhammad Ali <
> redmine@ruby-lang.org> writes:
> |
> |Bug #1392: Object#extend leaks memory on Ruby 1.9.1
> |http://redmine.ruby-lang.org/issues/show/1392
>
> |A few bytes are leaked every time Object#extend is called, here is a
> sample 1.9.1 script
>
> It does not leak memory.  the version that use #extend allocates
> internal class-like object for each hash object, so that it allocates
> lot more objects than #include version, thus requires more heap space
> to be allocated.  The GC does reclaim the unused objects, but it may
> not be able to return heap space to the underlying OS.
>
> To confirm there's no memory leak, replace sleep with
>
>  GC.start
>  p ObjectSpace.count_objects
>
> It prints the number of live objects, e.g.
>
> {:TOTAL=>17185, :FREE=>9590, :T_OBJECT=>5, :T_CLASS=>474, :T_MODULE=>20,
> :T_FLOAT=>6, :T_STRING=>1551, :T_REGEXP=>10, :T_ARRAY=>23, :T_HASH=>3,
> :T_BIGNUM=>2, :T_FILE=>3, :T_DATA=>28, :T_COMPLEX=>1, :T_NODE=>5451,
> :T_ICLASS=>18}
>
>                                                        matz.
>
>

[-- Attachment #2: Type: text/html, Size: 2205 bytes --]

^ permalink raw reply	[relevance 0%]

* [ruby-core:23258] Re: [Bug #1392] Object#extend leaks memory on Ruby 1.9.1
  @ 2009-04-20  3:43  5% ` Yukihiro Matsumoto
  2009-04-20 13:23  0%   ` [ruby-core:23262] " Muhammad A. Ali
  0 siblings, 1 reply; 71+ results
From: Yukihiro Matsumoto @ 2009-04-20  3:43 UTC (permalink / raw)
  To: ruby-core

Hi,

In message "Re: [ruby-core:23252] [Bug #1392] Object#extend leaks memory on Ruby 1.9.1"
    on Sun, 19 Apr 2009 07:18:18 +0900, Muhammad Ali <redmine@ruby-lang.org> writes:
|
|Bug #1392: Object#extend leaks memory on Ruby 1.9.1
|http://redmine.ruby-lang.org/issues/show/1392

|A few bytes are leaked every time Object#extend is called, here is a sample 1.9.1 script

It does not leak memory.  the version that use #extend allocates
internal class-like object for each hash object, so that it allocates
lot more objects than #include version, thus requires more heap space
to be allocated.  The GC does reclaim the unused objects, but it may
not be able to return heap space to the underlying OS.

To confirm there's no memory leak, replace sleep with

  GC.start
  p ObjectSpace.count_objects

It prints the number of live objects, e.g.

{:TOTAL=>17185, :FREE=>9590, :T_OBJECT=>5, :T_CLASS=>474, :T_MODULE=>20, :T_FLOAT=>6, :T_STRING=>1551, :T_REGEXP=>10, :T_ARRAY=>23, :T_HASH=>3, :T_BIGNUM=>2, :T_FILE=>3, :T_DATA=>28, :T_COMPLEX=>1, :T_NODE=>5451, :T_ICLASS=>18}

							matz.

^ permalink raw reply	[relevance 5%]

* [ruby-core:20497] Re: Status of copy-on-write friendly garbage collector
  @ 2008-12-12  0:37  2% ` Yukihiro Matsumoto
  0 siblings, 0 replies; 71+ results
From: Yukihiro Matsumoto @ 2008-12-12  0:37 UTC (permalink / raw)
  To: ruby-core

[-- Attachment #1: Type: text/plain, Size: 426 bytes --]

Hi,

In message "Re: [ruby-core:20481] Re: Status of copy-on-write friendly garbage collector"
    on Fri, 12 Dec 2008 00:11:52 +0900, "Roger Pack" <rogerpack2005@gmail.com> writes:

|I assume that it works now, and was merged into trunk?

It works now, but have not yet been merged it since it still slows
down non-forking programs.  I attach the diff from trunk for those who
want to try and inspect the idea.

							matz.

[-- Attachment #2: o1_bitmap_marking.diff --]
[-- Type: application/octet-stream, Size: 19281 bytes --]

diff --git a/debug.c b/debug.c
index bfce7ad..384fbb2 100644
--- a/debug.c
+++ b/debug.c
@@ -31,7 +31,7 @@ static const union {
         RUBY_ENC_CODERANGE_7BIT    = ENC_CODERANGE_7BIT,
         RUBY_ENC_CODERANGE_VALID   = ENC_CODERANGE_VALID,
         RUBY_ENC_CODERANGE_BROKEN  = ENC_CODERANGE_BROKEN, 
-        RUBY_FL_MARK        = FL_MARK,
+        RUBY_FL_ALIGNOFF    = FL_ALIGNOFF,
         RUBY_FL_RESERVED    = FL_RESERVED,
         RUBY_FL_FINALIZE    = FL_FINALIZE,
         RUBY_FL_TAINT       = FL_TAINT,
diff --git a/gc.c b/gc.c
index d2ef85f..864143a 100644
--- a/gc.c
+++ b/gc.c
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <setjmp.h>
 #include <sys/types.h>
+#include <math.h>
 
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
@@ -248,6 +249,13 @@ typedef struct RVALUE {
 	    VALUE flags;		/* always 0 for freed obj */
 	    struct RVALUE *next;
 	} free;
+	struct {
+	    VALUE flags;
+	    struct RVALUE *next;
+	    int *map;
+	    VALUE slot;
+	    int limit;
+	} bitmap;
 	struct RBasic  basic;
 	struct RObject object;
 	struct RClass  klass;
@@ -279,6 +287,7 @@ struct heaps_slot {
     void *membase;
     RVALUE *slot;
     int limit;
+    RVALUE *bitmap;
 };
 
 #define HEAP_MIN_SLOTS 10000
@@ -308,6 +317,7 @@ typedef struct rb_objspace {
 	RVALUE *freelist;
 	RVALUE *range[2];
 	RVALUE *freed;
+	RVALUE *freed_bitmap;
     } heap;
     struct {
 	int dont_gc;
@@ -379,22 +389,12 @@ rb_objspace_alloc(void)
 #endif
 
 /* tiny heap size */
-/* 32KB */
-/*#define HEAP_SIZE 0x8000 */
-/* 128KB */
-/*#define HEAP_SIZE 0x20000 */
-/* 64KB */
-/*#define HEAP_SIZE 0x10000 */
-/* 16KB */
-#define HEAP_SIZE 0x4000
-/* 8KB */
-/*#define HEAP_SIZE 0x2000 */
-/* 4KB */
-/*#define HEAP_SIZE 0x1000 */
-/* 2KB */
-/*#define HEAP_SIZE 0x800 */
-
-#define HEAP_OBJ_LIMIT (HEAP_SIZE / sizeof(struct RVALUE))
+#define BITMAP_ALIGN 0x4000
+
+/* (16KB/sizeof(RVALUE) + 2) * sizeof(RVALUE) */
+#define HEAP_SIZE 0x4024
+#define BITMAP_MASK  0xFFFFc000
+#define HEAP_OBJ_LIMIT (HEAP_SIZE / sizeof(struct RVALUE) - 1)
 
 extern VALUE rb_cMutex;
 extern st_table *rb_class_tbl;
@@ -783,6 +783,149 @@ allocate_heaps(rb_objspace_t *objspace, size_t next_heaps_length)
     heaps_length = next_heaps_length;
 }
 
+
+#define FIND_BITMAP(res, p) do {\
+    if (((RVALUE *)p)->as.free.flags & FL_ALIGNOFF) {\
+        res = (RVALUE *)((((VALUE)p & BITMAP_MASK) + BITMAP_ALIGN) / sizeof(RVALUE) * sizeof(RVALUE)); \
+    }\
+    else {\
+        res = (RVALUE *)(((VALUE)p & BITMAP_MASK) / sizeof(RVALUE) * sizeof(RVALUE));\
+    }\
+} while(0)
+
+#define NUM_IN_SLOT(p, slot) (((VALUE)p - (VALUE)slot)/sizeof(RVALUE))
+#define BITMAP_INDEX(bmap, p) (NUM_IN_SLOT(p, bmap->as.bitmap.slot) / (sizeof(int) * 8))
+// #define BITMAP_INDEX(bmap, p) (NUM_IN_SLOT(p, bmap->as.bitmap.slot) >> 5)
+#define BITMAP_OFFSET(bmap, p) (NUM_IN_SLOT(p, bmap->as.bitmap.slot) & ((sizeof(int) * 8)-1))
+#define MARKED_IN_BITMAP(bmap, p) (bmap->as.bitmap.map[BITMAP_INDEX(bmap, p)] & 1 << BITMAP_OFFSET(bmap, p))
+#define MARK_IN_BITMAP(bmap, p) (bmap->as.bitmap.map[BITMAP_INDEX(bmap, p)] |= 1 << BITMAP_OFFSET(bmap, p))
+#define CLEAR_IN_BITMAP(bmap, p) (bmap->as.bitmap.map[BITMAP_INDEX(bmap, p)] &= ~(1 << BITMAP_OFFSET(bmap, p)))
+#define MARKED_IN_BITMAP_DIRECT(map, index, offset) (map[index] & 1 << offset)
+#define MARK_IN_BITMAP_DIRECT(map, index, offset) (map[index] |= 1 << offset)
+
+//for debug
+void
+bitmap_p(RVALUE *p)
+{
+    RVALUE *bmap;
+    int index, offset, marked;
+
+    FIND_BITMAP(bmap, p);
+    index = BITMAP_INDEX(bmap, p);
+    offset = BITMAP_OFFSET(bmap, p);
+    marked = MARKED_IN_BITMAP(bmap, p);
+    printf("bitmap : ((RVALUE *)%p)\n", bmap);
+    printf("map_index : %d | offset : %d\n", index, offset);
+    printf("is mark ? %s\n", marked? "true" : "false");
+}
+
+VALUE
+find_bitmap(RVALUE *p) {
+    RVALUE *res;
+
+    FIND_BITMAP(res, p);
+    return (VALUE)res;
+}
+
+void
+dump_bitmap(RVALUE *bmap) {
+    int i;
+    
+    for (i = 0; i < 26; i++) {
+	printf("dump %p map %d : %d %s\n", bmap, i, bmap->as.bitmap.map[i], bmap->as.bitmap.map[i]? "remain" : "clean");
+    }
+}
+
+void
+bitmap2obj(RVALUE *bmap, int index, int offset)
+{
+    printf("(RVALUE *)%p\n", (RVALUE *)(bmap->as.bitmap.slot + (index * sizeof(int) * 8 + offset) * sizeof(RVALUE)));
+}
+
+
+static void
+make_bitmap(struct heaps_slot *slot)
+{
+    RVALUE *p, *pend, *bitmap, *last, *border;
+    int *map = 0;
+    int size;
+   
+    p = slot->slot;
+    pend = p + slot->limit;
+    last = pend - 1;
+    RBASIC(last)->flags = 0;
+    FIND_BITMAP(bitmap, last);
+    if (bitmap < p || pend <= bitmap) {
+	rb_bug("not include in heap slot: result bitmap(%p), find (%p), p (%p), pend(%p)", bitmap, last, p, pend);
+    }
+    border = bitmap;
+    if (!((VALUE)border % BITMAP_ALIGN)) {
+	border--;
+    }
+    while (p < pend) {
+	if (p <= border) {
+	    RBASIC(p)->flags = FL_ALIGNOFF;
+	}
+	else {
+	    RBASIC(p)->flags = 0;
+	}
+	p++;
+    }
+
+    size = sizeof(int) * (HEAP_OBJ_LIMIT / (sizeof(int) * 8)+1);
+    map = (int *)malloc(size);
+    if (map == 0) {
+	rb_memerror();
+    }
+    MEMZERO(map, int, (size/sizeof(int)));
+    bitmap->as.bitmap.flags |= T_BITMAP;
+    bitmap->as.bitmap.map = map;
+    bitmap->as.bitmap.slot = (VALUE)slot->slot;
+    bitmap->as.bitmap.limit = slot->limit;
+    slot->bitmap = bitmap;
+}
+
+void
+test_bitmap(RVALUE *p, RVALUE *pend)
+{
+    RVALUE *first, *bmap = 0, *bmap_tmp;
+    int i;
+
+    first = p;
+    FIND_BITMAP(bmap_tmp, p);
+    while (p < pend) {
+	if (MARKED_IN_BITMAP(bmap, p)) printf("already marking! %p\n", p);
+	if (bmap_tmp != p) {
+	    FIND_BITMAP(bmap, p);
+	    if (bmap_tmp != bmap) printf("diffrence bmap %p : %p\n", bmap_tmp, bmap);
+	    MARK_IN_BITMAP(bmap, p);
+	}
+	else {
+	    MARK_IN_BITMAP(bmap, p);
+	}
+	if (!MARKED_IN_BITMAP(bmap, p)) printf("not marking! %p\n", p);
+	p++;
+    }
+    for (i =0; i < 26; i++) {
+	printf("bitmap[%d] : %x\n", i, bmap->as.bitmap.map[i]);
+    }
+    p = first;
+    while (p < pend) {
+	if (bmap_tmp != p) {
+	    FIND_BITMAP(bmap, p);
+	    CLEAR_IN_BITMAP(bmap, p);
+	}
+	else {
+	    CLEAR_IN_BITMAP(bmap, p);
+	}
+	if (MARKED_IN_BITMAP(bmap, p)) printf("not clear! %p\n", p);
+	p++;
+    }
+    for (i =0; i < 26; i++) {
+	printf("bitmap[%d] : %x\n", i, bmap->as.bitmap.map[i]);
+    }
+}
+
 static void
 assign_heap_slot(rb_objspace_t *objspace)
 {
@@ -801,9 +944,6 @@ assign_heap_slot(rb_objspace_t *objspace)
     membase = p;
     if ((VALUE)p % sizeof(RVALUE) != 0) {
 	p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
-	if ((HEAP_SIZE - HEAP_OBJ_LIMIT * sizeof(RVALUE)) < ((char*)p - (char*)membase)) {
-	    objs--;
-	}
     }
 
     lo = 0;
@@ -825,6 +965,7 @@ assign_heap_slot(rb_objspace_t *objspace)
     if (hi < heaps_used) {
 	MEMMOVE(&heaps[hi+1], &heaps[hi], struct heaps_slot, heaps_used - hi);
     }
+
     heaps[hi].membase = membase;
     heaps[hi].slot = p;
     heaps[hi].limit = objs;
@@ -833,10 +974,12 @@ assign_heap_slot(rb_objspace_t *objspace)
     if (himem < pend) himem = pend;
     heaps_used++;
 
+    make_bitmap(&heaps[hi]);
     while (p < pend) {
-	p->as.free.flags = 0;
-	p->as.free.next = freelist;
-	freelist = p;
+	if (BUILTIN_TYPE(p) != T_BITMAP) {
+	    p->as.free.next = freelist;
+	    freelist = p;
+	}
 	p++;
     }
 }
@@ -888,6 +1031,7 @@ static VALUE
 rb_newobj_from_heap(rb_objspace_t *objspace)
 {
     VALUE obj;
+    int bmap_left = 0;
 	
     if ((ruby_gc_stress && !ruby_disable_gc_stress) || !freelist) {
     	if (!heaps_increment(objspace) && !garbage_collect(objspace)) {
@@ -899,7 +1043,13 @@ rb_newobj_from_heap(rb_objspace_t *objspace)
     obj = (VALUE)freelist;
     freelist = freelist->as.free.next;
 
+    if (RANY(obj)->as.free.flags & FL_ALIGNOFF) {
+	bmap_left = Qtrue;
+    }
     MEMZERO((void*)obj, RVALUE, 1);
+    if (bmap_left) {
+	RANY(obj)->as.free.flags = FL_ALIGNOFF;
+    }
 #ifdef GC_DEBUG
     RANY(obj)->file = rb_sourcefile();
     RANY(obj)->line = rb_sourceline();
@@ -915,13 +1065,15 @@ rb_fill_value_cache(rb_thread_t *th)
     rb_objspace_t *objspace = &rb_objspace;
     int i;
     VALUE rv;
+    RVALUE *bmap;
 
     /* LOCK */
     for (i=0; i<RUBY_VM_VALUE_CACHE_SIZE; i++) {
 	VALUE v = rb_newobj_from_heap(objspace);
 
 	th->value_cache[i] = v;
-	RBASIC(v)->flags = FL_MARK;
+	FIND_BITMAP(bmap, v);
+	MARK_IN_BITMAP(bmap, v);
     }
     th->value_cache_ptr = &th->value_cache[0];
     rv = rb_newobj_from_heap(objspace);
@@ -960,7 +1112,7 @@ rb_newobj(void)
 
 #if USE_VALUE_CACHE
     if (v) {
-	RBASIC(v)->flags = 0;
+	FL_FORCE_SET(p, 0);
 	th->value_cache_ptr++;
     }
     else {
@@ -1085,18 +1237,21 @@ init_mark_stack(rb_objspace_t *objspace)
 static void gc_mark(rb_objspace_t *objspace, VALUE ptr, int lev);
 static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev);
 
+#define IS_FREE_CELL(obj) ((obj->as.basic.flags & ~(FL_ALIGNOFF)) == 0)
+
 static void
 gc_mark_all(rb_objspace_t *objspace)
 {
-    RVALUE *p, *pend;
+    RVALUE *p, *pend, *bmap;
     size_t i;
 
     init_mark_stack(objspace);
     for (i = 0; i < heaps_used; i++) {
 	p = heaps[i].slot; pend = p + heaps[i].limit;
+	bmap = heaps[i].bitmap;
 	while (p < pend) {
-	    if ((p->as.basic.flags & FL_MARK) &&
-		(p->as.basic.flags != FL_MARK)) {
+	    if (MARKED_IN_BITMAP(bmap, p) &&
+		!(IS_FREE_CELL(p))) {
 		gc_mark_children(objspace, (VALUE)p, 0);
 	    }
 	    p++;
@@ -1271,13 +1426,15 @@ rb_gc_mark_maybe(VALUE obj)
 static void
 gc_mark(rb_objspace_t *objspace, VALUE ptr, int lev)
 {
-    register RVALUE *obj;
+    register RVALUE *obj, *bmap;
 
     obj = RANY(ptr);
     if (rb_special_const_p(ptr)) return; /* special const not marked */
-    if (obj->as.basic.flags == 0) return;       /* free cell */
-    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
-    obj->as.basic.flags |= FL_MARK;
+    if (IS_FREE_CELL(obj)) return;       /* free cell */
+    if (BUILTIN_TYPE(obj) == T_BITMAP) return;
+    FIND_BITMAP(bmap, obj);
+    if (MARKED_IN_BITMAP(bmap, obj)) return;  /* already marked */
+    MARK_IN_BITMAP(bmap, obj);
 
     if (lev > GC_LEVEL_MAX || (lev == 0 && stack_check())) {
 	if (!mark_stack_overflow) {
@@ -1303,16 +1460,17 @@ rb_gc_mark(VALUE ptr)
 static void
 gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev)
 {
-    register RVALUE *obj = RANY(ptr);
+    register RVALUE *obj = RANY(ptr), *bmap;
 
     goto marking;		/* skip */
 
   again:
     obj = RANY(ptr);
     if (rb_special_const_p(ptr)) return; /* special const not marked */
-    if (obj->as.basic.flags == 0) return;       /* free cell */
-    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
-    obj->as.basic.flags |= FL_MARK;
+    if (IS_FREE_CELL(obj)) return;       /* free cell */
+    FIND_BITMAP(bmap, obj);
+    if (MARKED_IN_BITMAP(bmap, obj)) return;  /* already marked */
+    MARK_IN_BITMAP(bmap, obj);
 
   marking:
     if (FL_TEST(obj, FL_EXIVAR)) {
@@ -1573,8 +1731,12 @@ static int obj_free(rb_objspace_t *, VALUE);
 static inline void
 add_freelist(rb_objspace_t *objspace, RVALUE *p)
 {
+    RVALUE *bmap;
+
     VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
-    p->as.free.flags = 0;
+    FL_FORCE_SET(p, 0);
+    FIND_BITMAP(bmap, p);
+    CLEAR_IN_BITMAP(bmap, p);
     p->as.free.next = freelist;
     freelist = p;
 }
@@ -1600,15 +1762,17 @@ static void
 free_unused_heaps(rb_objspace_t *objspace)
 {
     size_t i, j;
-    RVALUE *last = 0;
+    RVALUE *last = 0, *bmap = 0;
 
     for (i = j = 1; j < heaps_used; i++) {
 	if (heaps[i].limit == 0) {
 	    if (!last) {
 		last = heaps[i].membase;
+		bmap = heaps[i].bitmap;
 	    }
 	    else {
 		free(heaps[i].membase);
+		free(heaps[i].bitmap->as.bitmap.map);
 	    }
 	    heaps_used--;
 	}
@@ -1622,10 +1786,13 @@ free_unused_heaps(rb_objspace_t *objspace)
     if (last) {
 	if (last < heaps_freed) {
 	    free(heaps_freed);
+	    free(objspace->heap.freed_bitmap->as.bitmap.map);
 	    heaps_freed = last;
+	    heaps_freed = bmap;
 	}
 	else {
 	    free(last);
+	    free(bmap->as.bitmap.map);
 	}
     }
 }
@@ -1653,25 +1820,35 @@ gc_sweep(rb_objspace_t *objspace)
 	int free_num = 0, final_num = 0;
 	RVALUE *free = freelist;
 	RVALUE *final = final_list;
-	int deferred;
+	int *map = heaps[i].bitmap->as.bitmap.map;
+	int deferred, bmap_index = 0, bmap_offset = 0;
 
 	p = heaps[i].slot; pend = p + heaps[i].limit;
 	while (p < pend) {
-	    if (!(p->as.basic.flags & FL_MARK)) {
-		if (p->as.basic.flags &&
+	    if (BUILTIN_TYPE(p) == T_BITMAP) {
+		free_num++;
+	    }
+	    else if(!(MARKED_IN_BITMAP_DIRECT(map, bmap_index, bmap_offset))) {
+		if (!(IS_FREE_CELL(p)) &&
 		    ((deferred = obj_free(objspace, (VALUE)p)) ||
 		     ((FL_TEST(p, FL_FINALIZE)) && need_call_final))) {
 		    if (!deferred) {
-			p->as.free.flags = T_ZOMBIE;
+			FL_FORCE_SET(p, T_ZOMBIE);
 			RDATA(p)->dfree = 0;
 		    }
-		    p->as.free.flags |= FL_MARK;
 		    p->as.free.next = final_list;
 		    final_list = p;
 		    final_num++;
 		}
 		else {
-		    add_freelist(objspace, p);
+		    /* Do not touch the fields if they don't have to be modified.
+		     * This is in order to preserve copy-on-write semantics.
+		     */
+		    if (!IS_FREE_CELL(p))
+			FL_FORCE_SET(p, 0);
+		    if (p->as.free.next != freelist)
+			p->as.free.next = freelist;
+		    freelist = p;
 		    free_num++;
 		}
 	    }
@@ -1680,11 +1857,16 @@ gc_sweep(rb_objspace_t *objspace)
 		/* do nothing remain marked */
 	    }
 	    else {
-		RBASIC(p)->flags &= ~FL_MARK;
 		live++;
 	    }
 	    p++;
+	    bmap_offset++;
+	    if (bmap_offset >= (sizeof(int) * 8)) {
+		bmap_index++;
+		bmap_offset = 0;
+	    }
 	}
+	MEMZERO(heaps[i].bitmap->as.bitmap.map, int, bmap_index+1);
 	if (final_num + free_num == heaps[i].limit && freed > do_heap_free) {
 	    RVALUE *pp;
 
@@ -1714,11 +1896,16 @@ gc_sweep(rb_objspace_t *objspace)
 
     /* clear finalization list */
     if (final_list) {
+	RVALUE *bmap, *pp;
+	for (pp = final_list; pp != 0; pp = pp->as.free.next) {
+	    FIND_BITMAP(bmap, pp);
+	    MARK_IN_BITMAP(bmap, pp);
+	}
 	GC_PROF_SET_HEAP_INFO;
 	deferred_final_list = final_list;
 	RUBY_VM_SET_FINALIZER_INTERRUPT(GET_THREAD());
     }
-    else{
+    else {
 	free_unused_heaps(objspace);
 	GC_PROF_SET_HEAP_INFO;
     }
@@ -1734,7 +1921,7 @@ rb_gc_force_recycle(VALUE p)
 static inline void
 make_deferred(RVALUE *p)
 {
-    p->as.basic.flags = (p->as.basic.flags & ~T_MASK) | T_ZOMBIE;
+    FL_FORCE_SET(p, ((p->as.basic.flags & ~T_MASK) | T_ZOMBIE));
 }
 
 static inline void
@@ -2102,12 +2289,13 @@ os_obj_of(rb_objspace_t *objspace, VALUE of)
 
 	p = heaps[i].slot; pend = p + heaps[i].limit;
 	for (;p < pend; p++) {
-	    if (p->as.basic.flags) {
+	    if (!IS_FREE_CELL(p)) {
 		switch (BUILTIN_TYPE(p)) {
 		  case T_NONE:
 		  case T_ICLASS:
 		  case T_NODE:
 		  case T_ZOMBIE:
+		  case T_BITMAP:
 		    continue;
 		  case T_CLASS:
 		    if (FL_TEST(p, FL_SINGLETON)) continue;
@@ -2311,10 +2499,12 @@ rb_gc_finalize_deferred(void)
 static int
 chain_finalized_object(st_data_t key, st_data_t val, st_data_t arg)
 {
-    RVALUE *p = (RVALUE *)key, **final_list = (RVALUE **)arg;
+    RVALUE *p = (RVALUE *)key, **final_list = (RVALUE **)arg, *bmap;
     if (p->as.basic.flags & FL_FINALIZE) {
 	if (BUILTIN_TYPE(p) != T_ZOMBIE) {
-	    p->as.free.flags = FL_MARK | T_ZOMBIE; /* remain marked */
+	    FL_FORCE_SET(p, T_ZOMBIE);
+	    FIND_BITMAP(bmap, p);
+	    MARK_IN_BITMAP(bmap, p);
 	    RDATA(p)->dfree = 0;
 	}
 	p->as.free.next = *final_list;
@@ -2358,7 +2548,7 @@ rb_gc_call_finalizer_at_exit(void)
 	    if (BUILTIN_TYPE(p) == T_DATA &&
 		DATA_PTR(p) && RANY(p)->as.data.dfree &&
 		RANY(p)->as.basic.klass != rb_cThread && RANY(p)->as.basic.klass != rb_cMutex) {
-		p->as.free.flags = 0;
+		FL_FORCE_SET(p, 0);
 		if ((long)RANY(p)->as.data.dfree == -1) {
 		    xfree(DATA_PTR(p));
 		}
@@ -2372,6 +2562,7 @@ rb_gc_call_finalizer_at_exit(void)
 		if (RANY(p)->as.file.fptr) {
 		    make_io_deferred(RANY(p));
 		    RANY(p)->as.free.next = final_list;
+		    FL_FORCE_SET(p, 0);
 		    final_list = p;
 		}
 	    }
@@ -2564,7 +2755,7 @@ count_objects(int argc, VALUE *argv, VALUE os)
 
         p = heaps[i].slot; pend = p + heaps[i].limit;
         for (;p < pend; p++) {
-            if (p->as.basic.flags) {
+	    if (!IS_FREE_CELL(p)) {
                 counts[BUILTIN_TYPE(p)]++;
             }
             else {
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index b1fe650..40eca5f 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -310,6 +310,7 @@ enum ruby_value_type {
     RUBY_T_FALSE  = 0x13,
     RUBY_T_SYMBOL = 0x14,
     RUBY_T_FIXNUM = 0x15,
+    RUBY_T_BITMAP = 0x19,
 
     RUBY_T_UNDEF  = 0x1b,
     RUBY_T_NODE   = 0x1c,
@@ -334,6 +335,7 @@ enum ruby_value_type {
 #define T_BIGNUM RUBY_T_BIGNUM
 #define T_FILE   RUBY_T_FILE
 #define T_FIXNUM RUBY_T_FIXNUM
+#define T_BITMAP RUBY_T_BITMAP
 #define T_TRUE   RUBY_T_TRUE
 #define T_FALSE  RUBY_T_FALSE
 #define T_DATA   RUBY_T_DATA
@@ -499,9 +501,17 @@ char *rb_str2cstr(VALUE,long*);
 #define CHR2FIX(x) INT2FIX((long)((x)&0xff))
 
 VALUE rb_newobj(void);
+#define FL_FORCE_SET(obj,t) do {\
+    if (RBASIC(obj)->flags & FL_ALIGNOFF) {\
+	RBASIC(obj)->flags = FL_ALIGNOFF | t;\
+    }\
+    else {\
+	RBASIC(obj)->flags = t;\
+    }\
+} while(0)
 #define NEWOBJ(obj,type) type *obj = (type*)rb_newobj()
 #define OBJSETUP(obj,c,t) do {\
-    RBASIC(obj)->flags = (t);\
+    FL_FORCE_SET(obj, t);\
     RBASIC(obj)->klass = (c);\
     if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT | FL_UNTRUSTED);\
 } while (0)
@@ -777,7 +787,7 @@ struct RBignum {
 #define RCOMPLEX(obj) (R_CAST(RComplex)(obj))
 
 #define FL_SINGLETON FL_USER0
-#define FL_MARK      (((VALUE)1)<<5)
+#define FL_ALIGNOFF  (((VALUE)1)<<5)
 #define FL_RESERVED  (((VALUE)1)<<6) /* will be used in the future GC */
 #define FL_FINALIZE  (((VALUE)1)<<7)
 #define FL_TAINT     (((VALUE)1)<<8)
diff --git a/object.c b/object.c
index be99de6..7cc9f32 100644
--- a/object.c
+++ b/object.c
@@ -233,7 +233,8 @@ rb_obj_clone(VALUE obj)
     }
     clone = rb_obj_alloc(rb_obj_class(obj));
     RBASIC(clone)->klass = rb_singleton_class_clone(obj);
-    RBASIC(clone)->flags = (RBASIC(obj)->flags | FL_TEST(clone, FL_TAINT) | FL_TEST(clone, FL_UNTRUSTED)) & ~(FL_FREEZE|FL_FINALIZE);
+    RBASIC(clone)->flags = ((RBASIC(obj)->flags & ~(FL_ALIGNOFF|FL_FREEZE|FL_FINALIZE)) |
+			    FL_TEST(clone, FL_ALIGNOFF|FL_TAINT|FL_UNTRUSTED));
     init_copy(clone, obj);
     RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE;
 
diff --git a/vm.c b/vm.c
index 782fc99..11d0ebe 100644
--- a/vm.c
+++ b/vm.c
@@ -1479,7 +1479,7 @@ thread_free(void *ptr)
 	    VALUE *ptr = th->value_cache_ptr;
 	    while (*ptr) {
 		VALUE v = *ptr;
-		RBASIC(v)->flags = 0;
+		FL_FORCE_SET(v, 0);
 		RBASIC(v)->klass = 0;
 		ptr++;
 	    }
@@ -1789,7 +1789,7 @@ Init_VM(void)
 
     /* ::VM::FrozenCore */
     fcore = rb_class_new(rb_cBasicObject);
-    RBASIC(fcore)->flags = T_ICLASS;
+    FL_FORCE_SET(fcore, T_ICLASS);
     klass = rb_singleton_class(fcore);
     rb_define_method_id(klass, id_core_set_method_alias, m_core_set_method_alias, 3);
     rb_define_method_id(klass, id_core_set_variable_alias, m_core_set_variable_alias, 2);

^ permalink raw reply related	[relevance 2%]

* [ruby-core:19114] GC.reachability_paths
       [not found]     <e1c05edd0810021611q59402efjcd203d4a885811f1@mail.gmail.com>
@ 2008-10-02 23:10  3% ` Aman Gupta
  0 siblings, 0 replies; 71+ results
From: Aman Gupta @ 2008-10-02 23:10 UTC (permalink / raw)
  To: ruby-core

I modified the patch at
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/151854 to
work with 1.8.7-p72, but it dies with the following error:

ruby-1.8.7-p72 aman$ ruby -e 'o = Object.new; p GC.reachability_paths(o)'
-e:1:in `inspect': method `inspect' called on terminated object
(0x13cd38) (NotImplementedError)
       from -e:1:in `p'
       from -e:1

The patch (http://gist.github.com/14471):

diff --git a/gc.c b/gc.c
index 45facf0..a246ce9 100644
--- a/gc.c
+++ b/gc.c
@@ -74,7 +74,12 @@ static unsigned long malloc_increase = 0;
 static unsigned long malloc_limit = GC_MALLOC_LIMIT;
 static void run_final();
 static VALUE nomem_error;
+#ifdef DEBUG_REACHABILITY
+static VALUE garbage_collect0 _((VALUE));
+#define garbage_collect() garbage_collect0(0)
+#else
 static void garbage_collect();
+#endif

 int ruby_gc_stress = 0;

@@ -761,16 +766,55 @@ rb_gc_mark_maybe(obj)

 #define GC_LEVEL_MAX 250

+#ifdef DEBUG_REACHABILITY
+VALUE rb_reach_test_obj      = Qnil;
+VALUE rb_reach_test_result   = Qnil;
+VALUE rb_reach_test_path     = Qnil;
+
+static void
+rb_gc_unmark()
+{
+    RVALUE *p, *pend;
+    int i, used = heaps_used;
+
+    for (i = 0; i < used; i++) {
+       p = heaps[i].slot; pend = p + heaps[i].limit;
+       while (p < pend) {
+           RBASIC(p)->flags &= ~FL_MARK;
+           p++;
+       }
+    }
+}
+#endif
+
 static void
 gc_mark(ptr, lev)
    VALUE ptr;
    int lev;
 {
    register RVALUE *obj;
+#ifdef DEBUG_REACHABILITY
+    long saved_len = 0;
+    VALUE inspect = rb_intern("inspect");
+#endif

    obj = RANY(ptr);
    if (rb_special_const_p(ptr)) return; /* special const not marked */
    if (obj->as.basic.flags == 0) return;       /* free cell */
+#ifdef DEBUG_REACHABILITY
+    if (!NIL_P(rb_reach_test_obj) &&
+        (obj->as.basic.flags & T_MASK) != T_NODE) {
+       saved_len = RARRAY(rb_reach_test_path)->len;
+       if ((VALUE)obj == rb_reach_test_obj) {
+           rb_warn("  ...found, after %ld steps!", saved_len);
+           rb_ary_push(rb_reach_test_result,
+                       rb_ary_dup(rb_reach_test_path));
+       }
+       else if (!(obj->as.basic.flags & FL_MARK)) {
+           rb_ary_push(rb_reach_test_path, (VALUE)obj);
+       }
+    }
+#endif
    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
    obj->as.basic.flags |= FL_MARK;

@@ -787,6 +831,11 @@ gc_mark(ptr, lev)
       return;
    }
    gc_mark_children(ptr, lev+1);
+#ifdef DEBUG_REACHABILITY
+    if (!NIL_P(rb_reach_test_path)) {
+       RARRAY(rb_reach_test_path)->len = saved_len;
+    }
+#endif
 }

 void
@@ -1369,9 +1418,25 @@ int rb_setjmp (rb_jmp_buf);
 #endif /* __human68k__ or DJGPP */
 #endif /* __GNUC__ */

+#ifdef DEBUG_REACHABILITY
+#define IF_DEBUG_REACHABILITY(does) if (obj) {does;}
+#else
+#define IF_DEBUG_REACHABILITY(does)
+#endif
+
+#ifdef DEBUG_REACHABILITY
+static VALUE
+garbage_collect0(obj)
+    VALUE obj;
+#else
 static void
 garbage_collect()
+#endif
 {
+#ifdef DEBUG_REACHABILITY
+    int i = 0;
+    VALUE result;
+#endif
    struct gc_list *list;
    struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug??  */
    jmp_buf save_regs_gc_mark;
@@ -1382,40 +1447,84 @@ garbage_collect()
       rb_bug("cross-thread violation on rb_gc()");
    }
 #endif
-    if (dont_gc || during_gc) {
-       if (!freelist) {
-           add_heap();
+
+#ifdef DEBUG_REACHABILITY
+    if (obj) {
+       if (!NIL_P(rb_reach_test_obj) ||
+           !NIL_P(rb_reach_test_result) ||
+           !NIL_P(rb_reach_test_path)) {
+           rb_raise(rb_eRuntimeError, "reachability_paths called recursively");
       }
-       return;
+
+       rb_reach_test_obj    = obj;
+       rb_reach_test_result = rb_ary_new();
+       rb_reach_test_path   = rb_ary_new();
+    }
+    else
+#endif
+    {
+    if (dont_gc || during_gc) {
+      if (!freelist) {
+          add_heap();
+      }
+#ifdef DEBUG_REACHABILITY
+      return 0;
+#else
+      return;
+#endif
    }
-    if (during_gc) return;
    during_gc++;
+    }

    init_mark_stack();

    gc_mark((VALUE)ruby_current_node, 0);

    /* mark frame stack */
+    IF_DEBUG_REACHABILITY(rb_warn("Checking frame stack..."));
    for (frame = ruby_frame; frame; frame = frame->prev) {
+       IF_DEBUG_REACHABILITY(
+           NODE *node = frame->node;
+           if (node) {
+               rb_ary_push(rb_reach_test_path,
+                           rb_sprintf("frame %d: %s line %d", i,
node->nd_file, nd_line(node)));
+           });
       rb_gc_mark_frame(frame);
+       IF_DEBUG_REACHABILITY((rb_ary_pop(rb_reach_test_path), i++));
       if (frame->tmp) {
           struct FRAME *tmp = frame->tmp;
+#ifdef DEBUG_REACHABILITY
+           int ti = 0;
+#endif
           while (tmp) {
+               IF_DEBUG_REACHABILITY(
+                   NODE *node = tmp->node;
+                   if (node) {
+                       rb_ary_push(rb_reach_test_path,
+                                   rb_sprintf("tmp frame %d: %s line %d",
+                                              ti, node->nd_file,
nd_line(node)));
+                   });
               rb_gc_mark_frame(tmp);
+               IF_DEBUG_REACHABILITY((rb_ary_pop(rb_reach_test_path), ti++));
               tmp = tmp->prev;
           }
       }
    }
+    IF_DEBUG_REACHABILITY(rb_warn("Checking ruby_class..."));
    gc_mark((VALUE)ruby_scope, 0);
+    IF_DEBUG_REACHABILITY(rb_warn("Checking ruby_scope..."));
    gc_mark((VALUE)ruby_dyna_vars, 0);
    if (finalizer_table) {
+       IF_DEBUG_REACHABILITY(rb_warn("Checking finalizer_table..."));
       mark_tbl(finalizer_table, 0);
    }

    FLUSH_REGISTER_WINDOWS;
    /* This assumes that all registers are saved into the jmp_buf
(and stack) */
    rb_setjmp(save_regs_gc_mark);
+    IF_DEBUG_REACHABILITY(rb_warn("Checking save_regs_gc_mark..."));
    mark_locations_array((VALUE*)save_regs_gc_mark,
sizeof(save_regs_gc_mark) / sizeof(VALUE *));
+    IF_DEBUG_REACHABILITY(rb_warn("Checking stack_start..."));
 #if STACK_GROW_DIRECTION < 0
    rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start);
 #elif STACK_GROW_DIRECTION > 0
@@ -1435,24 +1544,35 @@ garbage_collect()
    rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2),
                        (VALUE*)((char*)rb_gc_stack_start + 2));
 #endif
+    IF_DEBUG_REACHABILITY(rb_warn("Checking threads..."));
    rb_gc_mark_threads();

    /* mark protected global variables */
+    IF_DEBUG_REACHABILITY(rb_warn("Checking C globals..."));
    for (list = global_List; list; list = list->next) {
+       IF_DEBUG_REACHABILITY(rb_ary_push(rb_reach_test_path, rb_sprintf("C
global %d", i)));
       rb_gc_mark_maybe(*list->varptr);
+       IF_DEBUG_REACHABILITY((rb_ary_pop(rb_reach_test_path), i++));
    }
+    IF_DEBUG_REACHABILITY(rb_warn("Checking end_proc..."));
    rb_mark_end_proc();
+    IF_DEBUG_REACHABILITY(rb_warn("Checking global_tbl..."));
    rb_gc_mark_global_tbl();

+    IF_DEBUG_REACHABILITY(rb_warn("Checking class_tbl..."));
    rb_mark_tbl(rb_class_tbl);
+    IF_DEBUG_REACHABILITY(rb_warn("Checking trap_list..."));
    rb_gc_mark_trap_list();

    /* mark generic instance variables for special constants */
+    IF_DEBUG_REACHABILITY(rb_warn("Checking generic_ivar_tbl..."));
    rb_mark_generic_ivar_tbl();

+    IF_DEBUG_REACHABILITY(rb_warn("Checking mark parser..."));
    rb_gc_mark_parser();

    /* gc_mark objects whose marking are not completed*/
+    IF_DEBUG_REACHABILITY(rb_warn("Checking mark stack..."));
    do {
       while (!MARK_STACK_EMPTY) {
           if (mark_stack_overflow){
@@ -1465,6 +1585,20 @@ garbage_collect()
       rb_gc_abort_threads();
    } while (!MARK_STACK_EMPTY);

+    IF_DEBUG_REACHABILITY(
+       rb_warn("Unmarking...");
+       rb_gc_unmark();
+
+       rb_warn("Done.");
+
+       result = rb_reach_test_result;
+
+        rb_reach_test_obj    = Qnil;
+        rb_reach_test_result = Qnil;
+        rb_reach_test_path   = Qnil;
+
+       return result);
+
    gc_sweep();
 }

@@ -2075,6 +2209,15 @@ rb_obj_id(VALUE obj)
    return (VALUE)((long)obj|FIXNUM_FLAG);
 }

+static VALUE
+rbx_reachability_paths(mod, obj)
+    VALUE mod;
+    VALUE obj;
+{
+    if (rb_special_const_p(obj)) return Qnil;
+    return garbage_collect0(obj);
+}
+
 /*
 *  The <code>GC</code> module provides an interface to Ruby's mark and
 *  sweep garbage collection mechanism. Some of the underlying methods
@@ -2092,6 +2235,9 @@ Init_GC()
    rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
    rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0);
    rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1);
+#ifdef DEBUG_REACHABILITY
+    rb_define_singleton_method(rb_mGC, "reachability_paths",
rbx_reachability_paths, 1);
+#endif
    rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);

    rb_mObSpace = rb_define_module("ObjectSpace");
@@ -2115,6 +2261,10 @@ Init_GC()
    source_filenames = st_init_strtable();

    rb_global_variable(&nomem_error);
+#ifdef DEBUG_REACHABILITY
+    rb_global_variable(&rb_reach_test_result);
+    rb_global_variable(&rb_reach_test_path);
+#endif
    nomem_error = rb_exc_new3(rb_eNoMemError,
                             rb_obj_freeze(rb_str_new2("failed to
allocate memory")));
    OBJ_TAINT(nomem_error);
diff --git a/sprintf.c b/sprintf.c
index 9cdf8bc..d3104b7 100644
--- a/sprintf.c
+++ b/sprintf.c
@@ -846,3 +846,41 @@ fmt_setup(buf, c, flags, width, prec)
    *buf++ = c;
    *buf = '\0';
 }
+
+#undef FILE
+#define FILE rb_printf_buffer
+#define __sbuf rb_printf_sbuf
+#define __sFILE rb_printf_sfile
+#undef feof
+#undef ferror
+#undef clearerr
+#undef fileno
+#if SIZEOF_LONG < SIZEOF_VOIDP
+# if  SIZEOF_LONG_LONG == SIZEOF_VOIDP
+#  define _HAVE_SANE_QUAD_
+#  define _HAVE_LLP64_
+#  define quad_t LONG_LONG
+#  define u_quad_t unsigned LONG_LONG
+# endif
+#endif
+#undef vsnprintf
+#undef snprintf
+#include "missing/vsnprintf.c"
+
+VALUE
+rb_sprintf(const char *format, ...)
+{
+    VALUE result;
+    va_list ap;
+    char *str;
+
+    va_start(ap, format);
+    vasprintf(&str, format, ap);
+    va_end(ap);
+
+    printf("STRING: %s\n", str);
+    result = rb_str_new2(str);
+    free(str);
+
+    return result;
+}
\ No newline at end of file
diff --git a/variable.c b/variable.c
index 50ecf04..b0ef111 100644
--- a/variable.c
+++ b/variable.c
@@ -458,6 +458,13 @@ readonly_setter(val, id, var)
    rb_name_error(id, "%s is a read-only variable", rb_id2name(id));
 }

+#ifdef DEBUG_REACHABILITY
+extern VALUE rb_reach_test_path;
+#define IF_DEBUG_REACHABILITY(does) do {if
(!NIL_P(rb_reach_test_path)) {does;}} while (0)
+#else
+#define IF_DEBUG_REACHABILITY(does)
+#endif
+
 static int
 mark_global_entry(key, entry)
    ID key;
@@ -465,11 +472,25 @@ mark_global_entry(key, entry)
 {
    struct trace_var *trace;
    struct global_variable *var = entry->var;
+#ifdef DEBUG_REACHABILITY
+    int i = 0;
+#endif

+    IF_DEBUG_REACHABILITY(
+       rb_ary_push(rb_reach_test_path,
+                   rb_sprintf("Ruby global %s", rb_id2name(key))));
    (*var->marker)(var->data);
+    IF_DEBUG_REACHABILITY(rb_ary_pop(rb_reach_test_path));
+
    trace = var->trace;
    while (trace) {
-       if (trace->data) rb_gc_mark_maybe(trace->data);
+       if (trace->data) {
+           IF_DEBUG_REACHABILITY(
+               rb_ary_push(rb_reach_test_path,
+                           rb_sprintf("Ruby global %s trace %d",
rb_id2name(key), i++)));
+           rb_gc_mark_maybe(trace->data);
+           IF_DEBUG_REACHABILITY(rb_ary_pop(rb_reach_test_path));
+       }
       trace = trace->next;
    }
    return ST_CONTINUE;


 Aman Gupta

^ permalink raw reply related	[relevance 3%]

* [ruby-core:18763] Re: [ANN] Ruby 1.9.1 feature freeze
  2008-09-08  9:05 11%   ` [ruby-core:18490] " Nobuyoshi Nakada
@ 2008-09-20 18:49 11%     ` Roger Pack
  0 siblings, 0 replies; 71+ results
From: Roger Pack @ 2008-09-20 18:49 UTC (permalink / raw)
  To: ruby-core

> I propose a new method, #location than those two new methods.
...
> --
> Nobu Nakada

Interestingly, there already was an rb_proc_location method in 1.9
[just no Proc#location nor Method#location nor Binding#location].

Anyway, here's Nobu Nakada's patch with the method name changed to
source_location [should work against SVN head].

Note also the recent creation of
Feature #578: add method to disassemble Proc objects

Thanks for your help.  I know I'm annoying with this :)
-=R

Index: proc.c
===================================================================
--- proc.c	(revision 19438)
+++ proc.c	(working copy)
@@ -509,11 +509,11 @@
 {
     rb_proc_t *proc;
     rb_block_t *blockptr = 0;
+    rb_iseq_t *iseq;
     GetProcPtr(procval, proc);
+    iseq = proc->block.iseq;
+    if (BUILTIN_TYPE(iseq) == T_NODE || iseq->arg_block != -1) {

-    if (BUILTIN_TYPE(proc->block.iseq) == T_NODE ||
-	proc->block.iseq->arg_block != -1) {
-
 	if (rb_block_given_p()) {
 	    rb_proc_t *proc;
 	    VALUE procval;
@@ -620,10 +620,9 @@
     return iseq;
 }

-VALUE
-rb_proc_location(VALUE self)
+static VALUE
+iseq_location(rb_iseq_t *iseq)
 {
-    rb_iseq_t *iseq = get_proc_iseq(self);
     VALUE loc[2];

     if (!iseq) return Qnil;
@@ -639,6 +638,20 @@

 /*
  * call-seq:
+ *    prc.source_location  => [String, Fixnum]
+ *
+ * returns the ruby source filename and line number containing this proc
+ * or nil if this proc was not defined in ruby (i.e. native)
+ */
+
+VALUE
+rb_proc_source_location(VALUE self)
+{
+    return iseq_location(get_proc_iseq(self));
+}
+
+/*
+ * call-seq:
  *   prc == other_proc   =>  true or false
  *
  * Return <code>true</code> if <i>prc</i> is the same object as
@@ -1437,7 +1450,40 @@
     return rb_mod_method_arity(CLASS_OF(obj), id);
 }

+static rb_iseq_t *
+get_method_iseq(VALUE method)
+{
+    struct METHOD *data;
+    NODE *body;
+    rb_iseq_t *iseq;
+
+    Data_Get_Struct(method, struct METHOD, data);
+    body = data->body;
+    switch (nd_type(body)) {
+      case RUBY_VM_METHOD_NODE:
+       GetISeqPtr((VALUE)body->nd_body, iseq);
+       if (RUBY_VM_NORMAL_ISEQ_P(iseq)) break;
+      default:
+       return 0;
+    }
+    return iseq;
+}
+
 /*
+ * call-seq:
+ *    meth.source_location  => [String, Fixnum]
+ *
+ * returns the ruby source filename and line number containing this method
+ * or nil if this method was not defined in ruby (i.e. native)
+ */
+
+VALUE
+rb_method_source_location(VALUE method)
+{
+    return iseq_location(get_method_iseq(method));
+}
+
+/*
  *  call-seq:
  *   meth.to_s      =>  string
  *   meth.inspect   =>  string
@@ -1768,6 +1814,7 @@
     rb_define_method(rb_cProc, "lambda?", proc_lambda_p, 0);
     rb_define_method(rb_cProc, "binding", proc_binding, 0);
     rb_define_method(rb_cProc, "curry", proc_curry, -1);
+    rb_define_method(rb_cProc, "source_location", rb_proc_source_location, 0);

     /* Exceptions */
     rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError);
@@ -1802,6 +1849,7 @@
     rb_define_method(rb_cMethod, "name", method_name, 0);
     rb_define_method(rb_cMethod, "owner", method_owner, 0);
     rb_define_method(rb_cMethod, "unbind", method_unbind, 0);
+    rb_define_method(rb_cMethod, "source_location",
rb_method_source_location, 0);
     rb_define_method(rb_mKernel, "method", rb_obj_method, 1);
     rb_define_method(rb_mKernel, "public_method", rb_obj_public_method, 1);

@@ -1819,6 +1867,7 @@
     rb_define_method(rb_cUnboundMethod, "name", method_name, 0);
     rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0);
     rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1);
+    rb_define_method(rb_cUnboundMethod, "source_location",
rb_method_source_location, 0);

     /* Module#*_method */
     rb_define_method(rb_cModule, "instance_method", rb_mod_instance_method, 1);
Index: thread.c
===================================================================
--- thread.c	(revision 19438)
+++ thread.c	(working copy)
@@ -528,10 +528,10 @@
     }
     GetThreadPtr(thread, th);
     if (th->first_args) {
-	VALUE rb_proc_location(VALUE self);
+	VALUE rb_proc_source_location(VALUE self);
 	VALUE proc = th->first_proc, line, loc;
 	const char *file;
-        if (!proc || !RTEST(loc = rb_proc_location(proc))) {
+        if (!proc || !RTEST(loc = rb_proc_source_location(proc))) {
             rb_raise(rb_eThreadError, "already initialized thread");
         }
 	file = RSTRING_PTR(RARRAY_PTR(loc)[0]);

^ permalink raw reply	[relevance 11%]

* [ruby-core:18490] Re: [ANN] Ruby 1.9.1 feature freeze
  @ 2008-09-08  9:05 11%   ` Nobuyoshi Nakada
  2008-09-20 18:49 11%     ` [ruby-core:18763] " Roger Pack
  0 siblings, 1 reply; 71+ results
From: Nobuyoshi Nakada @ 2008-09-08  9:05 UTC (permalink / raw)
  To: ruby-core

Hi,

At Sun, 7 Sep 2008 04:53:43 +0900,
Yukihiro Matsumoto wrote in [ruby-core:18471]:
> This is a proposal to add __file__ and __line__ methods to Method and
> Proc objects.  Issues are:
> 
>   * the method names.  I don't think proposed names that are
>     surrounded by underscores are appropriate.
>   * non-Ruby defined methods/procs.  the patch raises TypeError, but
>     is it really appropriate?  Should they return nil for such cases?
>   * use-case.  the proposal comes with use-case sourceref.rb, but any
>     other use case?

I propose a new method, #location than those two new methods.

\f
Index: proc.c
===================================================================
--- proc.c	(revision 19215)
+++ proc.c	(working copy)
@@ -510,9 +510,9 @@ proc_call(int argc, VALUE *argv, VALUE p
     rb_proc_t *proc;
     rb_block_t *blockptr = 0;
+    rb_iseq_t *iseq;
     GetProcPtr(procval, proc);
 
-    if (BUILTIN_TYPE(proc->block.iseq) == T_NODE ||
-	proc->block.iseq->arg_block != -1) {
-
+    iseq = proc->block.iseq;
+    if (BUILTIN_TYPE(iseq) == T_NODE || iseq->arg_block != -1) {
 	if (rb_block_given_p()) {
 	    rb_proc_t *proc;
@@ -621,8 +621,7 @@ get_proc_iseq(VALUE self)
 }
 
-VALUE
-rb_proc_location(VALUE self)
+static VALUE
+iseq_location(rb_iseq_t *iseq)
 {
-    rb_iseq_t *iseq = get_proc_iseq(self);
     VALUE loc[2];
 
@@ -640,4 +639,18 @@ rb_proc_location(VALUE self)
 /*
  * call-seq:
+ *    prc.location  => [String, Fixnum]
+ *
+ * returns the ruby source filename and line number containing this proc
+ * or nil if this proc was not defined in ruby (i.e. native)
+ */
+
+VALUE
+rb_proc_location(VALUE self)
+{
+    return iseq_location(get_proc_iseq(self));
+}
+
+/*
+ * call-seq:
  *   prc == other_proc   =>  true or false
  *
@@ -1438,4 +1451,37 @@ rb_obj_method_arity(VALUE obj, ID id)
 }
 
+static rb_iseq_t *
+get_method_iseq(VALUE method)
+{
+    struct METHOD *data;
+    NODE *body;
+    rb_iseq_t *iseq;
+
+    Data_Get_Struct(method, struct METHOD, data);
+    body = data->body;
+    switch (nd_type(body)) {
+      case RUBY_VM_METHOD_NODE:
+	GetISeqPtr((VALUE)body->nd_body, iseq);
+	if (RUBY_VM_NORMAL_ISEQ_P(iseq)) break;
+      default:
+	return 0;
+    }
+    return iseq;
+}
+
+/*
+ * call-seq:
+ *    meth.location  => [String, Fixnum]
+ *
+ * returns the ruby source filename and line number containing this method
+ * or nil if this method was not defined in ruby (i.e. native)
+ */
+
+VALUE
+rb_method_location(VALUE method)
+{
+    return iseq_location(get_method_iseq(method));
+}
+
 /*
  *  call-seq:
@@ -1769,4 +1815,5 @@ Init_Proc(void)
     rb_define_method(rb_cProc, "binding", proc_binding, 0);
     rb_define_method(rb_cProc, "curry", proc_curry, -1);
+    rb_define_method(rb_cProc, "location", rb_proc_location, 0);
 
     /* Exceptions */
@@ -1803,4 +1850,5 @@ Init_Proc(void)
     rb_define_method(rb_cMethod, "owner", method_owner, 0);
     rb_define_method(rb_cMethod, "unbind", method_unbind, 0);
+    rb_define_method(rb_cMethod, "location", rb_method_location, 0);
     rb_define_method(rb_mKernel, "method", rb_obj_method, 1);
     rb_define_method(rb_mKernel, "public_method", rb_obj_public_method, 1);
@@ -1820,4 +1868,5 @@ Init_Proc(void)
     rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0);
     rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1);
+    rb_define_method(rb_cUnboundMethod, "location", rb_method_location, 0);
 
     /* Module#*_method */
\f

-- 
Nobu Nakada

^ permalink raw reply	[relevance 11%]

* Re: Copy-on-write friendly garbage collector
    2008-03-08 10:01  2%       ` Daniel DeLorme
@ 2008-03-12 17:23 11%       ` Hongli Lai
  1 sibling, 0 replies; 71+ results
From: Hongli Lai @ 2008-03-12 17:23 UTC (permalink / raw)
  To: ruby-core

[-- Attachment #1: Type: text/plain, Size: 713 bytes --]

Daniel DeLorme wrote:
> I believe I managed to close the performance gap to only 6% slower than 
> the current implementation (but I must admit I have trouble getting 
> consistently reproducible benchmarks). The attached patch should be 
> added on top of the one in Matz' email.
> 
> -- 
> Daniel
> 

Great work Daniel. I don't measure the same amount of speedup that you 
claim in your email, but there is definitely a small speedup.

I've added some further further optimizations. 
find_position_in_bitfield() now uses bit operators instead of division 
and modulo operators. This should speed things up a little more.

The attached patch is created against Ruby 1.8, but it shows what I've 
exactly changed.

[-- Attachment #2: gc-optimizations.diff --]
[-- Type: text/x-patch, Size: 2554 bytes --]

diff --git a/gc.c b/gc.c
index cb18a79..3ba5ec5 100644
--- a/gc.c
+++ b/gc.c
@@ -1142,6 +1142,7 @@ gc_sweep()
     int i;
     unsigned long live = 0;
     unsigned long free_min = 0;
+    struct heaps_slot *heap;
 
     for (i = 0; i < heaps_used; i++) {
         free_min += heaps[i].limit;
@@ -1154,9 +1155,11 @@ gc_sweep()
 	/* should not reclaim nodes during compilation
            if yacc's semantic stack is not allocated on machine stack */
 	for (i = 0; i < heaps_used; i++) {
-	    p = heaps[i].slot; pend = p + heaps[i].limit;
+	    heap = &heaps[i];
+
+	    p = heap->slot; pend = heap->slotlimit;
 	    while (p < pend) {
-		if (!rb_mark_table_contains(p) && BUILTIN_TYPE(p) == T_NODE)
+		if (!rb_mark_table_heap_contains(heap, p) && BUILTIN_TYPE(p) == T_NODE)
 		    gc_mark((VALUE)p, 0);
 		p++;
 	    }
@@ -1184,7 +1187,7 @@ gc_sweep()
 		    obj_free((VALUE)p);
 		}
 		if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
-		    rb_mark_table_add(p); /* remain marked */
+		    rb_mark_table_heap_add(heap, p); /* remain marked */
 		    p->as.free.next = final_list;
 		    final_list = p;
 		}
diff --git a/marktable.c b/marktable.c
index 7424633..412616f 100644
--- a/marktable.c
+++ b/marktable.c
@@ -34,10 +34,26 @@ find_position_in_bitfield(struct heaps_slot *hs, RVALUE *object,
                           unsigned int *bitfield_index, unsigned int *bitfield_offset)
 {
 	unsigned int index;
-
 	index = object - hs->slot;
-	*bitfield_index = index / (sizeof(int) * 8);
-	*bitfield_offset = index % (sizeof(int) * 8);
+	
+	/*
+	 * We use bit operators to calculate the position in the bit field, whenever possible.
+	 * This only works if sizeof(int) is a multiple of 2, but I don't know of any platform
+	 * on which that is not true.
+	 *
+	 * The INT_BITS_LOG macro's value must be equal to the base 2 logarithm of sizeof(int).
+	 */
+	#ifdef __i386__
+		#define INT_BITS_LOG 5
+	#endif
+	
+	#ifdef INT_BITS_LOG
+		*bitfield_index = index >> INT_BITS_LOG;
+		*bitfield_offset = index & ((1 << INT_BITS_LOG) - 1);
+	#else
+		*bitfield_index = index / (sizeof(int) * 8);
+		*bitfield_offset = index % (sizeof(int) * 8);
+	#endif
 }
 
 
@@ -81,6 +97,14 @@ rb_mark_table_add(RVALUE *object)
 	}
 }
 
+static inline void
+rb_mark_table_heap_add(struct heaps_slot *hs, RVALUE *object)
+{
+	unsigned int bitfield_index, bitfield_offset;
+	find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset);
+	hs->marks[bitfield_index] |= (1 << bitfield_offset);
+}
+
 static inline int
 rb_mark_table_contains(RVALUE *object)
 {

^ permalink raw reply related	[relevance 11%]

* Re: Copy-on-write friendly garbage collector
  @ 2008-03-08 10:01  2%       ` Daniel DeLorme
  2008-03-12 17:23 11%       ` Hongli Lai
  1 sibling, 0 replies; 71+ results
From: Daniel DeLorme @ 2008-03-08 10:01 UTC (permalink / raw)
  To: ruby-core

[-- Attachment #1: Type: text/plain, Size: 843 bytes --]

Third email in a row... I hope that's not considered spamming ~_~

Since the patch was based on r15675, I tried to merge that plus my 
changes into the trunk (r15730) but ran into some conflicts. While 
resolving them, I realized that r15683 and 15684 (the apparent source of 
the conflict) were sorting the heap list by order of memory location. 
But that's not needed if a linear search is more efficient than a 
bsearch, so I removed the sorting. New heaps are now added at the end of 
the list and the list is searched from last to first (therefore largest 
to smallest).

So now, for the following test case which generates 9 heaps
   GC.disable
   x=(1..1000000).map{"x"*10}
   GC.enable
   GC.start
The COW-friendly version is only 1-2% slower than r15730.

I hope this makes it into the trunk but please do review the code.

--
Daniel

[-- Attachment #2: cow-friendly.patch --]
[-- Type: text/x-patch, Size: 15532 bytes --]

Index: debug.c
===================================================================
--- debug.c	(revision 15730)
+++ debug.c	(working copy)
@@ -29,8 +29,8 @@
         RUBY_ENC_CODERANGE_7BIT    = ENC_CODERANGE_7BIT,
         RUBY_ENC_CODERANGE_VALID   = ENC_CODERANGE_VALID,
         RUBY_ENC_CODERANGE_BROKEN  = ENC_CODERANGE_BROKEN, 
-        RUBY_FL_MARK        = FL_MARK,
-        RUBY_FL_RESERVED    = FL_RESERVED,
+        RUBY_FL_RESERVED0   = FL_RESERVED0,
+        RUBY_FL_RESERVED1   = FL_RESERVED1,
         RUBY_FL_FINALIZE    = FL_FINALIZE,
         RUBY_FL_TAINT       = FL_TAINT,
         RUBY_FL_EXIVAR      = FL_EXIVAR,
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 15730)
+++ include/ruby/ruby.h	(working copy)
@@ -621,8 +621,8 @@
 #define RVALUES(obj) (R_CAST(RValues)(obj))
 
 #define FL_SINGLETON FL_USER0
-#define FL_MARK      (((VALUE)1)<<5)
-#define FL_RESERVED  (((VALUE)1)<<6) /* will be used in the future GC */
+#define FL_RESERVED0 (((VALUE)1)<<5) /* will be used in the future GC */
+#define FL_RESERVED1 (((VALUE)1)<<6) /* will be used in the future GC */
 #define FL_FINALIZE  (((VALUE)1)<<7)
 #define FL_TAINT     (((VALUE)1)<<8)
 #define FL_EXIVAR    (((VALUE)1)<<9)
@@ -716,6 +716,7 @@
 void rb_register_mark_object(VALUE);
 void rb_gc_register_address(VALUE*);
 void rb_gc_unregister_address(VALUE*);
+int rb_gc_is_thread_marked(VALUE);
 
 ID rb_intern(const char*);
 ID rb_intern2(const char*, long);
Index: gc.c
===================================================================
--- gc.c	(revision 15730)
+++ gc.c	(working copy)
@@ -22,8 +22,14 @@
 #include "gc.h"
 #include <stdio.h>
 #include <setjmp.h>
+#include <math.h>
 #include <sys/types.h>
 
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
@@ -145,6 +151,9 @@
     void *membase;
     RVALUE *slot;
     int limit;
+    RVALUE *slotlimit;
+    int *marks;
+    int marks_size;
 } *heaps;
 static int heaps_length = 0;
 static int heaps_used   = 0;
@@ -322,7 +331,29 @@
 	RUBY_CRITICAL(free(x));
 }
 
+static int debugging = 0;
 
+#define OPTION_ENABLED(name) (getenv((name)) && *getenv((name)) && *getenv((name)) != '0')
+
+static void *
+alloc_ruby_heap(size_t size)
+{
+    return malloc(size);
+}
+
+static void
+free_ruby_heap(void *heap)
+{
+    free(heap);
+}
+
+static void
+init_debugging()
+{
+    debugging = OPTION_ENABLED("RUBY_GC_DEBUG");
+}
+
+
 /*
  *  call-seq:
  *     GC.enable    => true or false
@@ -413,11 +444,107 @@
     }
 }
 
+static struct heaps_slot *last_heap = NULL;
+
+static inline struct heaps_slot *
+find_heap_slot_for_object(RVALUE *object)
+{
+    struct heaps_slot *heap;
+    register int i;
+
+    /* Look in the cache first. */
+    if (last_heap != NULL && object >= last_heap->slot
+	&& object < last_heap->slotlimit) {
+	return last_heap;
+    }
+    /* find heap_slot for object using linear search
+     * (faster than bsearch because there are only a few heaps)
+     */
+    i = heaps_used;
+    while (i) {
+	i--;
+	heap = &heaps[i];
+	if (heap->slot <= object) {
+	    if (object < heap->slotlimit) {
+		/* Cache this result. According to empirical evidence, the chance is
+		 * high that the next lookup will be for the same heap slot.
+		 */
+		last_heap = heap;
+		return heap;
+	    }
+	}
+    }
+    return NULL;
+}
+
+static inline void
+find_position_in_bitfield(struct heaps_slot *hs, RVALUE *object,
+                          unsigned int *bitfield_index, unsigned int *bitfield_offset)
+{
+    unsigned int index;
+
+    index = object - hs->slot;
+    *bitfield_index = index / (sizeof(int) * 8);
+    *bitfield_offset = index % (sizeof(int) * 8);
+}
+
+
 static void
+rb_mark_table_add(RVALUE *object)
+{
+    struct heaps_slot *hs;
+    unsigned int bitfield_index, bitfield_offset;
+
+    hs = find_heap_slot_for_object(object);
+    if (hs != NULL) {
+	find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset);
+	hs->marks[bitfield_index] |= (1 << bitfield_offset);
+    }
+}
+
+static inline int
+rb_mark_table_heap_contains(struct heaps_slot *hs, RVALUE *object)
+{
+    unsigned int bitfield_index, bitfield_offset;
+
+    find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset);
+    return hs->marks[bitfield_index] & (1 << bitfield_offset);
+}
+
+static inline int
+rb_mark_table_contains(RVALUE *object)
+{
+    struct heaps_slot *hs;
+
+    hs = find_heap_slot_for_object(object);
+    if (hs != NULL) {
+	return rb_mark_table_heap_contains(hs, object);
+    }
+}
+
+static inline void
+rb_mark_table_heap_remove(struct heaps_slot *hs, RVALUE *object)
+{
+    unsigned int bitfield_index, bitfield_offset;
+    find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset);
+    hs->marks[bitfield_index] &= ~(1 << bitfield_offset);
+}
+
+static void
+rb_mark_table_remove(RVALUE *object)
+{
+    struct heaps_slot *hs;
+
+    hs = find_heap_slot_for_object(object);
+    if (hs != NULL) {
+	rb_mark_table_heap_remove(hs, object);
+    }
+}
+
+static void
 add_heap(void)
 {
-    RVALUE *p, *pend, *membase;
-    long hi, lo, mid;
+    RVALUE *p, *pend;
 
     if (heaps_used == heaps_length) {
 	/* Realloc heaps */
@@ -438,45 +565,26 @@
     }
 
     for (;;) {
-	RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1)));
+	RUBY_CRITICAL(p = (RVALUE*)alloc_ruby_heap(sizeof(RVALUE)*(heap_slots+1)));
 	if (p == 0) {
 	    if (heap_slots == HEAP_MIN_SLOTS) {
 		rb_memerror();
 	    }
 	    heap_slots = HEAP_MIN_SLOTS;
+	    continue;
 	}
-	else {
-	    break;
-	}
+	heaps[heaps_used].membase = p;
+	if ((VALUE)p % sizeof(RVALUE) == 0)
+	    heap_slots += 1;
+	else
+	    p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
+	heaps[heaps_used].slot = p;
+	heaps[heaps_used].limit = heap_slots;
+	heaps[heaps_used].slotlimit = p + heap_slots;
+        heaps[heaps_used].marks_size = (int) (ceil(heap_slots / (sizeof(int) * 8.0)));
+        heaps[heaps_used].marks = (int *) calloc(heaps[heaps_used].marks_size, sizeof(int));
+	break;
     }
-
-    lo = 0;
-    hi = heaps_used;
-    while (lo < hi) {
-	mid = (lo + hi) / 2;
-	membase = heaps[mid].membase;
-	if (membase < p) {
-	    lo = mid + 1;
-	}
-	else if (membase > p) {
-	    hi = mid;
-	}
-	else {
-	    rb_bug("same heap slot is allocated: %p at %ld", p, mid);
-	}
-    }
-
-    membase = p;
-    if ((VALUE)p % sizeof(RVALUE) == 0)
-	heap_slots += 1;
-    else
-	p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
-    if (hi < heaps_used) {
-	MEMMOVE(&heaps[hi+1], &heaps[hi], struct heaps_slot, heaps_used - hi);
-    }
-    heaps[hi].membase = membase;
-    heaps[hi].slot = p;
-    heaps[hi].limit = heap_slots;
     pend = p + heap_slots;
     if (lomem == 0 || lomem > p) lomem = p;
     if (himem < pend) himem = pend;
@@ -508,6 +616,7 @@
     freelist = freelist->as.free.next;
 
     MEMZERO((void*)obj, RVALUE, 1);
+    RANY(obj)->as.free.flags = 0;
 #ifdef GC_DEBUG
     RANY(obj)->file = rb_sourcefile();
     RANY(obj)->line = rb_sourceline();
@@ -710,14 +819,15 @@
 gc_mark_all(void)
 {
     RVALUE *p, *pend;
+    struct heaps_slot *heap;
     int i;
 
     init_mark_stack();
     for (i = 0; i < heaps_used; i++) {
-	p = heaps[i].slot; pend = p + heaps[i].limit;
+	heap = &heaps[i];
+	p = heap->slot; pend = heap->slotlimit;
 	while (p < pend) {
-	    if ((p->as.basic.flags & FL_MARK) &&
-		(p->as.basic.flags != FL_MARK)) {
+	    if (rb_mark_table_heap_contains(heap, p) && (p->as.basic.flags != 0)) {
 		gc_mark_children((VALUE)p, 0);
 	    }
 	    p++;
@@ -751,21 +861,8 @@
     if (p < lomem || p > himem) return Qfalse;
     if ((VALUE)p % sizeof(RVALUE) != 0) return Qfalse;
 
-    /* check if p looks like a pointer using bsearch*/
-    lo = 0;
-    hi = heaps_used;
-    while (lo < hi) {
-	mid = (lo + hi) / 2;
-	heap = &heaps[mid];
-	if (heap->slot <= p) {
-	    if (p < heap->slot + heap->limit)
-		return Qtrue;
-	    lo = mid + 1;
-	}
-	else {
-	    hi = mid;
-	}
-    }
+    if (find_heap_slot_for_object(p))
+	return Qtrue;
     return Qfalse;
 }
 
@@ -871,8 +968,8 @@
     obj = RANY(ptr);
     if (rb_special_const_p(ptr)) return; /* special const not marked */
     if (obj->as.basic.flags == 0) return;       /* free cell */
-    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
-    obj->as.basic.flags |= FL_MARK;
+    if (rb_mark_table_contains(obj)) return;  /* already marked */
+    rb_mark_table_add(obj);
 
     if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) {
 	if (!mark_stack_overflow) {
@@ -906,8 +1003,8 @@
     obj = RANY(ptr);
     if (rb_special_const_p(ptr)) return; /* special const not marked */
     if (obj->as.basic.flags == 0) return;       /* free cell */
-    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
-    obj->as.basic.flags |= FL_MARK;
+    if (rb_mark_table_contains(obj)) return;  /* already marked */
+    rb_mark_table_add(obj);
 
   marking:
     if (FL_TEST(obj, FL_EXIVAR)) {
@@ -1161,10 +1258,15 @@
     while (p) {
 	RVALUE *tmp = p->as.free.next;
 	run_final((VALUE)p);
-	if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
+	/* Don't free objects that are singletons, or objects that are already freed.
+	 * The latter is to prevent the unnecessary marking of memory pages as dirty,
+	 * which can destroy copy-on-write semantics.
+	 */
+	if (!FL_TEST(p, FL_SINGLETON) && p->as.free.flags != 0) {
             VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
 	    p->as.free.flags = 0;
 	    p->as.free.next = freelist;
+	    rb_mark_table_remove(p);
 	    freelist = p;
 	}
 	p = tmp;
@@ -1178,7 +1280,8 @@
 
     for (i = j = 1; j < heaps_used; i++) {
 	if (heaps[i].limit == 0) {
-	    free(heaps[i].membase);
+	    free_ruby_heap(heaps[i].membase);
+	    free(heaps[i].marks);
 	    heaps_used--;
 	}
 	else {
@@ -1219,32 +1322,38 @@
 	int n = 0;
 	RVALUE *free = freelist;
 	RVALUE *final = final_list;
+	struct heaps_slot *heap = &heaps[i];
 
-	p = heaps[i].slot; pend = p + heaps[i].limit;
+	p = heap->slot; pend = heap->slotlimit;
 	while (p < pend) {
-	    if (!(p->as.basic.flags & FL_MARK)) {
+	    if (!rb_mark_table_heap_contains(heap, p)) {
 		if (p->as.basic.flags) {
 		    obj_free((VALUE)p);
 		}
 		if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
-		    p->as.free.flags = FL_MARK; /* remain marked */
+		    p->as.free.flags = FL_FINALIZE;
 		    p->as.free.next = final_list;
 		    final_list = p;
 		}
 		else {
                     VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
-		    p->as.free.flags = 0;
-		    p->as.free.next = freelist;
+		    /* Do not touch the fields if they don't have to be modified.
+		     * This is in order to preserve copy-on-write semantics.
+		     */
+		    if (p->as.free.flags != 0)
+			p->as.free.flags = 0;
+		    if (p->as.free.next != freelist)
+			p->as.free.next = freelist;
 		    freelist = p;
 		}
 		n++;
 	    }
-	    else if (RBASIC(p)->flags == FL_MARK) {
+	    else if (RBASIC(p)->flags == FL_FINALIZE) {
 		/* objects to be finalized */
-		/* do nothing remain marked */
+		/* do nothing here */
 	    }
 	    else {
-		RBASIC(p)->flags &= ~FL_MARK;
+		rb_mark_table_heap_remove(heap, p);
 		live++;
 	    }
 	    p++;
@@ -1286,6 +1395,7 @@
     VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
     RANY(p)->as.free.flags = 0;
     RANY(p)->as.free.next = freelist;
+    rb_mark_table_remove((RVALUE *) p);
     freelist = RANY(p);
 }
 
@@ -1476,6 +1586,7 @@
 
     FLUSH_REGISTER_WINDOWS;
     /* This assumes that all registers are saved into the jmp_buf (and stack) */
+    memset(save_regs_gc_mark, 0, sizeof(save_regs_gc_mark));
     setjmp(save_regs_gc_mark);
     mark_locations_array((VALUE*)save_regs_gc_mark,
 			 sizeof(save_regs_gc_mark) / sizeof(VALUE));
@@ -1515,6 +1626,7 @@
 
     SET_STACK_END;
 
+    last_heap = NULL;
     init_mark_stack();
 
     th->vm->self ? rb_gc_mark(th->vm->self) : rb_vm_mark(th->vm);
@@ -1616,6 +1728,18 @@
     rb_gc_stack_maxsize = size;
 }
 
+int
+rb_gc_is_thread_marked(the_thread)
+    VALUE the_thread;
+{
+    if (FL_ABLE(the_thread)) {
+	return rb_mark_table_contains((RVALUE *) the_thread);
+    }
+    else {
+	return 0;
+    }
+}
+
 void
 Init_stack(VALUE *addr)
 {
@@ -1837,12 +1961,9 @@
     VALUE of;
 
     rb_secure(4);
-    if (argc == 0) {
+    if (rb_scan_args(argc, argv, "01", &of) == 0) {
 	of = 0;
     }
-    else {
-	rb_scan_args(argc, argv, "01", &of);
-    }
     RETURN_ENUMERATOR(os, 1, &of);
     return os_obj_of(of);
 }
@@ -2025,6 +2146,7 @@
 rb_gc_call_finalizer_at_exit(void)
 {
     RVALUE *p, *pend;
+    struct heaps_slot *heap;
     int i;
 
     /* finalizers are part of garbage collection */
@@ -2048,12 +2170,14 @@
     }
     /* run data object's finalizers */
     for (i = 0; i < heaps_used; i++) {
-	p = heaps[i].slot; pend = p + heaps[i].limit;
+	heap = &heaps[i];
+	p = heap->slot; pend = heap->slotlimit;
 	while (p < pend) {
 	    if (BUILTIN_TYPE(p) == T_DATA &&
 		DATA_PTR(p) && RANY(p)->as.data.dfree &&
 		RANY(p)->as.basic.klass != rb_cThread) {
 		p->as.free.flags = 0;
+		rb_mark_table_heap_remove(heap, p);
 		if ((long)RANY(p)->as.data.dfree == -1) {
 		    RUBY_CRITICAL(free(DATA_PTR(p)));
 		}
@@ -2065,6 +2189,7 @@
 	    else if (BUILTIN_TYPE(p) == T_FILE) {
 		if (rb_io_fptr_finalize(RANY(p)->as.file.fptr)) {
 		    p->as.free.flags = 0;
+		    rb_mark_table_heap_remove(heap, p);
                     VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
 		}
 	    }
@@ -2285,6 +2410,61 @@
     return hash;
 }
 
+static VALUE
+os_statistics()
+{
+    int i;
+    int n = 0;
+    unsigned int objects = 0;
+    unsigned int total_heap_size = 0;
+    unsigned int ast_nodes = 0;
+    char message[1024];
+
+    for (i = 0; i < heaps_used; i++) {
+	RVALUE *p, *pend;
+
+	p = heaps[i].slot;
+	pend = p + heaps[i].limit;
+	for (;p < pend; p++) {
+	    if (p->as.basic.flags) {
+		int isAST = 0;
+		switch (TYPE(p)) {
+		  case T_ICLASS:
+		  case T_NODE:
+		    isAST = 1;
+		    break;
+		  case T_CLASS:
+		    if (FL_TEST(p, FL_SINGLETON)) {
+		        isAST = 1;
+		        break;
+		    }
+		  default:
+		    break;
+		}
+		objects++;
+		if (isAST) {
+		   ast_nodes++;
+		}
+	    }
+	}
+	total_heap_size += (void*)pend - heaps[i].membase;
+    }
+
+    snprintf(message, sizeof(message),
+        "Number of objects: %d (%d AST nodes, %.2f%%)\n"
+        "Heap slot size: %d\n"
+        "Number of heaps: %d\n"
+        "Total size of objects: %.2f KB\n"
+        "Total size of heaps: %.2f KB\n",
+        objects, ast_nodes, ast_nodes * 100 / (double) objects,
+        sizeof(RVALUE),
+        heaps_used,
+        objects * sizeof(RVALUE) / 1024.0,
+        total_heap_size / 1024.0
+    );
+    return rb_str_new2(message);
+}
+
 /*
  *  The <code>GC</code> module provides an interface to Ruby's mark and
  *  sweep garbage collection mechanism. Some of the underlying methods
@@ -2317,6 +2497,8 @@
 
     rb_define_module_function(rb_mObSpace, "_id2ref", id2ref, 1);
 
+    rb_define_module_function(rb_mObSpace, "statistics", os_statistics, 0);
+
     rb_gc_register_address(&rb_mObSpace);
     rb_global_variable(&finalizers);
     rb_gc_unregister_address(&rb_mObSpace);
@@ -2332,4 +2514,6 @@
     rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0);
 
     rb_define_module_function(rb_mObSpace, "count_objects", count_objects, -1);
+
+    init_debugging();
 }

^ permalink raw reply	[relevance 2%]

* Re: Copy-on-write friendly garbage collector
  @ 2008-03-03 13:11  3% ` Yukihiro Matsumoto
    0 siblings, 1 reply; 71+ results
From: Yukihiro Matsumoto @ 2008-03-03 13:11 UTC (permalink / raw)
  To: ruby-core

Hi,

In message "Re: Copy-on-write friendly garbage collector"
    on Mon, 3 Mar 2008 18:48:34 +0900, Hongli Lai <hongli@plan99.net> writes:

|I've written patch which makes Ruby's garbage collector copy-on-write 
|friendly. Details can be found on my blog, 
|http://izumi.plan99.net/blog/index.php/category/optimizing-rails/, in 
|the "Making Ruby's garbage collector copy-on-write friendly" series.
|
|Matz had shown interest in merging the patch into Ruby 1.9. I'm 
|wondering whether that has already been done, and if not, whether I can 
|be of any assistance.

Here's the patch against the latest trunk (r15675).  It's still 8-10%
slower than the current implementation.

							matz.
diff --git a/debug.c b/debug.c
index d7f99ed..dfcb523 100644
--- a/debug.c
+++ b/debug.c
@@ -29,8 +29,8 @@ static const union {
         RUBY_ENC_CODERANGE_7BIT    = ENC_CODERANGE_7BIT,
         RUBY_ENC_CODERANGE_VALID   = ENC_CODERANGE_VALID,
         RUBY_ENC_CODERANGE_BROKEN  = ENC_CODERANGE_BROKEN, 
-        RUBY_FL_MARK        = FL_MARK,
-        RUBY_FL_RESERVED    = FL_RESERVED,
+        RUBY_FL_RESERVED0   = FL_RESERVED0,
+        RUBY_FL_RESERVED1   = FL_RESERVED1,
         RUBY_FL_FINALIZE    = FL_FINALIZE,
         RUBY_FL_TAINT       = FL_TAINT,
         RUBY_FL_EXIVAR      = FL_EXIVAR,
diff --git a/gc.c b/gc.c
index c47f8a0..38a9fe7 100644
--- a/gc.c
+++ b/gc.c
@@ -22,8 +22,14 @@
 #include "gc.h"
 #include <stdio.h>
 #include <setjmp.h>
+#include <math.h>
 #include <sys/types.h>
 
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
@@ -145,6 +151,8 @@ static struct heaps_slot {
     void *membase;
     RVALUE *slot;
     int limit;
+    int *marks;
+    int marks_size;
 } *heaps;
 static int heaps_length = 0;
 static int heaps_used   = 0;
@@ -322,6 +330,36 @@ ruby_xfree(void *x)
 	RUBY_CRITICAL(free(x));
 }
 
+static int debugging = 0;
+
+#define DEBUG_POINT(message) \
+	do { \
+		if (debugging) { \
+			printf("%s\n", message); \
+			getchar(); \
+		} \
+	} while (0)
+
+#define OPTION_ENABLED(name) (getenv((name)) && *getenv((name)) && *getenv((name)) != '0')
+
+static void *
+alloc_ruby_heap(size_t size)
+{
+    return malloc(size);
+}
+
+static void
+free_ruby_heap(void *heap)
+{
+    free(heap);
+}
+
+static void
+init_debugging()
+{
+    debugging = OPTION_ENABLED("RUBY_GC_DEBUG");
+}
+
 
 /*
  *  call-seq:
@@ -413,6 +451,106 @@ rb_gc_unregister_address(VALUE *addr)
     }
 }
 
+static struct heaps_slot *last_heap = NULL;
+
+static inline struct heaps_slot *
+find_heap_slot_for_object(RVALUE *object)
+{
+    struct heaps_slot *heap;
+    register long hi, lo, mid;
+
+    /* Look in the cache first. */
+    if (last_heap != NULL && object >= last_heap->slot
+	&& object < last_heap->slot + last_heap->limit) {
+	return last_heap;
+    }
+    /* find heap_slot for object using bsearch*/
+    lo = 0;
+    hi = heaps_used;
+    while (lo < hi) {
+	mid = (lo + hi) / 2;
+	heap = &heaps[mid];
+	if (heap->slot <= object) {
+	    if (object < heap->slot + heap->limit) {
+		/* Cache this result. According to empirical evidence, the chance is
+		 * high that the next lookup will be for the same heap slot.
+		 */
+		last_heap = heap;
+		return heap;
+	    }
+	    lo = mid + 1;
+	}
+	else {
+	    hi = mid;
+	}
+    }
+    return NULL;
+}
+
+static inline void
+find_position_in_bitfield(struct heaps_slot *hs, RVALUE *object,
+                          unsigned int *bitfield_index, unsigned int *bitfield_offset)
+{
+    unsigned int index;
+
+    index = object - hs->slot;
+    *bitfield_index = index / (sizeof(int) * 8);
+    *bitfield_offset = index % (sizeof(int) * 8);
+}
+
+
+static void
+rb_mark_table_add(RVALUE *object)
+{
+    struct heaps_slot *hs;
+    unsigned int bitfield_index, bitfield_offset;
+
+    hs = find_heap_slot_for_object(object);
+    if (hs != NULL) {
+	find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset);
+	hs->marks[bitfield_index] |= (1 << bitfield_offset);
+    }
+}
+
+static inline int
+rb_mark_table_heap_contains(struct heaps_slot *hs, RVALUE *object)
+{
+    unsigned int bitfield_index, bitfield_offset;
+
+    find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset);
+    return hs->marks[bitfield_index] & (1 << bitfield_offset);
+}
+
+static inline int
+rb_mark_table_contains(RVALUE *object)
+{
+    struct heaps_slot *hs;
+
+    hs = find_heap_slot_for_object(object);
+    if (hs != NULL) {
+	return rb_mark_table_heap_contains(hs, object);
+    }
+}
+
+static inline void
+rb_mark_table_heap_remove(struct heaps_slot *hs, RVALUE *object)
+{
+    unsigned int bitfield_index, bitfield_offset;
+    find_position_in_bitfield(hs, object, &bitfield_index, &bitfield_offset);
+    hs->marks[bitfield_index] &= ~(1 << bitfield_offset);
+}
+
+static void
+rb_mark_table_remove(RVALUE *object)
+{
+    struct heaps_slot *hs;
+
+    hs = find_heap_slot_for_object(object);
+    if (hs != NULL) {
+	rb_mark_table_heap_remove(hs, object);
+    }
+}
+
 static int
 heap_cmp(const void *ap, const void *bp, void *dummy)
 {
@@ -445,7 +583,7 @@ add_heap(void)
     }
 
     for (;;) {
-	RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1)));
+	RUBY_CRITICAL(p = (RVALUE*)alloc_ruby_heap(sizeof(RVALUE)*(heap_slots+1)));
 	if (p == 0) {
 	    if (heap_slots == HEAP_MIN_SLOTS) {
 		rb_memerror();
@@ -460,6 +598,8 @@ add_heap(void)
 	    p = (RVALUE*)((VALUE)p + sizeof(RVALUE) - ((VALUE)p % sizeof(RVALUE)));
 	heaps[heaps_used].slot = p;
 	heaps[heaps_used].limit = heap_slots;
+        heaps[heaps_used].marks_size = (int) (ceil(heap_slots / (sizeof(int) * 8.0)));
+        heaps[heaps_used].marks = (int *) calloc(heaps[heaps_used].marks_size, sizeof(int));
 	break;
     }
     pend = p + heap_slots;
@@ -494,6 +634,7 @@ rb_newobj_from_heap(void)
     freelist = freelist->as.free.next;
 
     MEMZERO((void*)obj, RVALUE, 1);
+    RANY(obj)->as.free.flags = 0;
 #ifdef GC_DEBUG
     RANY(obj)->file = rb_sourcefile();
     RANY(obj)->line = rb_sourceline();
@@ -702,8 +843,7 @@ gc_mark_all(void)
     for (i = 0; i < heaps_used; i++) {
 	p = heaps[i].slot; pend = p + heaps[i].limit;
 	while (p < pend) {
-	    if ((p->as.basic.flags & FL_MARK) &&
-		(p->as.basic.flags != FL_MARK)) {
+	    if (rb_mark_table_contains(p) && (p->as.basic.flags != 0)) {
 		gc_mark_children((VALUE)p, 0);
 	    }
 	    p++;
@@ -737,21 +877,8 @@ is_pointer_to_heap(void *ptr)
     if (p < lomem || p > himem) return Qfalse;
     if ((VALUE)p % sizeof(RVALUE) != 0) return Qfalse;
 
-    /* check if p looks like a pointer using bsearch*/
-    lo = 0;
-    hi = heaps_used;
-    while (lo < hi) {
-	mid = (lo + hi) / 2;
-	heap = &heaps[mid];
-	if (heap->slot <= p) {
-	    if (p < heap->slot + heap->limit)
-		return Qtrue;
-	    lo = mid + 1;
-	}
-	else {
-	    hi = mid;
-	}
-    }
+    if (find_heap_slot_for_object(p))
+	return Qtrue;
     return Qfalse;
 }
 
@@ -857,8 +984,8 @@ gc_mark(VALUE ptr, int lev)
     obj = RANY(ptr);
     if (rb_special_const_p(ptr)) return; /* special const not marked */
     if (obj->as.basic.flags == 0) return;       /* free cell */
-    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
-    obj->as.basic.flags |= FL_MARK;
+    if (rb_mark_table_contains(obj)) return;  /* already marked */
+    rb_mark_table_add(obj);
 
     if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) {
 	if (!mark_stack_overflow) {
@@ -892,8 +1019,8 @@ gc_mark_children(VALUE ptr, int lev)
     obj = RANY(ptr);
     if (rb_special_const_p(ptr)) return; /* special const not marked */
     if (obj->as.basic.flags == 0) return;       /* free cell */
-    if (obj->as.basic.flags & FL_MARK) return;  /* already marked */
-    obj->as.basic.flags |= FL_MARK;
+    if (rb_mark_table_contains(obj)) return;  /* already marked */
+    rb_mark_table_add(obj);
 
   marking:
     if (FL_TEST(obj, FL_EXIVAR)) {
@@ -1147,10 +1274,15 @@ finalize_list(RVALUE *p)
     while (p) {
 	RVALUE *tmp = p->as.free.next;
 	run_final((VALUE)p);
-	if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */
+	/* Don't free objects that are singletons, or objects that are already freed.
+	 * The latter is to prevent the unnecessary marking of memory pages as dirty,
+	 * which can destroy copy-on-write semantics.
+	 */
+	if (!FL_TEST(p, FL_SINGLETON) && p->as.free.flags != 0) {
             VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
 	    p->as.free.flags = 0;
 	    p->as.free.next = freelist;
+	    rb_mark_table_remove(p);
 	    freelist = p;
 	}
 	p = tmp;
@@ -1164,7 +1296,8 @@ free_unused_heaps(void)
 
     for (i = j = 1; j < heaps_used; i++) {
 	if (heaps[i].limit == 0) {
-	    free(heaps[i].membase);
+	    free_ruby_heap(heaps[i].membase);
+	    free(heaps[i].marks);
 	    heaps_used--;
 	}
 	else {
@@ -1208,29 +1341,34 @@ gc_sweep(void)
 
 	p = heaps[i].slot; pend = p + heaps[i].limit;
 	while (p < pend) {
-	    if (!(p->as.basic.flags & FL_MARK)) {
+	    if (!rb_mark_table_contains(p)) {
 		if (p->as.basic.flags) {
 		    obj_free((VALUE)p);
 		}
 		if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
-		    p->as.free.flags = FL_MARK; /* remain marked */
+		    p->as.free.flags = FL_FINALIZE;
 		    p->as.free.next = final_list;
 		    final_list = p;
 		}
 		else {
                     VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
-		    p->as.free.flags = 0;
-		    p->as.free.next = freelist;
+		    /* Do not touch the fields if they don't have to be modified.
+		     * This is in order to preserve copy-on-write semantics.
+		     */
+		    if (p->as.free.flags != 0)
+			p->as.free.flags = 0;
+		    if (p->as.free.next != freelist)
+			p->as.free.next = freelist;
 		    freelist = p;
 		}
 		n++;
 	    }
-	    else if (RBASIC(p)->flags == FL_MARK) {
+	    else if (RBASIC(p)->flags == FL_FINALIZE) {
 		/* objects to be finalized */
-		/* do nothing remain marked */
+		/* do nothing here */
 	    }
 	    else {
-		RBASIC(p)->flags &= ~FL_MARK;
+		rb_mark_table_heap_remove(&heaps[i], p);
 		live++;
 	    }
 	    p++;
@@ -1272,6 +1410,7 @@ rb_gc_force_recycle(VALUE p)
     VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
     RANY(p)->as.free.flags = 0;
     RANY(p)->as.free.next = freelist;
+    rb_mark_table_remove((RVALUE *) p);
     freelist = RANY(p);
 }
 
@@ -1462,6 +1601,7 @@ mark_current_machine_context(rb_thread_t *th)
 
     FLUSH_REGISTER_WINDOWS;
     /* This assumes that all registers are saved into the jmp_buf (and stack) */
+    memset(save_regs_gc_mark, 0, sizeof(save_regs_gc_mark));
     setjmp(save_regs_gc_mark);
     mark_locations_array((VALUE*)save_regs_gc_mark,
 			 sizeof(save_regs_gc_mark) / sizeof(VALUE));
@@ -1501,6 +1641,7 @@ garbage_collect(void)
 
     SET_STACK_END;
 
+    last_heap = NULL;
     init_mark_stack();
 
     th->vm->self ? rb_gc_mark(th->vm->self) : rb_vm_mark(th->vm);
@@ -1602,6 +1743,18 @@ ruby_set_stack_size(size_t size)
     rb_gc_stack_maxsize = size;
 }
 
+int
+rb_gc_is_thread_marked(the_thread)
+    VALUE the_thread;
+{
+    if (FL_ABLE(the_thread)) {
+	return rb_mark_table_contains((RVALUE *) the_thread);
+    }
+    else {
+	return 0;
+    }
+}
+
 void
 Init_stack(VALUE *addr)
 {
@@ -2037,6 +2190,7 @@ rb_gc_call_finalizer_at_exit(void)
 		DATA_PTR(p) && RANY(p)->as.data.dfree &&
 		RANY(p)->as.basic.klass != rb_cThread) {
 		p->as.free.flags = 0;
+		rb_mark_table_remove(p);
 		if ((long)RANY(p)->as.data.dfree == -1) {
 		    RUBY_CRITICAL(free(DATA_PTR(p)));
 		}
@@ -2048,6 +2202,7 @@ rb_gc_call_finalizer_at_exit(void)
 	    else if (BUILTIN_TYPE(p) == T_FILE) {
 		if (rb_io_fptr_finalize(RANY(p)->as.file.fptr)) {
 		    p->as.free.flags = 0;
+		    rb_mark_table_remove(p);
                     VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
 		}
 	    }
@@ -2268,6 +2423,61 @@ count_objects(int argc, VALUE *argv, VALUE os)
     return hash;
 }
 
+static VALUE
+os_statistics()
+{
+    int i;
+    int n = 0;
+    unsigned int objects = 0;
+    unsigned int total_heap_size = 0;
+    unsigned int ast_nodes = 0;
+    char message[1024];
+
+    for (i = 0; i < heaps_used; i++) {
+	RVALUE *p, *pend;
+
+	p = heaps[i].slot;
+	pend = p + heaps[i].limit;
+	for (;p < pend; p++) {
+	    if (p->as.basic.flags) {
+		int isAST = 0;
+		switch (TYPE(p)) {
+		  case T_ICLASS:
+		  case T_NODE:
+		    isAST = 1;
+		    break;
+		  case T_CLASS:
+		    if (FL_TEST(p, FL_SINGLETON)) {
+		        isAST = 1;
+		        break;
+		    }
+		  default:
+		    break;
+		}
+		objects++;
+		if (isAST) {
+		   ast_nodes++;
+		}
+	    }
+	}
+	total_heap_size += (void*)pend - heaps[i].membase;
+    }
+
+    snprintf(message, sizeof(message),
+        "Number of objects: %d (%d AST nodes, %.2f%%)\n"
+        "Heap slot size: %d\n"
+        "Number of heaps: %d\n"
+        "Total size of objects: %.2f KB\n"
+        "Total size of heaps: %.2f KB\n",
+        objects, ast_nodes, ast_nodes * 100 / (double) objects,
+        sizeof(RVALUE),
+        heaps_used,
+        objects * sizeof(RVALUE) / 1024.0,
+        total_heap_size / 1024.0
+    );
+    return rb_str_new2(message);
+}
+
 /*
  *  The <code>GC</code> module provides an interface to Ruby's mark and
  *  sweep garbage collection mechanism. Some of the underlying methods
@@ -2300,6 +2510,8 @@ Init_GC(void)
 
     rb_define_module_function(rb_mObSpace, "_id2ref", id2ref, 1);
 
+    rb_define_module_function(rb_mObSpace, "statistics", os_statistics, 0);
+
     rb_gc_register_address(&rb_mObSpace);
     rb_global_variable(&finalizers);
     rb_gc_unregister_address(&rb_mObSpace);
@@ -2315,4 +2527,6 @@ Init_GC(void)
     rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0);
 
     rb_define_module_function(rb_mObSpace, "count_objects", count_objects, -1);
+
+    init_debugging();
 }
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 4438bc3..1626a7e 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -621,8 +621,8 @@ struct RBignum {
 #define RVALUES(obj) (R_CAST(RValues)(obj))
 
 #define FL_SINGLETON FL_USER0
-#define FL_MARK      (((VALUE)1)<<5)
-#define FL_RESERVED  (((VALUE)1)<<6) /* will be used in the future GC */
+#define FL_RESERVED0 (((VALUE)1)<<5) /* will be used in the future GC */
+#define FL_RESERVED1 (((VALUE)1)<<6) /* will be used in the future GC */
 #define FL_FINALIZE  (((VALUE)1)<<7)
 #define FL_TAINT     (((VALUE)1)<<8)
 #define FL_EXIVAR    (((VALUE)1)<<9)
@@ -716,6 +716,7 @@ void rb_global_variable(VALUE*);
 void rb_register_mark_object(VALUE);
 void rb_gc_register_address(VALUE*);
 void rb_gc_unregister_address(VALUE*);
+int rb_gc_is_thread_marked(VALUE);
 
 ID rb_intern(const char*);
 ID rb_intern2(const char*, long);

^ permalink raw reply related	[relevance 3%]

* IRHG -- When GC is processing T_NODES -- Do they follow the VID's
@ 2008-02-14  5:59  6% Charles Thornton
  0 siblings, 0 replies; 71+ results
From: Charles Thornton @ 2008-02-14  5:59 UTC (permalink / raw)
  To: ruby-core

I have a question about T_NODE Processing in gc_mark_Children().

Is T_NODE and other Objects nodes processed separately?

That is  does  processing  trace VID's found in T_Nodes.

 Chuck T.

^ permalink raw reply	[relevance 6%]

* Re: IRHG -- Dumping T-Nodes
  2008-02-09  9:04  0% ` Eric Hodel
@ 2008-02-09 10:18  6%   ` Charles Thornton
  0 siblings, 0 replies; 71+ results
From: Charles Thornton @ 2008-02-09 10:18 UTC (permalink / raw)
  To: ruby-core

Eric Hodel wrote:
> On Feb 9, 2008, at 24:03 AM, Charles Thornton wrote:
>
>> OK - Here is the problem
>>
>> I want to modify 1.8.6 source to allow
>> the printing of the completed T_NODE
>> structure (the AST?) in my own format.
>>
>> I assume that I can write a Ruby Callable
>> extension that can dump the T_NODE
>> structure at the time of my call.
>>
>> Can this be done, and can someone
>> give the bare essentials on how to do it.
>
> Look at the ParseTree gem.
>
>
>
>
I have been looking a 'rubynode' .

The problem is I don't have a clear idea of the
actual structure of the AST.

I assume that their is a tree structure of Nodes

What I need to know is the BASIC outline of
structures, the head ot the AST, and how NODES
a linked or referenced.

I know the a T_NODE object can point a other
T_NODE object (u1,u2,u3), 

But beyond that I am floundering a bit.

   Chuck T.

^ permalink raw reply	[relevance 6%]

* Re: IRHG -- Dumping T-Nodes
  2008-02-09  8:03  6% IRHG -- Dumping T-Nodes Charles Thornton
@ 2008-02-09  9:04  0% ` Eric Hodel
  2008-02-09 10:18  6%   ` Charles Thornton
  0 siblings, 1 reply; 71+ results
From: Eric Hodel @ 2008-02-09  9:04 UTC (permalink / raw)
  To: ruby-core

On Feb 9, 2008, at 24:03 AM, Charles Thornton wrote:

> OK - Here is the problem
>
> I want to modify 1.8.6 source to allow
> the printing of the completed T_NODE
> structure (the AST?) in my own format.
>
> I assume that I can write a Ruby Callable
> extension that can dump the T_NODE
> structure at the time of my call.
>
> Can this be done, and can someone
> give the bare essentials on how to do it.

Look at the ParseTree gem.

^ permalink raw reply	[relevance 0%]

* IRHG -- Dumping T-Nodes
@ 2008-02-09  8:03  6% Charles Thornton
  2008-02-09  9:04  0% ` Eric Hodel
  0 siblings, 1 reply; 71+ results
From: Charles Thornton @ 2008-02-09  8:03 UTC (permalink / raw)
  To: ruby-core

OK - Here is the problem

I want to modify 1.8.6 source to allow
the printing of the completed T_NODE
structure (the AST?) in my own format.

I assume that I can write a Ruby Callable
extension that can dump the T_NODE
structure at the time of my call.

Can this be done, and can someone
give the bare essentials on how to do it.

  Chuck T.

^ permalink raw reply	[relevance 6%]

* Re: IRHG - TNODE Documentation?
  2008-01-30 16:36  5% ` Paul Brannan
  2008-01-30 17:37  0%   ` Rocky Bernstein
@ 2008-01-30 19:25  0%   ` Charles Thornton
  1 sibling, 0 replies; 71+ results
From: Charles Thornton @ 2008-01-30 19:25 UTC (permalink / raw)
  To: ruby-core

Paul Brannan wrote:
> On Wed, Jan 30, 2008 at 03:42:29PM +0900, Charles Thornton wrote:
>   
>> Is there any documentation on the TNODE
>> types and their relation to ruby structures/code?
>>     
>
> You mean the T_NODE types?
>
> I've been documenting some of them in nodewrap cvs.  See
> nodewrap/ext/node_help.txt.
>
> There's also some documentation for the various nodes in Ludicrous.
>
> Paul
>
>
>
>
>
>   
Exactly what URL do you find "nodewrap/ext/node_help.txt"

Again, a specific URL for  "Ludicrous" would help - google
kept thinking I was talking about a RAP Star?

 Your Slow Child,
        
               Chuck T.

^ permalink raw reply	[relevance 0%]

* Re: IRHG - TNODE Documentation?
  2008-01-30 16:36  5% ` Paul Brannan
@ 2008-01-30 17:37  0%   ` Rocky Bernstein
  2008-01-30 19:25  0%   ` Charles Thornton
  1 sibling, 0 replies; 71+ results
From: Rocky Bernstein @ 2008-01-30 17:37 UTC (permalink / raw)
  To: ruby-core

[-- Attachment #1: Type: text/plain, Size: 519 bytes --]

This is great! Should it be added to http://rubystuff.org/nodewrap/doc/ ?

On Jan 30, 2008 11:36 AM, Paul Brannan <pbrannan@atdesk.com> wrote:

> On Wed, Jan 30, 2008 at 03:42:29PM +0900, Charles Thornton wrote:
> > Is there any documentation on the TNODE
> > types and their relation to ruby structures/code?
>
> You mean the T_NODE types?
>
> I've been documenting some of them in nodewrap cvs.  See
> nodewrap/ext/node_help.txt.
>
> There's also some documentation for the various nodes in Ludicrous.
>
> Paul
>
>
>

[-- Attachment #2: Type: text/html, Size: 870 bytes --]

^ permalink raw reply	[relevance 0%]

* Re: IRHG - TNODE Documentation?
  @ 2008-01-30 16:36  5% ` Paul Brannan
  2008-01-30 17:37  0%   ` Rocky Bernstein
  2008-01-30 19:25  0%   ` Charles Thornton
  0 siblings, 2 replies; 71+ results
From: Paul Brannan @ 2008-01-30 16:36 UTC (permalink / raw)
  To: ruby-core

On Wed, Jan 30, 2008 at 03:42:29PM +0900, Charles Thornton wrote:
> Is there any documentation on the TNODE
> types and their relation to ruby structures/code?

You mean the T_NODE types?

I've been documenting some of them in nodewrap cvs.  See
nodewrap/ext/node_help.txt.

There's also some documentation for the various nodes in Ludicrous.

Paul

^ permalink raw reply	[relevance 5%]

* Re: gc.c -- possible logic error?
  @ 2007-09-30  4:31 14% ` Tanaka Akira
  0 siblings, 0 replies; 71+ results
From: Tanaka Akira @ 2007-09-30  4:31 UTC (permalink / raw)
  To: ruby-core

In article <Pine.GSO.4.64.0709281302390.26570@brains.eng.cse.dmu.ac.uk>,
  Hugh Sasse <hgs@dmu.ac.uk> writes:

> I've been looking at Tom Copeland's memory allocation problem:
>
> http://tomcopeland.blogs.com/juniordeveloper/2007/09/tracking-down-a.html

I think OpenStruct needs much more memory than Hash.

It needs accessor methods for all member of all objects.

I implemented ObjectSpace.count_objects to count objects.

% ./ruby -rpp -e 'pp ObjectSpace.count_objects'
{:T_ARRAY=>1261,
 :T_BIGNUM=>42,
 :T_CLASS=>418,
 :T_DATA=>297,
 :T_FILE=>5,
 :T_FLOAT=>6,
 :T_HASH=>3,
 :T_ICLASS=>21,
 :T_MATCH=>1,
 :T_MODULE=>18,
 :T_NODE=>10918,
 :T_OBJECT=>7,
 :T_REGEXP=>5,
 :T_STRING=>3101,
 :T_VALUES=>2,
 :freed=>11895}

This means that there are 1261 arrays, etc.

ObjectSpace.count_objects can be used to count objects
required by Hash/OpenStruct.

Hash:

% ./ruby -e '          
o = {}
GC.start; c = ObjectSpace.count_objects
10.times {|i|
  o["foo#{i}"] = 1
  GC.start; c2 = ObjectSpace.count_objects
  c.keys.each {|k| n = c2[k] - c[k]; print "#{k}:#{n} " if 0<n }; puts
  c = c2
}
'
T_STRING:28 T_HASH:1 
T_STRING:1 T_ARRAY:1 T_HASH:1 
T_STRING:1 
T_STRING:1 
T_STRING:1 
T_STRING:1 
T_STRING:1 
T_STRING:1 
T_STRING:1 
T_STRING:1 

Hash needs no extra objects.  It just needs a string for
the key.

Internally Hash use st_table.  st_table needs a
struct st_table_entry for each entry.
The size of struct st_table_entry is 6 words (Ruby 1.9)
which is 24bytes on 32-bit environment.

OpenStruct:

% ./ruby -rostruct -e '
o = OpenStruct.new
GC.start; c = ObjectSpace.count_objects
10.times {|i|
  o.send("foo#{i}=", 1)
  GC.start; c2 = ObjectSpace.count_objects
  c.keys.each {|k| n = c2[k] - c[k]; print "#{k}:#{n} " if 0<n }; puts
  c = c2
}
'
T_CLASS:1 T_STRING:30 T_ARRAY:1 T_HASH:1 T_DATA:6 T_NODE:7 
T_STRING:2 T_HASH:1 T_DATA:6 T_VALUES:1 T_NODE:7 
T_STRING:2 T_DATA:6 T_VALUES:1 T_NODE:7 
T_STRING:2 T_DATA:6 T_VALUES:1 T_NODE:7 
T_STRING:2 T_DATA:6 T_VALUES:1 T_NODE:7 
T_STRING:2 T_DATA:6 T_VALUES:1 T_NODE:7 
T_STRING:2 T_DATA:6 T_VALUES:1 T_NODE:7 
T_STRING:2 T_DATA:6 T_VALUES:1 T_NODE:7 
T_STRING:2 T_DATA:6 T_VALUES:1 T_NODE:7 
T_STRING:2 T_DATA:6 T_VALUES:1 T_NODE:7 

OpenStruct member needs 1 string, 6 data, 1 values and 7
nodes, addition to a key string and struct st_table_entry.
(OpenStruct uses a Hash)

Since a object needs 20bytes, it require 20*(1+6+1+7) =
300bytes at least.

Also T_STRING, T_DATA and T_VALUES may need more memory
allocated by malloc.

So I guess it is not memory leak but OpenStruct is memory
eater.

ObjectSpace.count_objects implementation:

Index: gc.c
===================================================================
--- gc.c	(revision 13576)
+++ gc.c	(working copy)
@@ -2145,6 +2145,70 @@
     return (VALUE)((SIGNED_VALUE)obj|FIXNUM_FLAG);
 }
 
+static VALUE
+count_objects(VALUE klass)
+{
+    long counts[T_MASK+1];
+    long freed = 0;
+    int i;
+    VALUE hash;
+
+    for (i = 0; i <= T_MASK; i++) {
+        counts[i] = 0;
+    }
+
+    for (i = 0; i < heaps_used; i++) {
+        RVALUE *p, *pend;
+
+        p = heaps[i].slot; pend = p + heaps[i].limit;
+        for (;p < pend; p++) {
+            if (p->as.basic.flags) {
+                counts[BUILTIN_TYPE(p)]++;
+            }
+            else {
+                freed++;
+            }
+        }
+    }
+
+    hash = rb_hash_new();
+    rb_hash_aset(hash, ID2SYM(rb_intern("freed")), LONG2NUM(freed));
+    for (i = 0; i <= T_MASK; i++) {
+        VALUE type;
+        switch (i) {
+          case T_NONE:          type = ID2SYM(rb_intern("T_NONE")); break;
+          case T_NIL:           type = ID2SYM(rb_intern("T_NIL")); break;
+          case T_OBJECT:        type = ID2SYM(rb_intern("T_OBJECT")); break;
+          case T_CLASS:         type = ID2SYM(rb_intern("T_CLASS")); break;
+          case T_ICLASS:        type = ID2SYM(rb_intern("T_ICLASS")); break;
+          case T_MODULE:        type = ID2SYM(rb_intern("T_MODULE")); break;
+          case T_FLOAT:         type = ID2SYM(rb_intern("T_FLOAT")); break;
+          case T_STRING:        type = ID2SYM(rb_intern("T_STRING")); break;
+          case T_REGEXP:        type = ID2SYM(rb_intern("T_REGEXP")); break;
+          case T_ARRAY:         type = ID2SYM(rb_intern("T_ARRAY")); break;
+          case T_FIXNUM:        type = ID2SYM(rb_intern("T_FIXNUM")); break;
+          case T_HASH:          type = ID2SYM(rb_intern("T_HASH")); break;
+          case T_STRUCT:        type = ID2SYM(rb_intern("T_STRUCT")); break;
+          case T_BIGNUM:        type = ID2SYM(rb_intern("T_BIGNUM")); break;
+          case T_FILE:          type = ID2SYM(rb_intern("T_FILE")); break;
+          case T_TRUE:          type = ID2SYM(rb_intern("T_TRUE")); break;
+          case T_FALSE:         type = ID2SYM(rb_intern("T_FALSE")); break;
+          case T_DATA:          type = ID2SYM(rb_intern("T_DATA")); break;
+          case T_MATCH:         type = ID2SYM(rb_intern("T_MATCH")); break;
+          case T_SYMBOL:        type = ID2SYM(rb_intern("T_SYMBOL")); break;
+          case T_VALUES:        type = ID2SYM(rb_intern("T_VALUES")); break;
+          case T_BLOCK:         type = ID2SYM(rb_intern("T_BLOCK")); break;
+          case T_UNDEF:         type = ID2SYM(rb_intern("T_UNDEF")); break;
+          case T_NODE:          type = ID2SYM(rb_intern("T_NODE")); break;
+          default:              type = INT2NUM(i); break;
+        }
+        if (counts[i])
+            rb_hash_aset(hash, type, LONG2NUM(counts[i]));
+    }
+
+    return hash;
+}
+
 /*
  *  The <code>GC</code> module provides an interface to Ruby's mark and
  *  sweep garbage collection mechanism. Some of the underlying methods
@@ -2190,4 +2254,6 @@
     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);
+
+    rb_define_module_function(rb_mObSpace, "count_objects", count_objects, 0);
 }
-- 
Tanaka Akira

^ permalink raw reply	[relevance 14%]

* [BUG] (1.9) Wrong arity of Procs obtained with somemethod.to_proc.
@ 2007-04-29 10:56  5% Mauricio Fernandez
  0 siblings, 0 replies; 71+ results
From: Mauricio Fernandez @ 2007-04-29 10:56 UTC (permalink / raw)
  To: ruby-core


$ ./ruby19 -ve "def foo(a, x, y, *b); end; p method(:foo).to_proc.arity"
ruby 1.9.0 (2007-04-26 patchlevel 0) [i686-linux]
-1

when it should resemble

$ ruby185-p12 -ve "def foo(a, x, y, *b); end; p method(:foo).to_proc.arity"
ruby 1.8.5 (2006-12-25 patchlevel 12) [i686-linux]
-4

The bug is distinct from the one in [ruby-core:11029] and predates it.

The comment in the function is very telling:

static VALUE
method_proc(VALUE method)
{
    VALUE proc;
    /*
     * class Method
     *   def to_proc
     *     proc{|*args|
     *       self.call(*args)
     *     }
     *   end
     * end
     */
    proc = rb_iterate((VALUE (*)(VALUE))mproc, 0, bmcall, method);
    return proc;
}


In proc_arity, the second branch is being followed:

    if (iseq && BUILTIN_TYPE(iseq) != T_NODE) {
	if (iseq->arg_rest == 0 && iseq->arg_opts == 0) {
	    return INT2FIX(iseq->argc);
	}
	else {
	    return INT2FIX(-iseq->argc - 1);
	}
    }
    else {
	return INT2FIX(-1);
    }

-- 
Mauricio Fernandez  -   http://eigenclass.org   -  singular Ruby
                        ** Latest postings **
On GC and finalizers in Ruby, corrected weak hash table implementations
  http://eigenclass.org/hiki/deferred-finalizers-in-Ruby
simplefold: better vim folding (Ruby, Objective Caml, Perl, PHP, Java)
  http://eigenclass.org/hiki/simplefold

^ permalink raw reply	[relevance 5%]

* Re: [patch] Re: [BUG] Proc#arity regression or bug in RDoc
  2007-04-27  5:12  6%   ` [patch] " Adam Bozanich
@ 2007-04-29  4:37  5%     ` Adam Bozanich
  0 siblings, 0 replies; 71+ results
From: Adam Bozanich @ 2007-04-29  4:37 UTC (permalink / raw)
  To: ruby-core

[-- Attachment #1: Type: text/plain, Size: 3814 bytes --]

Cleaned it up a bit & added some tests to sample/test.rb.  Not sure where
you guys prefer the unit tests to go.  Is there a specific policy?  Also, is
it better to submit small patches like this to rubyforge or directly this
list?

-Adam

Index: proc.c
===================================================================
--- proc.c      (revision 12228)
+++ proc.c      (working copy)
@@ -434,9 +434,9 @@
     GetProcPtr(self, proc);
     iseq = proc->block.iseq;
     if (iseq && BUILTIN_TYPE(iseq) != T_NODE) {
-       if (iseq->arg_rest == 0 && iseq->arg_opts == 0) {
-           return INT2FIX(iseq->argc);
-       }
+       if( iseq->arg_rest < 0 ) {
+               return INT2FIX(iseq->argc);
+       }
        else {
            return INT2FIX(-iseq->argc - 1);
        }
Index: sample/test.rb
===================================================================
--- sample/test.rb      (revision 12228)
+++ sample/test.rb      (working copy)
@@ -1283,6 +1283,36 @@
 lambda(&method(:test_ok)).call(true)
 lambda(&block_get{|a,n| test_ok(a,n)}).call(true, 2)

+# Proc#arity
+test_ok( Proc.new {}.arity        ,  0 )
+test_ok( Proc.new {||}.arity      ,  0 )
+test_ok( Proc.new {|a|}.arity     ,  1 )
+test_ok( Proc.new {|a,b|}.arity   ,  2 )
+test_ok( Proc.new {|a,b,c|}.arity ,  3 )
+test_ok( Proc.new {|*a|}.arity    , -1 )
+test_ok( Proc.new {|a,*b|}.arity  , -2 )
+
+# Method#arity
+class C
+  def one;    end
+  def two(a); end
+  def three(*a);  end
+  def four(a, b); end
+  def five(a, b, *c);    end
+  def six(a, b, *c, &d); end
+end
+c = C.new
+test_ok( c.method(:one).arity   , 0 )
+test_ok( c.method(:two).arity   , 1 )
+test_ok( c.method(:three).arity , -1 )
+test_ok( c.method(:four).arity  , 2 )
+test_ok( c.method(:five).arity  , -3 )
+test_ok( c.method(:six).arity   , -3 )
+test_ok( "cat".method(:size).arity    , 0 )
+test_ok( "cat".method(:replace).arity , 1 )
+test_ok( "cat".method(:squeeze).arity , -1 )
+test_ok( "cat".method(:count).arity   , -1 )
+
 class ITER_TEST1
    def a
      block_given?


On 4/26/07, Adam Bozanich <adam.boz@gmail.com> wrote:
>
>
> On 4/26/07, Mauricio Fernandez <mfp@acm.org> wrote:
> >
> > On Thu, Apr 26, 2007 at 06:55:46PM +0900, Mauricio Fernandez wrote:
> > > $ ruby19 -v -e "p proc{}.arity"
> > > ruby 1.9.0 (2007-02-07 patchlevel 0) [i686-linux]
> > > 0
> > > $ ./ruby19 -v -e "p proc{}.arity"
> > > ruby 1.9.0 (2007-04-26 patchlevel 0) [i686-linux]
> > > -1
> > >
> > > However, the RDoc documentation attached to proc_arity still says that
> > it
> > > should return 0, so there's a bug, either in the code (wrong
> > iseq->argc ?) or
> > > in the docs (if the latter, the patch below should do).
> >
> > It seems it's a regression after all; no time to fix it now, but I've
> > found
> > when it happened:
> >
> > ruby-trunk-12116$ ./ruby -v -e "p proc{}.arity"
> > ruby 1.9.0 (2007-03-21 patchlevel 0) [i686-linux]
> > 0
> >
> > ruby-trunk-12117$ ./ruby -v -e "p proc{}.arity"
> > ruby 1.9.0 (2007-03-21 patchlevel 0) [i686-linux]
> > -1
> >
> >
> This makes arity behave like the docs specify for both method.arity and
> proc.arity.  I'm sure it's naive, but it seems to work.
>
> -Adam
>
> Index: proc.c
> ===================================================================
> --- proc.c      (revision 12226)
> +++ proc.c      (working copy)
> @@ -434,11 +434,11 @@
>      GetProcPtr(self, proc);
>      iseq = proc->block.iseq;
>      if (iseq && BUILTIN_TYPE(iseq) != T_NODE) {
> -       if (iseq->arg_rest == 0 && iseq->arg_opts == 0) {
> -           return INT2FIX(iseq->argc);
> -       }
> +       if( iseq->arg_rest < 0 ) {
> +               return INT2FIX(iseq->argc);
> +       }
>         else {
> -           return INT2FIX(-iseq->argc - 1);
> +           return INT2FIX(-(iseq->argc + 1));
>         }
>      }
>      else {
>
>

[-- Attachment #2: Type: text/html, Size: 6450 bytes --]

^ permalink raw reply	[relevance 5%]

* [patch] Re: [BUG] Proc#arity regression or bug in RDoc
  @ 2007-04-27  5:12  6%   ` Adam Bozanich
  2007-04-29  4:37  5%     ` Adam Bozanich
  0 siblings, 1 reply; 71+ results
From: Adam Bozanich @ 2007-04-27  5:12 UTC (permalink / raw)
  To: ruby-core

[-- Attachment #1: Type: text/plain, Size: 1615 bytes --]

On 4/26/07, Mauricio Fernandez <mfp@acm.org> wrote:
>
> On Thu, Apr 26, 2007 at 06:55:46PM +0900, Mauricio Fernandez wrote:
> > $ ruby19 -v -e "p proc{}.arity"
> > ruby 1.9.0 (2007-02-07 patchlevel 0) [i686-linux]
> > 0
> > $ ./ruby19 -v -e "p proc{}.arity"
> > ruby 1.9.0 (2007-04-26 patchlevel 0) [i686-linux]
> > -1
> >
> > However, the RDoc documentation attached to proc_arity still says that
> it
> > should return 0, so there's a bug, either in the code (wrong iseq->argc
> ?) or
> > in the docs (if the latter, the patch below should do).
>
> It seems it's a regression after all; no time to fix it now, but I've
> found
> when it happened:
>
> ruby-trunk-12116$ ./ruby -v -e "p proc{}.arity"
> ruby 1.9.0 (2007-03-21 patchlevel 0) [i686-linux]
> 0
>
> ruby-trunk-12117$ ./ruby -v -e "p proc{}.arity"
> ruby 1.9.0 (2007-03-21 patchlevel 0) [i686-linux]
> -1
>
>
This makes arity behave like the docs specify for both method.arity and
proc.arity.  I'm sure it's naive, but it seems to work.

-Adam

Index: proc.c
===================================================================
--- proc.c      (revision 12226)
+++ proc.c      (working copy)
@@ -434,11 +434,11 @@
     GetProcPtr(self, proc);
     iseq = proc->block.iseq;
     if (iseq && BUILTIN_TYPE(iseq) != T_NODE) {
-       if (iseq->arg_rest == 0 && iseq->arg_opts == 0) {
-           return INT2FIX(iseq->argc);
-       }
+       if( iseq->arg_rest < 0 ) {
+               return INT2FIX(iseq->argc);
+       }
        else {
-           return INT2FIX(-iseq->argc - 1);
+           return INT2FIX(-(iseq->argc + 1));
        }
     }
     else {

[-- Attachment #2: Type: text/html, Size: 2728 bytes --]

^ permalink raw reply	[relevance 6%]

* Re: patch bignums
  @ 2006-09-22  0:22  3%   ` Nobuyoshi Nakada
  0 siblings, 0 replies; 71+ results
From: Nobuyoshi Nakada @ 2006-09-22  0:22 UTC (permalink / raw)
  To: ruby-core

Hi,

At Fri, 22 Sep 2006 03:33:03 +0900,
Sam Roberts wrote in [ruby-core:08907]:
> > I use attached .gdbinit.
> 
> Did the attachment get stripped or forgotten?

Forgotten, sorry.

\f
define rp
  if ($arg0 & 0x1)
    echo T_FIXNUM\n
    print (long)$arg0 >> 1
  else
  if ($arg0 == 0)
    echo T_FALSE\n
  else
  if ($arg0 == 2)
    echo T_TRUE\n
  else
  if ($arg0 == 4)
    echo T_NIL\n
  else
  if ($arg0 == 6)
    echo T_UNDEF\n
  else
  if (($arg0 & 0xff) == 0x0e)
    echo T_SYMBOL\n
    output $arg0 >> 8
    echo \n
    call rb_id2name($arg0 >> 8)
  else
    set $rbasic = (struct RBasic*)$arg0
  #  output  $rbasic
  #  echo \ =\ 
  #  output *$rbasic
  #  echo \n
    set $flags = (*$rbasic).flags & 0x3f
    if ($flags == 0x01)
      echo T_NIL\n
      echo impossible\n
    else
    if ($flags == 0x02)
      echo T_OBJECT\n
      print *(struct RObject*)$rbasic
    else
    if ($flags == 0x03)
      echo T_CLASS\n
      print *(struct RClass*)$rbasic
#      rb_classname($arg0)
    else
    if ($flags == 0x04)
      echo T_ICLASS\n
      print *(struct RClass*)$rbasic
    else
    if ($flags == 0x05)
      echo T_MODULE\n
      print *(struct RClass*)$rbasic
    else
    if ($flags == 0x06)
      echo T_FLOAT\n
      print *(struct RFloat*)$rbasic
    else
    if ($flags == 0x07)
      echo T_STRING\n
      print *(struct RString*)$rbasic
    else
    if ($flags == 0x08)
      echo T_REGEXP\n
      print *(struct RRegexp*)$rbasic
    else
    if ($flags == 0x09)
      echo T_ARRAY\n
      print *(struct RArray*)$rbasic
    else
    if ($flags == 0x0a)
      echo T_FIXNUM\n
      echo impossible\n
    else
    if ($flags == 0x0b)
      echo T_HASH\n
      print *(struct RHash*)$rbasic
    else
    if ($flags == 0x0c)
      echo T_STRUCT\n
      print *(struct RStruct*)$rbasic
    else
    if ($flags == 0x0d)
      echo T_BIGNUM\n
      print *(struct RBignum*)$rbasic
    else
    if ($flags == 0x0e)
      echo T_FILE\n
      print *(struct RFile*)$rbasic
    else
    if ($flags == 0x20 || $flags == 0x10)
      echo T_TRUE\n
      echo impossible\n
    else
    if ($flags == 0x21 || $flags == 0x11)
      echo T_FALSE\n
      echo impossible\n
    else
    if ($flags == 0x22 || $flags == 0x12)
      echo T_DATA\n
      print *(struct RData*)$rbasic
    else
    if ($flags == 0x23 || $flags == 0x13)
      echo T_MATCH\n
      print *(struct RMatch*)$rbasic
    else
    if ($flags == 0x24 || $flags == 0x14)
      echo T_SYMBOL\n
      echo impossible\n
    else
    if ($flags == 0x3c || $flags == 0x1c)
      echo T_UNDEF\n
      echo impossible\n
    else
    if ($flags == 0x3b)
      echo T_BLOCK\n
    else
    if ($flags == 0x3d || $flags == 0x1d)
      echo T_VARMAP\n
    else
    if ($flags == 0x3e || $flags == 0x1e)
      echo T_SCOPE\n
    else
    if ($flags == 0x3f || $flags == 0x1f)
      echo T_NODE\n
      print (NODE*)$arg0
    else
      echo Unknown\n
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end
    end

  end
  end
  end
  end
  end
  end
end
document rp
display builtin ruby object
end

define nd_type
  print (enum node_type)((((NODE*)$arg0)->flags>>node_typemask)&node_typeshift)
end
document nd_type
display the type of ruby node
end

define nd_file
  print ((NODE*)$arg0)->nd_file
end
document nd_file
display the source file name of node
end

define nd_line
  print ((unsigned int)((((NODE*)$arg0)->flags>>node_lshift)&node_lmask))
end
document nd_line
display the line number of node
end

# display the members of ruby node

define nd_head
  print "u1.node"
  what $arg0.u1.node
  p $arg0.u1.node
end

define nd_alen
  print "u2.argc"
  what $arg0.u2.argc
  p $arg0.u2.argc
end

define nd_next
  print "u3.node"
  what $arg0.u3.node
  p $arg0.u3.node
end


define nd_cond
  print "u1.node"
  what $arg0.u1.node
  p $arg0.u1.node
end

define nd_body
  print "u2.node"
  what $arg0.u2.node
  p $arg0.u2.node
end

define nd_else
  print "u3.node"
  what $arg0.u3.node
  p $arg0.u3.node
end


define nd_orig
  print "u3.value"
  what $arg0.u3.value
  p $arg0.u3.value
end


define nd_resq
  print "u2.node"
  what $arg0.u2.node
  p $arg0.u2.node
end

define nd_ensr
  print "u3.node"
  what $arg0.u3.node
  p $arg0.u3.node
end


define nd_1st
   print "u1.node"
   what $arg0.u1.node
   p $arg0.u1.node
end

define nd_2nd
   print "u2.node"
   what $arg0.u2.node
   p $arg0.u2.node
end


define nd_stts
  print "u1.node"
  what $arg0.u1.node
  p $arg0.u1.node
end


define nd_entry
 print "u3.entry"
 what $arg0.u3.entry
 p $arg0.u3.entry
end

define nd_vid
   print "u1.id"
   what $arg0.u1.id
   p $arg0.u1.id
end

define nd_cflag
 print "u2.id"
 what $arg0.u2.id
 p $arg0.u2.id
end

define nd_cval
  print "u3.value"
  what $arg0.u3.value
  p $arg0.u3.value
end


define nd_cnt
   print "u3.cnt"
   what $arg0.u3.cnt
   p $arg0.u3.cnt
end

define nd_tbl
   print "u1.tbl"
   what $arg0.u1.tbl
   p $arg0.u1.tbl
end


define nd_var
   print "u1.node"
   what $arg0.u1.node
   p $arg0.u1.node
end

define nd_ibdy
  print "u2.node"
  what $arg0.u2.node
  p $arg0.u2.node
end

define nd_iter
  print "u3.node"
  what $arg0.u3.node
  p $arg0.u3.node
end


define nd_value
 print "u2.node"
 what $arg0.u2.node
 p $arg0.u2.node
end

define nd_aid
   print "u3.id"
   what $arg0.u3.id
   p $arg0.u3.id
end


define nd_lit
   print "u1.value"
   what $arg0.u1.value
   p $arg0.u1.value
end


define nd_frml
  print "u1.node"
  what $arg0.u1.node
  p $arg0.u1.node
end

define nd_rest
  print "u2.argc"
  what $arg0.u2.argc
  p $arg0.u2.argc
end

define nd_opt
   print "u1.node"
   what $arg0.u1.node
   p $arg0.u1.node
end


define nd_recv
  print "u1.node"
  what $arg0.u1.node
  p $arg0.u1.node
end

define nd_mid
   print "u2.id"
   what $arg0.u2.id
   p $arg0.u2.id
end

define nd_args
  print "u3.node"
  what $arg0.u3.node
  p $arg0.u3.node
end


define nd_noex
  print "u1.id"
  what $arg0.u1.id
  p $arg0.u1.id
end

define nd_defn
  print "u3.node"
  what $arg0.u3.node
  p $arg0.u3.node
end


define nd_old
   print "u1.id"
   what $arg0.u1.id
   p $arg0.u1.id
end

define nd_new
   print "u2.id"
   what $arg0.u2.id
   p $arg0.u2.id
end


define nd_cfnc
  print "u1.cfunc"
  what $arg0.u1.cfunc
  p $arg0.u1.cfunc
end

define nd_argc
  print "u2.argc"
  what $arg0.u2.argc
  p $arg0.u2.argc
end


define nd_cname
 print "u1.id"
 what $arg0.u1.id
 p $arg0.u1.id
end

define nd_super
 print "u3.node"
 what $arg0.u3.node
 p $arg0.u3.node
end


define nd_modl
  print "u1.id"
  what $arg0.u1.id
  p $arg0.u1.id
end

define nd_clss
  print "u1.value"
  what $arg0.u1.value
  p $arg0.u1.value
end


define nd_beg
   print "u1.node"
   what $arg0.u1.node
   p $arg0.u1.node
end

define nd_end
   print "u2.node"
   what $arg0.u2.node
   p $arg0.u2.node
end

define nd_state
 print "u3.state"
 what $arg0.u3.state
 p $arg0.u3.state
end

define nd_rval
  print "u2.value"
  what $arg0.u2.value
  p $arg0.u2.value
end


define nd_nth
   print "u2.argc"
   what $arg0.u2.argc
   p $arg0.u2.argc
end


define nd_tag
   print "u1.id"
   what $arg0.u1.id
   p $arg0.u1.id
end

define nd_tval
  print "u2.value"
  what $arg0.u2.value
  p $arg0.u2.value
end

define rb_p
  call rb_p($arg0)
end

define rb_id2name
  call rb_id2name($arg0)
end

define rb_classname
  call classname($arg0)
  rb_p $
  p *(struct RClass*)$arg0
end

define rb_backtrace
  call rb_backtrace()
end
\f

-- 
Nobu Nakada

^ permalink raw reply	[relevance 3%]

* Re: Wilderness: NODE Obj and Class Obj --- Can they be ID'ed by inspection?
  @ 2006-01-23 19:22  5% ` Charles Mills
  0 siblings, 0 replies; 71+ results
From: Charles Mills @ 2006-01-23 19:22 UTC (permalink / raw)
  To: ruby-core

On Jan 23, 2006, at 12:43 AM, Charles Thornton wrote:

> I think I know the answer, but...
>
> If I look at an object without knowing if it is a NODE or a CLASS,  
> can I tell the difference???
>
> -- 
> GodFather -- 667 Neighbor of the Beast
>

Yes.
#define T_CLASS  0x03
#define T_NODE   0x3f

BUILTIN_TYPE(v)
or in gdb
((RVALUE*)v)->as.basic.flags & T_MASK

-Charlie

^ permalink raw reply	[relevance 5%]

* Re: Wilderness: I Have formatted README.EXT into an HTML Document
  @ 2005-10-27 14:16  1% ` Nikolai Weibull
  0 siblings, 0 replies; 71+ results
From: Nikolai Weibull @ 2005-10-27 14:16 UTC (permalink / raw)
  To: ruby-core

[-- Attachment #1: Type: text/plain, Size: 792 bytes --]

Charles E. Thornton wrote:

> I have taken README.EXT (English Version Only) and have reformatted
> it as a html document.

How did you do the conversion?  I’m attaching a slight rewrite of the
README.EXT to use docutils syntax so that we can easily produce many
formats (although I’ve since given up on docutils as I prefer using TeX
directly).  My version is attached.  Should be easier to keep one file
in sync than two, so perhaps README.EXT can be updated to use the
docutils format, or perhaps asciidoc which the git people are using for
their documentation?

        nikolai

-- 
Nikolai Weibull: now available free of charge at http://bitwi.se/!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

[-- Attachment #2: on-writing-ruby-extensions.txt --]
[-- Type: text/plain, Size: 33623 bytes --]

==========================
On Writing Ruby Extensions
==========================



This document explains how to make extension libraries for Ruby.



:Author: Nikolai Weibull
:Date: 2004-11-19
:Revision: 1.0



.. contents:: Table of Contents




Basic Knowledge
===============


In C, variables have types and data do not have types.  In contrast, Ruby
variables do not have a static type, and data themselves have types, so data
will need to be converted between the languages.

Data in Ruby are represented by C type ``VALUE``.  Each ``VALUE`` data has its
data-type.

To retrieve C data from a ``VALUE``, you need to:

  1.  Identify the VALUE's data type
  2.  Convert the VALUE into C data

Converting to the wrong data type may cause serious problems.


Data-types
----------

The Ruby interpreter has the following data types:

==============  =========================
C               Ruby
==============  =========================
``T_NIL``       nil
``T_OBJECT``    ordinary object
``T_CLASS``     class
``T_MODULE``    module
``T_FLOAT``     floating point number
``T_STRING``    string
``T_REGEXP``    regular expression
``T_ARRAY``     array
``T_FIXNUM``    Fixnum(31bit integer)
``T_HASH``      associative array
``T_STRUCT``    (Ruby) structure
``T_BIGNUM``    multi precision integer
``T_FILE``      IO
``T_TRUE``      true
``T_FALSE``     false
``T_DATA``      data
``T_SYMBOL``    symbol
==============  =========================

In addition, there are several other types used internally::

  T_ICLASS
  T_MATCH
  T_UNDEF
  T_VARMAP
  T_SCOPE
  T_NODE

Most of the types are represented by C structures.


Check Data Type of the ``VALUE``
--------------------------------

The macro ``TYPE()`` defined in ``ruby.h`` shows the data type of the
``VALUE``.  ``TYPE()`` returns the constant number ``T_``\ *XXX* described above.
To handle data types, your code will look something like this::

  switch (TYPE(obj)) {
    case T_FIXNUM:
      /* process Fixnum */
      break;
    case T_STRING:
      /* process String */
      break;
    case T_ARRAY:
      /* process Array */
      break;
    default:
      /* raise exception */
      rb_raise(rb_eTypeError, "not valid value");
      break;
  }

There is the data-type check function ::

  void Check_Type(VALUE value, int type)

which raises an exception if the ``VALUE`` does not have the type specified.

There are also faster check macros for ``Fixnum``\ s and ``nil``::

  FIXNUM_P(obj)
  NIL_P(obj)


Convert ``VALUE`` Into C Data
-----------------------------

The data for type ``T_NIL``, ``T_FALSE``, ``T_TRUE`` are ``nil``, ``true``,
``false`` respectively.  They are singletons for the data type.

The ``T_FIXNUM`` data is a 31bit length fixed integer (63bit length on some
machines), which can be convert to a C integer by using the ``FIX2INT()``
macro.  There is also ``NUM2INT()`` which converts any Ruby numbers into C
integers.  The ``NUM2INT()`` macro includes a type check, so an exception will
be raised if the conversion failed.  ``NUM2DBL()`` can be used to retrieve the
double float value in same way.

To get ``char*`` from a ``VALUE``, version 1.7 recommend to use new macros
``StringValue()`` and ``StringValuePtr()``.  ``StringValue(var)`` replaces
``var``'s value to the result of ``var.to_str()``.  ``StringValuePtr(var)``
does same replacement and returns ``char*`` representation of ``var``.  These
macros will skip the replacement if ``var`` is a ``String``.  Notice that the
macros requires to take only lvalue as their argument, to change the value of
var in the replacement. 

In version 1.6 or earlier, ``STR2CSTR()`` was used to do same thing but now it
is obsoleted in version 1.7 because of ``STR2CSTR()`` has a risk of dangling
pointer problem in ``to_str()`` impliclit conversion.

Other data types have corresponding C structures, e.g. ``struct RArray`` for
``T_ARRAY`` etc.  The ``VALUE`` of the type which has corresponding structure
can be cast to retrieve the pointer to the ``struct``.  The casting macro will
be of the form ``R``\ *XXX* for each data type; for instance, ``RARRAY(obj)``.
See ``<ruby.h>``.

For example, ``RSTRING(size)->len`` is the way to get the size of the Ruby
String object.  The allocated region can be accessed by ``RSTRING(str)->ptr``.
For arrays, use ``RARRAY(ary)->len`` and ``RARRAY(ary)->ptr`` respectively.

.. note:
  Do not change the value of the structure directly, unless you are responsible
  for the result.  This ends up being the cause of interesting bugs.


Convert C Data Into ``VALUE``
-----------------------------

To convert C data to Ruby values:

``FIXNUM``
  left shift 1 bit, and turn on LSB.

Other pointer values
  cast to ``VALUE``.

You can determine whether a ``VALUE`` is pointer or not by checking its LSB.  

.. note:
  Ruby does not allow arbitrary pointer values to be a ``VALUE``.  They should
  be pointers to the structures which Ruby knows about.  The known structures
  are defined in ``<ruby.h>``.

To convert C numbers to Ruby values, use these macros:

``INT2FIX()``
  for integers within 31bits.
``INT2NUM()``
  for arbitrary sized integer.

``INT2NUM()`` converts an integer into a ``Bignum`` if it is out of the
``FIXNUM`` range, but is a bit slower.


Manipulating Ruby Data
----------------------

As I already mentioned, it is not recommended to modify an object's internal
structure.  To manipulate objects, use the functions supplied by the Ruby
interpreter. Some (not all) of the useful functions are listed below.

String Functions
~~~~~~~~~~~~~~~~

``rb_str_new(const char *ptr, long len)``
  Creates a new Ruby string.

``rb_str_new2(const char *ptr)``
  Creates a new Ruby string from a C string.  This is equivalent to
  ``rb_str_new(ptr, strlen(ptr))``.

``rb_tainted_str_new(const char *ptr, long len)``
  Creates a new tainted Ruby string.  Strings from external data sources should
  be tainted.

``rb_tainted_str_new2(const char *ptr)``
  Creates a new tainted Ruby string from a C string.

``rb_str_cat(VALUE str, const char *ptr, long len)``
  Appends len bytes of data from ptr to the Ruby string.

Array Functions
~~~~~~~~~~~~~~~

``rb_ary_new()``
  Creates an array with no elements.

``rb_ary_new2(long len)``
  Creates an array with no elements, allocating internal buffer for ``len``
  elements.

``rb_ary_new3(long n, ...)``
  Creates an ``n``\ -element array from the arguments.

``rb_ary_new4(long n, VALUE *elts)``
  Creates an ``n``\ -element array from a C array.

``rb_ary_push(VALUE ary, VALUE val)``
  Push ``val``  onto the array.

``rb_ary_pop(VALUE ary)``
  Pop top value off of the array.

``rb_ary_shift(VALUE ary)``
  Shift the first value off of the array.

``rb_ary_unshift(VALUE ary, VALUE val)``
  Unshift ``val`` at the beginning of the array.



Extending Ruby with C
=====================


Adding new Features to Ruby
----------------------------

You can add new features (classes, methods, etc.) to the Ruby interpreter.
Ruby provides APIs for defining the following things:

  * Classes, Modules
  * Methods, Singleton Methods
  * Constants

Class/Module Definition
~~~~~~~~~~~~~~~~~~~~~~~

To define a class or module, use the functions below::

  VALUE rb_define_class(const char *name, VALUE super)
  VALUE rb_define_module(const char *name)

These functions return the newly created class or module.  You may want to save
this reference into a variable to use later.

To define nested classes or modules, use the functions below::

  VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
  VALUE rb_define_module_under(VALUE outer, const char *name)

Method/Singleton Method Definition
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To define methods or singleton methods, use these functions::

  void rb_define_method(VALUE klass, const char *name, 
                        VALUE (*func)(), int argc)

  void rb_define_singleton_method(VALUE object, const char *name, 
                                  VALUE (*func)(), int argc)

The ``argc`` represents the number of the arguments to the C function, which
must be less than 17.  But I believe you don't need that much.  ``:-)``

If ``argc`` is negative, it specifies the calling sequence, not number of the
arguments.  

If ``argc`` is -1, the function will be called as ::

  VALUE func(int argc, VALUE *argv, VALUE obj)

where ``argc`` is the actual number of arguments, ``argv`` is the C array of
the arguments, and ``obj`` is the receiver.

If ``argc`` is -2, the arguments are passed in a Ruby array. The function will
be called like ::

  VALUE func(VALUE obj, VALUE args)

where ``obj`` is the receiver, and ``args`` is the Ruby array containing actual
arguments.

There are two more functions to define methods.  One is to define private
methods::

  void rb_define_private_method(VALUE klass, const char *name, 
                                VALUE (*func)(), int argc)

The other is to define module functions, which are private AND singleton
methods of the module.  For example, ``sqrt`` is the module function defined in
``Math`` module.  It can be call in the form like ::

  Math.sqrt(4)

or ::

  include Math
  sqrt(4)

To define module functions, use ::

  void rb_define_module_function(VALUE module, const char *name, 
                                 VALUE (*func)(), int argc)

Oh, in addition, function-like methods, which are private methods defined in
the ``Kernel`` module, can be defined using ::

  void rb_define_global_function(const char *name, VALUE (*func)(), int argc)

Furthermore, to define an method alias, use ::

  void rb_define_alias(VALUE module, const char* new, const char* old);

Constant Definitions
~~~~~~~~~~~~~~~~~~~~

We have 2 functions to define constants::

  void rb_define_const(VALUE klass, const char *name, VALUE val)
  void rb_define_global_const(const char *name, VALUE val)

The former is to define a constant under specified class/module.  The latter is
to define a global constant.


Use Ruby Features from C
------------------------

There are several ways to invoke Ruby's features from C code.

Evaluate Ruby Programs in a String
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The easiest way to use Ruby's functionality from a C program is to
evaluate the string as Ruby program.  This function will do the job::

  VALUE rb_eval_string(const char *str)

Evaluation is done under the current context, thus current local variables
of the innermost method (which is defined by Ruby) can be accessed.

``ID`` or ``Symbol``
~~~~~~~~~~~~~~~~~~~~

You can invoke methods directly, without parsing the string.  First I need to
explain about symbols (whose data type is ``ID``).  ``ID`` is the integer
number to represent Ruby's identifiers such as variable names.  It can be
accessed from Ruby in the form ::

  :identifier

You can get the symbol value from a string within C code by using ::

  rb_intern(const char *name)

Invoke Ruby Method from C
~~~~~~~~~~~~~~~~~~~~~~~~~

To invoke methods directly, you can use the function below ::

  VALUE rb_funcall(VALUE recv, ID mid, int argc, ...)

This function invokes a method on the ``recv``, with the method name
specified by the symbol ``mid``.

Accessing the Variables and Constants
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can access class variables and instance variables using access functions.
Also, global variables can be shared between both environments.  There's no way
to access Ruby's local variables.

The functions to access/modify instance variables are below::

  VALUE rb_ivar_get(VALUE obj, ID id)
  VALUE rb_ivar_set(VALUE obj, ID id, VALUE val)

``id`` must be the symbol, which can be retrieved by ``rb_intern()``.

To access the constants of the class/module::

  VALUE rb_const_get(VALUE obj, ID id)

See `Constant Definitions`_ for defining new constant.



Information Sharing Between Ruby and C
======================================


Ruby Constants that can be Accessed from C
------------------------------------------

The following Ruby constants can be referred from C::

  Qtrue
  Qfalse

which are the boolean values.  ``Qfalse`` is ``false`` in C also (i.e., it's
0).

::

  Qnil

Ruby ``nil`` in C scope.


Global Variables Shared Between C and Ruby
------------------------------------------

Information can be shared between the two environments using shared global
variables.  To define them, you can use functions listed below::

  void rb_define_variable(const char *name, VALUE *var)

This function defines the variable which is shared by both environments.  The
value of the global variable pointed to by ``var`` can be accessed through
Ruby's global variable named ``name``.

You can define read-only (from Ruby, of course) variables using the function
below. ::

  void rb_define_readonly_variable(const char *name, VALUE *var)

You can defined hooked variables.  The accessor functions (getter and setter)
are called on access to the hooked variables. ::

  void rb_define_hooked_variable(constchar *name, VALUE *var,
                                 VALUE (*getter)(), void (*setter)())

If you need to supply either setter or getter, just supply ``NULL`` for the
hook you don't need.  If both hooks are ``NULL``,
``rb_define_hooked_variable()`` works just like ``rb_define_variable()``. ::

  void rb_define_virtual_variable(const char *name,
                                  VALUE (*getter)(), void (*setter)())

This function defines a Ruby global variable without a corresponding C
variable.  The value of the variable will be set/get only by hooks.

The prototypes of the getter and setter functions are as follows::

  (*getter)(ID id, void *data, struct global_entry* entry);
  (*setter)(VALUE val, ID id, void *data, struct global_entry* entry);


Encapsulate C Data into Ruby Object
-----------------------------------

To wrap and objectify a C pointer as a Ruby object (so called ``DATA``), use
``Data_Wrap_Struct()``. ::

  Data_Wrap_Struct(klass, mark, free, ptr)

``Data_Wrap_Struct()`` returns a created ``DATA`` object.  The ``klass`` argument
is the class for the ``DATA`` object.  The ``mark`` argument is the function to mark
Ruby objects pointed by this data.  The ``free`` argument is the function to free
the pointer allocation.  If this is -1, the pointer will be just freed.  The
functions ``mark`` and ``free`` will be called from garbage collector.

You can allocate and wrap the structure in one step. ::

  Data_Make_Struct(klass, type, mark, free, sval)

This macro returns an allocated ``Data`` object, wrapping the pointer to the
structure, which is also allocated.  This macro works like ::

  (sval = ALLOC(type), Data_Wrap_Struct(klass, mark, free, sval))

Arguments ``klass``, ``mark``, and ``free`` work like their counterparts in
``Data_Wrap_Struct()``.  A pointer to the allocated structure will be assigned
to ``sval``, which should be a pointer of the type specified.

To retrieve the C pointer from the ``Data`` object, use the macro
``Data_Get_Struct()``. ::

  Data_Get_Struct(obj, type, sval)

A pointer to the structure will be assigned to the variable ``sval``.

See the example below for details. 



Example - Creating a DBM Extension
==================================

OK, here's the example of making an extension library.  This is the extension
to access DBMs.  The full source is included in the ``ext/`` directory in the
Ruby's source tree.


Make the Directory
------------------

::

  % mkdir ext/dbm

Make a directory for the extension library under ext directory.


Create ``MANIFEST`` File
------------------------

::

  % cd ext/dbm
  % touch MANIFEST

There should be ``MANIFEST`` file in the directory for the extension
library.  Make an empty file for now.

Design the Library
------------------

You need to design the library features, before making it.

Write C Code
------------

You need to write C code for your extension library.  If your library has
only one source file, choosing *LIBRARY*\ ``.c`` as a file name is preferred.
On the other hand, in case your library has multiple source files, avoid
choosing *LIBRARY*\ ``.c`` for a file name.  It may conflict with an
intermediate file *LIBRARY*\ ``.o`` on some platforms.

Ruby will execute the initializing function named ``Init_``\ *LIBRARY* in the
library.  For example, ``Init_``\ *dbm*\ ``()`` will be executed when loading
the library.

Here's the example of an initializing function::

  Init_dbm()
  {
      /* define DBM class */
      cDBM = rb_define_class("DBM", rb_cObject);
      /* DBM includes Enumerate module */
      rb_include_module(cDBM, rb_mEnumerable);

      /* DBM has class method open(): arguments are received as C array */
      rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1);

      /* DBM instance method close(): no args */
      rb_define_method(cDBM, "close", fdbm_close, 0);
      /* DBM instance method []: 1 argument */
      rb_define_method(cDBM, "[]", fdbm_fetch, 1);
                  :

      /* ID for a instance variable to store DBM data */
      id_dbm = rb_intern("dbm");
  }

The dbm extension wraps the dbmdata ``struct`` in the C environment using
``Data_Make_Struct``::

  struct dbmdata {
      int  di_size;
      DBM *di_dbm;
  };


  obj = Data_Make_Struct(klass, struct dbmdata, 0, free_dbm, dbmp);

This code wraps the ``dbmdata`` structure into a Ruby object.  We avoid
wrapping ``DBM*`` directly, because we want to cache size information.

To retrieve the ``dbmdata`` structure from a Ruby object, we define the
following macro::

  #define GetDBM(obj, dbmp) {\
      Data_Get_Struct(obj, struct dbmdata, dbmp);\
      if (dbmp->di_dbm == 0) closed_dbm();\
  }

This sort of complicated macro does the retrieving and close checking for the
DBM.

There are three kinds of way to receive method arguments.  First, methods with
a fixed number of arguments receive arguments like this::

  static VALUE
  fdbm_delete(obj, keystr)
      VALUE obj, keystr;
  {
          :
  }

The first argument of the C function is the self, the rest are the arguments to
the method.

Second, methods with an arbitrary number of arguments receive arguments like
this::

  static VALUE
  fdbm_s_open(argc, argv, klass)
      int argc;
      VALUE *argv;
      VALUE klass;
  {
          :
      if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) {
          mode = 0666;            /* default value */
      }
          :
  }

The first argument is the number of method arguments, the second argument is
the C array of the method arguments, and the third argument is the receiver of
the method.

You can use the function ``rb_scan_args()`` to check and retrieve the
arguments.  For example, ``"11"`` means that the method requires at least one
argument, and at most receives two arguments.

Methods with an arbitrary number of arguments can receive arguments by Ruby's
array, like this::

  static VALUE
  fdbm_indexes(obj, args)
      VALUE obj, args;
  {
          :
  }

The first argument is the receiver, the second one is the Ruby array
which contains the arguments to the method.

.. note::

  GC should know about global variables which refer to Ruby's objects, but are
  not exported to the Ruby world.  You need to protect them by ::

    void rb_global_variable(VALUE *var)

Prepare ``extconf.rb``
----------------------

If the file named ``extconf.rb`` exists, it will be executed to generate
``Makefile``.  If not, the compilation scheme will try to generate ``Makefile``
anyway.

``extconf.rb`` is the file for check compilation conditions etc.  You need to
put ::

  require 'mkmf'

at the top of the file.  You can use the functions below to check various
conditions.

=========================== =================================================
Function                    Check
=========================== =================================================
``have_library(lib, func)`` check whether library containing function exists.
``have_func(func, header)`` check whether function exists
``have_header(header)``     check whether header file exists
``create_makefile(target)`` generate Makefile
=========================== =================================================

The value of the variables below will affect the Makefile.

============  =============================================================
Variable      Effect
============  =============================================================
``$CFLAGS``   included in ``CFLAGS`` ``make(1)`` variable (such as ``-I``)
``$LDFLAGS``  included in ``LDFLAGS`` ``make(1)`` variable (such as ``-L``)
============  =============================================================

If a compilation condition is not fulfilled, you should not call
``create_makefile``.  The Makefile will not generated, compilation will not be
done.


Prepare ``depend`` (optional)
-----------------------------

If the file named ``depend`` exists, ``Makefile`` will include that file to
check dependencies.  You can make this file by invoking ::

  % gcc -MM *.c > depend

It's no harm.  Prepare it.


Put File Names into ``MANIFEST`` (optional)
-------------------------------------------

::

  % find * -type f -print > MANIFEST
  % vi MANIFEST

Append file names into ``MANIFEST``.  The compilation scheme requires
``MANIFEST`` only to exist, but it's better to take this step in order to
distinguish which files are required.


Generate ``Makefile``
---------------------

Try generating the Makefile by running ::

  % ruby extconf.rb

You don't need this step if you put the extension library under the ``ext``
directory of the ruby source tree.  In that case, compilation of the
interpreter will do this step for you.

``make(1)``
-----------

Type ::

  % make

to compile your extension.  You don't need this step either if you have put the
extension library under the ``ext`` directory of the ruby source tree.

Debug
-----

You may need to ``rb_debug`` the extension.  Extensions can be linked
statically by the adding directory name in the ``ext/Setup`` file so that you
can inspect the extension with the debugger.


Done, now you Have the Extension Library
----------------------------------------

You can do anything you want with your library.  The author of Ruby will not
claim any restrictions on your code depending on the Ruby API.  Feel free to
use, modify, distribute or sell your program.



Appendix A. Ruby Source Files Overview
======================================


Ruby Language Core
  ``class.c``
  ``error.c``
  ``eval.c``
  ``gc.c``
  ``object.c``
  ``parse.y``
  ``variable.c``

Utility Functions
  ``dln.c``
  ``regex.c``
  ``st.c``
  ``util.c``

Ruby Interpreter Implementation
  ``dmyext.c``
  ``inits.c``
  ``main.c``
  ``ruby.c``
  ``version.c``

Class Library
  ``array.c``
  ``bignum.c``
  ``compar.c``
  ``dir.c``
  ``enum.c``
  ``file.c``
  ``hash.c``
  ``io.c``
  ``marshal.c``
  ``math.c``
  ``numeric.c``
  ``pack.c``
  ``prec.c``
  ``process.c``
  ``random.c``
  ``range.c``
  ``re.c``
  ``signal.c``
  ``sprintf.c``
  ``string.c``
  ``struct.c``
  ``time.c``



Appendix B. Ruby Extension API Reference
========================================


Types
-----

``VALUE``
  The type for the Ruby object.  Actual structures are defined in ``ruby.h``,
  such as ``struct RString``, etc.  To refer the values in structures, use
  casting macros like ``RSTRING(obj)``.


Variables and Constants
-----------------------

``Qnil``
  const: ``nil`` object

``Qtrue``
  const: ``true`` object (default true value)

``Qfalse``
  const: ``false`` object


C Pointer Wrapping
------------------

``Data_Wrap_Struct(VALUE klass, void (*mark)(), void (*free)(), void *sval)``
  Wrap a C pointer into a Ruby object.  If object has references to other Ruby
  objects, they should be marked by using the ``mark`` function during the GC
  process.  Otherwise, ``mark`` should be ``NULL``.  When this object is no
  longer referred by anywhere, the pointer will be discarded by ``free``
  function.

``Data_Make_Struct(klass, type, mark, free, sval)``
  This macro allocates memory using ``malloc()``, assigns it to the variable
  ``sval``, and returns the ``DATA`` encapsulating the pointer to memory
  region.

``Data_Get_Struct(data, type, sval)``
  This macro retrieves the pointer value from ``DATA``, and assigns it to the
  variable ``sval``. 


Checking Data Types
-------------------

``TYPE(value)``
``FIXNUM_P(value)``
``NIL_P(value)``
``void Check_Type(VALUE value, int type)``
``void Check_SafeStr(VALUE value)``


Data Type Conversion
--------------------

``FIX2INT(value)``
``INT2FIX(i)``
``NUM2INT(value)``
``INT2NUM(i)``
``NUM2DBL(value)``
``rb_float_new(f)``
``STR2CSTR(value)``
``rb_str_new2(s)``

Defining Class/Module
---------------------

``VALUE rb_define_class(const char *name, VALUE super)``
  Defines a new Ruby class as a subclass of ``super``.

``VALUE rb_define_class_under(VALUE module, const char *name, VALUE super)``
  Creates a new Ruby class as a subclass of ``super``, under the module's
  namespace.

``VALUE rb_define_module(const char *name)``
  Defines a new Ruby module.

``VALUE rb_define_module_under(VALUE module, const char *name, VALUE super)``
  Defines a new Ruby module under the module's namespace.

``void rb_include_module(VALUE klass, VALUE module)``
  Includes module into ``klass``.  If ``klass`` already includes it, just
  ignored.

``void rb_extend_object(VALUE object, VALUE module)``
  Extend the object with the module's attributes.


Defining Global Variables
-------------------------

``void rb_define_variable(const char *name, VALUE *var)``
  Defines a global variable which is shared between C and Ruby.  If ``name``
  contains a character which is not allowed to be part of the symbol, it can't
  be seen from Ruby programs.

``void rb_define_readonly_variable(const char *name, VALUE *var)``
  Defines a read-only global variable.  Works just like
  ``rb_define_variable()``, except defined variable is read-only.

``void rb_define_virtual_variable(const char *name, VALUE (*getter)(), VALUE (*setter)())``

Defines a virtual variable, whose behavior is defined by a pair of C functions.
The ``getter`` function is called when the variable is referred.  The
``setter`` function is called when the value is set to the variable.  The
prototype for getter/setter functions are::

  VALUE getter(ID id)
  void setter(VALUE val, ID id)

The getter function must return the value for the access.

``void rb_define_hooked_variable(const char *name, VALUE *var, VALUE (*getter)(), VALUE (*setter)())``

Defines hooked variable.  It's a virtual variable with a C variable.  
The getter is called as ::

  VALUE getter(ID id, VALUE *var)

returning a new value.  The setter is called as ::

  void setter(VALUE val, ID id, VALUE *var)

GC requires C global variables which hold Ruby values to be marked.

``void rb_global_variable(VALUE *var)``

Tells GC to protect these variables.


Constant Definition
-------------------

``void rb_define_const(VALUE klass, const char *name, VALUE val)``
  Defines a new constant under the class/module.

``void rb_define_global_const(const char *name, VALUE val)``
  Defines a global constant.  This is just the same as ::

     rb_define_const(cKernal, name, val)


Method Definition
-----------------

``rb_define_method(VALUE klass, const char *name, VALUE (*func)(), int argc)``
  Defines a method for the class.  ``func`` is the function pointer.  ``argc``
  is the number of arguments.  if ``argc`` is -1, the function will receive 3
  arguments: ``argc``, ``argv``, and ``self``.  if ``argc`` is -2, the function
  will receive 2 arguments, ``self`` and ``args``, where ``args`` is a Ruby
  array of the method arguments.

``rb_define_private_method(VALUE klass, const char *name, VALUE (*func)(), int argc)``
  Defines a private method for the class.  Arguments are same as
  ``rb_define_method()``.

``rb_define_singleton_method(VALUE klass, const char *name, VALUE (*func)(), int argc)``
  Defines a singleton method.  Arguments are same as ``rb_define_method()``.

``rb_scan_args(int argc, VALUE *argv, const char *fmt, ...)``
  Retrieve argument from ``argc`` and ``argv``.  The ``fmt`` is the format
  string for the arguments, such as ``"12"`` for 1 non-optional argument, 2
  optional arguments.  If ``*`` appears at the end of ``fmt``, it means the
  rest of the arguments are assigned to the corresponding variable, packed in
  an array.


Invoking Ruby Method
--------------------

``VALUE rb_funcall(VALUE recv, ID mid, int narg, ...)``
  Invokes a method.  To retrieve ``mid`` from a method name, use
  ``rb_intern()``.

``VALUE rb_funcall2(VALUE recv, ID mid, int argc, VALUE *argv)``
  Invokes a method, passing arguments by an array of values.

``VALUE rb_eval_string(const char *str)``
  Compiles and executes the string as a Ruby program.

``ID rb_intern(const char *name)``
  Returns ID corresponding to the name.

``char *rb_id2name(ID id)``
  Returns the name corresponding ID.

``char *rb_class2name(VALUE klass)``
  Returns the name of the class.

``int rb_respond_to(VALUE object, ID id)``
  Returns ``true`` if the object responds to the message specified by ``id``.


Instance Variables
------------------

``VALUE rb_iv_get(VALUE obj, const char *name)``
  Retrieve the value of the instance variable.  If the name is not prefixed by
  ``@``, that variable will be inaccessible from Ruby.

``VALUE rb_iv_set(VALUE obj, const char *name, VALUE val)``
  Sets the value of the instance variable.


Control Structure
-----------------

``VALUE rb_iterate(VALUE (*func1)(), void *arg1, VALUE (*func2)(), void *arg2)``
  Calls the function ``func1``, supplying ``func2`` as the block.  ``func1``
  will be called with the argument ``arg1``.  ``func2`` receives the value from
  yield as the first argument, ``arg2`` as the second argument.
 
``VALUE rb_yield(VALUE val)``
  Evaluates the block with value ``val``.

``VALUE rb_rescue(VALUE (*func1)(), void *arg1, VALUE (*func2)(), void *arg2)``
  Calls the function ``func1``, with ``arg1`` as the argument.  If an exception
  occurs during ``func1``, it calls ``func2`` with ``arg2`` as the argument.
  The return value of ``rb_rescue()`` is the return value from ``func1`` if no
  exception occurs, from ``func2`` otherwise.

``VALUE rb_ensure(VALUE (*func1)(), void *arg1, void (*func2)(), void *arg2)``
  Calls the function ``func1`` with ``arg1`` as the argument, then calls
  ``func2`` with ``arg2`` if execution terminated.  The return value from
  ``rb_ensure()`` is that of ``func1``.


Exceptions and Errors
---------------------

``void rb_warn(const char *fmt, ...)``
  Prints a warning message according to a ``printf``\ -like format.

``void rb_warning(const char *fmt, ...)``
  Prints a warning message according to a ``printf``\ -like format, if
  ``$VERBOSE`` is ``true``.

``void rb_raise(rb_eRuntimeError, const char *fmt, ...)``
  Raises ``RuntimeError``.  The ``fmt`` is a format string just like
  ``printf()``.

``void rb_raise(VALUE exception, const char *fmt, ...)``
  Raises a class exception.  The ``fmt`` is a format string just like
  ``printf()``.

``void rb_fatal(const char *fmt, ...)``
  Raises a fatal error, terminates the interpreter.  No exception handling will
  be done for fatal errors, but ensure blocks will be executed.

``void rb_bug(const char *fmt, ...)``
  Terminates the interpreter immediately.  This function should be called under
  the situation caused by the bug in the interpreter.  No exception handling
  nor ensure execution will be done.

Initialize and Starting the Interpreter
---------------------------------------

The embedding API functions are below (not needed for extension libraries).

``void ruby_init()``
  Initializes the interpreter.

``void ruby_options(int argc, char **argv)``
  Process command line arguments for the interpreter.

``void ruby_run()``
  Starts execution of the interpreter.

``void ruby_script(char *name)``
  Specifies the name of the script ($0).



Appendix C. Functions Available in ``extconf.rb``
=================================================


The following functions are available in ``extconf.rb``.

``have_library(lib, func)``
  Checks whether the library exists, containing the specified function.
  Returns true if the library exists.

``find_library(lib, func, path...)``
  Checks whether a library which contains the specified function exists in
  ``path``.  Returns true if the library exists.

``have_func(func, header)``
  Checks whether ``func`` exists with ``header``.  Returns true if the function
  exists.  To check functions in an additional library, you need to check that
  library first using ``have_library()``.

``have_header(header)``
  Checks whether ``header`` exists.  Returns true if the header file exists.

``create_makefile(target)``
  Generates the Makefile for the extension library.  If you don't invoke this
  method, the compilation will not be done.

``with_config(withval[, default=nil])``
  Parses the command line options and returns the value specified by
  ``--with-<withval>``.

``dir_config(target[, default_dir])``
  See below.

``dir_config(target[, default_include, default_lib])``
  Parses the command line options and adds the directories specified by
  ``--with-<target>-dir``, ``--with-<target>-include``, and/or
  ``--with-<target>-lib`` to ``$CFLAGS`` and/or ``$LDFLAGS``.
  ``--with-<target>-dir=/path`` is equivalent to
  ``--with-<target>-include=/path/include --with-<target>-lib=/path/lib``.
  Returns an array of the added directories (``[include_dir, lib_dir]``).



.. arch-tag: a88f96c7-556b-4505-a963-72e8cdbc8d0f
.. vim: set ft=rst et sw=2 sts=2:

^ permalink raw reply	[relevance 1%]

* Re: T_BLKTAG
  @ 2005-10-15  6:48  5% ` Yukihiro Matsumoto
  0 siblings, 0 replies; 71+ results
From: Yukihiro Matsumoto @ 2005-10-15  6:48 UTC (permalink / raw)
  To: ruby-core

Hi,

In message "Re: T_BLKTAG"
    on Sat, 15 Oct 2005 15:34:58 +0900, Charles Mills <cmills@freeshell.org> writes:

|What is T_BLKTAG used for?  I see it in the Ruby sources, but the  
|only place it is used is in ruby.h and gc.c.  No objects with type  
|T_BLKTAG are ever created.

It's sentinel marker to denote non-object value type (T_NODE etc).

							matz.

^ permalink raw reply	[relevance 5%]

* GC tweak
@ 2005-07-13 17:17  3% Stefan Kaes
  0 siblings, 0 replies; 71+ results
From: Stefan Kaes @ 2005-07-13 17:17 UTC (permalink / raw)
  To: ruby-core

[-- Attachment #1: Type: text/plain, Size: 1002 bytes --]

I have found that the performance of current garbage collector 
implementation very much depends on the code size of the application. 
The behaviour is not linear in the code size. Sometimes adding more code 
will cause run GC less often, sometimes it will cause more collections, 
because the code's AST just fits inside the available heap. Especially 
for long running server applications, like RAILS, this behaviour leaves 
a lot to be desired.

I have created a small patch that enables several GC parameters to be 
set using environment variables. Most importantly, the initial heap size 
can be specified (RUBY_HEAP_MIN_SLOTS) and GC statistics can be obtained 
by setting RUBY_GC_STATS to 1.

By tuning the initial heap size and RUBY_GC_MALLOC_LIMIT, I have seen 
improvements ranging from 10 to 30%.

I would really like to see something like this included in 1.8.3 or 1.9, 
if possible. The patch is farely trivial, and does not change any GC 
internals.

Any comments?

Cheers,

Stefan Kaes


[-- Attachment #2: rubygc.patch --]
[-- Type: text/plain, Size: 6842 bytes --]

--- gc.c.orig	2005-06-30 09:53:27.000000000 +0200
+++ gc.c	2005-07-03 16:59:41.815484680 +0200
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <setjmp.h>
 #include <sys/types.h>
+#include <strings.h>
 
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
@@ -118,6 +119,7 @@
     if (malloc_increase > malloc_limit) {
 	garbage_collect();
     }
+
     RUBY_CRITICAL(mem = malloc(size));
     if (!mem) {
 	garbage_collect();
@@ -308,7 +310,7 @@
 static RVALUE *freelist = 0;
 static RVALUE *deferred_final_list = 0;
 
-#define HEAPS_INCREMENT 10
+static int heaps_increment = 10;
 static struct heaps_slot {
     RVALUE *slot;
     int limit;
@@ -316,13 +318,57 @@
 static int heaps_length = 0;
 static int heaps_used   = 0;
 
-#define HEAP_MIN_SLOTS 10000
-static int heap_slots = HEAP_MIN_SLOTS;
+static int heap_min_slots = 10000;
+static int heap_slots = 10000;
+
+static int heap_free_min = 4096;
 
-#define FREE_MIN  4096
+static long initial_malloc_limit = GC_MALLOC_LIMIT;
+
+static int gc_stats = 0;
 
 static RVALUE *himem, *lomem;
 
+static void set_gc_parameters()
+{
+    char* min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS");
+    if (min_slots_ptr != NULL) {
+	int min_slots_i = atoi(min_slots_ptr);
+	if (min_slots_i > 0) {
+	    heap_slots = min_slots_i;
+	    heap_min_slots = min_slots_i;
+	}
+    }
+    char* free_min_ptr = getenv("RUBY_HEAP_FREE_MIN");
+    if (free_min_ptr != NULL) {
+	int free_min_i = atoi(free_min_ptr);
+	if (free_min_i > 0) {
+	    heap_free_min = free_min_i;
+	}
+    }
+    char* heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT");
+    if (heap_incr_ptr != NULL) {
+	int heap_incr_i = atoi(heap_incr_ptr);
+	if (heap_incr_i > 0) {
+	    heaps_increment = heap_incr_i;
+	}
+    }
+    char* gc_stats_ptr = getenv("RUBY_GC_STATS");
+    if (gc_stats_ptr != NULL) {
+	int gc_stats_i = atoi(gc_stats_ptr);
+	if (gc_stats_i > 0) {
+	    gc_stats = gc_stats_i;
+	}
+    }
+    char* malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT");
+    if (malloc_limit_ptr != NULL) {
+	int malloc_limit_i = atol(malloc_limit_ptr);
+	if (malloc_limit_i > 0) {
+	    initial_malloc_limit = malloc_limit_i;
+	}
+    }
+}
+
 static void
 add_heap()
 {
@@ -333,7 +379,7 @@
 	struct heaps_slot *p;
 	int length;
 
-	heaps_length += HEAPS_INCREMENT;
+	heaps_length += heaps_increment;
 	length = heaps_length*sizeof(struct heaps_slot);
 	RUBY_CRITICAL(
 	    if (heaps_used > 0) {
@@ -350,10 +396,10 @@
 	RUBY_CRITICAL(p = heaps[heaps_used].slot = (RVALUE*)malloc(sizeof(RVALUE)*heap_slots));
 	heaps[heaps_used].limit = heap_slots;
 	if (p == 0) {
-	    if (heap_slots == HEAP_MIN_SLOTS) {
+	    if (heap_slots == heap_min_slots) {
 		rb_memerror();
 	    }
-	    heap_slots = HEAP_MIN_SLOTS;
+	    heap_slots = heap_min_slots;
 	    continue;
 	}
 	break;
@@ -1031,6 +1077,39 @@
     }
 }
 
+static char* obj_type(int tp)
+{
+    switch (tp) {
+	case T_NIL    : return "NIL";   
+	case T_OBJECT : return "OBJECT";
+	case T_CLASS  : return "CLASS";
+	case T_ICLASS : return "ICLASS";
+	case T_MODULE : return "MODULE";
+	case T_FLOAT  : return "FLOAT";
+	case T_STRING : return "STRING";
+	case T_REGEXP : return "REGEXP";
+	case T_ARRAY  : return "ARRAY";
+	case T_FIXNUM : return "FIXNUM";
+	case T_HASH   : return "HASH";
+	case T_STRUCT : return "STRUCT";
+	case T_BIGNUM : return "BIGNUM";
+	case T_FILE   : return "FILE";
+	    
+	case T_TRUE   : return "TRUE";
+	case T_FALSE  : return "FALSE";
+	case T_DATA   : return "DATA";
+	case T_MATCH  : return "MATCH";
+	case T_SYMBOL : return "SYMBOL";
+	    
+	case T_BLKTAG : return "BLKTAG";
+	case T_UNDEF  : return "UNDEF";
+	case T_VARMAP : return "VARMAP";
+	case T_SCOPE  : return "SCOPE";
+	case T_NODE   : return "NODE";
+	default: return "____";
+    }
+}
+
 static void
 gc_sweep()
 {
@@ -1039,6 +1118,14 @@
     int i;
     unsigned long live = 0;
 
+    unsigned long really_freed = 0;
+    int free_counts[256];
+    int live_counts[256];
+
+    if (gc_stats) {
+	for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; }
+    }
+
     if (ruby_in_compile && ruby_parser_stack_on_heap()) {
 	/* should not reclaim nodes during compilation
            if yacc's semantic stack is not allocated on machine stack */
@@ -1068,6 +1155,9 @@
 	    if (!(p->as.basic.flags & FL_MARK)) {
 		if (p->as.basic.flags) {
 		    obj_free((VALUE)p);
+		    if (gc_stats) {
+			really_freed++;
+		    }
 		}
 		if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
 		    p->as.free.flags = FL_MARK; /* remain marked */
@@ -1075,6 +1165,12 @@
 		    final_list = p;
 		}
 		else {
+		    if (gc_stats) {
+			int obt = p->as.basic.flags & T_MASK;
+			if (obt) {
+			    free_counts[obt]++;
+			}
+		    }
 		    p->as.free.flags = 0;
 		    p->as.free.next = freelist;
 		    freelist = p;
@@ -1088,10 +1184,13 @@
 	    else {
 		RBASIC(p)->flags &= ~FL_MARK;
 		live++;
+		if (gc_stats) {
+		    live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++;
+		}
 	    }
 	    p++;
 	}
-	if (n == heaps[i].limit && freed > FREE_MIN) {
+	if (n == heaps[i].limit && freed > heap_free_min) {
 	    RVALUE *pp;
 
 	    heaps[i].limit = 0;
@@ -1106,14 +1205,28 @@
     }
     if (malloc_increase > malloc_limit) {
 	malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
-	if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
+	if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit;
     }
     malloc_increase = 0;
-    if (freed < FREE_MIN) {
+    if (freed < heap_free_min) {
 	add_heap();
     }
     during_gc = 0;
 
+    if (gc_stats) {
+	fprintf(stderr, "objects processed: %.7d\n", live+freed);
+	fprintf(stderr, "live objects     : %.7d\n", live);
+	fprintf(stderr, "freelist objects : %.7d\n", freed - really_freed);
+	fprintf(stderr, "freed objects    : %.7d\n", really_freed);
+	for(i=0; i<256; i++) {
+	    if (free_counts[i]>0) {
+		fprintf(stderr,
+			"kept %.7d / freed %.7d objects of type %s\n",
+			live_counts[i], free_counts[i], obj_type(i));
+	    }
+	}
+    }
+
     /* clear finalization list */
     if (final_list) {
 	deferred_final_list = final_list;
@@ -1327,6 +1440,12 @@
     if (during_gc) return;
     during_gc++;
 
+    struct timeval gctv1, gctv2;
+    if (gc_stats) {
+	gettimeofday(&gctv1, NULL);
+	fprintf(stderr, "Garbage collection started\n");
+    }
+
     init_mark_stack();
     
     /* mark frame stack */
@@ -1409,6 +1528,16 @@
 	}
     }
     gc_sweep();
+
+    if (gc_stats) {
+	gettimeofday(&gctv2, NULL);
+	fprintf(stderr, "Garbage collection completed\n");
+	gettimeofday(&gctv2, NULL);
+	fprintf(stderr, "GC time: %d msec\n",
+		((gctv2.tv_sec * 1000000 + gctv2.tv_usec)
+		-(gctv1.tv_sec * 1000000 + gctv1.tv_usec))/1000);
+    }
+
 }
 
 void
@@ -1530,6 +1659,7 @@
     if (!rb_gc_stack_start) {
 	Init_stack(0);
     }
+    set_gc_parameters();
     add_heap();
 }
 

^ permalink raw reply	[relevance 3%]

* Re: _id2ref bug? (another break)
  2003-08-16  9:35  5%               ` ts
@ 2003-08-16 11:02  0%                 ` nobu.nokada
  0 siblings, 0 replies; 71+ results
From: nobu.nokada @ 2003-08-16 11:02 UTC (permalink / raw)
  To: ruby-core

Hi,

At Sat, 16 Aug 2003 18:35:30 +0900,
ts wrote:
> R> This isn't so strange.  If T_NODE are kept in the same pool as
> R> everything else, then it's entirely possible to get one by accident,
> 
>  and this means that you have a bug in your source. You can retrieve a
>  valid object, which was not the original object : difficult to trust your
>  code in this case.

Ryan is correct.

  $ ruby -e 'x = ""; eval("x"); y = ""; x = [x.id, y.id]; x.min.step(x.max, 10){|i| p ObjectSpace._id2ref(i)}'
  ""
  -e:1: [BUG] Segmentation fault
  ruby 1.8.0 (2003-08-15) [i686-linux]

  Aborted (core dumped)

And I guess this would make better message than
[ruby-core:01417].

\f
Index: gc.c
===================================================================
RCS file: /cvs/ruby/src/ruby/gc.c,v
retrieving revision 1.155
diff -u -2 -p -r1.155 gc.c
--- gc.c	14 Aug 2003 17:19:23 -0000	1.155
+++ gc.c	16 Aug 2003 10:58:42 -0000
@@ -1637,8 +1637,8 @@ id2ref(obj, id)
 
     ptr = id ^ FIXNUM_FLAG;	/* unset FIXNUM_FLAG */
-    if (!is_pointer_to_heap((void *)ptr)) {
+    if (!is_pointer_to_heap((void *)ptr) || BUILTIN_TYPE(ptr) >= T_BLKTAG) {
 	rb_raise(rb_eRangeError, "0x%lx is not id value", p0);
     }
-    if (RBASIC(ptr)->klass == 0) {
+    if (BUILTIN_TYPE(ptr) == 0 || RBASIC(ptr)->klass == 0) {
 	rb_raise(rb_eRangeError, "0x%lx is recycled object", p0);
     }
\f

-- 
Nobu Nakada

^ permalink raw reply	[relevance 0%]

* Re: _id2ref bug? (another break)
  2003-08-15 17:42  7%             ` Ryan Pavlik
@ 2003-08-16  9:35  5%               ` ts
  2003-08-16 11:02  0%                 ` nobu.nokada
  0 siblings, 1 reply; 71+ results
From: ts @ 2003-08-16  9:35 UTC (permalink / raw)
  To: ruby-core; +Cc: ruby-core

>>>>> "R" == Ryan Pavlik <rpav@users.sourceforge.net> writes:

R> This isn't so strange.  If T_NODE are kept in the same pool as
R> everything else, then it's entirely possible to get one by accident,

 and this means that you have a bug in your source. You can retrieve a
 valid object, which was not the original object : difficult to trust your
 code in this case.


Guy Decoux

^ permalink raw reply	[relevance 5%]

* Re: _id2ref bug? (another break)
  2003-08-15 10:17  5%           ` ts
@ 2003-08-15 17:42  7%             ` Ryan Pavlik
  2003-08-16  9:35  5%               ` ts
  0 siblings, 1 reply; 71+ results
From: Ryan Pavlik @ 2003-08-15 17:42 UTC (permalink / raw)
  To: ruby-core

On Fri, 15 Aug 2003 19:17:14 +0900
ts <decoux@moulon.inra.fr> wrote:

> >>>>> "n" == nobu nokada <nobu.nokada@softhome.net> writes:
> 
> n> BUILTIN_TYPE 63 is T_NODE, which must not appear in Ruby.  Try
> n> with changing the patched line as following.
> 
>  I find this strange and I see only 2 possibilities :
>     * he make something strange in his module
>     * he has a bug
> 
>  Can I see the complete source of his module ?

The only modules I'm using (in addition to anything builtin) are MySQL
and StrongTyping, neither of which deal with T_NODE afaik.

This isn't so strange.  If T_NODE are kept in the same pool as
everything else, then it's entirely possible to get one by accident,
given IDs are basically pointers.  I have checks in place to validate
objects (make sure the one I get back from the weakref is the original I
was looking for), it's just T_NODE and the other internal ones don't
work right from ruby (I'm guessing they're not "real" ruby objects).

Anyway, the original caching code I posted is nearly identical to what's
going on.  I just have enough code and data passing through the system
that eventually I get a T_NODE reference, I guess.

(Actually the cache code I posted has a minor bug, in that it doesn't
validate the object it gets back, you just need to add

    return nil unless o._oid == oid

right after the _id2ref line.)


-- 
Ryan Pavlik <rpav@users.sf.net>

"Oh for the love of evil, not this again." - 8BT

^ permalink raw reply	[relevance 7%]

* Re: _id2ref bug? (another break)
  2003-08-15  3:35  5%         ` nobu.nokada
  2003-08-15  4:19  0%           ` Ryan Pavlik
@ 2003-08-15 10:17  5%           ` ts
  2003-08-15 17:42  7%             ` Ryan Pavlik
  1 sibling, 1 reply; 71+ results
From: ts @ 2003-08-15 10:17 UTC (permalink / raw)
  To: ruby-core; +Cc: ruby-core

>>>>> "n" == nobu nokada <nobu.nokada@softhome.net> writes:

n> BUILTIN_TYPE 63 is T_NODE, which must not appear in Ruby.  Try
n> with changing the patched line as following.

 I find this strange and I see only 2 possibilities :
    * he make something strange in his module
    * he has a bug

 Can I see the complete source of his module ?


Guy Decoux

^ permalink raw reply	[relevance 5%]

* Re: _id2ref bug? (another break)
  2003-08-15  3:35  5%         ` nobu.nokada
@ 2003-08-15  4:19  0%           ` Ryan Pavlik
  2003-08-15 10:17  5%           ` ts
  1 sibling, 0 replies; 71+ results
From: Ryan Pavlik @ 2003-08-15  4:19 UTC (permalink / raw)
  To: ruby-core

On Fri, 15 Aug 2003 12:35:32 +0900
nobu.nokada@softhome.net wrote:

> Hi,
> 
> At Fri, 15 Aug 2003 11:37:42 +0900,
> Ryan Pavlik wrote:
> >     printf("id2ref - %d, %d\n", BUILTIN_TYPE(ptr), RBASIC(ptr)->klass);
> > 
> > When running:
> > 
> >     id2ref - 63, 135382017
> >     /usr/local/encap/mephle-0.8.0/share/mephle/Driver/Storage_cache.rb:36:
> >     [BUG] Segmentation fault
> 
> BUILTIN_TYPE 63 is T_NODE, which must not appear in Ruby.  Try
> with changing the patched line as following.
> 
>     if (BUILTIN_TYPE(ptr) == 0 || BUILTIN_TYPE(ptr) >= T_BLKTAG ||
> 	RBASIC(ptr)->klass == 0) {

This fixes it.  Thanks.

-- 
Ryan Pavlik <rpav@users.sf.net>

"I distinctly remember dancing on your grave." - 8BT

^ permalink raw reply	[relevance 0%]

* Re: _id2ref bug? (another break)
  @ 2003-08-15  3:35  5%         ` nobu.nokada
  2003-08-15  4:19  0%           ` Ryan Pavlik
  2003-08-15 10:17  5%           ` ts
  0 siblings, 2 replies; 71+ results
From: nobu.nokada @ 2003-08-15  3:35 UTC (permalink / raw)
  To: ruby-core

Hi,

At Fri, 15 Aug 2003 11:37:42 +0900,
Ryan Pavlik wrote:
>     printf("id2ref - %d, %d\n", BUILTIN_TYPE(ptr), RBASIC(ptr)->klass);
> 
> When running:
> 
>     id2ref - 63, 135382017
>     /usr/local/encap/mephle-0.8.0/share/mephle/Driver/Storage_cache.rb:36:
>     [BUG] Segmentation fault

BUILTIN_TYPE 63 is T_NODE, which must not appear in Ruby.  Try
with changing the patched line as following.

    if (BUILTIN_TYPE(ptr) == 0 || BUILTIN_TYPE(ptr) >= T_BLKTAG ||
	RBASIC(ptr)->klass == 0) {

-- 
Nobu Nakada

^ permalink raw reply	[relevance 5%]

* RE: A truth? patch  + benchmarks
  2002-08-01  7:02  5%     ` Yukihiro Matsumoto
@ 2002-08-02  7:12  0%       ` Christoph
  0 siblings, 0 replies; 71+ results
From: Christoph @ 2002-08-02  7:12 UTC (permalink / raw)
  To: ruby-core



> -----Original Message-----
> From: Yukihiro Matsumoto [mailto:matz@ruby-lang.org]
> Sent: Thursday, August 01, 2002 9:03 AM
> To: ruby-core@ruby-lang.org
> Subject: Re: A truth? patch + benchmarks
> 
> Hi,
> 
> In message "RE: A truth? patch  + benchmarks"
>     on 02/08/01, "Christoph" <chr_news@gmx.net> writes:
> 
> |>  Not really sure but the values < 64 reserved for T_MASK
> |>
> |> #define T_NIL    0x01
> |> #define T_OBJECT 0x02
> |> [etc]
> |> #define T_NODE   0x3f
> |>
> |> #define T_MASK   0x3f
> |
> |Hm, what about using FL_USER7? More generally, is there any
> |unused flag left?
> 
> Unfortunately, there's no bit available for all objects.  All flag
> bits are used to represent NODEs' line number.

To bad ... but maybe we might see something like it in 2.0? (or
even better body smatter cooks something up for the current 
development line - maybe only replace the RTEST calls in the
crucial IF_NODE, WHILE_NODE ...  part?)

> 
> By the way, I still don't know why the inlined function is faster than
> the simple macro.  Does anybody reveal the secret for me?

I don't know (besides a not particular helpful  ``your compiler
always knows best'' ;-). Anyway  I run the two tests (on Mswin32)
subdividing the macro call RTEST(v) following strategy c) (of
my previous post)

PURE_TEST(v) = .. original macro call for
            ruby_verbose and ruby_debug test.

and setting  the rest of the RTEST(obj) macro calls to


static inline int
rb_truth_test(VALUE obj)
{
  if (~Qnil & obj) return 1;
  return 0;
}


Not surprisingly, this version tested as fast or faster then
any of my other test candidates.



/Christoph

^ permalink raw reply	[relevance 0%]

* Re: A truth? patch  + benchmarks
  2002-08-01  6:39  0%   ` Christoph
@ 2002-08-01  7:02  5%     ` Yukihiro Matsumoto
  2002-08-02  7:12  0%       ` Christoph
  0 siblings, 1 reply; 71+ results
From: Yukihiro Matsumoto @ 2002-08-01  7:02 UTC (permalink / raw)
  To: ruby-core

Hi,

In message "RE: A truth? patch  + benchmarks"
    on 02/08/01, "Christoph" <chr_news@gmx.net> writes:

|>  Not really sure but the values < 64 reserved for T_MASK
|> 
|> #define T_NIL    0x01
|> #define T_OBJECT 0x02
|> [etc]
|> #define T_NODE   0x3f
|> 
|> #define T_MASK   0x3f
|
|Hm, what about using FL_USER7? More generally, is there any 
|unused flag left?

Unfortunately, there's no bit available for all objects.  All flag
bits are used to represent NODEs' line number.

By the way, I still don't know why the inlined function is faster than
the simple macro.  Does anybody reveal the secret for me?

							matz.

^ permalink raw reply	[relevance 5%]

* RE: A truth? patch  + benchmarks
  2002-07-31 15:03  5% ` ts
@ 2002-08-01  6:39  0%   ` Christoph
  2002-08-01  7:02  5%     ` Yukihiro Matsumoto
  0 siblings, 1 reply; 71+ results
From: Christoph @ 2002-08-01  6:39 UTC (permalink / raw)
  To: ruby-core



> -----Original Message-----
> From: ts [mailto:decoux@moulon.inra.fr]
> Sent: Wednesday, July 31, 2002 5:04 PM
> To: ruby-core@ruby-lang.org
> Cc: ruby-core@ruby-lang.org
> Subject: Re: A truth? patch + benchmarks
> 
> >>>>> "C" == Christoph  <chr_news@gmx.net> writes:
> 
> C> I also cooked up simple minded an implementation. It is based on
> C> a FL_FALSE flag (I defined it to be 1<<5 not sure if this can
> C> case any problem?) similar to the frozen or tainted flags - that
> C> is I added there methods (the method names ain't great ..)
> 
>  Not really sure but the values < 64 reserved for T_MASK
> 
> #define T_NIL    0x01
> #define T_OBJECT 0x02
> [etc]
> #define T_NODE   0x3f
> 
> #define T_MASK   0x3f

Hm, what about using FL_USER7? More generally, is there any 
unused flag left?


/Christoph

^ permalink raw reply	[relevance 0%]

* Re: A truth? patch  + benchmarks
  @ 2002-07-31 15:03  5% ` ts
  2002-08-01  6:39  0%   ` Christoph
  0 siblings, 1 reply; 71+ results
From: ts @ 2002-07-31 15:03 UTC (permalink / raw)
  To: ruby-core; +Cc: ruby-core

>>>>> "C" == Christoph  <chr_news@gmx.net> writes:

C> I also cooked up simple minded an implementation. It is based on
C> a FL_FALSE flag (I defined it to be 1<<5 not sure if this can
C> case any problem?) similar to the frozen or tainted flags - that
C> is I added there methods (the method names ain't great ..)

 Not really sure but the values < 64 reserved for T_MASK

#define T_NIL    0x01
#define T_OBJECT 0x02
[etc]
#define T_NODE   0x3f

#define T_MASK   0x3f


Guy Decoux

^ permalink raw reply	[relevance 5%]

Results 1-71 of 71 | reverse | options above
-- pct% links below jump to the message on this page, permalinks otherwise --
2002-07-31 14:47     A truth? patch + benchmarks Christoph
2002-07-31 15:03  5% ` ts
2002-08-01  6:39  0%   ` Christoph
2002-08-01  7:02  5%     ` Yukihiro Matsumoto
2002-08-02  7:12  0%       ` Christoph
2003-08-14 16:45     _id2ref bug? Ryan Pavlik
2003-08-14 16:57     ` Yukihiro Matsumoto
2003-08-14 18:09       ` _id2ref bug? (REPRODUCED, short) Ryan Pavlik
2003-08-15  0:21         ` Yukihiro Matsumoto
2003-08-15  2:37           ` _id2ref bug? (another break) Ryan Pavlik
2003-08-15  3:35  5%         ` nobu.nokada
2003-08-15  4:19  0%           ` Ryan Pavlik
2003-08-15 10:17  5%           ` ts
2003-08-15 17:42  7%             ` Ryan Pavlik
2003-08-16  9:35  5%               ` ts
2003-08-16 11:02  0%                 ` nobu.nokada
2005-07-13 17:17  3% GC tweak Stefan Kaes
2005-10-15  6:34     T_BLKTAG Charles Mills
2005-10-15  6:48  5% ` T_BLKTAG Yukihiro Matsumoto
2005-10-27  3:33     Wilderness: I Have formatted README.EXT into an HTML Document Charles E. Thornton
2005-10-27 14:16  1% ` Nikolai Weibull
2006-01-23  8:43     Wilderness: NODE Obj and Class Obj --- Can they be ID'ed by inspection? Charles Thornton
2006-01-23 19:22  5% ` Charles Mills
2006-09-21 16:30     patch bignums Nobuyoshi Nakada
2006-09-21 18:33     ` Sam Roberts
2006-09-22  0:22  3%   ` Nobuyoshi Nakada
2007-04-26  9:55     [BUG] Proc#arity regression or bug in RDoc Mauricio Fernandez
2007-04-26 10:40     ` Mauricio Fernandez
2007-04-27  5:12  6%   ` [patch] " Adam Bozanich
2007-04-29  4:37  5%     ` Adam Bozanich
2007-04-29 10:56  5% [BUG] (1.9) Wrong arity of Procs obtained with somemethod.to_proc Mauricio Fernandez
2007-09-28 12:57     gc.c -- possible logic error? Hugh Sasse
2007-09-30  4:31 14% ` Tanaka Akira
2008-01-30  6:42     IRHG - TNODE Documentation? Charles Thornton
2008-01-30 16:36  5% ` Paul Brannan
2008-01-30 17:37  0%   ` Rocky Bernstein
2008-01-30 19:25  0%   ` Charles Thornton
2008-02-09  8:03  6% IRHG -- Dumping T-Nodes Charles Thornton
2008-02-09  9:04  0% ` Eric Hodel
2008-02-09 10:18  6%   ` Charles Thornton
2008-02-14  5:59  6% IRHG -- When GC is processing T_NODES -- Do they follow the VID's Charles Thornton
2008-03-03  9:48     Copy-on-write friendly garbage collector Hongli Lai
2008-03-03 13:11  3% ` Yukihiro Matsumoto
2008-03-08  5:34       ` Daniel DeLorme
2008-03-08  7:50         ` Daniel DeLorme
2008-03-08 10:01  2%       ` Daniel DeLorme
2008-03-12 17:23 11%       ` Hongli Lai
2008-09-04 16:13     [ruby-core:18452] [ANN] Ruby 1.9.1 feature freeze Roger Pack
2008-09-06 19:53     ` [ruby-core:18471] " Yukihiro Matsumoto
2008-09-08  9:05 11%   ` [ruby-core:18490] " Nobuyoshi Nakada
2008-09-20 18:49 11%     ` [ruby-core:18763] " Roger Pack
     [not found]     <e1c05edd0810021611q59402efjcd203d4a885811f1@mail.gmail.com>
2008-10-02 23:10  3% ` [ruby-core:19114] GC.reachability_paths Aman Gupta
2008-12-11 15:11     [ruby-core:20481] Re: Status of copy-on-write friendly garbage collector Roger Pack
2008-12-12  0:37  2% ` [ruby-core:20497] " Yukihiro Matsumoto
2009-04-18 22:18     [ruby-core:23252] [Bug #1392] Object#extend leaks memory on Ruby 1.9.1 Muhammad Ali
2009-04-20  3:43  5% ` [ruby-core:23258] " Yukihiro Matsumoto
2009-04-20 13:23  0%   ` [ruby-core:23262] " Muhammad A. Ali
2009-04-20 14:22  0%     ` [ruby-core:23263] " Muhammad A. Ali
2009-07-02 17:11  4% [ruby-core:24118] [Bug #1716] set_trace_func/raise related segfault, one line repro Jedediah Smith
2009-09-14  9:57  5% [ruby-core:25571] Implicit block argument in Procs Cody Brocious
2011-07-02  5:18     [ruby-core:37730] [Ruby 1.9 - Bug #4962][Open] come back gem_prelude! Yusuke Endoh
2011-07-06 21:21     ` [ruby-core:37833] [Ruby 1.9 - Bug #4962] " Eric Hodel
2011-07-06 22:02       ` [ruby-core:37834] " Benoit Daloze
2011-07-06 22:26  4%     ` [ruby-core:37835] " Eric Hodel
2011-11-14 18:50     [ruby-core:41038] [ruby-trunk - Bug #5634][Open] yield and binding Thomas Sawyer
2011-11-15 10:37  1% ` [ruby-core:41060] [ruby-trunk - Bug #5634] " Heesob Park
2013-03-14  3:10     [ruby-core:53392] [ruby-trunk - Bug #8092][Open] [patch] gc: improve accuracy of objspace_live_num() and allocated/freed counters tmm1 (Aman Gupta)
2013-03-18  8:32  4% ` [ruby-core:53496] [ruby-trunk - Bug #8092] " authorNari (Narihiro Nakamura)
2013-03-18 13:27  4% ` [ruby-core:53504] " tmm1 (Aman Gupta)
2013-12-07 16:17 10% [ruby-core:58948] [ruby-trunk - Bug #9226][Open] Getting method `inspect' called on unexpected T_NODE object (0x000000025ddea8 flags=0x109089c klass=0x0) (NotImplementedError) from Hash#inspect myronmarston (Myron Marston)
2013-12-07 23:29 10% ` [ruby-core:58950] [ruby-trunk - Bug #9226] " tmm1 (Aman Gupta)
2013-12-08  0:10 10% ` [ruby-core:58951] " charliesome (Charlie Somerville)
2013-12-08  0:11 10% ` [ruby-core:58952] " tmm1 (Aman Gupta)
2013-12-08  2:51 10% ` [ruby-core:58958] " ko1 (Koichi Sasada)
2013-12-08  3:06 10% ` [ruby-core:58959] " tmm1 (Aman Gupta)
2013-12-08  6:27 10% ` [ruby-core:58960] [ruby-trunk - Bug #9226][Open] " ko1 (Koichi Sasada)
2013-12-08  8:32 10% ` [ruby-core:58964] [ruby-trunk - Bug #9226] " myronmarston (Myron Marston)
2013-12-08  8:32 10% ` [ruby-core:58965] " myronmarston (Myron Marston)
2013-12-10  4:13 10% ` [ruby-core:59016] " tmm1 (Aman Gupta)
2013-12-10  5:48 10% ` [ruby-core:59018] " tmm1 (Aman Gupta)
     [not found]     <redmine.issue-10037.20140715053007@ruby-lang.org>
2014-07-15  9:51  9% ` [ruby-core:63729] [ruby-trunk - Bug #10037] Since r46798 on Solaris, "[BUG] rb_vm_get_cref: unreachable" during make ko1
     [not found]     <redmine.issue-10232.20140912012732@ruby-lang.org>
2014-09-12  1:27  4% ` [ruby-core:64979] [ruby-trunk - Bug #10232] [Open] Trivial change of IMMEDIATE VALUE bits layout ko1
2014-09-12  3:10  4% ` [ruby-core:64986] [ruby-trunk - Bug #10232] " normalperson
2014-09-12  3:31  4% ` [ruby-core:64987] " ko1
2014-11-27 11:28  4% ` [ruby-core:66522] " ko1
2017-02-06  2:55  4% ` [ruby-core:79444] [Ruby trunk Bug#10232][Rejected] " ko1
     [not found]     <redmine.issue-11360.20150717052032@ruby-lang.org>
2015-07-17  5:20  5% ` [ruby-core:70006] [Ruby trunk - Bug #11360] [Open] Singleton class doesn't appear by ObjectSpace.each_object ko1
2015-07-17  5:45  5% ` [ruby-core:70007] [Ruby trunk - Bug #11360] " ko1
2015-07-17  9:43  4% ` [ruby-core:70010] " eregontp
2015-07-21 15:04  4% ` [ruby-core:70071] " matz
     [not found]     <redmine.issue-11740.20151125102527@ruby-lang.org>
2015-12-16  8:06  5% ` [ruby-core:72180] [Ruby trunk - Bug #11740] ObjectSpace.each_object exposes internal metaclasses ko1
2015-12-22  2:36  5% ` [ruby-core:72425] " shugo
     [not found]     <redmine.issue-14762.20180516010931@ruby-lang.org>
2018-05-16  6:01     ` [ruby-core:87067] [Ruby trunk Misc#14762] [PATCH] gc.c: use ccan/list ko1
2018-05-16  9:38  5%   ` [ruby-core:87076] " Eric Wong
     [not found]     <redmine.issue-15650.20190309221037@ruby-lang.org>
2019-03-09 22:11  4% ` [ruby-core:91731] [Ruby trunk Bug#15650] Segmentation fault when accessing $! in at_exit within a forked process buszkiewiczm
2019-03-11  7:03  5% ` [ruby-core:91762] " naruse
2019-03-12 21:06  5% ` [ruby-core:91792] " nagachika00
2019-03-31 15:01  5% ` [ruby-core:92065] " usa
2021-08-14  4:20  6% [ruby-core:104916] [Ruby master Bug#18075] Crasher using ripper + yydebug ryand-ruby

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).