@Specialization protected void doObject(Object value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { MaterializedFrame profiledFrame = enclosingFrameProfile.profile(enclosingFrame); Object newValue = shareObjectValue( profiledFrame, frameSlot, storedObjectProfile.profile(value), mode, true); FrameSlotChangeMonitor.setObjectAndInvalidate( profiledFrame, frameSlot, newValue, true, invalidateProfile); }
@NodeChildren({ @NodeChild(value = "enclosingFrame", type = AccessEnclosingFrameNode.class), @NodeChild(value = "frameSlotNode", type = FrameSlotNode.class) }) protected abstract static class ResolvedWriteSuperFrameVariableNode extends WriteSuperFrameVariableNode { private final ValueProfile storedObjectProfile = ValueProfile.createClassProfile(); private final BranchProfile invalidateProfile = BranchProfile.create(); private final ValueProfile enclosingFrameProfile = ValueProfile.createClassProfile(); private final Mode mode; public ResolvedWriteSuperFrameVariableNode(Mode mode) { this.mode = mode; } protected abstract FrameSlotNode getFrameSlotNode(); @Specialization(guards = "isLogicalKind(enclosingFrame, frameSlot)") protected void doLogical(byte value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { FrameSlotChangeMonitor.setByteAndInvalidate( enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile); } @Specialization(guards = "isIntegerKind(enclosingFrame, frameSlot)") protected void doInteger(int value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { FrameSlotChangeMonitor.setIntAndInvalidate( enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile); } @Specialization(guards = "isDoubleKind(enclosingFrame, frameSlot)") protected void doDouble(double value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { FrameSlotChangeMonitor.setDoubleAndInvalidate( enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile); } @Specialization protected void doObject(Object value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { MaterializedFrame profiledFrame = enclosingFrameProfile.profile(enclosingFrame); Object newValue = shareObjectValue( profiledFrame, frameSlot, storedObjectProfile.profile(value), mode, true); FrameSlotChangeMonitor.setObjectAndInvalidate( profiledFrame, frameSlot, newValue, true, invalidateProfile); } }
private static final class WriteSuperFrameVariableConditionalNode extends WriteSuperFrameVariableNode { @Child private ResolvedWriteSuperFrameVariableNode writeNode; @Child private WriteSuperFrameVariableNode nextNode; @Child private RNode rhs; private final ValueProfile enclosingFrameProfile = ValueProfile.createClassProfile(); private final ConditionProfile hasValueProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile nullSuperFrameProfile = ConditionProfile.createBinaryProfile(); WriteSuperFrameVariableConditionalNode( ResolvedWriteSuperFrameVariableNode writeNode, WriteSuperFrameVariableNode nextNode, RNode rhs) { this.writeNode = writeNode; this.nextNode = nextNode; this.rhs = rhs; } @Override public Object getName() { return writeNode.getName(); } @Override public RNode getRhs() { return rhs; } @Override public void execute(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame) { MaterializedFrame profiledEnclosingFrame = enclosingFrameProfile.profile(enclosingFrame); if (hasValueProfile.profile(writeNode.getFrameSlotNode().hasValue(profiledEnclosingFrame))) { writeNode.execute(frame, value, profiledEnclosingFrame); } else { MaterializedFrame superFrame = RArguments.getEnclosingFrame(profiledEnclosingFrame); if (nullSuperFrameProfile.profile(superFrame == null)) { // Might be the case if "{ x <<- 42 }": This is in globalEnv! superFrame = REnvironment.globalEnv().getFrame(); } nextNode.execute(frame, value, superFrame); } } @Override public void execute(VirtualFrame frame, Object value) { assert RArguments.getEnclosingFrame(frame) != null; execute(frame, value, RArguments.getEnclosingFrame(frame)); } }
@Override public void execute(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame) { MaterializedFrame profiledEnclosingFrame = enclosingFrameProfile.profile(enclosingFrame); if (hasValueProfile.profile(writeNode.getFrameSlotNode().hasValue(profiledEnclosingFrame))) { writeNode.execute(frame, value, profiledEnclosingFrame); } else { MaterializedFrame superFrame = RArguments.getEnclosingFrame(profiledEnclosingFrame); if (nullSuperFrameProfile.profile(superFrame == null)) { // Might be the case if "{ x <<- 42 }": This is in globalEnv! superFrame = REnvironment.globalEnv().getFrame(); } nextNode.execute(frame, value, superFrame); } }
public final Object callDirect(Object... args) { compilationProfile.reportDirectCall(); profileArguments(args); try { Object result = doInvoke(args); Class<?> klass = profiledReturnType; if (klass != null && CompilerDirectives.inCompiledCode() && profiledReturnTypeAssumption.isValid()) { result = unsafeCast(result, klass, true, true); } return result; } catch (Throwable t) { t = exceptionProfile.profile(t); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else if (t instanceof Error) { throw (Error) t; } else { CompilerDirectives.transferToInterpreter(); throw new RuntimeException(t); } } }
@Specialization(guards = "isDoubleKind(enclosingFrame, frameSlot)") protected void doDouble(double value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { FrameSlotChangeMonitor.setDoubleAndInvalidate( enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile); }
@Specialization(guards = "isIntegerKind(enclosingFrame, frameSlot)") protected void doInteger(int value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { FrameSlotChangeMonitor.setIntAndInvalidate( enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile); }
@Specialization(guards = "isLogicalKind(enclosingFrame, frameSlot)") protected void doLogical(byte value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { FrameSlotChangeMonitor.setByteAndInvalidate( enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile); }
/** * {@link WriteSuperFrameVariableNode} captures a write to a variable in some parent frame. * * <p>The state starts out a "unresolved" and transforms to "resolved". */ @SuppressWarnings("unused") @NodeChildren({ @NodeChild(value = "enclosingFrame", type = AccessEnclosingFrameNode.class), @NodeChild(value = "frameSlotNode", type = FrameSlotNode.class) }) @NodeField(name = "mode", type = Mode.class) public abstract class WriteSuperFrameVariableNode extends WriteSuperFrameVariableNodeHelper { private final ValueProfile storedObjectProfile = ValueProfile.createClassProfile(); private final BranchProfile invalidateProfile = BranchProfile.create(); private final ValueProfile enclosingFrameProfile = ValueProfile.createClassProfile(); protected abstract FrameSlotNode getFrameSlotNode(); public abstract Mode getMode(); public static WriteVariableNode create(String name, RNode rhs, Mode mode) { return new UnresolvedWriteSuperFrameVariableNode(name, rhs, mode); } @Specialization(guards = "isLogicalKind(frame, frameSlot)") protected void doLogical( VirtualFrame frame, byte value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { FrameSlotChangeMonitor.setByteAndInvalidate( enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile); } @Specialization(guards = "isIntegerKind(frame, frameSlot)") protected void doInteger( VirtualFrame frame, int value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { FrameSlotChangeMonitor.setIntAndInvalidate( enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile); } @Specialization(guards = "isDoubleKind(frame, frameSlot)") protected void doDouble( VirtualFrame frame, double value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { FrameSlotChangeMonitor.setDoubleAndInvalidate( enclosingFrameProfile.profile(enclosingFrame), frameSlot, value, true, invalidateProfile); } @Specialization protected void doObject( VirtualFrame frame, Object value, MaterializedFrame enclosingFrame, FrameSlot frameSlot) { MaterializedFrame profiledFrame = enclosingFrameProfile.profile(enclosingFrame); Object newValue = shareObjectValue( profiledFrame, frameSlot, storedObjectProfile.profile(value), getMode(), true); FrameSlotChangeMonitor.setObjectAndInvalidate( profiledFrame, frameSlot, newValue, true, invalidateProfile); } public static class UnresolvedWriteSuperFrameVariableNode extends WriteSuperFrameVariableNodeHelper { @Child private RNode rhs; private final String symbol; private final BaseWriteVariableNode.Mode mode; public UnresolvedWriteSuperFrameVariableNode( String symbol, RNode rhs, BaseWriteVariableNode.Mode mode) { this.rhs = rhs; this.symbol = symbol; this.mode = mode; } @Override public String getName() { return symbol; } @Override public RNode getRhs() { return rhs; } @Override public void execute(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame) { CompilerDirectives.transferToInterpreterAndInvalidate(); if (getName().isEmpty()) { throw RError.error(this, RError.Message.ZERO_LENGTH_VARIABLE); } final WriteSuperFrameVariableNodeHelper writeNode; if (REnvironment.isGlobalEnvFrame(enclosingFrame)) { /* * we've reached the global scope, do unconditional write. if this is the first node * in the chain, needs the rhs and enclosingFrame nodes */ AccessEnclosingFrameNode enclosingFrameNode = RArguments.getEnclosingFrame(frame) == enclosingFrame ? new AccessEnclosingFrameNode() : null; writeNode = WriteSuperFrameVariableNodeGen.create( getRhs(), enclosingFrameNode, FrameSlotNode.create( findOrAddFrameSlot( enclosingFrame.getFrameDescriptor(), symbol, FrameSlotKind.Illegal)), getName(), mode); } else { WriteSuperFrameVariableNode actualWriteNode = WriteSuperFrameVariableNodeGen.create( null, null, FrameSlotNode.create(symbol), this.getName(), mode); writeNode = new WriteSuperFrameVariableConditionalNode( actualWriteNode, new UnresolvedWriteSuperFrameVariableNode(symbol, null, mode), getRhs()); } replace(writeNode).execute(frame, value, enclosingFrame); } @Override public void execute(VirtualFrame frame, Object value) { CompilerDirectives.transferToInterpreterAndInvalidate(); MaterializedFrame enclosingFrame = RArguments.getEnclosingFrame(frame); if (enclosingFrame != null) { execute(frame, value, enclosingFrame); } else { // we're in global scope, do a local write instead replace(UnresolvedWriteLocalFrameVariableNodeGen.create(getRhs(), symbol, mode)) .execute(frame, value); } } } public static class WriteSuperFrameVariableConditionalNode extends WriteSuperFrameVariableNodeHelper { @Child private WriteSuperFrameVariableNode writeNode; @Child private WriteSuperFrameVariableNodeHelper nextNode; @Child private RNode rhs; private final ValueProfile enclosingFrameProfile = ValueProfile.createClassProfile(); private final ConditionProfile hasValueProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile nullSuperFrameProfile = ConditionProfile.createBinaryProfile(); WriteSuperFrameVariableConditionalNode( WriteSuperFrameVariableNode writeNode, WriteSuperFrameVariableNodeHelper nextNode, RNode rhs) { this.writeNode = writeNode; this.nextNode = nextNode; this.rhs = rhs; } @Override public Object getName() { return writeNode.getName(); } @Override public RNode getRhs() { return rhs; } @Override public void execute(VirtualFrame frame, Object value, MaterializedFrame enclosingFrame) { MaterializedFrame profiledEnclosingFrame = enclosingFrameProfile.profile(enclosingFrame); if (hasValueProfile.profile(writeNode.getFrameSlotNode().hasValue(profiledEnclosingFrame))) { writeNode.execute(frame, value, profiledEnclosingFrame); } else { MaterializedFrame superFrame = RArguments.getEnclosingFrame(profiledEnclosingFrame); if (nullSuperFrameProfile.profile(superFrame == null)) { // Might be the case if "{ x <<- 42 }": This is in globalEnv! superFrame = REnvironment.globalEnv().getFrame(); } nextNode.execute(frame, value, superFrame); } } @Override public void execute(VirtualFrame frame, Object value) { assert RArguments.getEnclosingFrame(frame) != null; execute(frame, value, RArguments.getEnclosingFrame(frame)); } } }
/** Call target that is optimized by Graal upon surpassing a specific invocation threshold. */ public class OptimizedCallTarget extends InstalledCode implements RootCallTarget, LoopCountReceiver, ReplaceObserver { private static final RootNode UNINITIALIZED = RootNode.createConstantNode(null); protected final GraalTruffleRuntime runtime; private SpeculationLog speculationLog; protected final CompilationProfile compilationProfile; protected final CompilationPolicy compilationPolicy; private final OptimizedCallTarget sourceCallTarget; private final AtomicInteger callSitesKnown = new AtomicInteger(0); private final ValueProfile exceptionProfile = ValueProfile.createClassProfile(); @CompilationFinal private Class<?>[] profiledArgumentTypes; @CompilationFinal private Assumption profiledArgumentTypesAssumption; @CompilationFinal private Class<?> profiledReturnType; @CompilationFinal private Assumption profiledReturnTypeAssumption; private final RootNode rootNode; private volatile RootNode uninitializedRootNode = UNINITIALIZED; /* Experimental fields for new splitting. */ private final Map<TruffleStamp, OptimizedCallTarget> splitVersions = new HashMap<>(); private TruffleStamp argumentStamp = DefaultTruffleStamp.getInstance(); private TruffleInlining inlining; private int cachedNonTrivialNodeCount = -1; private int cloneIndex; /** * When this call target is inlined, the inlining {@link InstalledCode} registers this assumption. * It gets invalidated when a node rewriting is performed. This ensures that all compiled methods * that have this call target inlined are properly invalidated. */ private final CyclicAssumption nodeRewritingAssumption; private volatile Future<?> compilationTask; public final RootNode getRootNode() { return rootNode; } public OptimizedCallTarget( OptimizedCallTarget sourceCallTarget, RootNode rootNode, GraalTruffleRuntime runtime, CompilationPolicy compilationPolicy, SpeculationLog speculationLog) { super(rootNode.toString()); this.sourceCallTarget = sourceCallTarget; this.runtime = runtime; this.speculationLog = speculationLog; this.rootNode = rootNode; this.compilationPolicy = compilationPolicy; this.rootNode.adoptChildren(); this.rootNode.applyInstrumentation(); if (TruffleCallTargetProfiling.getValue()) { this.compilationProfile = new TraceCompilationProfile(); } else { this.compilationProfile = new CompilationProfile(); } this.nodeRewritingAssumption = new CyclicAssumption("nodeRewritingAssumption of " + rootNode.toString()); } public final void log(String message) { runtime.log(message); } public final boolean isCompiling() { return getCompilationTask() != null; } private static RootNode cloneRootNode(RootNode root) { if (root == null || !root.isCloningAllowed()) { return null; } return NodeUtil.cloneNode(root); } public Assumption getNodeRewritingAssumption() { return nodeRewritingAssumption.getAssumption(); } public final void mergeArgumentStamp(TruffleStamp p) { this.argumentStamp = this.argumentStamp.join(p); } public final TruffleStamp getArgumentStamp() { return argumentStamp; } public int getCloneIndex() { return cloneIndex; } public OptimizedCallTarget cloneUninitialized() { ensureCloned(); RootNode copiedRoot = cloneRootNode(uninitializedRootNode); if (copiedRoot == null) { return null; } OptimizedCallTarget splitTarget = (OptimizedCallTarget) runtime.createClonedCallTarget(this, copiedRoot); splitTarget.cloneIndex = cloneIndex++; return splitTarget; } private void ensureCloned() { if (uninitializedRootNode == UNINITIALIZED) { synchronized (this) { if (uninitializedRootNode == UNINITIALIZED) { this.uninitializedRootNode = sourceCallTarget == null ? cloneRootNode(rootNode) : sourceCallTarget.uninitializedRootNode; } } } } public Map<TruffleStamp, OptimizedCallTarget> getSplitVersions() { return splitVersions; } public SpeculationLog getSpeculationLog() { return speculationLog; } @Override public Object call(Object... args) { compilationProfile.reportIndirectCall(); if (profiledArgumentTypesAssumption != null && profiledArgumentTypesAssumption.isValid()) { // Argument profiling is not possible for targets of indirect calls. CompilerDirectives.transferToInterpreterAndInvalidate(); profiledArgumentTypesAssumption.invalidate(); profiledArgumentTypes = null; } return doInvoke(args); } public final Object callDirect(Object... args) { compilationProfile.reportDirectCall(); profileArguments(args); try { Object result = doInvoke(args); Class<?> klass = profiledReturnType; if (klass != null && CompilerDirectives.inCompiledCode() && profiledReturnTypeAssumption.isValid()) { result = unsafeCast(result, klass, true, true); } return result; } catch (Throwable t) { t = exceptionProfile.profile(t); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else if (t instanceof Error) { throw (Error) t; } else { CompilerDirectives.transferToInterpreter(); throw new RuntimeException(t); } } } public final Object callInlined(Object... arguments) { compilationProfile.reportInlinedCall(); VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), arguments); return callProxy(frame); } @ExplodeLoop public void profileArguments(Object[] args) { Assumption typesAssumption = profiledArgumentTypesAssumption; if (typesAssumption == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); initializeProfiledArgumentTypes(args); } else { Class<?>[] types = profiledArgumentTypes; if (types != null) { if (types.length != args.length) { CompilerDirectives.transferToInterpreterAndInvalidate(); typesAssumption.invalidate(); profiledArgumentTypes = null; } else if (typesAssumption.isValid()) { for (int i = 0; i < types.length; i++) { Class<?> type = types[i]; Object value = args[i]; if (type != null && (value == null || value.getClass() != type)) { CompilerDirectives.transferToInterpreterAndInvalidate(); updateProfiledArgumentTypes(args, types); break; } } } } } } private void initializeProfiledArgumentTypes(Object[] args) { CompilerAsserts.neverPartOfCompilation(); profiledArgumentTypesAssumption = Truffle.getRuntime().createAssumption("Profiled Argument Types"); if (TruffleArgumentTypeSpeculation.getValue()) { Class<?>[] result = new Class<?>[args.length]; for (int i = 0; i < args.length; i++) { result[i] = classOf(args[i]); } profiledArgumentTypes = result; } } private void updateProfiledArgumentTypes(Object[] args, Class<?>[] types) { CompilerAsserts.neverPartOfCompilation(); profiledArgumentTypesAssumption.invalidate(); for (int j = 0; j < types.length; j++) { types[j] = joinTypes(types[j], classOf(args[j])); } profiledArgumentTypesAssumption = Truffle.getRuntime().createAssumption("Profiled Argument Types"); } private static Class<?> classOf(Object arg) { return arg != null ? arg.getClass() : null; } private static Class<?> joinTypes(Class<?> class1, Class<?> class2) { if (class1 == class2) { return class1; } else { return null; } } protected Object doInvoke(Object[] args) { return callBoundary(args); } @TruffleCallBoundary protected final Object callBoundary(Object[] args) { if (CompilerDirectives.inInterpreter()) { // We are called and we are still in Truffle interpreter mode. interpreterCall(); } else { // We come here from compiled code } return callRoot(args); } public final Object callRoot(Object[] originalArguments) { Object[] args = originalArguments; if (CompilerDirectives.inCompiledCode()) { Assumption argumentTypesAssumption = this.profiledArgumentTypesAssumption; if (argumentTypesAssumption != null && argumentTypesAssumption.isValid()) { args = unsafeCast( castArrayFixedLength(args, profiledArgumentTypes.length), Object[].class, true, true); args = castArguments(args); } } VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), args); Object result = callProxy(frame); profileReturnType(result); return result; } public void profileReturnType(Object result) { Assumption returnTypeAssumption = profiledReturnTypeAssumption; if (returnTypeAssumption == null) { if (TruffleReturnTypeSpeculation.getValue()) { CompilerDirectives.transferToInterpreterAndInvalidate(); profiledReturnType = (result == null ? null : result.getClass()); profiledReturnTypeAssumption = Truffle.getRuntime().createAssumption("Profiled Return Type"); } } else if (profiledReturnType != null) { if (result == null || profiledReturnType != result.getClass()) { CompilerDirectives.transferToInterpreterAndInvalidate(); profiledReturnType = null; returnTypeAssumption.invalidate(); } } } @Override public void invalidate() { invalidate(null, null); } protected void invalidate(Object source, CharSequence reason) { if (isValid()) { this.runtime.invalidateInstalledCode(this, source, reason); } cachedNonTrivialNodeCount = -1; } public TruffleInlining getInlining() { return inlining; } public void setInlining(TruffleInlining inliningDecision) { this.inlining = inliningDecision; } private boolean cancelInstalledTask(Node source, CharSequence reason) { return this.runtime.cancelInstalledTask(this, source, reason); } private void interpreterCall() { if (isValid()) { // Stubs were deoptimized => reinstall. this.runtime.reinstallStubs(); } else { if (uninitializedRootNode == UNINITIALIZED) { ensureCloned(); } compilationProfile.reportInterpreterCall(); if (!isCompiling() && compilationPolicy.shouldCompile(compilationProfile, getCompilerOptions())) { compile(); } } } public final void compile() { if (!isCompiling()) { ensureCloned(); runtime.compile( this, TruffleBackgroundCompilation.getValue() && !TruffleCompilationExceptionsAreThrown.getValue()); } } public void notifyCompilationFailed(Throwable t) { if (t instanceof BailoutException && !((BailoutException) t).isPermanent()) { /* * Non permanent bailouts are expected cases. A non permanent bailout would be for * example class redefinition during code installation. As opposed to permanent * bailouts, non permanent bailouts will trigger recompilation and are not considered a * failure state. */ } else { compilationPolicy.recordCompilationFailure(t); if (TruffleCompilationExceptionsAreThrown.getValue()) { throw new OptimizationFailedException(t, this); } if (TruffleCompilationExceptionsArePrinted.getValue() || TruffleCompilationExceptionsAreFatal.getValue()) { printException(t); if (TruffleCompilationExceptionsAreFatal.getValue()) { System.exit(-1); } } } } private void printException(Throwable e) { StringWriter string = new StringWriter(); e.printStackTrace(new PrintWriter(string)); log(string.toString()); } public void notifyCompilationFinished(boolean successful) { if (successful && inlining != null) { dequeueInlinedCallSites(inlining); } setCompilationTask(null); } private void dequeueInlinedCallSites(TruffleInlining parentDecision) { for (TruffleInliningDecision decision : parentDecision) { if (decision.isInline()) { OptimizedCallTarget target = decision.getTarget(); target.cancelInstalledTask( decision.getProfile().getCallNode(), "Inlining caller compiled."); dequeueInlinedCallSites(decision); } } } protected final Object callProxy(VirtualFrame frame) { try { return getRootNode().execute(frame); } finally { // this assertion is needed to keep the values from being cleared as non-live locals assert frame != null && this != null; } } public final int getKnownCallSiteCount() { return callSitesKnown.get(); } public final void incrementKnownCallSites() { callSitesKnown.incrementAndGet(); } public final void decrementKnownCallSites() { callSitesKnown.decrementAndGet(); } public final OptimizedCallTarget getSourceCallTarget() { return sourceCallTarget; } @Override public String toString() { CompilerAsserts.neverPartOfCompilation(); String superString = rootNode.toString(); if (isValid()) { superString += " <opt>"; } if (sourceCallTarget != null) { superString += " <split-" + cloneIndex + "-" + argumentStamp.toStringShort() + ">"; } return superString; } public CompilationProfile getCompilationProfile() { return compilationProfile; } @ExplodeLoop private Object[] castArguments(Object[] originalArguments) { Class<?>[] types = profiledArgumentTypes; Object[] castArguments = new Object[types.length]; for (int i = 0; i < types.length; i++) { castArguments[i] = types[i] != null ? unsafeCast(originalArguments[i], types[i], true, true) : originalArguments[i]; } return castArguments; } private static Object castArrayFixedLength( Object[] args, @SuppressWarnings("unused") int length) { return args; } public static VirtualFrame createFrame(FrameDescriptor descriptor, Object[] args) { if (TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue()) { return new FrameWithoutBoxing(descriptor, args); } else { return new FrameWithBoxing(descriptor, args); } } public List<OptimizedDirectCallNode> getCallNodes() { final List<OptimizedDirectCallNode> callNodes = new ArrayList<>(); getRootNode() .accept( new NodeVisitor() { public boolean visit(Node node) { if (node instanceof OptimizedDirectCallNode) { callNodes.add((OptimizedDirectCallNode) node); } return true; } }); return callNodes; } @Override public void reportLoopCount(int count) { compilationProfile.reportLoopCount(count); } @Override public boolean nodeReplaced(Node oldNode, Node newNode, CharSequence reason) { CompilerAsserts.neverPartOfCompilation(); if (isValid()) { invalidate(newNode, reason); } /* Notify compiled method that have inlined this call target that the tree changed. */ nodeRewritingAssumption.invalidate(); compilationProfile.reportNodeReplaced(); if (cancelInstalledTask(newNode, reason)) { compilationProfile.reportInvalidated(); } return false; } public void accept(NodeVisitor visitor, boolean includeInlinedNodes) { TruffleInlining inliner = getInlining(); if (includeInlinedNodes && inliner != null) { inlining.accept(this, visitor); } else { getRootNode().accept(visitor); } } public Stream<Node> nodeStream(boolean includeInlinedNodes) { Iterator<Node> iterator; TruffleInlining inliner = getInlining(); if (includeInlinedNodes && inliner != null) { iterator = inliner.makeNodeIterator(this); } else { iterator = NodeUtil.makeRecursiveIterator(this.getRootNode()); } return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false); } public final int getNonTrivialNodeCount() { if (cachedNonTrivialNodeCount == -1) { cachedNonTrivialNodeCount = calculateNonTrivialNodes(getRootNode()); } return cachedNonTrivialNodeCount; } public static int calculateNonTrivialNodes(Node node) { NonTrivialNodeCountVisitor visitor = new NonTrivialNodeCountVisitor(); node.accept(visitor); return visitor.nodeCount; } public Map<String, Object> getDebugProperties() { Map<String, Object> properties = new LinkedHashMap<>(); AbstractDebugCompilationListener.addASTSizeProperty(this, properties); properties.putAll(getCompilationProfile().getDebugProperties()); return properties; } public static Method getCallDirectMethod() { try { return OptimizedCallTarget.class.getDeclaredMethod("callDirect", Object[].class); } catch (NoSuchMethodException | SecurityException e) { throw new JVMCIError(e); } } public static Method getCallInlinedMethod() { try { return OptimizedCallTarget.class.getDeclaredMethod("callInlined", Object[].class); } catch (NoSuchMethodException | SecurityException e) { throw new JVMCIError(e); } } private CompilerOptions getCompilerOptions() { final CompilerOptions options = rootNode.getCompilerOptions(); if (options != null) { return options; } return DefaultCompilerOptions.INSTANCE; } @SuppressWarnings({"unchecked", "unused"}) private static <T> T unsafeCast(Object value, Class<T> type, boolean condition, boolean nonNull) { return (T) value; } private static final class NonTrivialNodeCountVisitor implements NodeVisitor { public int nodeCount; public boolean visit(Node node) { if (!node.getCost().isTrivial()) { nodeCount++; } return true; } } @Override public final boolean equals(Object obj) { return obj == this; } @Override public final int hashCode() { return System.identityHashCode(this); } Future<?> getCompilationTask() { return compilationTask; } void setCompilationTask(Future<?> compilationTask) { this.compilationTask = compilationTask; } }
abstract class PositionCheckNode extends Node { protected final Class<?> positionClass; protected final int dimensionIndex; protected final int numDimensions; protected final VectorLengthProfile positionLengthProfile = VectorLengthProfile.create(); protected final BranchProfile error = BranchProfile.create(); protected final boolean replace; protected final RType containerType; @Child private PositionCastNode castNode; @Child private RLengthNode positionLengthNode = RLengthNode.create(); @Child private PositionCharacterLookupNode characterLookup; PositionCheckNode( ElementAccessMode mode, RType containerType, Object positionValue, int dimensionIndex, int numDimensions, boolean exact, boolean replace) { this.positionClass = positionValue.getClass(); this.dimensionIndex = dimensionIndex; this.numDimensions = numDimensions; this.replace = replace; this.containerType = containerType; this.castNode = PositionCastNode.create(mode, replace); if (positionValue instanceof String || positionValue instanceof RAbstractStringVector) { boolean useNAForNotFound = !replace && isListLike(containerType) && mode.isSubscript(); characterLookup = new PositionCharacterLookupNode( mode, numDimensions, dimensionIndex, useNAForNotFound, exact); } } protected static boolean isListLike(RType type) { switch (type) { case Language: case DataFrame: case Expression: case PairList: case List: return true; } return false; } public boolean isIgnoreDimension() { return positionClass == RMissing.class; } public Class<?> getPositionClass() { return positionClass; } public final boolean isSupported(Object object) { return object.getClass() == positionClass; } public static PositionCheckNode createNode( ElementAccessMode mode, RType containerType, Object position, int positionIndex, int numDimensions, boolean exact, boolean replace, boolean recursive) { if (mode.isSubset()) { return PositionCheckSubsetNodeGen.create( mode, containerType, position, positionIndex, numDimensions, exact, replace); } else { return PositionCheckSubscriptNodeGen.create( mode, containerType, position, positionIndex, numDimensions, exact, replace, recursive); } } protected boolean isMultiDimension() { return numDimensions > 1; } public final Object execute( PositionProfile profile, RAbstractContainer vector, int[] vectorDimensions, int vectorLength, Object position) { Object castPosition = castNode.execute(positionClass.cast(position)); int dimensionLength; if (numDimensions == 1) { dimensionLength = vectorLength; } else { assert vectorDimensions != null; assert vectorDimensions.length == numDimensions; dimensionLength = vectorDimensions[dimensionIndex]; } if (characterLookup != null) { castPosition = characterLookup.execute(vector, (RAbstractStringVector) castPosition, dimensionLength); } RTypedValue positionVector = (RTypedValue) profilePosition(castPosition); int positionLength; if (positionVector instanceof RMissing) { positionLength = -1; } else { positionLength = positionLengthProfile.profile(((RAbstractVector) positionVector).getLength()); } assert isValidCastedType(positionVector) : "result type of a position cast node must be integer or logical"; return execute(profile, dimensionLength, positionVector, positionLength); } private final ValueProfile castedValue = ValueProfile.createClassProfile(); Object profilePosition(Object positionVector) { return castedValue.profile(positionVector); } private static boolean isValidCastedType(RTypedValue positionVector) { RType type = positionVector.getRType(); return type == RType.Integer || type == RType.Logical || type == RType.Character || type == RType.Double || type == RType.Null; } public abstract Object execute( PositionProfile statistics, int dimensionLength, Object position, int positionLength); }
Object profilePosition(Object positionVector) { return castedValue.profile(positionVector); }