Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polyglot unable to evaluate python dictionary objects #3630

Closed
AigarsS opened this issue Jul 25, 2024 · 3 comments
Closed

Polyglot unable to evaluate python dictionary objects #3630

AigarsS opened this issue Jul 25, 2024 · 3 comments
Assignees
Labels

Comments

@AigarsS
Copy link

AigarsS commented Jul 25, 2024

I tried using truffleruby 24.0.1 with python, but it fails evaluating python's dictionary, it works fine for arrays.

:~$ ruby -v
truffleruby 24.0.1, like ruby 3.2.2, GraalVM CE JVM [x86_64-linux]
:~$ ruby --polyglot
[ruby] WARNING: truffleruby starts IRB when stdin is a TTY instead of reading from stdin, use '-' to read from stdin
irb(main):001:0> Polyglot.eval('python', '{"key1": "value1"}')
[ruby] WARNING StackOverflowError
[ruby] WARNING StackOverflowError                         
<internal:core> core/truffle/polyglot.rb:351:in `each': stack level too deep (SystemStackError)
        from com.oracle.truffle.api.strings.TStringOps.runCalcStringAttributesLatin1(TStringOps.java:1295)
        from <internal:core> core/truffle/polyglot.rb:355:in `each'
        from <internal:core> core/truffle/polyglot.rb:355:in `each'
        from <internal:core> core/truffle/polyglot.rb:355:in `each'
        from <internal:core> core/truffle/polyglot.rb:355:in `each'
        from <internal:core> core/truffle/polyglot.rb:355:in `each'
        from <internal:core> core/truffle/polyglot.rb:355:in `each'
        from <internal:core> core/truffle/polyglot.rb:355:in `each'
        from <internal:core> core/truffle/polyglot.rb:355:in `each'
        from <internal:core> core/truffle/polyglot.rb:355:in `each'
        from <internal:core> core/truffle/polyglot.rb:355:in `each'
        from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	... 885 levels...
irb(main):002:0> Polyglot.eval('python', '["key1", "value1"]')
=> #<Polyglot::ForeignArray[Python] list:0x4ff ["key1", "value1"]>
@eregon
Copy link
Member

eregon commented Jul 29, 2024

Thanks for the report, it seems an issue of inspect for foreign objects.
Using to_s via e.g. puts works fine and prints #<Polyglot::ForeignHashIterable[Python] {'key1': 'value1'}>.

Running it outside of IRB gives a clearer error:

p :START
h = Polyglot.eval("python", '{"key1": "value1"}')
p :OK
p h
$ truffleruby-polyglot-get python
$ ruby --polyglot pyinterop.rb
:START
:OK
[ruby] WARNING StackOverflowError
[ruby] WARNING StackOverflowError
<internal:core> core/truffle/polyglot.rb:351:in `each': stack level too deep (SystemStackError)
	from java.nio.CharBuffer.<init>(CharBuffer.java:319)
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	...
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:355:in `each'
	from <internal:core> core/truffle/polyglot.rb:99:in `each'
	from <internal:core> core/enumerable.rb:108:in `map'
	from <internal:core> core/truffle/interop_operations.rb:97:in `foreign_inspect_nonrecursive'
	from <internal:core> core/truffle/polyglot.rb:468:in `block in inspect'
	from <internal:core> core/truffle/thread_operations.rb:75:in `detect_recursion'
	from <internal:core> core/truffle/polyglot.rb:467:in `inspect'
	from <internal:core> core/post.rb:80:in `block in p'
	from <internal:core> core/post.rb:80:in `each'
	from <internal:core> core/post.rb:80:in `p'
	from pyinterop.rb:4:in `<main>'

@eregon
Copy link
Member

eregon commented Jul 29, 2024

We can see better what's going on with:

h = Polyglot.eval("python", '{"key1": "value1"}')
puts h
p h.class.ancestors

iterator = Truffle::Interop.hash_entries_iterator(h)
p iterator.class.ancestors

iterator2 = Truffle::Interop.iterator(iterator)
p iterator.equal?(iterator2)

p iterator.method(:each)

# p h

which gives

#<Polyglot::ForeignHashIterable[Python] {'key1': 'value1'}>
[Polyglot::ForeignHashIterable, Polyglot::HashTrait, Polyglot::IterableTrait, Enumerable, Polyglot::ForeignObject, Polyglot::ObjectTrait, Object, Kernel, BasicObject]
[Polyglot::ForeignIterableIterator, Polyglot::IterableTrait, Polyglot::IteratorTrait, Enumerable, Polyglot::ForeignObject, Polyglot::ObjectTrait, Object, Kernel, BasicObject]
true
#<Method: Polyglot::ForeignIterableIterator(Polyglot::IterableTrait)#each(&block) <internal:core> core/truffle/polyglot.rb:351>

The hash_entries_iterator has both the Iterator and Iterable traits.
Both of these traits define each, but unfortunately the order is wrong and IterableTrait wins, and that one ends up calling each on Truffle::Interop.iterator(self):

iterator = Truffle::Interop.iterator(self)
iterator.each(&block)

But Truffle::Interop.iterator(self) is the same object in this case since it's both iterable and iterator.
So IteratorTrait#each must be before iterable in the ancestors to fix this.

@eregon eregon self-assigned this Jul 29, 2024
@eregon
Copy link
Member

eregon commented Jul 29, 2024

Fix in #3634

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants