Skip to content

Commit

Permalink
Showing 22 changed files with 223 additions and 156 deletions.
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/module/extend_object_tags.txt

This file was deleted.

4 changes: 0 additions & 4 deletions spec/truffle/tags/core/module/module_function_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
fails:Module#module_function is a private method
fails:Module#module_function on Class raises a TypeError if calling after rebinded to Class
fails:Module#module_function with specific method names tries to convert the given names to strings using to_str
fails:Module#module_function with specific method names raises a TypeError when the given names can't be converted to string using to_str
fails:Module#module_function as a toggle (no arguments) in a Module body affects evaled method definitions also even when outside the eval itself
fails:Module#module_function as a toggle (no arguments) in a Module body functions normally if both toggle and definitions inside a eval
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/module/private_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
fails:Module#private is a private method
fails:Module#private makes a public Object instance method private in Kernel
fails:Module#private raises a NameError when given an undefined name
fails:Module#private without arguments sets visibility to following method definitions
fails:Module#private without arguments stops setting visibility if the body encounters other visibility setters without arguments
fails:Module#private without arguments continues setting visibility if the body encounters other visibility setters with arguments
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/module/protected_tags.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
fails:Module#protected is a private method
fails:Module#protected makes a public Object instance method protected in Kernel
fails:Module#protected raises a NameError when given an undefined name
fails:Module#protected without arguments sets visibility to following method definitions
fails:Module#protected without arguments stops setting visibility if the body encounters other visibility setters without arguments
fails:Module#protected without arguments continues setting visibility if the body encounters other visibility setters with arguments
3 changes: 0 additions & 3 deletions spec/truffle/tags/core/module/public_tags.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
fails:Module#public is a private method
fails:Module#public on a superclass method calls the redefined method
fails:Module#public makes a private Object instance method public in Kernel
fails:Module#public raises a NameError when given an undefined name
fails:Module#public without arguments stops setting visibility if the body encounters other visibility setters without arguments
fails:Module#public without arguments does not affect method definitions when itself is inside an eval and method definitions are outside
fails:Module#public without arguments affects evaled method definitions when itself is outside the eval
Original file line number Diff line number Diff line change
@@ -39,6 +39,8 @@ public SymbolOrToStrNode(SymbolOrToStrNode prev) {
toStr = prev.toStr;
}

public abstract String executeToJavaString(VirtualFrame frame, Object object);

@Specialization
public String coerceRubySymbol(RubySymbol symbol) {
return symbol.toString();
Original file line number Diff line number Diff line change
@@ -1936,11 +1936,8 @@ public RubyArray initialize(RubyArray array, RubyArray copy, UndefinedPlaceholde

}

@CoreMethod(names = "initialize_copy", visibility = Visibility.PRIVATE, required = 1, raiseIfFrozenSelf = true)
@NodeChildren({
@NodeChild(value = "self"),
@NodeChild(value = "from")
})
@CoreMethod(names = "initialize_copy", required = 1, raiseIfFrozenSelf = true)
@NodeChildren({ @NodeChild(value = "self"), @NodeChild(value = "from") })
@ImportGuards(ArrayGuards.class)
public abstract static class InitializeCopyNode extends RubyNode {
// TODO(cs): what about allocationSite ?
Original file line number Diff line number Diff line change
@@ -174,7 +174,7 @@ protected boolean notSameClass(Object a, Object b) {

}

@CoreMethod(names = "initialize", needsSelf = false, visibility = Visibility.PRIVATE)
@CoreMethod(names = "initialize", needsSelf = false)
public abstract static class InitializeNode extends CoreMethodNode {

public InitializeNode(RubyContext context, SourceSection sourceSection) {
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@
@CoreClass(name = "Binding")
public abstract class BindingNodes {

@CoreMethod(names = "initialize_copy", visibility = Visibility.PRIVATE, required = 1)
@CoreMethod(names = "initialize_copy", required = 1)
public abstract static class InitializeCopyNode extends CoreMethodNode {

public InitializeCopyNode(RubyContext context, SourceSection sourceSection) {
Original file line number Diff line number Diff line change
@@ -116,14 +116,19 @@ private static void addMethod(RubyClass rubyObjectClass, MethodDetails methodDet
}
}

private static void addMethod(RubyModule module, RubyRootNode rootNode, List<String> names, Visibility visibility) {
private static void addMethod(RubyModule module, RubyRootNode rootNode, List<String> names, final Visibility originalVisibility) {
for (String name : names) {
final RubyRootNode rootNodeCopy = NodeUtil.cloneNode(rootNode);

Visibility visibility = originalVisibility;
if (ModuleOperations.isMethodPrivateFromName(name)) {
visibility = Visibility.PRIVATE;
}

final InternalMethod method = new InternalMethod(rootNodeCopy.getSharedMethodInfo(), name, module, visibility, false,
Truffle.getRuntime().createCallTarget(rootNodeCopy), null);

module.addMethod(null, method.withVisibility(visibility).withNewName(name));
module.addMethod(null, method.withVisibility(visibility).withName(name));
}
}

Original file line number Diff line number Diff line change
@@ -573,11 +573,7 @@ public Object eval(RubyString source, RubyBinding binding, RubyString filename,

@Specialization(guards = "!isRubyBinding(binding)")
public Object eval(RubyString source, RubyBasicObject badBinding, UndefinedPlaceholder filename, UndefinedPlaceholder lineNumber) {
throw new RaiseException(
getContext().getCoreLibrary().typeError(
String.format("wrong argument type %s (expected binding)",
badBinding.getLogicalClass().getName()),
this));
throw new RaiseException(getContext().getCoreLibrary().typeErrorWrongArgumentType(badBinding, "binding", this));
}
}

@@ -870,7 +866,7 @@ public int hash(RubyBasicObject self) {

}

@CoreMethod(names = "initialize_copy", visibility = Visibility.PRIVATE, required = 1)
@CoreMethod(names = "initialize_copy", required = 1)
public abstract static class InitializeCopyNode extends CoreMethodNode {

public InitializeCopyNode(RubyContext context, SourceSection sourceSection) {
@@ -895,7 +891,7 @@ public Object initializeCopy(RubyBasicObject self, RubyBasicObject from) {

}

@CoreMethod(names = {"initialize_dup", "initialize_clone"}, visibility = Visibility.PRIVATE, required = 1)
@CoreMethod(names = { "initialize_dup", "initialize_clone" }, required = 1)
public abstract static class InitializeDupCloneNode extends CoreMethodNode {

@Child private CallDispatchHeadNode initializeCopyNode;
@@ -1603,7 +1599,7 @@ public boolean doesRespondTo(VirtualFrame frame, Object object, RubySymbol name,
}
}

@CoreMethod(names = "respond_to_missing?", required = 1, optional = 1, visibility = Visibility.PRIVATE)
@CoreMethod(names = "respond_to_missing?", required = 1, optional = 1)
public abstract static class RespondToMissingNode extends CoreMethodNode {

public RespondToMissingNode(RubyContext context, SourceSection sourceSection) {
170 changes: 138 additions & 32 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/ModuleNodes.java
Original file line number Diff line number Diff line change
@@ -16,6 +16,10 @@
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.FrameInstance;
import com.oracle.truffle.api.frame.FrameSlot;
import com.oracle.truffle.api.frame.FrameSlotKind;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.source.Source;
@@ -28,10 +32,12 @@
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.cast.BooleanCastNode;
import org.jruby.truffle.nodes.cast.BooleanCastNodeFactory;
import org.jruby.truffle.nodes.coerce.SymbolOrToStrNode;
import org.jruby.truffle.nodes.coerce.SymbolOrToStrNodeFactory;
import org.jruby.truffle.nodes.coerce.ToStrNodeFactory;
import org.jruby.truffle.nodes.control.SequenceNode;
import org.jruby.truffle.nodes.core.KernelNodes.BindingNode;
import org.jruby.truffle.nodes.core.ModuleNodesFactory.SetVisibilityNodeFactory;
import org.jruby.truffle.nodes.dispatch.*;
import org.jruby.truffle.nodes.methods.SetMethodDeclarationContext;
import org.jruby.truffle.nodes.methods.arguments.CheckArityNode;
@@ -1041,9 +1047,7 @@ public RubySymbol defineMethod(RubyModule module, String name, RubyProc proc, Un
public RubySymbol defineMethod(RubyModule module, String name, RubyMethod method, UndefinedPlaceholder block) {
notDesignedForCompilation();

module.addMethod(this, method.getMethod().withNewName(name));

return getContext().getSymbolTable().getSymbol(name);
return addMethod(module, name, method.getMethod());
}

@Specialization
@@ -1058,9 +1062,7 @@ public RubySymbol defineMethod(VirtualFrame frame, RubyModule module, String nam

// TODO CS 5-Apr-15 TypeError if the method came from a singleton

module.addMethod(this, method.getMethod().withNewName(name));

return getContext().getSymbolTable().getSymbol(name);
return addMethod(module, name, method.getMethod());
}

private RubySymbol defineMethod(RubyModule module, String name, RubyProc proc) {
@@ -1069,14 +1071,24 @@ private RubySymbol defineMethod(RubyModule module, String name, RubyProc proc) {
final CallTarget modifiedCallTarget = proc.getCallTargetForMethods();
final SharedMethodInfo info = proc.getSharedMethodInfo().withName(name);
final InternalMethod modifiedMethod = new InternalMethod(info, name, module, Visibility.PUBLIC, false, modifiedCallTarget, proc.getDeclarationFrame());
module.addMethod(this, modifiedMethod);

return addMethod(module, name, modifiedMethod);
}

private RubySymbol addMethod(RubyModule module, String name, InternalMethod method) {
method = method.withName(name);

if (ModuleOperations.isMethodPrivateFromName(name)) {
method = method.withVisibility(Visibility.PRIVATE);
}

module.addMethod(this, method);
return getContext().getSymbolTable().getSymbol(name);
}

}

@CoreMethod(names = "extend_object", required = 1)
@CoreMethod(names = "extend_object", required = 1, visibility = Visibility.PRIVATE)
public abstract static class ExtendObjectNode extends CoreMethodNode {

public ExtendObjectNode(RubyContext context, SourceSection sourceSection) {
@@ -1091,6 +1103,11 @@ public ExtendObjectNode(ExtendObjectNode prev) {
public RubyBasicObject extendObject(RubyModule module, RubyBasicObject object) {
notDesignedForCompilation();

if (module instanceof RubyClass) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().typeErrorWrongArgumentType(module, "Module", this));
}

object.getSingletonClass(this).include(this, module);
return module;
}
@@ -1133,7 +1150,7 @@ public RubyModule initialize(VirtualFrame frame, RubyModule module, RubyProc blo

}

@CoreMethod(names = "initialize_copy", visibility = Visibility.PRIVATE, required = 1)
@CoreMethod(names = "initialize_copy", required = 1)
public abstract static class InitializeCopyNode extends CoreMethodNode {

public InitializeCopyNode(RubyContext context, SourceSection sourceSection) {
@@ -1253,24 +1270,31 @@ public boolean isMethodDefined(RubyModule module, String name, boolean inherit)

}

@CoreMethod(names = "module_function", argumentsAsArray = true)
@CoreMethod(names = "module_function", argumentsAsArray = true, visibility = Visibility.PRIVATE)
public abstract static class ModuleFunctionNode extends CoreMethodNode {

@Child SetVisibilityNode setVisibilityNode;

public ModuleFunctionNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
setVisibilityNode = SetVisibilityNodeFactory.create(context, sourceSection, Visibility.MODULE_FUNCTION, null, null);
}

public ModuleFunctionNode(ModuleFunctionNode prev) {
super(prev);
setVisibilityNode = prev.setVisibilityNode;
}

@Specialization
public RubyModule moduleFunction(RubyModule module, Object... args) {
notDesignedForCompilation();
public RubyModule moduleFunction(VirtualFrame frame, RubyModule module, Object[] names) {
if (module instanceof RubyClass) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().typeError("module_function must be called for modules", this));
}

module.visibilityMethod(this, args, Visibility.MODULE_FUNCTION);
return module;
return setVisibilityNode.executeSetVisibility(frame, module, names);
}

}

@CoreMethod(names = "name")
@@ -1329,26 +1353,28 @@ public RubyArray nesting(VirtualFrame frame) {
}
}

@CoreMethod(names = "public", argumentsAsArray = true)
@CoreMethod(names = "public", argumentsAsArray = true, visibility = Visibility.PRIVATE)
public abstract static class PublicNode extends CoreMethodNode {

@Child SetVisibilityNode setVisibilityNode;

public PublicNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
setVisibilityNode = SetVisibilityNodeFactory.create(context, sourceSection, Visibility.PUBLIC, null, null);
}

public PublicNode(PublicNode prev) {
super(prev);
setVisibilityNode = prev.setVisibilityNode;
}

public abstract RubyModule executePublic(VirtualFrame frame, RubyModule module, Object[] args);

@Specialization
public RubyModule doPublic(RubyModule module, Object[] args) {
notDesignedForCompilation();

module.visibilityMethod(this, args, Visibility.PUBLIC);
return module;
public RubyModule doPublic(VirtualFrame frame, RubyModule module, Object[] names) {
return setVisibilityNode.executeSetVisibility(frame, module, names);
}

}

@CoreMethod(names = "public_class_method", argumentsAsArray = true)
@@ -1390,26 +1416,28 @@ public RubyModule publicClassMethod(RubyModule module, Object... args) {
}
}

@CoreMethod(names = "private", argumentsAsArray = true)
@CoreMethod(names = "private", argumentsAsArray = true, visibility = Visibility.PRIVATE)
public abstract static class PrivateNode extends CoreMethodNode {

@Child SetVisibilityNode setVisibilityNode;

public PrivateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
setVisibilityNode = SetVisibilityNodeFactory.create(context, sourceSection, Visibility.PRIVATE, null, null);
}

public PrivateNode(PrivateNode prev) {
super(prev);
setVisibilityNode = prev.setVisibilityNode;
}

public abstract RubyModule executePrivate(VirtualFrame frame, RubyModule module, Object[] args);

@Specialization
public RubyModule doPrivate(RubyModule module, Object[] args) {
notDesignedForCompilation();

module.visibilityMethod(this, args, Visibility.PRIVATE);
return module;
public RubyModule doPrivate(VirtualFrame frame, RubyModule module, Object[] names) {
return setVisibilityNode.executeSetVisibility(frame, module, names);
}

}

@CoreMethod(names = "private_class_method", argumentsAsArray = true)
@@ -1788,24 +1816,26 @@ public RubyModule publicConstant(RubyModule module, Object[] args) {
}
}

@CoreMethod(names = "protected", argumentsAsArray = true)
@CoreMethod(names = "protected", argumentsAsArray = true, visibility = Visibility.PRIVATE)
public abstract static class ProtectedNode extends CoreMethodNode {

@Child SetVisibilityNode setVisibilityNode;

public ProtectedNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
setVisibilityNode = SetVisibilityNodeFactory.create(context, sourceSection, Visibility.PROTECTED, null, null);
}

public ProtectedNode(ProtectedNode prev) {
super(prev);
setVisibilityNode = prev.setVisibilityNode;
}

@Specialization
public RubyModule doProtected(VirtualFrame frame, RubyModule module, Object... args) {
notDesignedForCompilation();

module.visibilityMethod(this, args, Visibility.PROTECTED);
return module;
public RubyModule doProtected(VirtualFrame frame, RubyModule module, Object[] names) {
return setVisibilityNode.executeSetVisibility(frame, module, names);
}

}

@CoreMethod(names = "remove_class_variable", required = 1)
@@ -1955,4 +1985,80 @@ private RubyModule undefMethod(RubyModule module, String name) {
}

}

@NodeChildren({ @NodeChild(value = "module"), @NodeChild(value = "names") })
public abstract static class SetVisibilityNode extends RubyNode {

@Child SymbolOrToStrNode symbolOrToStrNode;

private final Visibility visibility;

public SetVisibilityNode(RubyContext context, SourceSection sourceSection, Visibility visibility) {
super(context, sourceSection);
this.visibility = visibility;
this.symbolOrToStrNode = SymbolOrToStrNodeFactory.create(context, sourceSection, null);
}

public SetVisibilityNode(SetVisibilityNode prev) {
super(prev);
visibility = prev.visibility;
symbolOrToStrNode = prev.symbolOrToStrNode;
}

public abstract RubyModule executeSetVisibility(VirtualFrame frame, RubyModule module, Object[] arguments);

@Specialization
RubyModule setVisibility(VirtualFrame frame, RubyModule module, Object[] names) {
notDesignedForCompilation();

if (names.length == 0) {
setCurrentVisibility(visibility);
} else {
for (Object name : names) {
final String methodName = symbolOrToStrNode.executeToJavaString(frame, name);
setMethodVisibility(module, methodName);
}
}

return module;
}

private void setMethodVisibility(RubyModule module, final String methodName) {
final InternalMethod method = module.deepMethodSearch(methodName);

if (method == null) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().nameErrorUndefinedMethod(methodName, module, this));
}

/*
* If the method was already defined in this class, that's fine
* {@link addMethod} will overwrite it, otherwise we do actually
* want to add a copy of the method with a different visibility
* to this module.
*/
if (visibility == Visibility.MODULE_FUNCTION) {
module.addMethod(this, method.withVisibility(Visibility.PRIVATE));
module.getSingletonClass(this).addMethod(this, method.withVisibility(Visibility.PUBLIC));
} else {
module.addMethod(this, method.withVisibility(visibility));
}
}

private void setCurrentVisibility(Visibility visibility) {
notDesignedForCompilation();

final Frame callerFrame = Truffle.getRuntime().getCallerFrame().getFrame(FrameInstance.FrameAccess.READ_WRITE, false);

assert callerFrame != null;
assert callerFrame.getFrameDescriptor() != null;

final FrameSlot visibilitySlot = callerFrame.getFrameDescriptor().findOrAddFrameSlot(
RubyModule.VISIBILITY_FRAME_SLOT_ID, "visibility for frame", FrameSlotKind.Object);

callerFrame.setObject(visibilitySlot, visibility);
}

}

}
Original file line number Diff line number Diff line change
@@ -1377,7 +1377,7 @@ public RubyString initialize(VirtualFrame frame, RubyString self, Object from) {
}
}

@CoreMethod(names = "initialize_copy", visibility = Visibility.PRIVATE, required = 1)
@CoreMethod(names = "initialize_copy", required = 1)
public abstract static class InitializeCopyNode extends CoreMethodNode {

public InitializeCopyNode(RubyContext context, SourceSection sourceSection) {
Original file line number Diff line number Diff line change
@@ -232,7 +232,7 @@ public abstract static class RaiseNode extends CoreMethodNode {

public RaiseNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
initialize = DispatchHeadNodeFactory.createMethodCall(context);
initialize = DispatchHeadNodeFactory.createMethodCallOnSelf(context);
}

public RaiseNode(RaiseNode prev) {
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ public Object execute(VirtualFrame frame) {

if (!(childValue instanceof RubyMatchData || childValue instanceof RubyNilClass || childValue instanceof RubyNilClass)) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().typeError("wrong argument type (expected MatchData)", this));
throw new RaiseException(getContext().getCoreLibrary().typeErrorWrongArgumentType(childValue, "MatchData", this));
}

return childValue;
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.objects.SingletonClassNode;
import org.jruby.truffle.nodes.objects.SingletonClassNodeFactory;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.TruffleFatalException;
@@ -75,7 +76,7 @@ public RubySymbol execute(VirtualFrame frame) {
private static Visibility getVisibility(Frame frame, String name) {
notDesignedForCompilation();

if (name.equals("initialize") || name.equals("initialize_copy") || name.equals("initialize_clone") || name.equals("initialize_dup") || name.equals("respond_to_missing?")) {
if (ModuleOperations.isMethodPrivateFromName(name)) {
return Visibility.PRIVATE;
} else {
return getVisibility(frame);
Original file line number Diff line number Diff line change
@@ -12,8 +12,10 @@
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.nodes.Node;

import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyClass;
@@ -182,25 +184,31 @@ private static RubyConstant lookupConstantWithInherit(RubyContext context, RubyM

@TruffleBoundary
public static Map<String, InternalMethod> getAllMethods(RubyModule module) {
CompilerAsserts.neverPartOfCompilation();

final Map<String, InternalMethod> methods = new HashMap<>();

// Look in the current module
methods.putAll(module.getMethods());

// Look in ancestors
for (RubyModule ancestor : module.parentAncestors()) {
for (Map.Entry<String, InternalMethod> method : ancestor.getMethods().entrySet()) {
if (!methods.containsKey(method.getKey())) {
methods.put(method.getKey(), method.getValue());
for (RubyModule ancestor : module.ancestors()) {
for (InternalMethod method : ancestor.getMethods().values()) {
if (!methods.containsKey(method.getName())) {
methods.put(method.getName(), method);
}
}
}

return methods;
}

@TruffleBoundary
public static Map<String, InternalMethod> withoutUndefinedMethods(Map<String, InternalMethod> methods) {
Map<String, InternalMethod> definedMethods = new HashMap<>();
for (String name : methods.keySet()) {
InternalMethod method = methods.get(name);
if (!method.isUndefined()) {
definedMethods.put(name, method);
}
}
return definedMethods;
}

@TruffleBoundary
public static InternalMethod lookupMethod(RubyModule module, String name) {
CompilerAsserts.neverPartOfCompilation();
@@ -330,4 +338,12 @@ public static void setClassVariable(RubyModule module, String name, Object value
module.setClassVariable(currentNode, name, value);
}

public static boolean isMethodPrivateFromName(String name) {
CompilerAsserts.neverPartOfCompilation();

return (name.equals("initialize") || name.equals("initialize_copy") ||
name.equals("initialize_clone") || name.equals("initialize_dup") ||
name.equals("respond_to_missing?"));
}

}
Original file line number Diff line number Diff line change
@@ -848,6 +848,12 @@ public RubyException typeErrorCantCoerce(Object from, String to, Node currentNod
return typeError(String.format("%s can't be coerced into %s", from, to), currentNode);
}

public RubyException typeErrorWrongArgumentType(Object object, String expectedType, Node currentNode) {
CompilerAsserts.neverPartOfCompilation();
String badClassName = getLogicalClass(object).getName();
return typeError(String.format("wrong argument type %s (expected %s)", badClassName, expectedType), currentNode);
}

public RubyException nameError(String message, String name, Node currentNode) {
CompilerAsserts.neverPartOfCompilation();
RubyException nameError = new RubyException(nameErrorClass, context.makeString(message), RubyCallStack.getBacktrace(currentNode));
Original file line number Diff line number Diff line change
@@ -320,15 +320,22 @@ public void undefMethod(Node currentNode, InternalMethod method) {
* Used for alias_method, visibility changes, etc.
*/
@TruffleBoundary
private InternalMethod deepMethodSearch(String name) {
public InternalMethod deepMethodSearch(String name) {
InternalMethod method = ModuleOperations.lookupMethod(this, name);
if (method != null && !method.isUndefined()) {
return method;
}

// Also search on Object if we are a Module. JRuby calls it deepMethodSearch().
if (method == null && isOnlyAModule()) { // TODO: handle undefined methods
if (isOnlyAModule()) { // TODO: handle undefined methods
method = ModuleOperations.lookupMethod(context.getCoreLibrary().getObjectClass(), name);

if (method != null && !method.isUndefined()) {
return method;
}
}

return method;
return null;
}

@TruffleBoundary
@@ -342,7 +349,7 @@ public void alias(Node currentNode, String newName, String oldName) {
throw new RaiseException(getContext().getCoreLibrary().noMethodErrorOnModule(oldName, this, currentNode));
}

addMethod(currentNode, method.withNewName(newName));
addMethod(currentNode, method.withName(newName));
}

@TruffleBoundary
@@ -439,59 +446,6 @@ public Assumption getUnmodifiedAssumption() {
return unmodifiedAssumption.getAssumption();
}

public static void setCurrentVisibility(Visibility visibility) {
RubyNode.notDesignedForCompilation();

final Frame callerFrame = Truffle.getRuntime().getCallerFrame().getFrame(FrameInstance.FrameAccess.READ_WRITE, false);

assert callerFrame != null;
assert callerFrame.getFrameDescriptor() != null;

final FrameSlot visibilitySlot = callerFrame.getFrameDescriptor().findOrAddFrameSlot(
RubyModule.VISIBILITY_FRAME_SLOT_ID, "visibility for frame", FrameSlotKind.Object);

callerFrame.setObject(visibilitySlot, visibility);
}

public void visibilityMethod(Node currentNode, Object[] arguments, Visibility visibility) {
RubyNode.notDesignedForCompilation();

if (arguments.length == 0) {
setCurrentVisibility(visibility);
} else {
for (Object arg : arguments) {
final String methodName;

if (arg instanceof RubySymbol) {
methodName = ((RubySymbol) arg).toString();
} else if (arg instanceof RubyString) {
methodName = ((RubyString) arg).toString();
} else {
throw new UnsupportedOperationException();
}

final InternalMethod method = deepMethodSearch(methodName);

if (method == null) {
throw new RuntimeException("Couldn't find method " + arg.toString());
}

/*
* If the method was already defined in this class, that's fine
* {@link addMethod} will overwrite it, otherwise we do actually
* want to add a copy of the method with a different visibility
* to this module.
*/
if (visibility == Visibility.MODULE_FUNCTION) {
addMethod(currentNode, method.withVisibility(Visibility.PRIVATE));
getSingletonClass(currentNode).addMethod(currentNode, method.withVisibility(Visibility.PUBLIC));
} else {
addMethod(currentNode, method.withVisibility(visibility));
}
}
}
}

public Map<String, RubyConstant> getConstants() {
return constants;
}
@@ -613,33 +567,24 @@ public static interface MethodFilter {
}

public Collection<RubySymbol> filterMethods(boolean includeAncestors, MethodFilter filter) {
final Set<RubySymbol> filtered = new HashSet<>();

final Map<String, InternalMethod> allMethods;
if (includeAncestors) {
for (RubyModule parent : parentAncestors()) {
for (InternalMethod method : parent.methods.values()) {
doFilterMethod(method, filter, filtered);
}
}
allMethods = ModuleOperations.getAllMethods(this);
} else {
allMethods = getMethods();
}
final Map<String, InternalMethod> methods = ModuleOperations.withoutUndefinedMethods(allMethods);

final Set<RubySymbol> filtered = new HashSet<>();
for (InternalMethod method : methods.values()) {
doFilterMethod(method, filter, filtered);
if (filter.filter(method)) {
filtered.add(getContext().getSymbolTable().getSymbol(method.getName()));
}
}

return filtered;
}

private void doFilterMethod(InternalMethod method, MethodFilter filter, Set<RubySymbol> filtered) {
final RubySymbol symbol = getContext().getSymbolTable().getSymbol(method.getName());

if (method.isUndefined()) {
filtered.remove(symbol);
} else if (filter.filter(method)){
filtered.add(symbol);
}
}

public static class ModuleAllocator implements Allocator {

@Override
Original file line number Diff line number Diff line change
@@ -81,8 +81,12 @@ public InternalMethod withDeclaringModule(RubyModule newDeclaringModule) {
}
}

public InternalMethod withNewName(String newName) {
return new InternalMethod(sharedMethodInfo, newName, declaringModule, visibility, undefined, callTarget, declarationFrame);
public InternalMethod withName(String newName) {
if (newName.equals(name)) {
return this;
} else {
return new InternalMethod(sharedMethodInfo, newName, declaringModule, visibility, undefined, callTarget, declarationFrame);
}
}

public InternalMethod withVisibility(Visibility newVisibility) {
4 changes: 3 additions & 1 deletion truffle/src/main/ruby/core/rubinius/common/exception.rb
Original file line number Diff line number Diff line change
@@ -57,7 +57,9 @@ def exception(message=nil)
# Exception#initialize (via __initialize__) is exactly what MRI
# does.
e = clone
e.__initialize__(message)
Rubinius.privately do # Truffle: added the privately block as Exception#initialize (and its alias) should be private
e.__initialize__(message)
end
return e
end
end
2 changes: 2 additions & 0 deletions truffle/src/main/ruby/core/rubinius/delta/class.rb
Original file line number Diff line number Diff line change
@@ -28,4 +28,6 @@

class Class
undef_method :append_features
undef_method :extend_object
undef_method :module_function
end

0 comments on commit 06c53b9

Please sign in to comment.