Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 696656709875
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: da4d8bc53fec
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Mar 30, 2016

  1. Copy the full SHA
    c4647f5 View commit details
  2. Copy the full SHA
    7219bb6 View commit details
  3. Copy the full SHA
    da4d8bc View commit details
9 changes: 6 additions & 3 deletions truffle/src/main/java/org/jruby/truffle/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -30,6 +30,7 @@
import org.jruby.ext.ffi.Platform;
import org.jruby.ext.ffi.Platform.OS_TYPE;
import org.jruby.runtime.Constants;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.encoding.EncodingService;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.array.ArrayNodes;
@@ -53,6 +54,7 @@
import org.jruby.truffle.core.method.UnboundMethodNodesFactory;
import org.jruby.truffle.core.module.ModuleNodes;
import org.jruby.truffle.core.module.ModuleNodesFactory;
import org.jruby.truffle.core.module.ModuleOperations;
import org.jruby.truffle.core.mutex.MutexNodesFactory;
import org.jruby.truffle.core.numeric.BignumNodesFactory;
import org.jruby.truffle.core.numeric.FixnumNodesFactory;
@@ -1261,10 +1263,11 @@ public DynamicObject noMethodErrorOnReceiver(String name, Object receiver, Node
final DynamicObject logicalClass = getLogicalClass(receiver);
final String moduleName = Layouts.MODULE.getFields(logicalClass).getName();

// Do not call to_s on BasicObject
final Object to_s = getContext().getCodeLoader().inline(currentNode, "o.to_s if c.instance_methods.include?(:to_s)", "o", receiver, "c", logicalClass);
// e.g. BasicObject does not have to_s
final boolean hasToS = ModuleOperations.lookupMethod(logicalClass, "to_s", Visibility.PUBLIC) != null;
final Object stringRepresentation = hasToS ? getContext().send(receiver, "to_s", null) : getNilObject();

return noMethodError(String.format("undefined method `%s' for %s:%s", name, to_s, moduleName), name, currentNode);
return noMethodError(String.format("undefined method `%s' for %s:%s", name, stringRepresentation, moduleName), name, currentNode);
}

public DynamicObject privateMethodError(String name, Object self, Node currentNode) {
Original file line number Diff line number Diff line change
@@ -12,37 +12,53 @@
import org.jruby.runtime.Visibility;
import org.jruby.truffle.language.methods.InternalMethod;

public interface MethodFilter {
public abstract class MethodFilter {

MethodFilter PUBLIC = new MethodFilter() {
private MethodFilter() {
}

public static final MethodFilter PUBLIC = new MethodFilter() {
@Override
public boolean filter(InternalMethod method) {
return method.getVisibility() == Visibility.PUBLIC;
}
};

MethodFilter PUBLIC_PROTECTED = new MethodFilter() {
public static final MethodFilter PUBLIC_PROTECTED = new MethodFilter() {
@Override
public boolean filter(InternalMethod method) {
return method.getVisibility() == Visibility.PUBLIC ||
method.getVisibility() == Visibility.PROTECTED;
}
};

MethodFilter PROTECTED = new MethodFilter() {
public static final MethodFilter PROTECTED = new MethodFilter() {
@Override
public boolean filter(InternalMethod method) {
return method.getVisibility() == Visibility.PROTECTED;
}
};

MethodFilter PRIVATE = new MethodFilter() {
public static final MethodFilter PRIVATE = new MethodFilter() {
@Override
public boolean filter(InternalMethod method) {
return method.getVisibility() == Visibility.PRIVATE;
}
};

boolean filter(InternalMethod method);
public abstract boolean filter(InternalMethod method);

public static MethodFilter by(Visibility visibility) {
switch (visibility) {
case PUBLIC:
return PUBLIC;
case PROTECTED:
return PROTECTED;
case PRIVATE:
return PRIVATE;
default:
throw new UnsupportedOperationException("unsupported visibility: " + visibility);
}
}

}
159 changes: 61 additions & 98 deletions truffle/src/main/java/org/jruby/truffle/core/module/ModuleNodes.java
Original file line number Diff line number Diff line change
@@ -1534,14 +1534,14 @@ public DynamicObject privateClassMethod(VirtualFrame frame, DynamicObject module
}
}

@CoreMethod(names = "private_method_defined?", required = 1)
@CoreMethod(names = "public_instance_method", required = 1)
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "module"),
@NodeChild(type = RubyNode.class, value = "name")
})
public abstract static class PrivateMethodDefinedNode extends CoreMethodNode {
public abstract static class PublicInstanceMethodNode extends CoreMethodNode {

public PrivateMethodDefinedNode(RubyContext context, SourceSection sourceSection) {
public PublicInstanceMethodNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@@ -1551,22 +1551,34 @@ public RubyNode coerceToString(RubyNode name) {
}

@Specialization
public boolean isPrivateMethodDefined(DynamicObject module, String name) {
InternalMethod method = ModuleOperations.lookupMethod(module, name);
return method != null && method.getVisibility().isPrivate();
public DynamicObject publicInstanceMethod(DynamicObject module, String name) {
// TODO(CS, 11-Jan-15) cache this lookup
final InternalMethod method = ModuleOperations.lookupMethod(module, name);

if (method == null || method.isUndefined()) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(coreLibrary().nameErrorUndefinedMethod(name, module, this));
} else if (method.getVisibility() != Visibility.PUBLIC) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(coreLibrary().nameErrorPrivateMethod(name, module, this));
}

return Layouts.UNBOUND_METHOD.createUnboundMethod(coreLibrary().getUnboundMethodFactory(), module, method);
}

}

@CoreMethod(names = "protected_instance_methods", optional = 1)
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "module"),
@NodeChild(type = RubyNode.class, value = "includeAncestors")
})
public abstract static class ProtectedInstanceMethodsNode extends CoreMethodNode {
protected abstract static class AbstractInstanceMethodsNode extends CoreMethodNode {

public ProtectedInstanceMethodsNode(RubyContext context, SourceSection sourceSection) {
final Visibility visibility;

public AbstractInstanceMethodsNode(RubyContext context, SourceSection sourceSection, Visibility visibility) {
super(context, sourceSection);
this.visibility = visibility;
}

@CreateCast("includeAncestors")
@@ -1575,71 +1587,54 @@ public RubyNode coerceToBoolean(RubyNode includeAncestors) {
}

@Specialization
public DynamicObject protectedInstanceMethods(DynamicObject module, boolean includeAncestors) {
@TruffleBoundary
public DynamicObject getInstanceMethods(DynamicObject module, boolean includeAncestors) {
CompilerDirectives.transferToInterpreter();
Object[] objects = Layouts.MODULE.getFields(module).filterMethods(getContext(), includeAncestors, MethodFilter.PROTECTED).toArray();

Object[] objects = Layouts.MODULE.getFields(module).filterMethods(getContext(), includeAncestors, MethodFilter.by(visibility)).toArray();
return Layouts.ARRAY.createArray(coreLibrary().getArrayFactory(), objects, objects.length);
}

}

@CoreMethod(names = "protected_method_defined?", required = 1)
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "module"),
@NodeChild(type = RubyNode.class, value = "name")
})
public abstract static class ProtectedMethodDefinedNode extends CoreMethodNode {
@CoreMethod(names = "public_instance_methods", optional = 1)
public abstract static class PublicInstanceMethodsNode extends AbstractInstanceMethodsNode {

public ProtectedMethodDefinedNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
public PublicInstanceMethodsNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection, Visibility.PUBLIC);
}

@CreateCast("name")
public RubyNode coerceToString(RubyNode name) {
return NameToJavaStringNodeGen.create(getContext(), getSourceSection(), name);
}
}

@Specialization
public boolean isProtectedMethodDefined(DynamicObject module, String name) {
InternalMethod method = ModuleOperations.lookupMethod(module, name);
return method != null && method.getVisibility().isProtected();
@CoreMethod(names = "protected_instance_methods", optional = 1)
public abstract static class ProtectedInstanceMethodsNode extends AbstractInstanceMethodsNode {

public ProtectedInstanceMethodsNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection, Visibility.PROTECTED);
}

}

@CoreMethod(names = "private_instance_methods", optional = 1)
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "module"),
@NodeChild(type = RubyNode.class, value = "includeAncestors")
})
public abstract static class PrivateInstanceMethodsNode extends CoreMethodNode {
public abstract static class PrivateInstanceMethodsNode extends AbstractInstanceMethodsNode {

public PrivateInstanceMethodsNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

@CreateCast("includeAncestors")
public RubyNode coerceToBoolean(RubyNode includeAncestors) {
return BooleanCastWithDefaultNodeGen.create(getContext(), getSourceSection(), true, includeAncestors);
super(context, sourceSection, Visibility.PRIVATE);
}

@Specialization
public DynamicObject privateInstanceMethods(DynamicObject module, boolean includeAncestors) {
CompilerDirectives.transferToInterpreter();

Object[] objects = Layouts.MODULE.getFields(module).filterMethods(getContext(), includeAncestors, MethodFilter.PRIVATE).toArray();
return Layouts.ARRAY.createArray(coreLibrary().getArrayFactory(), objects, objects.length);
}
}

@CoreMethod(names = "public_instance_method", required = 1)

@NodeChildren({
@NodeChild(type = RubyNode.class, value = "module"),
@NodeChild(type = RubyNode.class, value = "name")
})
public abstract static class PublicInstanceMethodNode extends CoreMethodNode {
protected abstract static class AbstractMethodDefinedNode extends CoreMethodNode {

public PublicInstanceMethodNode(RubyContext context, SourceSection sourceSection) {
final Visibility visibility;

public AbstractMethodDefinedNode(RubyContext context, SourceSection sourceSection, Visibility visibility) {
super(context, sourceSection);
this.visibility = visibility;
}

@CreateCast("name")
@@ -1648,68 +1643,36 @@ public RubyNode coerceToString(RubyNode name) {
}

@Specialization
public DynamicObject publicInstanceMethod(DynamicObject module, String name) {
// TODO(CS, 11-Jan-15) cache this lookup
final InternalMethod method = ModuleOperations.lookupMethod(module, name);

if (method == null || method.isUndefined()) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(coreLibrary().nameErrorUndefinedMethod(name, module, this));
} else if (method.getVisibility() != Visibility.PUBLIC) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(coreLibrary().nameErrorPrivateMethod(name, module, this));
}

return Layouts.UNBOUND_METHOD.createUnboundMethod(coreLibrary().getUnboundMethodFactory(), module, method);
public boolean isMethodDefined(DynamicObject module, String name) {
// TODO (pitr-ch 30-Mar-2016): cache lookup
return ModuleOperations.lookupMethod(module, name, visibility) != null;
}

}

@CoreMethod(names = "public_instance_methods", optional = 1)
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "module"),
@NodeChild(type = RubyNode.class, value = "includeAncestors")
})
public abstract static class PublicInstanceMethodsNode extends CoreMethodNode {

public PublicInstanceMethodsNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}
@CoreMethod(names = "public_method_defined?", required = 1)
public abstract static class PublicMethodDefinedNode extends AbstractMethodDefinedNode {

@CreateCast("includeAncestors")
public RubyNode coerceToBoolean(RubyNode includeAncestors) {
return BooleanCastWithDefaultNodeGen.create(getContext(), getSourceSection(), true, includeAncestors);
public PublicMethodDefinedNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection, Visibility.PUBLIC);
}

@Specialization
public DynamicObject publicInstanceMethods(DynamicObject module, boolean includeAncestors) {
CompilerDirectives.transferToInterpreter();

Object[] objects = Layouts.MODULE.getFields(module).filterMethods(getContext(), includeAncestors, MethodFilter.PUBLIC).toArray();
return Layouts.ARRAY.createArray(coreLibrary().getArrayFactory(), objects, objects.length);
}
}

@CoreMethod(names = "public_method_defined?", required = 1)
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "module"),
@NodeChild(type = RubyNode.class, value = "name")
})
public abstract static class PublicMethodDefinedNode extends CoreMethodNode {
@CoreMethod(names = "protected_method_defined?", required = 1)
public abstract static class ProtectedMethodDefinedNode extends AbstractMethodDefinedNode {

public PublicMethodDefinedNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
public ProtectedMethodDefinedNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection, Visibility.PROTECTED);
}

@CreateCast("name")
public RubyNode coerceToString(RubyNode name) {
return NameToJavaStringNodeGen.create(getContext(), getSourceSection(), name);
}
}

@Specialization
public boolean isPublicMethodDefined(DynamicObject module, String name) {
InternalMethod method = ModuleOperations.lookupMethod(module, name);
return method != null && method.getVisibility() == Visibility.PUBLIC;
@CoreMethod(names = "private_method_defined?", required = 1)
public abstract static class PrivateMethodDefinedNode extends AbstractMethodDefinedNode {

public PrivateMethodDefinedNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection, Visibility.PRIVATE);
}

}
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.Layouts;
import org.jruby.truffle.language.LexicalScope;
@@ -295,6 +296,11 @@ public static InternalMethod lookupMethod(DynamicObject module, String name) {
return null;
}

public static InternalMethod lookupMethod(DynamicObject module, String name, Visibility visibility) {
InternalMethod method = lookupMethod(module, name);
return (method != null && method.getVisibility() == visibility) ? method : null;
}

public static InternalMethod lookupSuperMethod(InternalMethod currentMethod, DynamicObject objectMetaClass) {
assert RubyGuards.isRubyClass(objectMetaClass);
final String name = currentMethod.getSharedMethodInfo().getName(); // use the original name