Skip to content

Commit 7cbac45

Browse files
committed
[GR-40333] Ruby 3.1 Reuse MRI objspace.rb file
PullRequest: truffleruby/3698
2 parents 59ecd36 + ff1ef78 commit 7cbac45

File tree

7 files changed

+302
-28
lines changed

7 files changed

+302
-28
lines changed

lib/mri/objspace.rb

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# frozen_string_literal: true
2+
3+
unless defined?(::TruffleRuby)
4+
require 'objspace.so'
5+
end
6+
7+
module ObjectSpace
8+
class << self
9+
private :_dump
10+
private :_dump_all
11+
end
12+
13+
module_function
14+
15+
# call-seq:
16+
# ObjectSpace.dump(obj[, output: :string]) # => "{ ... }"
17+
# ObjectSpace.dump(obj, output: :file) # => #<File:/tmp/rubyobj20131125-88733-1xkfmpv.json>
18+
# ObjectSpace.dump(obj, output: :stdout) # => nil
19+
#
20+
# Dump the contents of a ruby object as JSON.
21+
#
22+
# This method is only expected to work with C Ruby.
23+
# This is an experimental method and is subject to change.
24+
# In particular, the function signature and output format are
25+
# not guaranteed to be compatible in future versions of ruby.
26+
def dump(obj, output: :string)
27+
out = case output
28+
when :file, nil
29+
require 'tempfile'
30+
Tempfile.create(%w(rubyobj .json))
31+
when :stdout
32+
STDOUT
33+
when :string
34+
+''
35+
when IO
36+
output
37+
else
38+
raise ArgumentError, "wrong output option: #{output.inspect}"
39+
end
40+
41+
ret = _dump(obj, out)
42+
return nil if output == :stdout
43+
ret
44+
end
45+
46+
47+
# call-seq:
48+
# ObjectSpace.dump_all([output: :file]) # => #<File:/tmp/rubyheap20131125-88469-laoj3v.json>
49+
# ObjectSpace.dump_all(output: :stdout) # => nil
50+
# ObjectSpace.dump_all(output: :string) # => "{...}\n{...}\n..."
51+
# ObjectSpace.dump_all(output:
52+
# File.open('heap.json','w')) # => #<File:heap.json>
53+
# ObjectSpace.dump_all(output: :string,
54+
# since: 42) # => "{...}\n{...}\n..."
55+
#
56+
# Dump the contents of the ruby heap as JSON.
57+
#
58+
# _since_ must be a non-negative integer or +nil+.
59+
#
60+
# If _since_ is a positive integer, only objects of that generation and
61+
# newer generations are dumped. The current generation can be accessed using
62+
# GC::count.
63+
#
64+
# Objects that were allocated without object allocation tracing enabled
65+
# are ignored. See ::trace_object_allocations for more information and
66+
# examples.
67+
#
68+
# If _since_ is omitted or is +nil+, all objects are dumped.
69+
#
70+
# This method is only expected to work with C Ruby.
71+
# This is an experimental method and is subject to change.
72+
# In particular, the function signature and output format are
73+
# not guaranteed to be compatible in future versions of ruby.
74+
def dump_all(output: :file, full: false, since: nil)
75+
out = case output
76+
when :file, nil
77+
require 'tempfile'
78+
Tempfile.create(%w(rubyheap .json))
79+
when :stdout
80+
STDOUT
81+
when :string
82+
+''
83+
when IO
84+
output
85+
else
86+
raise ArgumentError, "wrong output option: #{output.inspect}"
87+
end
88+
89+
ret = _dump_all(out, full, since)
90+
return nil if output == :stdout
91+
ret
92+
end
93+
end

lib/truffle/objspace.rb

+18-27
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ def count_tdata_objects(hash = {})
7676
hash
7777
end
7878

79-
def dump(object, output: :string)
80-
case output
81-
when :string
79+
# Helper method for ObjectSpace.dump
80+
def _dump(object, output)
81+
if Primitive.object_kind_of?(output, String)
8282
require 'json'
8383
json = {
8484
address: '0x' + object.object_id.to_s(16),
@@ -111,38 +111,25 @@ def dump(object, output: :string)
111111
})
112112
end
113113
JSON.generate(json)
114-
when :file
115-
require 'tempfile'
116-
f = Tempfile.new(['rubyobj', '.json'])
117-
f.write dump(object, output: :string)
118-
f.close
119-
f.path
120-
when :stdout
121-
puts dump(object, output: :string)
122-
nil
114+
else
115+
# IO
116+
output.write _dump(object, '')
117+
output
123118
end
124119
end
125120

126-
def dump_all(output: :file)
127-
case output
128-
when :string
121+
# Helper method for ObjectSpace.dump_all
122+
def _dump_all(output, full, since)
123+
if Primitive.object_kind_of?(output, String)
129124
objects = []
130125
ObjectSpace.each_object do |object|
131126
objects.push dump(object)
132127
end
133128
objects.join("\n")
134-
when :file
135-
require 'tempfile'
136-
f = Tempfile.new(['ruby', '.json'])
137-
f.write dump_all(output: :string)
138-
f.close
139-
f.path
140-
when :stdout
141-
puts dump_all(output: :string)
142-
nil
143-
when IO
144-
output.write dump_all(output: :string)
145-
nil
129+
else
130+
# IO
131+
output.write _dump_all('', full, since)
132+
output
146133
end
147134
end
148135

@@ -219,3 +206,7 @@ def allocation_sourceline(object)
219206
Primitive.allocation_sourceline(object)
220207
end
221208
end
209+
210+
# Reuse MRI objspace.rb (that implements dump and dump_all methods)
211+
# Relies on the order in $LOAD_PATH - lib/truffle is before lib/mri
212+
require_relative '../mri/objspace'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
require_relative '../../spec_helper'
2+
require 'objspace'
3+
4+
describe "ObjectSpace.dump_all" do
5+
it "dumps Ruby heap to string when passed output: :string" do
6+
stdout = ruby_exe(<<~RUBY, options: "-robjspace")
7+
string = "abc"
8+
dump = ObjectSpace.dump_all(output: :string)
9+
puts dump.class
10+
puts dump.include?('"value":"abc"')
11+
RUBY
12+
13+
stdout.should == "String\ntrue\n"
14+
end
15+
16+
it "dumps Ruby heap to a temporary file when passed output: :file" do
17+
stdout = ruby_exe(<<~RUBY, options: "-robjspace")
18+
string = "abc"
19+
file = ObjectSpace.dump_all(output: :file)
20+
21+
begin
22+
file.flush
23+
file.rewind
24+
content = file.read
25+
26+
puts file.class
27+
puts content.include?('"value":"abc"')
28+
ensure
29+
file.close
30+
File.unlink file.path
31+
end
32+
RUBY
33+
34+
stdout.should == "File\ntrue\n"
35+
end
36+
37+
it "dumps Ruby heap to a temporary file when :output not specified" do
38+
stdout = ruby_exe(<<~RUBY, options: "-robjspace")
39+
string = "abc"
40+
file = ObjectSpace.dump_all
41+
42+
begin
43+
file.flush
44+
file.rewind
45+
content = file.read
46+
47+
puts file.class
48+
puts content.include?('"value":"abc"')
49+
ensure
50+
file.close
51+
File.unlink file.path
52+
end
53+
RUBY
54+
55+
stdout.should == "File\ntrue\n"
56+
end
57+
58+
it "dumps Ruby heap to a temporary file when passed output: :nil" do
59+
stdout = ruby_exe(<<~RUBY, options: "-robjspace")
60+
string = "abc"
61+
file = ObjectSpace.dump_all(output: nil)
62+
63+
begin
64+
file.flush
65+
file.rewind
66+
content = file.read
67+
68+
puts file.class
69+
puts content.include?('"value":"abc"')
70+
ensure
71+
file.close
72+
File.unlink file.path
73+
end
74+
RUBY
75+
76+
stdout.should == "File\ntrue\n"
77+
end
78+
79+
it "dumps Ruby heap to stdout when passed output: :stdout" do
80+
stdout = ruby_exe(<<~RUBY, options: "-robjspace")
81+
string = "abc"
82+
ObjectSpace.dump_all(output: :stdout)
83+
RUBY
84+
85+
stdout.should include('"value":"abc"')
86+
end
87+
88+
it "dumps Ruby heap to provided IO when passed output: IO" do
89+
stdout = ruby_exe(<<~RUBY, options: "-robjspace -rtempfile")
90+
string = "abc"
91+
io = Tempfile.create("object_space_dump_all")
92+
93+
begin
94+
result = ObjectSpace.dump_all(output: io)
95+
io.rewind
96+
content = io.read
97+
98+
puts result.equal?(io)
99+
puts content.include?('"value":"abc"')
100+
ensure
101+
io.close
102+
File.unlink io.path
103+
end
104+
RUBY
105+
106+
stdout.should == "true\ntrue\n"
107+
end
108+
109+
it "raises ArgumentError when passed not supported :output value" do
110+
-> { ObjectSpace.dump_all(output: Object.new) }.should raise_error(ArgumentError, /wrong output option/)
111+
end
112+
end
+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
require_relative '../../spec_helper'
2+
require 'objspace'
3+
4+
describe "ObjectSpace.dump" do
5+
it "dumps the content of object as JSON" do
6+
require 'json'
7+
string = ObjectSpace.dump("abc")
8+
dump = JSON.parse(string)
9+
10+
dump['type'].should == "STRING"
11+
dump['value'].should == "abc"
12+
end
13+
14+
it "dumps to string when passed output: :string" do
15+
string = ObjectSpace.dump("abc", output: :string)
16+
string.should be_kind_of(String)
17+
string.should include('"value":"abc"')
18+
end
19+
20+
it "dumps to string when :output not specified" do
21+
string = ObjectSpace.dump("abc")
22+
string.should be_kind_of(String)
23+
string.should include('"value":"abc"')
24+
end
25+
26+
it "dumps to a temporary file when passed output: :file" do
27+
file = ObjectSpace.dump("abc", output: :file)
28+
file.should be_kind_of(File)
29+
30+
file.rewind
31+
content = file.read
32+
content.should include('"value":"abc"')
33+
ensure
34+
file.close
35+
File.unlink file.path
36+
end
37+
38+
it "dumps to a temporary file when passed output: :nil" do
39+
file = ObjectSpace.dump("abc", output: nil)
40+
file.should be_kind_of(File)
41+
42+
file.rewind
43+
file.read.should include('"value":"abc"')
44+
ensure
45+
file.close
46+
File.unlink file.path
47+
end
48+
49+
it "dumps to stdout when passed output: :stdout" do
50+
stdout = ruby_exe('ObjectSpace.dump("abc", output: :stdout)', options: "-robjspace").chomp
51+
stdout.should include('"value":"abc"')
52+
end
53+
54+
it "dumps to provided IO when passed output: IO" do
55+
filename = tmp("io_read.txt")
56+
io = File.open(filename, "w+")
57+
result = ObjectSpace.dump("abc", output: io)
58+
result.should.equal? io
59+
60+
io.rewind
61+
io.read.should include('"value":"abc"')
62+
ensure
63+
io.close
64+
rm_r filename
65+
end
66+
67+
it "raises ArgumentError when passed not supported :output value" do
68+
-> { ObjectSpace.dump("abc", output: Object.new) }.should raise_error(ArgumentError, /wrong output option/)
69+
end
70+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
slow:ObjectSpace.dump_all dumps Ruby heap to string when passed output: :string
2+
slow:ObjectSpace.dump_all dumps Ruby heap to a temporary file when passed output: :file
3+
slow:ObjectSpace.dump_all dumps Ruby heap to a temporary file when :output not specified
4+
slow:ObjectSpace.dump_all dumps Ruby heap to a temporary file when passed output: :nil
5+
slow:ObjectSpace.dump_all dumps Ruby heap to stdout when passed output: :stdout
6+
slow:ObjectSpace.dump_all dumps Ruby heap to provided IO when passed output: IO
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
slow:ObjectSpace.dump dumps to stdout when passed output: :stdout

tool/import-mri-files.sh

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ cp -R ../ruby/ext/fiddle/lib/fiddle.rb lib/mri
4949
cp ../ruby/ext/nkf/lib/*.rb lib/mri
5050
cp ../ruby/ext/monitor/lib/*.rb lib/mri
5151
mkdir lib/mri/objspace
52-
cp -R ../ruby/ext/objspace/lib/objspace/* lib/mri/objspace
52+
cp -R ../ruby/ext/objspace/lib/objspace lib/mri
53+
cp ../ruby/ext/objspace/lib/objspace.rb lib/mri
5354
cp -R ../ruby/ext/openssl/lib/* lib/mri
5455
cp ../ruby/ext/pty/lib/*.rb lib/mri
5556
cp ../ruby/ext/psych/lib/psych.rb lib/mri

0 commit comments

Comments
 (0)