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: be9d57f948b7
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 346f6dc78e9b
Choose a head ref
  • 2 commits
  • 7 files changed
  • 1 contributor

Commits on Dec 12, 2015

  1. [Truffle] Extract IsANode outside of KernelNodes.

    * Also optimize metaclass by caching the shape.
    eregon committed Dec 12, 2015
    Copy the full SHA
    ef2dbd6 View commit details
  2. [Truffle] Optimize Module#===.

    eregon committed Dec 12, 2015
    Copy the full SHA
    346f6dc View commit details
Original file line number Diff line number Diff line change
@@ -16,12 +16,13 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.KernelNodes;
import org.jruby.truffle.nodes.core.KernelNodesFactory;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.nodes.dispatch.MissingBehavior;
import org.jruby.truffle.nodes.objects.IsANode;
import org.jruby.truffle.nodes.objects.IsANodeGen;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;

@@ -31,14 +32,14 @@
@NodeChild(value = "value", type = RubyNode.class)
public abstract class NumericToFloatNode extends RubyNode {

@Child private KernelNodes.IsANode isANode;
@Child private IsANode isANode;
@Child CallDispatchHeadNode toFloatCallNode;

private final String method;

public NumericToFloatNode(RubyContext context, SourceSection sourceSection, String method) {
super(context, sourceSection);
isANode = KernelNodesFactory.IsANodeFactory.create(context, sourceSection, new RubyNode[] { null, null });
isANode = IsANodeGen.create(context, sourceSection, null, null);
this.method = method;
}

Original file line number Diff line number Diff line change
@@ -9,11 +9,9 @@
*/
package org.jruby.truffle.nodes.core;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.RootCallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.*;
import com.oracle.truffle.api.frame.*;
@@ -31,7 +29,6 @@
import org.jcodings.Encoding;
import org.jcodings.specific.USASCIIEncoding;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.exceptions.MainExitException;
import org.jruby.runtime.Visibility;
import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.RubyNode;
@@ -51,7 +48,6 @@
import org.jruby.truffle.nodes.core.ProcNodes.ProcNewNode;
import org.jruby.truffle.nodes.core.ProcNodesFactory.ProcNewNodeFactory;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.nodes.dispatch.DoesRespondDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.MissingBehavior;
@@ -1139,36 +1135,18 @@ public DynamicObject instanceVariables(DynamicObject self) {
}

@CoreMethod(names = { "is_a?", "kind_of?" }, required = 1)
public abstract static class IsANode extends CoreMethodArrayArgumentsNode {
public abstract static class KernelIsANode extends CoreMethodArrayArgumentsNode {

@Child MetaClassNode metaClassNode;
@Child IsANode isANode;

public IsANode(RubyContext context, SourceSection sourceSection) {
public KernelIsANode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
metaClassNode = MetaClassNodeGen.create(context, sourceSection, null);
isANode = IsANodeGen.create(context, sourceSection, null, null);
}

public abstract boolean executeIsA(Object self, DynamicObject rubyClass);

@Specialization(
limit = "getCacheLimit()",
guards = { "isRubyModule(module)", "getMetaClass(self) == cachedMetaClass", "module == cachedModule" },
assumptions = "getUnmodifiedAssumption(cachedModule)")
public boolean isACached(Object self,
DynamicObject module,
@Cached("getMetaClass(self)") DynamicObject cachedMetaClass,
@Cached("module") DynamicObject cachedModule,
@Cached("isA(cachedMetaClass, cachedModule)") boolean result) {
return result;
}

public Assumption getUnmodifiedAssumption(DynamicObject module) {
return Layouts.MODULE.getFields(module).getUnmodifiedAssumption();
}

@Specialization(guards = "isRubyModule(module)")
public boolean isAUncached(Object self, DynamicObject module) {
return isA(getMetaClass(self), module);
@Specialization
public boolean isA(Object self, DynamicObject module) {
return isANode.executeIsA(self, module);
}

@Specialization(guards = "!isRubyModule(module)")
@@ -1177,19 +1155,6 @@ public boolean isATypeError(Object self, Object module) {
throw new RaiseException(getContext().getCoreLibrary().typeError("class or module required", this));
}

@TruffleBoundary
protected boolean isA(DynamicObject metaClass, DynamicObject module) {
return ModuleOperations.assignableTo(metaClass, module);
}

protected DynamicObject getMetaClass(Object object) {
return metaClassNode.executeMetaClass(object);
}

protected int getCacheLimit() {
return getContext().getOptions().IS_A_CACHE;
}

}

@CoreMethod(names = "lambda", isModuleFunction = true, needsBlock = true)
27 changes: 15 additions & 12 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/MathNodes.java
Original file line number Diff line number Diff line change
@@ -15,11 +15,13 @@
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;

import org.jruby.RubyMath;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.nodes.dispatch.MissingBehavior;
import org.jruby.truffle.nodes.objects.IsANode;
import org.jruby.truffle.nodes.objects.IsANodeGen;
import org.jruby.truffle.runtime.NotProvided;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
@@ -312,12 +314,12 @@ protected double doFunction(double a) {
@CoreMethod(names = "frexp", isModuleFunction = true, required = 1)
public abstract static class FrExpNode extends CoreMethodArrayArgumentsNode {

@Child private KernelNodes.IsANode isANode;
@Child private IsANode isANode;
@Child private CallDispatchHeadNode floatNode;

public FrExpNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
isANode = KernelNodesFactory.IsANodeFactory.create(context, sourceSection, new RubyNode[]{null, null});
isANode = IsANodeGen.create(context, sourceSection, null, null);
floatNode = DispatchHeadNodeFactory.createMethodCall(context, MissingBehavior.RETURN_MISSING);
}

@@ -443,13 +445,13 @@ protected double doFunction(double a, double b) {
@CoreMethod(names = "ldexp", isModuleFunction = true, required = 2)
public abstract static class LdexpNode extends CoreMethodArrayArgumentsNode {

@Child private KernelNodes.IsANode isANode;
@Child private IsANode isANode;
@Child private CallDispatchHeadNode floatANode;
@Child private CallDispatchHeadNode integerBNode;

protected LdexpNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
isANode = KernelNodesFactory.IsANodeFactory.create(context, sourceSection, new RubyNode[]{null, null});
isANode = IsANodeGen.create(context, sourceSection, null, null);
floatANode = DispatchHeadNodeFactory.createMethodCall(context, MissingBehavior.RETURN_MISSING);
integerBNode = DispatchHeadNodeFactory.createMethodCall(context, MissingBehavior.RETURN_MISSING);
}
@@ -538,12 +540,12 @@ public double function(VirtualFrame frame, Object a, Object b) {
@CoreMethod(names = "lgamma", isModuleFunction = true, required = 1)
public abstract static class LGammaNode extends CoreMethodArrayArgumentsNode {

@Child private KernelNodes.IsANode isANode;
@Child private IsANode isANode;
@Child private CallDispatchHeadNode floatNode;

public LGammaNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
isANode = KernelNodesFactory.IsANodeFactory.create(context, sourceSection, new RubyNode[]{null, null});
isANode = IsANodeGen.create(context, sourceSection, null, null);
floatNode = DispatchHeadNodeFactory.createMethodCall(context, MissingBehavior.RETURN_MISSING);
}

@@ -758,12 +760,12 @@ protected double doFunction(double a) {

protected abstract static class SimpleMonadicMathNode extends CoreMethodArrayArgumentsNode {

@Child private KernelNodes.IsANode isANode;
@Child private IsANode isANode;
@Child private CallDispatchHeadNode floatNode;

protected SimpleMonadicMathNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
isANode = KernelNodesFactory.IsANodeFactory.create(context, sourceSection, new RubyNode[]{null, null});
isANode = IsANodeGen.create(context, sourceSection, null, null);
floatNode = DispatchHeadNodeFactory.createMethodCall(context, MissingBehavior.RETURN_MISSING);
}

@@ -807,13 +809,13 @@ public double function(VirtualFrame frame, Object a) {

protected abstract static class SimpleDyadicMathNode extends CoreMethodArrayArgumentsNode {

@Child protected KernelNodes.IsANode isANode;
@Child protected IsANode isANode;
@Child protected CallDispatchHeadNode floatANode;
@Child protected CallDispatchHeadNode floatBNode;

protected SimpleDyadicMathNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
isANode = KernelNodesFactory.IsANodeFactory.create(context, sourceSection, new RubyNode[]{null, null});
isANode = IsANodeGen.create(context, sourceSection, null, null);
floatANode = DispatchHeadNodeFactory.createMethodCall(context, MissingBehavior.RETURN_MISSING);
floatBNode = DispatchHeadNodeFactory.createMethodCall(context, MissingBehavior.RETURN_MISSING);
}
@@ -906,7 +908,8 @@ public double function(double a, double b) {

@Fallback
public double function(VirtualFrame frame, Object a, Object b) {
if (isANode.executeIsA(a, getContext().getCoreLibrary().getNumericClass()) && isANode.executeIsA(b, getContext().getCoreLibrary().getNumericClass())) {
if (isANode.executeIsA(a, getContext().getCoreLibrary().getNumericClass()) &&
isANode.executeIsA(b, getContext().getCoreLibrary().getNumericClass())) {
return doFunction(
floatANode.callFloat(frame, a, "to_f", null),
floatBNode.callFloat(frame, b, "to_f", null));
Original file line number Diff line number Diff line change
@@ -89,29 +89,18 @@ public static DynamicObject createRubyModule(RubyContext context, DynamicObject
@CoreMethod(names = "===", required = 1)
public abstract static class ContainsInstanceNode extends CoreMethodArrayArgumentsNode {

@Child private MetaClassNode metaClassNode;
@Child private IsANode isANode;

public ContainsInstanceNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
metaClassNode = MetaClassNodeGen.create(context, sourceSection, null);
isANode = IsANodeGen.create(context, sourceSection, null, null);
}

@Specialization
public boolean containsInstance(DynamicObject module, DynamicObject instance) {
return includes(Layouts.BASIC_OBJECT.getMetaClass(instance), module);
return isANode.executeIsA(instance, module);
}

@Specialization(guards = "!isDynamicObject(instance)")
public boolean containsInstance(DynamicObject module, Object instance) {
return includes(metaClassNode.executeMetaClass(instance), module);
}

@TruffleBoundary
public boolean includes(DynamicObject metaClass, DynamicObject module) {
assert RubyGuards.isRubyModule(metaClass);
assert RubyGuards.isRubyModule(module);
return ModuleOperations.includesModule(metaClass, module);
}
}

@CoreMethod(names = "<", required = 1)
Original file line number Diff line number Diff line change
@@ -9,24 +9,25 @@
*/
package org.jruby.truffle.nodes.exceptions;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.objects.IsANode;
import org.jruby.truffle.nodes.objects.IsANodeGen;
import org.jruby.truffle.runtime.RubyContext;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.KernelNodes;
import org.jruby.truffle.nodes.core.KernelNodesFactory;
import org.jruby.truffle.runtime.RubyContext;

/**
* Rescues any exception where {@code $!.is_a?(StandardError)}.
*/
public class RescueAnyNode extends RescueNode {

@Child private KernelNodes.IsANode isANode;
@Child private IsANode isANode;

public RescueAnyNode(RubyContext context, SourceSection sourceSection, RubyNode body) {
super(context, sourceSection, body);
isANode = KernelNodesFactory.IsANodeFactory.create(context, sourceSection, null);
isANode = IsANodeGen.create(context, sourceSection, null, null);
}

@Override
75 changes: 75 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/nodes/objects/IsANode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package org.jruby.truffle.nodes.objects;

import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.ModuleOperations;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.layouts.Layouts;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
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.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;

@NodeChildren({
@NodeChild("instance"),
@NodeChild("module")
})
public abstract class IsANode extends RubyNode {

@Child MetaClassWithShapeCacheNode metaClassNode;

public IsANode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
metaClassNode = MetaClassWithShapeCacheNodeGen.create(context, sourceSection, null);
}

public abstract boolean executeIsA(Object self, DynamicObject module);

@Specialization(
limit = "getCacheLimit()",
guards = { "isRubyModule(cachedModule)",
"metaClass(self) == cachedMetaClass", "module == cachedModule" },
assumptions = "getUnmodifiedAssumption(cachedModule)")
public boolean isACached(Object self,
DynamicObject module,
@Cached("metaClass(self)") DynamicObject cachedMetaClass,
@Cached("module") DynamicObject cachedModule,
@Cached("isA(cachedMetaClass, cachedModule)") boolean result) {
return result;
}

public Assumption getUnmodifiedAssumption(DynamicObject module) {
return Layouts.MODULE.getFields(module).getUnmodifiedAssumption();
}

@Specialization(guards = "isRubyModule(module)")
public boolean isAUncached(Object self, DynamicObject module) {
return isA(metaClass(self), module);
}

@Specialization(guards = "!isRubyModule(module)")
public boolean isATypeError(Object self, DynamicObject module) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().typeError("class or module required", this));
}

@TruffleBoundary
protected boolean isA(DynamicObject metaClass, DynamicObject module) {
return ModuleOperations.assignableTo(metaClass, module);
}

protected DynamicObject metaClass(Object object) {
return metaClassNode.executeMetaClass(object);
}

protected int getCacheLimit() {
return getContext().getOptions().IS_A_CACHE;
}

}
Original file line number Diff line number Diff line change
@@ -61,6 +61,8 @@
import org.jruby.truffle.nodes.core.KernelNodesFactory;
import org.jruby.truffle.nodes.objects.ClassNode;
import org.jruby.truffle.nodes.objects.ClassNodeGen;
import org.jruby.truffle.nodes.objects.IsANode;
import org.jruby.truffle.nodes.objects.IsANodeGen;
import org.jruby.truffle.nodes.yield.YieldDispatchHeadNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
@@ -231,14 +233,14 @@ public boolean vmObjectEqual(VirtualFrame frame, Object a, Object b) {
@RubiniusPrimitive(name = "vm_object_kind_of", needsSelf = false)
public static abstract class VMObjectKindOfPrimitiveNode extends RubiniusPrimitiveNode {

@Child private KernelNodes.IsANode isANode;
@Child private IsANode isANode;

public VMObjectKindOfPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
isANode = KernelNodesFactory.IsANodeFactory.create(context, sourceSection, new RubyNode[]{ null, null });
isANode = IsANodeGen.create(context, sourceSection, null, null);
}

@Specialization(guards = "isRubyModule(rubyClass)")
@Specialization
public boolean vmObjectKindOf(Object object, DynamicObject rubyClass) {
return isANode.executeIsA(object, rubyClass);
}