Skip to content

Commit

Permalink
Showing 23 changed files with 592 additions and 504 deletions.
Original file line number Diff line number Diff line change
@@ -7,47 +7,44 @@
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.constants;
package org.jruby.truffle.nodes;

import com.oracle.truffle.api.source.*;
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import org.jruby.truffle.nodes.*;
import org.jruby.truffle.nodes.cast.BoxingNode;
import org.jruby.truffle.nodes.dispatch.Dispatch;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNode;
import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.control.*;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public class ReadConstantHeadNode extends RubyNode {
public class ReadConstantNode extends RubyNode {

protected final String name;
@Child protected BoxingNode receiver;
@Child protected ReadConstantNode first;

public ReadConstantHeadNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) {
@Child protected DispatchHeadNode dispatch;

public ReadConstantNode(RubyContext context, SourceSection sourceSection, String name, RubyNode receiver) {
super(context, sourceSection);
this.name = name;
this.receiver = new BoxingNode(context, sourceSection, receiver);
first = new UninitializedReadConstantNode(name);
dispatch = new DispatchHeadNode(context, Dispatch.MissingBehavior.CALL_CONST_MISSING);
}

@Override
public Object execute(VirtualFrame frame) {
return first.execute(receiver.executeRubyBasicObject(frame));
}

@Override
public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
return first.executeBoolean(receiver.executeRubyBasicObject(frame));
}

@Override
public int executeIntegerFixnum(VirtualFrame frame) throws UnexpectedResultException {
return first.executeIntegerFixnum(receiver.executeRubyBasicObject(frame));
}

@Override
public double executeFloat(VirtualFrame frame) throws UnexpectedResultException {
return first.executeFloat(receiver.executeRubyBasicObject(frame));
return dispatch.dispatch(
frame,
NilPlaceholder.INSTANCE,
RubyArguments.getSelf(frame.getArguments()),
receiver.executeRubyBasicObject(frame),
name,
null,
new Object[]{},
Dispatch.DispatchAction.READ_CONSTANT);
}

@Override
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.nodes.constants;
package org.jruby.truffle.nodes;

import com.oracle.truffle.api.*;
import com.oracle.truffle.api.source.*;

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -176,7 +176,6 @@ private Object methodMissing(RubyBasicObject self, RubySymbol name, Object[] arg
throw new RaiseException(getContext().getCoreLibrary().nameErrorNoMethod(name.toString(), self.toString(), this));
}


}

@CoreMethod(names = {"send", "__send__"}, needsBlock = true, minArgs = 1, isSplatted = true)
119 changes: 69 additions & 50 deletions core/src/main/java/org/jruby/truffle/nodes/core/ModuleNodes.java
Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@
import org.jruby.truffle.translator.TranslatorDriver;

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

@CoreClass(name = "Module")
@@ -469,6 +470,74 @@ public boolean isConstDefined(RubyModule module, RubySymbol name, @SuppressWarni

}

@CoreMethod(names = "const_missing", needsSelf = false, minArgs = 1, maxArgs = 1)
public abstract static class ConstMissingNode extends CoreMethodNode {

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

public ConstMissingNode(ConstMissingNode prev) {
super(prev);
}

@Specialization
public Object methodMissing(RubySymbol name) {
throw new RaiseException(getContext().getCoreLibrary().nameErrorUninitializedConstant(name.toString(), this));
}

}

@CoreMethod(names = "const_set", minArgs = 2, maxArgs = 2)
public abstract static class ConstSetNode extends CoreMethodNode {

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

public ConstSetNode(ConstSetNode prev) {
super(prev);
}

@Specialization
public RubyModule setConstant(RubyModule module, RubyString name, Object object) {
notDesignedForCompilation();

module.setConstant(this, name.toString(), object);
return module;
}

}

@CoreMethod(names = "class_variable_get", minArgs = 1, maxArgs = 1)
public abstract static class ClassVariableGetNode extends CoreMethodNode {

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

public ClassVariableGetNode(ClassVariableGetNode prev) {
super(prev);
}

@Specialization
public Object getClassVariable(RubyModule module, RubyString name) {
notDesignedForCompilation();
return getClassVariable(module, name.toString());
}

@Specialization
public Object getClassVariable(RubyModule module, RubySymbol name) {
notDesignedForCompilation();
return getClassVariable(module, name.toString());
}

public Object getClassVariable(RubyModule module, String name){
return module.lookupClassVariable(RubyObject.checkClassVariableName(getContext(), name, this));
}

}

@CoreMethod(names = "define_method", needsBlock = true, minArgs = 1, maxArgs = 2)
public abstract static class DefineMethodNode extends CoreMethodNode {

@@ -1172,54 +1241,4 @@ public RubyModule undefMethod(RubyModule module, RubySymbol name) {
}

}

@CoreMethod(names = "const_set", minArgs = 2, maxArgs = 2)
public abstract static class ConstSetNode extends CoreMethodNode {

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

public ConstSetNode(ConstSetNode prev) {
super(prev);
}

@Specialization
public RubyModule setConstant(RubyModule module, RubyString name, Object object) {
notDesignedForCompilation();

module.setConstant(this, name.toString(), object);
return module;
}

}

@CoreMethod(names = "class_variable_get", minArgs = 1, maxArgs = 1)
public abstract static class ClassVariableGetNode extends CoreMethodNode {

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

public ClassVariableGetNode(ClassVariableGetNode prev) {
super(prev);
}

@Specialization
public Object getClassVariable(RubyModule module, RubyString name) {
notDesignedForCompilation();
return getClassVariable(module, name.toString());
}

@Specialization
public Object getClassVariable(RubyModule module, RubySymbol name) {
notDesignedForCompilation();
return getClassVariable(module, name.toString());
}

public Object getClassVariable(RubyModule module, String name){
return module.lookupClassVariable(RubyObject.checkClassVariableName(getContext(), name, this));
}

}
}
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.nodes.dispatch;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.Fallback;
@@ -29,34 +30,48 @@ public abstract class CachedBooleanDispatchNode extends CachedDispatchNode {
private final Assumption falseUnmodifiedAssumption;
private final RubyMethod falseMethod;
private final BranchProfile falseProfile = new BranchProfile();

private final Object falseValue;
@Child protected DirectCallNode falseCall;

private final Assumption trueUnmodifiedAssumption;
private final RubyMethod trueMethod;
private final BranchProfile trueProfile = new BranchProfile();

private final Object trueValue;
@Child protected DirectCallNode trueCall;

public CachedBooleanDispatchNode(
RubyContext context, Object cachedName, DispatchNode next,
Assumption falseUnmodifiedAssumption, RubyMethod falseMethod,
Assumption trueUnmodifiedAssumption, RubyMethod trueMethod) {
Assumption falseUnmodifiedAssumption, Object falseValue, RubyMethod falseMethod,
Assumption trueUnmodifiedAssumption, Object trueValue, RubyMethod trueMethod) {
super(context, cachedName, next);

this.falseUnmodifiedAssumption = falseUnmodifiedAssumption;
this.falseMethod = falseMethod;
falseCall = Truffle.getRuntime().createDirectCallNode(falseMethod.getCallTarget());
this.falseValue = falseValue;

if (falseMethod != null) {
falseCall = Truffle.getRuntime().createDirectCallNode(falseMethod.getCallTarget());
}

this.trueUnmodifiedAssumption = trueUnmodifiedAssumption;
this.trueMethod = trueMethod;
trueCall = Truffle.getRuntime().createDirectCallNode(trueMethod.getCallTarget());
this.trueValue = trueValue;

if (trueMethod != null) {
trueCall = Truffle.getRuntime().createDirectCallNode(trueMethod.getCallTarget());
}
}

public CachedBooleanDispatchNode(CachedBooleanDispatchNode prev) {
super(prev);
falseUnmodifiedAssumption = prev.falseUnmodifiedAssumption;
falseMethod = prev.falseMethod;
falseValue = prev.falseValue;
falseCall = prev.falseCall;
trueUnmodifiedAssumption = prev.trueUnmodifiedAssumption;
trueValue = prev.trueValue;
trueMethod = prev.trueMethod;
trueCall = prev.trueCall;
}
@@ -71,6 +86,8 @@ public Object dispatch(
Object blockObject,
Object argumentsObjects,
Dispatch.DispatchAction dispatchAction) {
CompilerAsserts.compilationConstant(dispatchAction);

if (receiverObject) {
trueProfile.enter();

@@ -100,6 +117,8 @@ public Object dispatch(
CompilerDirectives.unsafeCast(argumentsObjects, Object[].class, true)));
} else if (dispatchAction == Dispatch.DispatchAction.RESPOND) {
return true;
} else if (dispatchAction == Dispatch.DispatchAction.READ_CONSTANT) {
return trueValue;
} else {
throw new UnsupportedOperationException();
}
@@ -132,6 +151,8 @@ public Object dispatch(
CompilerDirectives.unsafeCast(argumentsObjects, Object[].class, true)));
} else if (dispatchAction == Dispatch.DispatchAction.RESPOND) {
return true;
} else if (dispatchAction == Dispatch.DispatchAction.READ_CONSTANT) {
return falseValue;
} else {
throw new UnsupportedOperationException();
}
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.nodes.dispatch;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.Fallback;
@@ -29,26 +30,32 @@ public abstract class CachedBoxedDispatchNode extends CachedDispatchNode {

private final LookupNode expectedLookupNode;
private final Assumption unmodifiedAssumption;
private final RubyMethod method;

private final Object value;

private final RubyMethod method;
@Child protected DirectCallNode callNode;

public CachedBoxedDispatchNode(RubyContext context, Object cachedName, DispatchNode next,
LookupNode expectedLookupNode, RubyMethod method) {
LookupNode expectedLookupNode, Object value, RubyMethod method) {
super(context, cachedName, next);

this.expectedLookupNode = expectedLookupNode;
this.unmodifiedAssumption = expectedLookupNode.getUnmodifiedAssumption();
this.method = method;
this.next = next;
this.value = value;
this.method = method;

callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget());
if (method != null) {
callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget());
}
}

public CachedBoxedDispatchNode(CachedBoxedDispatchNode prev) {
super(prev);
expectedLookupNode = prev.expectedLookupNode;
unmodifiedAssumption = prev.unmodifiedAssumption;
value = prev.value;
method = prev.method;
callNode = prev.callNode;
}
@@ -63,6 +70,8 @@ public Object dispatch(
Object blockObject,
Object argumentsObjects,
Dispatch.DispatchAction dispatchAction) {
CompilerAsserts.compilationConstant(dispatchAction);

// Check the lookup node is what we expect

if (receiverObject.getLookupNode() != expectedLookupNode) {
@@ -105,6 +114,8 @@ public Object dispatch(
CompilerDirectives.unsafeCast(argumentsObjects, Object[].class, true)));
} else if (dispatchAction == Dispatch.DispatchAction.RESPOND) {
return true;
} else if (dispatchAction == Dispatch.DispatchAction.READ_CONSTANT) {
return value;
} else {
throw new UnsupportedOperationException();
}
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.nodes.dispatch;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.Fallback;
@@ -63,7 +64,10 @@ public CachedBoxedMethodMissingDispatchNode(CachedBoxedMethodMissingDispatchNode
expectedLookupNode = prev.expectedLookupNode;
unmodifiedAssumption = prev.unmodifiedAssumption;
method = prev.method;
callNode = prev.callNode;

if (method != null) {
callNode = prev.callNode;
}
}

@Specialization(guards = "guardName")
@@ -76,6 +80,8 @@ public Object dispatch(
Object blockObject,
Object argumentsObjects,
Dispatch.DispatchAction dispatchAction) {
CompilerAsserts.compilationConstant(dispatchAction);

// Check the lookup node is what we expect

if (receiverObject.getLookupNode() != expectedLookupNode) {
@@ -124,6 +130,15 @@ public Object dispatch(
modifiedArgumentsObjects));
} else if (dispatchAction == Dispatch.DispatchAction.RESPOND) {
return false;
} else if (dispatchAction == Dispatch.DispatchAction.READ_CONSTANT) {
return callNode.call(
frame,
RubyArguments.pack(
method,
method.getDeclarationFrame(),
receiverObject,
CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false),
new Object[]{getCachedNameAsSymbol()}));
} else {
throw new UnsupportedOperationException();
}
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.nodes.dispatch;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
@@ -52,6 +53,8 @@ public Object dispatch(
Object blockObject,
Object argumentsObjects,
Dispatch.DispatchAction dispatchAction) {
CompilerAsserts.compilationConstant(dispatchAction);

// Check the lookup node is what we expect

if (receiverObject.getLookupNode() != expectedLookupNode) {
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.nodes.dispatch;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.Fallback;
@@ -27,22 +28,27 @@
public abstract class CachedBoxedSymbolDispatchNode extends CachedDispatchNode {

private final Assumption unmodifiedAssumption;
private final RubyMethod method;

private final Object value;

private final RubyMethod method;
@Child protected DirectCallNode callNode;

public CachedBoxedSymbolDispatchNode(RubyContext context, Object cachedName, DispatchNode next, RubyMethod method) {
public CachedBoxedSymbolDispatchNode(RubyContext context, Object cachedName, DispatchNode next, Object value, RubyMethod method) {
super(context, cachedName, next);

unmodifiedAssumption = context.getCoreLibrary().getSymbolClass().getUnmodifiedAssumption();
this.value = value;
this.method = method;

callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget());
if (method != null) {
callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget());
}
}

public CachedBoxedSymbolDispatchNode(CachedBoxedSymbolDispatchNode prev) {
super(prev);
unmodifiedAssumption = prev.unmodifiedAssumption;
value = prev.value;
method = prev.method;
callNode = prev.callNode;
}
@@ -57,6 +63,8 @@ public Object dispatch(
Object blockObject,
Object argumentsObjects,
Dispatch.DispatchAction dispatchAction) {
CompilerAsserts.compilationConstant(dispatchAction);

// Check no symbols have had their lookup modified

try {
@@ -102,6 +110,8 @@ public Object dispatch(
CompilerDirectives.unsafeCast(argumentsObjects, Object[].class, true)));
} else if (dispatchAction == Dispatch.DispatchAction.RESPOND) {
return true;
} else if (dispatchAction == Dispatch.DispatchAction.READ_CONSTANT) {
return value;
} else {
throw new UnsupportedOperationException();
}
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.nodes.dispatch;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.Fallback;
@@ -28,25 +29,31 @@ public abstract class CachedUnboxedDispatchNode extends CachedDispatchNode {

private final Class expectedClass;
private final Assumption unmodifiedAssumption;
private final RubyMethod method;

private final Object value;

private final RubyMethod method;
@Child protected DirectCallNode callNode;

public CachedUnboxedDispatchNode(RubyContext context, Object cachedName, DispatchNode next,
Class expectedClass, Assumption unmodifiedAssumption, RubyMethod method) {
Class expectedClass, Assumption unmodifiedAssumption, Object value,
RubyMethod method) {
super(context, cachedName, next);

this.expectedClass = expectedClass;
this.unmodifiedAssumption = unmodifiedAssumption;
this.value = value;
this.method = method;

this.callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget());
if (method != null) {
callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget());
}
}

public CachedUnboxedDispatchNode(CachedUnboxedDispatchNode prev) {
super(prev);
expectedClass = prev.expectedClass;
unmodifiedAssumption = prev.unmodifiedAssumption;
value = prev.value;
method = prev.method;
callNode = prev.callNode;
}
@@ -61,6 +68,8 @@ public Object dispatch(
Object blockObject,
Object argumentsObjects,
Dispatch.DispatchAction dispatchAction) {
CompilerAsserts.compilationConstant(dispatchAction);

// Check the class is what we expect

if (receiverObject.getClass() != expectedClass) {
@@ -102,6 +111,8 @@ public Object dispatch(
CompilerDirectives.unsafeCast(argumentsObjects, Object[].class, true)));
} else if (dispatchAction == Dispatch.DispatchAction.RESPOND) {
return true;
} else if (dispatchAction == Dispatch.DispatchAction.READ_CONSTANT) {
return value;
} else {
throw new UnsupportedOperationException();
}
16 changes: 14 additions & 2 deletions core/src/main/java/org/jruby/truffle/nodes/dispatch/Dispatch.java
Original file line number Diff line number Diff line change
@@ -13,12 +13,24 @@ public class Dispatch {

public static enum MissingBehavior {
RETURN_MISSING,
CALL_CONST_MISSING,
CALL_METHOD_MISSING
}

public static enum DispatchAction {
CALL,
RESPOND
READ_CONSTANT(false),
CALL(true),
RESPOND(true);

private final boolean isCall;

private DispatchAction(boolean isCall) {
this.isCall = isCall;
}

public boolean isCall() {
return isCall;
}
}

public static final Object MISSING = new Object();
Original file line number Diff line number Diff line change
@@ -10,19 +10,18 @@
package org.jruby.truffle.nodes.dispatch;

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeUtil;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyConstant;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyProc;
import org.jruby.truffle.runtime.core.RubyString;
import org.jruby.truffle.runtime.core.RubySymbol;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.methods.RubyMethod;

@NodeChildren({
@@ -53,20 +52,45 @@ public abstract Object executeDispatch(
Object argumentsObjects,
Dispatch.DispatchAction dispatchAction);

protected RubyConstant lookupConstant(
RubyBasicObject callingSelf,
RubyBasicObject receiver,
String name,
boolean ignoreVisibility,
Dispatch.DispatchAction dispatchAction) {
CompilerAsserts.neverPartOfCompilation();

RubyConstant constant;

constant = receiver.getLookupNode().lookupConstant(name);

if (constant == null && receiver instanceof RubyModule) {
/*
* FIXME(CS): I'm obviously doing something wrong with constant lookup in nested modules
* here, but explicitly looking in the Module itself, not its lookup node, seems to fix
* it for now.
*/

constant = ((RubyModule) receiver).lookupConstant(name);
}

return constant;
}

protected RubyMethod lookup(
RubyBasicObject callingSelf,
RubyBasicObject receiver,
String name,
boolean ignoreVisibility,
Dispatch.DispatchAction dispatchAction) throws UseMethodMissingException {
Dispatch.DispatchAction dispatchAction) {
CompilerAsserts.neverPartOfCompilation();

RubyMethod method = receiver.getLookupNode().lookupMethod(name);

// If no method was found, use #method_missing

if (method == null) {
throw new UseMethodMissingException();
return null;
}

// Check for methods that are explicitly undefined
@@ -85,7 +109,7 @@ protected RubyMethod lookup(
if (dispatchAction == Dispatch.DispatchAction.CALL) {
throw new RaiseException(getContext().getCoreLibrary().noMethodError(name, receiver.toString(), this));
} else if (dispatchAction == Dispatch.DispatchAction.RESPOND) {
throw new UseMethodMissingException();
return null;
} else {
throw new UnsupportedOperationException();
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import org.jruby.truffle.runtime.RubyConstant;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.*;
@@ -90,55 +91,117 @@ private Object doUnboxedObject(
Object methodReceiverObject) {
final RubyBasicObject boxedCallingSelf = getContext().getCoreLibrary().box(callingSelf);
final RubyBasicObject boxedReceiverObject = getContext().getCoreLibrary().box(receiverObject);
final RubyMethod method;

try {
method = lookup(boxedCallingSelf, boxedReceiverObject, methodName.toString(), ignoreVisibility,
if (dispatchAction.isCall()) {
final RubyMethod method = lookup(boxedCallingSelf, boxedReceiverObject, methodName.toString(), ignoreVisibility,
dispatchAction);
} catch (UseMethodMissingException e) {
final DispatchNode newDispatch = createMethodMissingNode(methodName, boxedCallingSelf,
boxedReceiverObject, dispatchAction);
return newDispatch.executeDispatch(frame, methodReceiverObject, boxedCallingSelf, boxedReceiverObject,
methodName, blockObject, argumentsObjects, dispatchAction);
}

if (receiverObject instanceof Boolean) {
try {
if (method == null) {
final DispatchNode newDispatch = createMethodMissingNode(methodName, boxedCallingSelf,
boxedReceiverObject, dispatchAction);
return newDispatch.executeDispatch(frame, methodReceiverObject, boxedCallingSelf, boxedReceiverObject,
methodName, blockObject, argumentsObjects, dispatchAction);
}

if (receiverObject instanceof Boolean) {
final Assumption falseUnmodifiedAssumption =
getContext().getCoreLibrary().getFalseClass().getUnmodifiedAssumption();

final RubyMethod falseMethod =
lookup(boxedCallingSelf, getContext().getCoreLibrary().box(false), methodName.toString(),
ignoreVisibility, dispatchAction);

if (falseMethod == null) {
throw new UnsupportedOperationException();
}

final Assumption trueUnmodifiedAssumption =
getContext().getCoreLibrary().getTrueClass().getUnmodifiedAssumption();

final RubyMethod trueMethod =
lookup(boxedCallingSelf, getContext().getCoreLibrary().box(true), methodName.toString(),
ignoreVisibility, dispatchAction);

if (trueMethod == null) {
throw new UnsupportedOperationException();
}

final CachedBooleanDispatchNode newDispatch = CachedBooleanDispatchNodeFactory.create(getContext(),
methodName, first, falseUnmodifiedAssumption, falseMethod, trueUnmodifiedAssumption,
trueMethod, null, null, null, null, null, null, null);
methodName, first,
falseUnmodifiedAssumption, null, falseMethod,
trueUnmodifiedAssumption, null, trueMethod,
null, null, null, null, null, null, null);

first.replace(newDispatch);

return newDispatch.executeDispatch(frame, methodReceiverObject, callingSelf, receiverObject,
methodName, blockObject, argumentsObjects, dispatchAction);
} catch (UseMethodMissingException e) {
throw new UnsupportedOperationException();
} else {
final CachedUnboxedDispatchNode newDispatch = CachedUnboxedDispatchNodeFactory.create(getContext(),
methodName, first, receiverObject.getClass(),
boxedReceiverObject.getRubyClass().getUnmodifiedAssumption(), null, method, null, null, null, null,
null, null, null);

first.replace(newDispatch);

return newDispatch.executeDispatch(frame, methodReceiverObject, callingSelf, receiverObject, methodName,
blockObject, argumentsObjects, dispatchAction);
}
} else {
final CachedUnboxedDispatchNode newDispatch = CachedUnboxedDispatchNodeFactory.create(getContext(),
methodName, first, receiverObject.getClass(),
boxedReceiverObject.getRubyClass().getUnmodifiedAssumption(), method, null, null, null, null,
null, null, null);
final RubyConstant constant = lookupConstant(boxedCallingSelf, boxedReceiverObject, methodName.toString(), ignoreVisibility,
dispatchAction);

first.replace(newDispatch);
if (constant == null) {
final DispatchNode newDispatch = createMethodMissingNode(methodName, boxedCallingSelf,
boxedReceiverObject, dispatchAction);
return newDispatch.executeDispatch(frame, methodReceiverObject, boxedCallingSelf, boxedReceiverObject,
methodName, blockObject, argumentsObjects, dispatchAction);
}

if (receiverObject instanceof Boolean) {
final Assumption falseUnmodifiedAssumption =
getContext().getCoreLibrary().getFalseClass().getUnmodifiedAssumption();

final RubyConstant falseConstant =
lookupConstant(boxedCallingSelf, getContext().getCoreLibrary().box(false), methodName.toString(),
ignoreVisibility, dispatchAction);

return newDispatch.executeDispatch(frame, methodReceiverObject, callingSelf, receiverObject, methodName,
blockObject, argumentsObjects, dispatchAction);
if (falseConstant == null) {
throw new UnsupportedOperationException();
}

final Assumption trueUnmodifiedAssumption =
getContext().getCoreLibrary().getTrueClass().getUnmodifiedAssumption();

final RubyConstant trueConstant =
lookupConstant(boxedCallingSelf, getContext().getCoreLibrary().box(true), methodName.toString(),
ignoreVisibility, dispatchAction);

if (trueConstant == null) {
throw new UnsupportedOperationException();
}

final CachedBooleanDispatchNode newDispatch = CachedBooleanDispatchNodeFactory.create(getContext(),
methodName, first,
falseUnmodifiedAssumption, falseConstant.getValue(), null,
trueUnmodifiedAssumption, trueConstant.getValue(), null,
null, null, null, null, null, null, null);

first.replace(newDispatch);

return newDispatch.executeDispatch(frame, methodReceiverObject, callingSelf, receiverObject,
methodName, blockObject, argumentsObjects, dispatchAction);
} else {
final CachedUnboxedDispatchNode newDispatch = CachedUnboxedDispatchNodeFactory.create(getContext(),
methodName, first, receiverObject.getClass(),
boxedReceiverObject.getRubyClass().getUnmodifiedAssumption(), constant.getValue(), null, null, null, null, null,
null, null, null);

first.replace(newDispatch);

return newDispatch.executeDispatch(frame, methodReceiverObject, callingSelf, receiverObject, methodName,
blockObject, argumentsObjects, dispatchAction);
}
}
}

@@ -154,31 +217,87 @@ private Object doRubyBasicObject(
Object methodReceiverObject) {
final RubyBasicObject boxedCallingSelf = getContext().getCoreLibrary().box(callingSelf);
final RubyBasicObject boxedReceiverObject = getContext().getCoreLibrary().box(receiverObject);
final RubyMethod method;

try {
method = lookup(boxedCallingSelf, boxedReceiverObject, methodName.toString(), ignoreVisibility,
if (dispatchAction.isCall()) {
final RubyMethod method = lookup(boxedCallingSelf, boxedReceiverObject, methodName.toString(), ignoreVisibility,
dispatchAction);
} catch (UseMethodMissingException e) {
final DispatchNode newDispatch = createMethodMissingNode(methodName, boxedCallingSelf,
boxedReceiverObject, dispatchAction);
return newDispatch.executeDispatch(frame, methodReceiverObject, boxedCallingSelf, boxedReceiverObject,
methodName, blockObject, argumentsObjects, dispatchAction);
}

final DispatchNode newDispatch;
if (method == null) {
final DispatchNode newDispatch = createMethodMissingNode(methodName, boxedCallingSelf,
boxedReceiverObject, dispatchAction);
return newDispatch.executeDispatch(frame, methodReceiverObject, boxedCallingSelf, boxedReceiverObject,
methodName, blockObject, argumentsObjects, dispatchAction);
}

final DispatchNode newDispatch;

if (receiverObject instanceof RubySymbol && RubySymbol.globalSymbolLookupNodeAssumption.isValid()) {
newDispatch = CachedBoxedSymbolDispatchNodeFactory.create(getContext(), methodName, first, method, null,
null, null, null, null, null, null);
if (receiverObject instanceof RubySymbol && RubySymbol.globalSymbolLookupNodeAssumption.isValid()) {
newDispatch = CachedBoxedSymbolDispatchNodeFactory.create(getContext(), methodName, first, null, method, null,
null, null, null, null, null, null);
} else {
newDispatch = CachedBoxedDispatchNodeFactory.create(getContext(), methodName, first,
boxedReceiverObject.getLookupNode(), null, method, null, null, null, null, null, null, null);
}

first.replace(newDispatch);
return newDispatch.executeDispatch(frame, methodReceiverObject, boxedCallingSelf, receiverObject,
methodName, blockObject, argumentsObjects, dispatchAction);
} else {
newDispatch = CachedBoxedDispatchNodeFactory.create(getContext(), methodName, first,
boxedReceiverObject.getLookupNode(), method, null, null, null, null, null, null, null);
final RubyConstant constant = lookupConstant(boxedCallingSelf, boxedReceiverObject, methodName.toString(), ignoreVisibility,
dispatchAction);

if (constant == null) {
final DispatchNode newDispatch = createConstantMissingNode(methodName, boxedCallingSelf,
boxedReceiverObject, dispatchAction);
return newDispatch.executeDispatch(frame, methodReceiverObject, boxedCallingSelf, boxedReceiverObject,
methodName, blockObject, argumentsObjects, dispatchAction);
}

final DispatchNode newDispatch;

if (receiverObject instanceof RubySymbol && RubySymbol.globalSymbolLookupNodeAssumption.isValid()) {
newDispatch = CachedBoxedSymbolDispatchNodeFactory.create(getContext(), methodName, first, constant.getValue(), null, null,
null, null, null, null, null, null);
} else {
newDispatch = CachedBoxedDispatchNodeFactory.create(getContext(), methodName, first,
boxedReceiverObject.getLookupNode(), constant.getValue(), null, null, null, null, null, null, null, null);
}

first.replace(newDispatch);
return newDispatch.executeDispatch(frame, methodReceiverObject, boxedCallingSelf, receiverObject,
methodName, blockObject, argumentsObjects, dispatchAction);
}
}

private DispatchNode createConstantMissingNode(
Object methodName,
RubyBasicObject callingSelf,
RubyBasicObject receiverObject,
Dispatch.DispatchAction dispatchAction) {
final DispatchNode first = getHeadNode().getFirstDispatchNode();

first.replace(newDispatch);
return newDispatch.executeDispatch(frame, methodReceiverObject, boxedCallingSelf, receiverObject,
methodName, blockObject, argumentsObjects, dispatchAction);
switch (missingBehavior) {
case RETURN_MISSING: {
return first.replace(CachedBoxedReturnMissingDispatchNodeFactory.create(getContext(), methodName, first,
receiverObject.getLookupNode(), null, null, null, null, null, null, null));
}

case CALL_CONST_MISSING: {
final RubyMethod method = lookup(callingSelf, receiverObject, "const_missing", ignoreVisibility, dispatchAction);

if (method == null) {
throw new RaiseException(getContext().getCoreLibrary().runtimeError(
receiverObject.toString() + " didn't have a #const_missing", this));
}

return first.replace(CachedBoxedMethodMissingDispatchNodeFactory.create(getContext(), methodName, first,
receiverObject.getLookupNode(), method, null, null, null, null, null, null, null));
}

default: {
throw new UnsupportedOperationException(missingBehavior.toString());
}
}
}

private DispatchNode createMethodMissingNode(
@@ -195,11 +314,9 @@ private DispatchNode createMethodMissingNode(
}

case CALL_METHOD_MISSING: {
final RubyMethod method;
final RubyMethod method = lookup(callingSelf, receiverObject, "method_missing", ignoreVisibility, dispatchAction);

try {
method = lookup(callingSelf, receiverObject, "method_missing", ignoreVisibility, dispatchAction);
} catch (UseMethodMissingException e2) {
if (method == null) {
throw new RaiseException(getContext().getCoreLibrary().runtimeError(
receiverObject.toString() + " didn't have a #method_missing", this));
}
Original file line number Diff line number Diff line change
@@ -23,8 +23,8 @@
import org.jruby.truffle.nodes.WriteNode;
import org.jruby.truffle.nodes.RubyCallNode;
import org.jruby.truffle.nodes.cast.*;
import org.jruby.truffle.nodes.constants.ReadConstantHeadNode;
import org.jruby.truffle.nodes.constants.WriteConstantNode;
import org.jruby.truffle.nodes.ReadConstantNode;
import org.jruby.truffle.nodes.WriteConstantNode;
import org.jruby.truffle.nodes.control.*;
import org.jruby.truffle.nodes.core.*;
import org.jruby.truffle.nodes.globals.CheckMatchVariableTypeNode;
@@ -625,7 +625,7 @@ public RubyNode visitClassVarNode(org.jruby.ast.ClassVarNode node) {
public RubyNode visitColon2Node(org.jruby.ast.Colon2Node node) {
final RubyNode lhs = node.getLeftNode().accept(this);

return new ReadConstantHeadNode(context, translate(node.getPosition()), node.getName(), lhs);
return new ReadConstantNode(context, translate(node.getPosition()), node.getName(), lhs);
}

@Override
@@ -636,7 +636,7 @@ public RubyNode visitColon3Node(org.jruby.ast.Colon3Node node) {

final ObjectLiteralNode root = new ObjectLiteralNode(context, sourceSection, context.getCoreLibrary().getMainObject());

return new ReadConstantHeadNode(context, sourceSection, node.getName(), root);
return new ReadConstantNode(context, sourceSection, node.getName(), root);
}

@Override
@@ -652,7 +652,7 @@ public RubyNode visitConstDeclNode(org.jruby.ast.ConstDeclNode node) {
public RubyNode visitConstNode(org.jruby.ast.ConstNode node) {
final SourceSection sourceSection = translate(node.getPosition());

return new ReadConstantHeadNode(context, sourceSection, node.getName(), new SelfNode(context, sourceSection));
return new ReadConstantNode(context, sourceSection, node.getName(), new SelfNode(context, sourceSection));
}

@Override
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@
import com.oracle.truffle.api.source.*;
import org.jruby.lexer.yacc.ISourcePosition;
import org.jruby.truffle.nodes.*;
import org.jruby.truffle.nodes.constants.*;
import org.jruby.truffle.nodes.control.*;
import org.jruby.truffle.nodes.literal.NilLiteralNode;
import org.jruby.truffle.nodes.methods.*;
@@ -83,7 +82,7 @@ public RubyNode visitConstNode(org.jruby.ast.ConstNode node) {

final SelfNode selfNode = new SelfNode(context, sourceSection);

return new ReadConstantHeadNode(context, sourceSection, node.getName(), selfNode);
return new ReadConstantNode(context, sourceSection, node.getName(), selfNode);
}

@Override
1 change: 1 addition & 0 deletions spec/truffle/tags/language/constants_tags.txt
Original file line number Diff line number Diff line change
@@ -30,3 +30,4 @@ fails:Literal (A::X) constant resolution with statically assigned constants sear
fails:Literal (A::X) constant resolution with statically assigned constants searches the superclass chain
fails:Constant resolution within methods with statically assigned constants does not search the lexical scope of qualifying modules
fails:Constant resolution within methods with dynamically assigned constants does not search the lexical scope of qualifying modules
fails:Constant resolution within methods with dynamically assigned constants returns the updated value when a constant is reassigned
1 change: 1 addition & 0 deletions spec/truffle/tags/language/defined_tags.txt
Original file line number Diff line number Diff line change
@@ -38,3 +38,4 @@ fails:The defined? keyword for loop expressions returns 'expression' for a 'redo
fails:The defined? keyword for loop expressions returns 'expression' for a 'retry' expression
fails:The defined? keyword for return expressions returns 'expression'
fails:The defined? keyword for loop expressions returns 'expression' for a 'for' expression
fails:The defined? keyword for a module method call scoped constant returns nil if the outer scope constant in the receiver is not defined
1 change: 1 addition & 0 deletions spec/truffle/tags/language/metaclass_tags.txt
Original file line number Diff line number Diff line change
@@ -3,3 +3,4 @@ fails:A constant on a metaclass cannot be accessed via object::CONST
fails:A constant on a metaclass raises a NameError for anonymous_module::CONST
fails(inherited):calling methods on the metaclass calls a method defined on the metaclass of the metaclass
fails:A constant on a metaclass is not preserved when the object is duped
fails:A constant on a metaclass is not defined in the metaclass opener's scope
1 change: 1 addition & 0 deletions spec/truffle/tags/language/singleton_class_tags.txt
Original file line number Diff line number Diff line change
@@ -16,3 +16,4 @@ fails(inherited):Class methods of a singleton class for a singleton class includ
fails:Instantiating a singleton class raises a TypeError when new is called
fails:Instantiating a singleton class raises a TypeError when allocate is called
fails:A constant on a singleton class is not preserved when the object is duped
fails:A constant on a singleton class is not defined in the singleton class opener's scope

0 comments on commit 60d8a86

Please sign in to comment.