diff --git a/src/main/java/org/truffleruby/language/objects/ForeignClassNode.java b/src/main/java/org/truffleruby/language/objects/ForeignClassNode.java index 8cadfeaa22b0..8d9f47c65cdb 100644 --- a/src/main/java/org/truffleruby/language/objects/ForeignClassNode.java +++ b/src/main/java/org/truffleruby/language/objects/ForeignClassNode.java @@ -79,14 +79,14 @@ protected static RubyClass cached(Node node, Object object, @CachedLibrary("object") InteropLibrary interop, @Cached("getTraits(object, interop)") int cachedTraits) { assert RubyGuards.isForeignObject(object); - return classForTraits(node, cachedTraits); + return classForTraits(node, object, cachedTraits); } @Specialization(replaces = "cached", limit = "getInteropCacheLimit()") protected static RubyClass uncached(Node node, Object object, @CachedLibrary("object") InteropLibrary interop) { assert RubyGuards.isForeignObject(object); - return classForTraits(node, getTraits(object, interop)); + return classForTraits(node, object, getTraits(object, interop)); } protected static int getTraits(Object object, InteropLibrary interop) { @@ -104,24 +104,26 @@ protected static int getTraits(Object object, InteropLibrary interop) { (interop.isString(object) ? Trait.STRING.bit : 0); } - private static RubyClass classForTraits(Node node, int traits) { - RubyClass rubyClass = coreLibrary(node).polyglotForeignClasses[traits]; - if (rubyClass == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - rubyClass = resolvePolyglotForeignClass(node, traits); - coreLibrary(node).polyglotForeignClasses[traits] = rubyClass; - } - return rubyClass; + private static RubyClass classForTraits(Node node, Object object, int traits) { + return resolvePolyglotForeignClass(node, object, traits); +// RubyClass rubyClass = coreLibrary(node).polyglotForeignClasses[traits]; +// if (rubyClass == null) { +// CompilerDirectives.transferToInterpreterAndInvalidate(); +// rubyClass = resolvePolyglotForeignClass(node, object, traits); +// coreLibrary(node).polyglotForeignClasses[traits] = rubyClass; +// } +// return rubyClass; } - private static RubyClass resolvePolyglotForeignClass(Node node, int traits) { - final ArrayList traitsList = new ArrayList<>(); + private static RubyClass resolvePolyglotForeignClass(Node node, Object object, int traits) { + final ArrayList args = new ArrayList<>(); + args.add(object); for (Trait trait : Trait.VALUES) { if (trait.isSet(traits)) { - traitsList.add(getSymbol(node, trait.name)); + args.add(getSymbol(node, trait.name)); } } - final Object[] traitSymbols = traitsList.toArray(); + final Object[] traitSymbols = args.toArray(); return (RubyClass) DispatchNode.getUncached().call(coreLibrary(node).truffleInteropOperationsModule, "resolve_polyglot_class", traitSymbols); } diff --git a/src/main/ruby/truffleruby/core/truffle/interop_operations.rb b/src/main/ruby/truffleruby/core/truffle/interop_operations.rb index d947de2ea5f1..898236dfa8a6 100644 --- a/src/main/ruby/truffleruby/core/truffle/interop_operations.rb +++ b/src/main/ruby/truffleruby/core/truffle/interop_operations.rb @@ -25,10 +25,10 @@ def self.enumerator_has_next?(enum) end end - RESOLVE_POLYGLOT_CLASS_MUTEX = Mutex.new + RESOLVE_POLYGLOT_CLASS_MUTEX = Object.new - def self.resolve_polyglot_class(*traits) - return Polyglot::ForeignObject if traits.empty? + def self.resolve_polyglot_class(object, *traits) + # return Polyglot::ForeignObject if traits.empty? name_traits = traits.dup @@ -46,20 +46,59 @@ def self.resolve_polyglot_class(*traits) end name = "Foreign#{name_traits.join}" + name = 'ForeignObject' if traits.empty? + traits_class = nil - RESOLVE_POLYGLOT_CLASS_MUTEX.synchronize do + TruffleRuby.synchronized(RESOLVE_POLYGLOT_CLASS_MUTEX) do if Polyglot.const_defined?(name, false) - Polyglot.const_get(name, false) + traits_class = Polyglot.const_get(name, false) else superclass = traits.include?(:Exception) ? Polyglot::ForeignException : Polyglot::ForeignObject - foreign_class = Class.new(superclass) + traits_class = Class.new(superclass) traits.reverse_each do |trait| - foreign_class.include Polyglot.const_get("#{trait}Trait", false) + traits_class.include Polyglot.const_get("#{trait}Trait", false) end - Polyglot.const_set(name, foreign_class) - foreign_class + Polyglot.const_set(name, traits_class) + traits_class end end + + foreign_class = traits_class + if Truffle::Interop.has_meta_object?(object) and language = Truffle::Interop.language(object) + TruffleRuby.synchronized(RESOLVE_POLYGLOT_CLASS_MUTEX) do + if Polyglot.const_defined?(language, false) + language_module = Polyglot.const_get(language, false) + else + language_module = Polyglot.const_set(language, Module.new) + end + + meta_object = Truffle::Interop.meta_object(object) + meta_object_name = Truffle::Interop.meta_qualified_name(meta_object) + + base = language_module + meta_components = meta_object_name.split('.') + meta_components[0...-1].each do |component| + component = component.capitalize + if base.const_defined?(component, false) + base = base.const_get(component, false) + else + base = base.const_set(component, Module.new) + end + end + final_component = meta_components.last + final_component = final_component.capitalize unless final_component.start_with?(/[A-Z]/) + + if base.const_defined?(final_component, false) + foreign_class = base.const_get(final_component) + raise unless foreign_class.superclass == traits_class + else + foreign_class = Class.new(traits_class) + base.const_set(final_component, foreign_class) + end + end + end + + foreign_class end def self.foreign_inspect_nonrecursive(object)