Skip to content

Commit c934877

Browse files
committed
[GR-16260] Avoid setting the class of a Ruby object.
PullRequest: truffleruby/874
2 parents 1bd82ea + f032276 commit c934877

File tree

5 files changed

+66
-66
lines changed

5 files changed

+66
-66
lines changed

src/main/ruby/core/exception.rb

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,7 @@ def self.new(*args)
391391
end
392392
end
393393

394-
error = allocate
395-
Truffle::Internal::Unsafe.set_class error, self
396-
Truffle.privately { error.initialize(*args) }
397-
error
394+
super(*args)
398395
end
399396
end
400397

src/main/ruby/core/io.rb

Lines changed: 12 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -805,27 +805,8 @@ def self.parse_mode(mode)
805805
ret
806806
end
807807

808-
def self.pipe(external=nil, internal=nil, options=nil)
809-
fds = FFI::MemoryPointer.new(:int, 2) do |ptr|
810-
r = Truffle::POSIX.pipe(ptr)
811-
Errno.handle if r == -1
812-
ptr.read_array_of_int(2)
813-
end
814-
815-
lhs = self.new(fds[0], RDONLY)
816-
rhs = self.new(fds[1], WRONLY)
817-
818-
lhs.close_on_exec = true
819-
rhs.close_on_exec = true
820-
821-
lhs.set_encoding external || Encoding.default_external,
822-
internal || Encoding.default_internal, options
823-
824-
lhs.sync = true
825-
rhs.sync = true
826-
827-
lhs.pipe = true
828-
rhs.pipe = true
808+
def self.pipe(external = nil, internal = nil, options = nil)
809+
lhs, rhs = Truffle::IOOperations.create_pipe(self, self, external, internal, options)
829810

830811
if block_given?
831812
begin
@@ -881,18 +862,16 @@ def self.popen(*args)
881862
readable = true
882863
end
883864

884-
pa_read, ch_write = pipe if readable
865+
# We only need the Bidirectional pipe if we're reading and writing.
866+
# Otherwise, we can just return the IO object for the proper half.
867+
read_class = (readable && writable) ? IO::BidirectionalPipe : self
868+
869+
pa_read, ch_write = Truffle::IOOperations.create_pipe(read_class, self) if readable
885870
ch_read, pa_write = pipe if writable
886871

887-
# We only need the Bidirectional pipe if we're reading and writing.
888-
# If we're only doing one, we can just return the IO object for
889-
# the proper half.
890872
if readable and writable
891-
# Transmogrify pa_read into a BidirectionalPipe object,
892-
# and then tell it about its pid and pa_write
893-
Truffle::Internal::Unsafe.set_class pa_read, IO::BidirectionalPipe
894873
pipe = pa_read
895-
pipe.set_pipe_info(pa_write)
874+
pipe.instance_variable_set(:@write, pa_write)
896875
elsif readable
897876
pipe = pa_read
898877
elsif writable
@@ -1149,7 +1128,7 @@ def self.setup(io, fd, mode=nil, sync=false)
11491128
end
11501129

11511130
# Close old descriptor if there was already one associated
1152-
io.close if io.descriptor
1131+
io.close if io.descriptor != -1
11531132

11541133
io.descriptor = fd
11551134
io.mode = mode || cur_mode
@@ -2228,7 +2207,8 @@ def reopen(other, mode=undefined)
22282207

22292208
Truffle::IOOperations.dup2_with_cloexec(io.fileno, @descriptor)
22302209

2231-
Truffle::Internal::Unsafe.set_class self, io.class
2210+
Truffle.invoke_primitive :vm_set_class, self, io.class
2211+
22322212
if io.respond_to?(:path)
22332213
@path = io.path
22342214
end
@@ -2673,18 +2653,11 @@ def encode_with coder
26732653

26742654
class IO::BidirectionalPipe < IO
26752655

2676-
def set_pipe_info(write)
2677-
@write = write
2678-
@sync = true
2679-
end
2680-
26812656
##
26822657
# Closes ios and flushes any pending writes to the
26832658
# operating system. The stream is unavailable for
26842659
# any further data operations; an IOError is raised
2685-
# if such an attempt is made. I/O streams are
2686-
# automatically closed when they are claimed by
2687-
# the garbage collector.
2660+
# if such an attempt is made.
26882661
#
26892662
# If ios is opened by IO.popen, close sets $?.
26902663
def close

src/main/ruby/core/marshal.rb

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,29 @@ def set_instance_variables(obj)
223223
end
224224
end
225225

226+
STRING_ALLOCATE = String.method(:__allocate__).unbind
227+
226228
def construct_string
227-
obj = get_byte_sequence
228-
Truffle::Internal::Unsafe.set_class(obj, get_user_class) if @user_class
229+
bytes = get_byte_sequence.force_encoding(Encoding::ASCII_8BIT)
229230

230-
set_object_encoding(obj, Encoding::ASCII_8BIT)
231+
if @user_class
232+
cls = get_user_class
233+
if cls < String
234+
obj = STRING_ALLOCATE.bind(cls).call
235+
else
236+
allocate = cls.method(:__allocate__)
237+
if allocate.unbind == STRING_ALLOCATE
238+
# For example, String.clone falls in this case
239+
obj = allocate.call
240+
else
241+
raise ArgumentError, 'dump format error (user class)'
242+
end
243+
end
244+
245+
Truffle.invoke_primitive(:string_initialize, obj, bytes, Encoding::ASCII_8BIT)
246+
else
247+
obj = bytes
248+
end
231249

232250
store_unique_object obj
233251
end
@@ -653,21 +671,24 @@ def construct_old_module
653671
obj
654672
end
655673

674+
ARRAY_ALLOCATE = Array.method(:__allocate__).unbind
656675
ARRAY_APPEND = Array.instance_method(:<<)
657676

658677
def construct_array
659-
obj = []
660-
store_unique_object obj
661-
662678
if @user_class
663679
cls = get_user_class()
664680
if cls < Array
665-
Truffle::Internal::Unsafe.set_class obj, cls
681+
obj = ARRAY_ALLOCATE.bind(cls).call
666682
else
667683
# This is what MRI does, it's weird.
668-
return cls.allocate
684+
obj = cls.allocate
685+
store_unique_object obj
686+
return obj
669687
end
688+
else
689+
obj = []
670690
end
691+
store_unique_object obj
671692

672693
construct_integer.times do |_i|
673694
ARRAY_APPEND.bind(obj).call(construct)

src/main/ruby/core/truffle/internal.rb

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,6 @@
3535
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3636

3737
module Truffle::Internal
38-
39-
module Unsafe
40-
def self.set_class(obj, cls)
41-
Truffle.primitive :vm_set_class
42-
43-
if obj.kind_of? ImmediateValue
44-
raise TypeError, 'Can not change the class of an immediate'
45-
end
46-
47-
raise ArgumentError, "Class #{cls} is not compatible with #{obj.inspect}"
48-
end
49-
end
50-
5138
def self.get_data(path, offset)
5239
file = File.open(path)
5340
file.seek(offset)

src/main/ruby/core/truffle/io_operations.rb

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ module IOOperations
1313
def self.last_line(a_binding)
1414
Truffle::KernelOperations.frame_local_variable_get(:$_, a_binding)
1515
end
16+
Truffle::Graal.always_split(method(:last_line))
1617

1718
def self.set_last_line(value, a_binding)
1819
Truffle::KernelOperations.frame_local_variable_set(:$_, a_binding, value)
1920
end
21+
Truffle::Graal.always_split(method(:set_last_line))
2022

2123
def self.print(io, args, last_line_binding)
2224
if args.empty?
@@ -96,7 +98,27 @@ def self.dup2_with_cloexec(old_fd, new_fd)
9698
end
9799
end
98100

99-
Truffle::Graal.always_split(method(:last_line))
100-
Truffle::Graal.always_split(method(:set_last_line))
101+
def self.pipe_end_setup(io)
102+
io.close_on_exec = true
103+
io.sync = true
104+
io.pipe = true
105+
io
106+
end
107+
108+
def self.create_pipe(read_class, write_class, external = nil, internal = nil, options = nil)
109+
fds = Truffle::FFI::MemoryPointer.new(:int, 2) do |ptr|
110+
res = Truffle::POSIX.pipe(ptr)
111+
Errno.handle if res == -1
112+
ptr.read_array_of_int(2)
113+
end
114+
115+
lhs = pipe_end_setup(read_class.new(fds[0], IO::RDONLY))
116+
rhs = pipe_end_setup(write_class.new(fds[1], IO::WRONLY))
117+
118+
lhs.set_encoding external || Encoding.default_external,
119+
internal || Encoding.default_internal, options
120+
121+
[lhs, rhs]
122+
end
101123
end
102124
end

0 commit comments

Comments
 (0)