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

[WIP] Create a Ruby Class per foreign meta object #3155

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover code?

// 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<RubySymbol> traitsList = new ArrayList<>();
private static RubyClass resolvePolyglotForeignClass(Node node, Object object, int traits) {
final ArrayList<Object> 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);
}
Expand Down
57 changes: 48 additions & 9 deletions src/main/ruby/truffleruby/core/truffle/interop_operations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand Down