CachedBooleanDispatchNode.java
/*
* Copyright (c) 2014 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.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;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.DirectCallNode;
import com.oracle.truffle.api.nodes.IndirectCallNode;
import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.utilities.BranchProfile;
import org.jruby.truffle.runtime.LexicalScope;
import org.jruby.truffle.runtime.RubyArguments;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyProc;
import org.jruby.truffle.runtime.methods.RubyMethod;
public abstract class CachedBooleanDispatchNode extends CachedDispatchNode {
private final Assumption falseUnmodifiedAssumption;
private final RubyMethod falseMethod;
private final BranchProfile falseProfile = BranchProfile.create();
private final Object falseValue;
@Child protected DirectCallNode falseCallDirect;
private final Assumption trueUnmodifiedAssumption;
private final RubyMethod trueMethod;
private final BranchProfile trueProfile = BranchProfile.create();
private final Object trueValue;
@Child protected DirectCallNode trueCallDirect;
@Child protected IndirectCallNode indirectCallNode;
public CachedBooleanDispatchNode(
RubyContext context, Object cachedName, DispatchNode next,
Assumption falseUnmodifiedAssumption, Object falseValue, RubyMethod falseMethod,
Assumption trueUnmodifiedAssumption, Object trueValue, RubyMethod trueMethod,
boolean indirect) {
super(context, cachedName, next, indirect);
this.falseUnmodifiedAssumption = falseUnmodifiedAssumption;
this.falseMethod = falseMethod;
this.falseValue = falseValue;
if (falseMethod != null) {
if (!indirect) {
falseCallDirect = Truffle.getRuntime().createDirectCallNode(falseMethod.getCallTarget());
if (falseCallDirect.isCallTargetCloningAllowed() && falseMethod.getSharedMethodInfo().shouldAlwaysSplit()) {
insert(falseCallDirect);
falseCallDirect.cloneCallTarget();
}
}
}
this.trueUnmodifiedAssumption = trueUnmodifiedAssumption;
this.trueMethod = trueMethod;
this.trueValue = trueValue;
if (trueMethod != null) {
if (!indirect) {
trueCallDirect = Truffle.getRuntime().createDirectCallNode(trueMethod.getCallTarget());
if (trueCallDirect.isCallTargetCloningAllowed() && trueMethod.getSharedMethodInfo().shouldAlwaysSplit()) {
insert(trueCallDirect);
trueCallDirect.cloneCallTarget();
}
}
}
if (indirect) {
indirectCallNode = Truffle.getRuntime().createIndirectCallNode();
}
}
public CachedBooleanDispatchNode(CachedBooleanDispatchNode prev) {
super(prev);
falseUnmodifiedAssumption = prev.falseUnmodifiedAssumption;
falseMethod = prev.falseMethod;
falseValue = prev.falseValue;
falseCallDirect = prev.falseCallDirect;
trueUnmodifiedAssumption = prev.trueUnmodifiedAssumption;
trueValue = prev.trueValue;
trueMethod = prev.trueMethod;
trueCallDirect = prev.trueCallDirect;
indirectCallNode = prev.indirectCallNode;
}
@Specialization(guards = "guardName")
public Object dispatch(
VirtualFrame frame,
LexicalScope lexicalScope,
boolean receiverObject,
Object methodName,
Object blockObject,
Object argumentsObjects,
Dispatch.DispatchAction dispatchAction) {
CompilerAsserts.compilationConstant(dispatchAction);
if (receiverObject) {
trueProfile.enter();
try {
trueUnmodifiedAssumption.check();
} catch (InvalidAssumptionException e) {
return resetAndDispatch(
frame,
lexicalScope,
receiverObject,
methodName,
CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false),
argumentsObjects,
dispatchAction,
"class modified");
}
if (dispatchAction == Dispatch.DispatchAction.CALL_METHOD) {
if (isIndirect()) {
return indirectCallNode.call(
frame,
trueMethod.getCallTarget(),
RubyArguments.pack(
trueMethod,
trueMethod.getDeclarationFrame(),
receiverObject,
CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false),
CompilerDirectives.unsafeCast(argumentsObjects, Object[].class, true)));
} else {
return trueCallDirect.call(
frame,
RubyArguments.pack(
trueMethod,
trueMethod.getDeclarationFrame(),
receiverObject,
CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false),
CompilerDirectives.unsafeCast(argumentsObjects, Object[].class, true)));
}
} else if (dispatchAction == Dispatch.DispatchAction.RESPOND_TO_METHOD) {
return true;
} else if (dispatchAction == Dispatch.DispatchAction.READ_CONSTANT) {
return trueValue;
} else {
throw new UnsupportedOperationException();
}
} else {
falseProfile.enter();
try {
falseUnmodifiedAssumption.check();
} catch (InvalidAssumptionException e) {
return resetAndDispatch(
frame,
lexicalScope,
receiverObject,
methodName,
CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false),
argumentsObjects,
dispatchAction,
"class modified");
}
if (dispatchAction == Dispatch.DispatchAction.CALL_METHOD) {
if (isIndirect()) {
return indirectCallNode.call(
frame,
falseMethod.getCallTarget(),
RubyArguments.pack(
falseMethod,
falseMethod.getDeclarationFrame(),
receiverObject,
CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false),
CompilerDirectives.unsafeCast(argumentsObjects, Object[].class, true)));
} else {
return falseCallDirect.call(
frame,
RubyArguments.pack(
falseMethod,
falseMethod.getDeclarationFrame(),
receiverObject,
CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false),
CompilerDirectives.unsafeCast(argumentsObjects, Object[].class, true)));
}
} else if (dispatchAction == Dispatch.DispatchAction.RESPOND_TO_METHOD) {
return true;
} else if (dispatchAction == Dispatch.DispatchAction.READ_CONSTANT) {
return falseValue;
} else {
throw new UnsupportedOperationException();
}
}
}
@Fallback
public Object dispatch(
VirtualFrame frame,
LexicalScope lexicalScope,
Object receiverObject,
Object methodName,
Object blockObject,
Object argumentsObjects,
Dispatch.DispatchAction dispatchAction) {
return next.executeDispatch(
frame,
lexicalScope,
receiverObject,
methodName,
blockObject,
argumentsObjects,
dispatchAction);
}
}