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

Commits on Sep 10, 2016

  1. Copy the full SHA
    f5fad85 View commit details
  2. 6
    Copy the full SHA
    b904bda View commit details
11 changes: 11 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/RubyContext.java
Original file line number Diff line number Diff line change
@@ -16,9 +16,11 @@
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.instrumentation.Instrumenter;
import com.oracle.truffle.api.object.DynamicObject;

import org.jruby.Ruby;
import org.jruby.truffle.builtins.PrimitiveManager;
import org.jruby.truffle.core.CoreLibrary;
import org.jruby.truffle.core.CoreMethods;
import org.jruby.truffle.core.encoding.EncodingManager;
import org.jruby.truffle.core.exception.CoreExceptions;
import org.jruby.truffle.core.kernel.AtExitManager;
@@ -88,6 +90,7 @@ public class RubyContext extends ExecutionContext {

private final NativePlatform nativePlatform;
private final CoreLibrary coreLibrary;
private final CoreMethods coreMethods;
private final ThreadManager threadManager;
private final LexicalScope rootLexicalScope;
private final InstrumentationServerManager instrumentationServerManager;
@@ -156,6 +159,10 @@ public RubyContext(Ruby jrubyRuntime, TruffleLanguage.Env env) {
coreLibrary.addCoreMethods(primitiveManager);
org.jruby.Main.printTruffleTimeMetric("after-load-nodes");

// Capture known builtin methods

coreMethods = new CoreMethods(coreLibrary);

// Load the reset of the core library

coreLibrary.loadRubyCore();
@@ -252,6 +259,10 @@ public CoreLibrary getCoreLibrary() {
return coreLibrary;
}

public CoreMethods getCoreMethods() {
return coreMethods;
}

public PrintStream getDebugStandardOut() {
return debugStandardOut;
}
68 changes: 68 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/core/CoreMethods.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.core;

import org.jruby.truffle.Layouts;
import org.jruby.truffle.core.numeric.FixnumNodesFactory;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.dispatch.RubyCallNode;
import org.jruby.truffle.language.dispatch.RubyCallNodeParameters;
import org.jruby.truffle.language.methods.InternalMethod;

import com.oracle.truffle.api.object.DynamicObject;

public class CoreMethods {

private final InternalMethod fixnumPlus;
private final InternalMethod fixnumMinus;
private final InternalMethod fixnumMul;
private final InternalMethod fixnumDiv;

public CoreMethods(CoreLibrary coreLibrary) {
fixnumPlus = getMethod(coreLibrary.getFixnumClass(), "+");
fixnumMinus = getMethod(coreLibrary.getFixnumClass(), "-");
fixnumMul = getMethod(coreLibrary.getFixnumClass(), "*");
fixnumDiv = getMethod(coreLibrary.getFixnumClass(), "/");
}

private InternalMethod getMethod(DynamicObject module, String name) {
InternalMethod method = Layouts.MODULE.getFields(module).getMethod(name);
if (method == null) {
throw new AssertionError();
}
return method;
}

public RubyNode createCallNode(RubyCallNodeParameters callParameters) {
if (callParameters.getBlock() != null || callParameters.isSplatted() || callParameters.isSafeNavigation()) {
return new RubyCallNode(callParameters);
}

int n = 1 /* self */ + callParameters.getArguments().length;

if (n == 2) {
switch (callParameters.getMethodName()) {
case "+":
return InlinedCoreMethodNode.inlineBuiltin(callParameters, fixnumPlus, FixnumNodesFactory.AddNodeFactory.getInstance());
case "-":
return InlinedCoreMethodNode.inlineBuiltin(callParameters, fixnumMinus, FixnumNodesFactory.SubNodeFactory.getInstance());
case "*":
return InlinedCoreMethodNode.inlineBuiltin(callParameters, fixnumMul, FixnumNodesFactory.MulNodeFactory.getInstance());
case "/":
return InlinedCoreMethodNode.inlineBuiltin(callParameters, fixnumDiv, FixnumNodesFactory.DivNodeFactory.getInstance());
default:
}
}

return new RubyCallNode(callParameters);
}


}
10 changes: 10 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/core/InlinableBuiltin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.jruby.truffle.core;

import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeInterface;

public interface InlinableBuiltin extends NodeInterface {

public Object executeBuiltin(VirtualFrame frame, Object... arguments);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.core;

import java.util.Arrays;
import java.util.List;

import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.CoreMethodNodeManager;
import org.jruby.truffle.core.array.ArrayUtils;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.dispatch.RubyCallNode;
import org.jruby.truffle.language.dispatch.RubyCallNodeParameters;
import org.jruby.truffle.language.methods.InternalMethod;
import org.jruby.truffle.language.methods.LookupMethodNode;
import org.jruby.truffle.language.methods.LookupMethodNodeGen;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.ExplodeLoop;

public class InlinedCoreMethodNode extends RubyNode {

private final RubyCallNodeParameters callNodeParameters;
private final InternalMethod method;

@Child InlinableBuiltin builtin;
@Child LookupMethodNode lookupMethodNode;
@Child RubyNode receiverNode;
@Children final RubyNode[] argumentNodes;

public InlinedCoreMethodNode(RubyCallNodeParameters callNodeParameters, InternalMethod method, InlinableBuiltin builtin) {
super(callNodeParameters.getContext(), callNodeParameters.getSection());
this.callNodeParameters = callNodeParameters;
this.method = method;
this.builtin = builtin;
this.lookupMethodNode = LookupMethodNodeGen.create(callNodeParameters.getContext(), callNodeParameters.getSection(), false, false, null, null);
this.receiverNode = callNodeParameters.getReceiver();
this.argumentNodes = callNodeParameters.getArguments();
}

public boolean guard(Object[] args) {
// TODO (eregon, 10 Sep 2016): specific to some Fixnum methods obviously, use a guard node or subclasses
return args[1] instanceof Integer;
}

@Override
public Object execute(VirtualFrame frame) {
final Object self = receiverNode.execute(frame);
final InternalMethod lookedUpMethod = lookupMethodNode.executeLookupMethod(frame, self, method.getName());
final Object[] arguments = executeArguments(frame, self);

if (lookedUpMethod != method || !guard(arguments)) {
CompilerDirectives.transferToInterpreterAndInvalidate();
RubyCallNode callNode = rewriteToCallNode();
Object[] argumentsObjects = ArrayUtils.extractRange(arguments, 1, arguments.length);
return callNode.executeWithArgumentEvaluated(frame, arguments[0], argumentsObjects);
}

return builtin.executeBuiltin(frame, arguments);
}

@ExplodeLoop
private Object[] executeArguments(VirtualFrame frame, Object self) {
final Object[] arguments = new Object[1 + argumentNodes.length];

arguments[0] = self;
for (int i = 0; i < argumentNodes.length; i++) {
arguments[1 + i] = argumentNodes[i].execute(frame);
}

return arguments;
}

private RubyCallNode rewriteToCallNode() {
CompilerDirectives.transferToInterpreterAndInvalidate();
RubyCallNode callNode = new RubyCallNode(callNodeParameters);
return replace(callNode, method.getName() + " was redefined");
}

public static InlinedCoreMethodNode inlineBuiltin(RubyCallNodeParameters callParameters, InternalMethod method, NodeFactory<? extends InlinableBuiltin> builtinFactory) {
final RubyContext context = callParameters.getContext();
// Let arguments to null as we need to execute self once to lookup resolves the same method
final List<RubyNode> arguments = Arrays.asList(new RubyNode[1 + callParameters.getArguments().length]);
final InlinableBuiltin builtinNode = CoreMethodNodeManager.createNodeFromFactory(context, callParameters.getSection(), builtinFactory, arguments);

return new InlinedCoreMethodNode(callParameters, method, builtinNode);
}

@Override
public Object isDefined(VirtualFrame frame) {
return rewriteToCallNode().isDefined(frame);
}

}
Original file line number Diff line number Diff line change
@@ -1182,7 +1182,7 @@ public abstract static class MethodNode extends CoreMethodNode {
public MethodNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
nameToJavaStringNode = NameToJavaStringNode.create();
lookupMethodNode = LookupMethodNodeGen.create(context, sourceSection, null, null);
lookupMethodNode = LookupMethodNodeGen.create(context, sourceSection, true, false, null, null);
respondToMissingNode = DispatchHeadNodeFactory.createMethodCall(getContext(), true);
}

@@ -1196,11 +1196,12 @@ public DynamicObject method(VirtualFrame frame, Object self, DynamicObject name,
@Cached("createBinaryProfile()") ConditionProfile notFoundProfile,
@Cached("createBinaryProfile()") ConditionProfile respondToMissingProfile) {
final String normalizedName = nameToJavaStringNode.executeToJavaString(frame, name);
InternalMethod method = lookupMethodNode.executeLookupMethod(self, normalizedName);
InternalMethod method = lookupMethodNode.executeLookupMethod(frame, self, normalizedName);

if (notFoundProfile.profile(method == null)) {
if (respondToMissingProfile.profile(respondToMissingNode.callBoolean(frame, self, "respond_to_missing?", null, name, true))) {
method = createMissingMethod(self, name, normalizedName);
final InternalMethod methodMissing = lookupMethodNode.executeLookupMethod(frame, self, "method_missing").withName(normalizedName);
method = createMissingMethod(self, name, normalizedName, methodMissing);
} else {
throw new RaiseException(coreExceptions().nameErrorUndefinedMethod(normalizedName, coreLibrary().getLogicalClass(self), this));
}
@@ -1210,18 +1211,15 @@ public DynamicObject method(VirtualFrame frame, Object self, DynamicObject name,
}

@TruffleBoundary
private InternalMethod createMissingMethod(Object self, DynamicObject name, final String normalizedName) {
InternalMethod method;
final InternalMethod methodMissing = lookupMethodNode.executeLookupMethod(self, "method_missing").withName(normalizedName);
private InternalMethod createMissingMethod(Object self, DynamicObject name, String normalizedName, InternalMethod methodMissing) {
final SharedMethodInfo info = methodMissing.getSharedMethodInfo().withName(normalizedName);

final RubyNode newBody = new CallMethodMissingWithStaticName(getContext(), info.getSourceSection(), name);
final RubyRootNode newRootNode = new RubyRootNode(getContext(), info.getSourceSection(), new FrameDescriptor(nil()), info, newBody, false);
final CallTarget newCallTarget = Truffle.getRuntime().createCallTarget(newRootNode);

final DynamicObject module = coreLibrary().getMetaClass(self);
method = new InternalMethod(info, normalizedName, module, Visibility.PUBLIC, newCallTarget);
return method;
return new InternalMethod(info, normalizedName, module, Visibility.PUBLIC, newCallTarget);
}

private static class CallMethodMissingWithStaticName extends RubyNode {
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@
import org.jruby.truffle.builtins.Primitive;
import org.jruby.truffle.builtins.PrimitiveArrayArgumentsNode;
import org.jruby.truffle.core.CoreLibrary;
import org.jruby.truffle.core.InlinableBuiltin;
import org.jruby.truffle.core.numeric.FixnumNodesFactory.DivNodeFactory;
import org.jruby.truffle.core.rope.LazyIntRope;
import org.jruby.truffle.language.NotProvided;
@@ -78,7 +79,9 @@ public Object negWithOverflow(long value) {
}

@CoreMethod(names = "+", required = 1)
public abstract static class AddNode extends BignumNodes.BignumCoreMethodNode {
public abstract static class AddNode extends BignumNodes.BignumCoreMethodNode implements InlinableBuiltin {

public abstract Object executeBuiltin(VirtualFrame frame, Object... arguments);

@Specialization(rewriteOn = ArithmeticException.class)
public int add(int a, int b) {
@@ -131,7 +134,9 @@ public Object addCoerced(
}

@CoreMethod(names = "-", required = 1)
public abstract static class SubNode extends BignumNodes.BignumCoreMethodNode {
public abstract static class SubNode extends BignumNodes.BignumCoreMethodNode implements InlinableBuiltin {

public abstract Object executeBuiltin(VirtualFrame frame, Object... arguments);

@Specialization(rewriteOn = ArithmeticException.class)
public int sub(int a, int b) {
@@ -184,7 +189,9 @@ public Object subCoerced(
}

@CoreMethod(names = "*", required = 1)
public abstract static class MulNode extends BignumNodes.BignumCoreMethodNode {
public abstract static class MulNode extends BignumNodes.BignumCoreMethodNode implements InlinableBuiltin {

public abstract Object executeBuiltin(VirtualFrame frame, Object... arguments);

@Specialization(rewriteOn = ArithmeticException.class)
public int mul(int a, int b) {
@@ -238,7 +245,7 @@ public Object mulCoerced(
}

@CoreMethod(names = { "/", "__slash__" }, required = 1)
public abstract static class DivNode extends CoreMethodArrayArgumentsNode {
public abstract static class DivNode extends CoreMethodArrayArgumentsNode implements InlinableBuiltin {

private final BranchProfile bGreaterZero = BranchProfile.create();
private final BranchProfile bGreaterZeroAGreaterEqualZero = BranchProfile.create();
@@ -249,6 +256,8 @@ public abstract static class DivNode extends CoreMethodArrayArgumentsNode {
private final BranchProfile bMinusOneANotMinimum = BranchProfile.create();
private final BranchProfile finalCase = BranchProfile.create();

public abstract Object executeBuiltin(VirtualFrame frame, Object... arguments);

public abstract Object executeDiv(VirtualFrame frame, Object a, Object b);

// int
Original file line number Diff line number Diff line change
@@ -9,15 +9,13 @@
*/
package org.jruby.truffle.language.dispatch;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.NodeUtil;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.module.ModuleOperations;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.methods.InternalMethod;
import org.jruby.truffle.language.methods.LookupMethodNode;

public abstract class DispatchNode extends RubyNode {

@@ -47,37 +45,13 @@ public abstract Object executeDispatch(
DynamicObject blockObject,
Object[] argumentsObjects);

@TruffleBoundary
protected InternalMethod lookup(
DynamicObject callerClass,
VirtualFrame frame,
Object receiver,
String name,
boolean ignoreVisibility) {
final InternalMethod method = ModuleOperations.lookupMethod(coreLibrary().getMetaClass(receiver), name);

// If no method was found, use #method_missing
if (method == null) {
return null;
}

// Check for methods that are explicitly undefined
if (method.isUndefined()) {
return null;
}

// Check visibility
if (!ignoreVisibility) {
if (getHeadNode().onlyCallPublic) {
if (!method.getVisibility().isPublic()) {
return null;
}
} else if (!method.isVisibleTo(callerClass)) {
return null;
}
}


return method;
return LookupMethodNode.lookupMethodWithVisibility(getContext(), frame, receiver, name,
ignoreVisibility, getHeadNode().onlyCallPublic, getDispatchAction() == DispatchAction.RESPOND_TO_METHOD);
}

protected Object resetAndDispatch(
Original file line number Diff line number Diff line change
@@ -93,6 +93,11 @@ public Object execute(VirtualFrame frame) {
}

final Object[] argumentsObjects = executeArguments(frame);

return executeWithArgumentEvaluated(frame, receiverObject, argumentsObjects);
}

public Object executeWithArgumentEvaluated(VirtualFrame frame, Object receiverObject, Object[] argumentsObjects) {
final DynamicObject blockObject = executeBlock(frame);

if (dispatchHead == null) {
Loading