@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; } } } } } }
@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); }
@Override public Object executeDispatch( VirtualFrame frame, Object receiverObject, Object methodName, DynamicObject blockObject, Object[] argumentsObjects) { try { unmodifiedAssumption.check(); } catch (InvalidAssumptionException e) { return resetAndDispatch( frame, receiverObject, methodName, blockObject, argumentsObjects, "class modified"); } if (!guard(methodName, receiverObject)) { return next.executeDispatch(frame, receiverObject, methodName, blockObject, argumentsObjects); } switch (getDispatchAction()) { case CALL_METHOD: return call(callNode, frame, method, expectedReceiver, blockObject, argumentsObjects); case RESPOND_TO_METHOD: return true; default: throw new UnsupportedOperationException(); } }
void invalidate() { if (version != null) { version.invalidate(); } else { assert chain == null; } }
@Override public Object executeDispatch( VirtualFrame frame, Object receiverObject, Object methodName, Object blockObject, Object argumentsObjects) { if (!guardName(methodName) || !(receiverObject instanceof RubySymbol)) { return next.executeDispatch(frame, receiverObject, methodName, blockObject, argumentsObjects); } // Check the class has not been modified try { unmodifiedAssumption.check(); } catch (InvalidAssumptionException e) { return resetAndDispatch( frame, receiverObject, methodName, (RubyProc) blockObject, argumentsObjects, "class modified"); } switch (getDispatchAction()) { case CALL_METHOD: { if (isIndirect()) { return indirectCallNode.call( frame, method.getCallTarget(), RubyArguments.pack( method, method.getDeclarationFrame(), receiverObject, (RubyProc) blockObject, (Object[]) argumentsObjects)); } else { return callNode.call( frame, RubyArguments.pack( method, method.getDeclarationFrame(), receiverObject, (RubyProc) blockObject, (Object[]) argumentsObjects)); } } case RESPOND_TO_METHOD: return true; case READ_CONSTANT: return value; default: throw new UnsupportedOperationException(); } }
@Override public Object executeDispatch( VirtualFrame frame, Object receiverObject, Object methodName, DynamicObject blockObject, Object[] argumentsObjects) { if (!guard(methodName, receiverObject)) { return next.executeDispatch(frame, receiverObject, methodName, blockObject, argumentsObjects); } // Check the class has not been modified try { unmodifiedAssumption.check(); } catch (InvalidAssumptionException e) { return resetAndDispatch( frame, receiverObject, methodName, blockObject, argumentsObjects, "class modified"); } switch (getDispatchAction()) { case CALL_METHOD: return MISSING; case RESPOND_TO_METHOD: return false; default: throw new UnsupportedOperationException(); } }
private void poll(Node currentNode, boolean fromBlockingCall) { try { assumption.check(); } catch (InvalidAssumptionException e) { assumptionInvalidated(currentNode, fromBlockingCall); } }
private boolean lazyUpdate(VirtualFrame frame) { if (version == null || !version.isValid()) { CompilerDirectives.transferToInterpreterAndInvalidate(); // i am allowed to pass in the virtual frame as its instances are always materialized return lazyUpdatedImpl(frame); } return true; }
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 double executeFloat(RubyBasicObject receiver) throws UnexpectedResultException { if (hasFloat && receiver.getRubyClass() == expectedClass && unmodifiedAssumption.isValid()) { return integerFixnumValue; } else { return next.executeFloat(receiver); } }
@Override public boolean executeBoolean(RubyBasicObject receiver) throws UnexpectedResultException { if (hasBoolean && receiver.getRubyClass() == expectedClass && unmodifiedAssumption.isValid()) { return booleanValue; } else { return next.executeBoolean(receiver); } }
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"); }
@Override public void leave(Node astNode, VirtualFrame frame, Object result) { try { inactiveAssumption.check(); } catch (InvalidAssumptionException e) { final ActiveLeaveDebugProbe activeNode = createActive(); replace(activeNode); activeNode.leave(astNode, frame, result); } }
@Override public long executeLongFixnum(RubyBasicObject receiver) throws UnexpectedResultException { if (hasLongFixnum && receiver.getRubyClass() == expectedClass && unmodifiedAssumption.isValid()) { return longFixnumValue; } else { return next.executeLongFixnum(receiver); } }
@Override public Object execute(RubyBasicObject receiver) { // TODO(CS): not sure trying next on invalid assumption is right... if (receiver.getRubyClass() == expectedClass && unmodifiedAssumption.isValid()) { return value; } else { return next.execute(receiver); } }
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; }
private void pauseAllThreadsAndExecute( Node currentNode, boolean isRubyThread, SafepointAction action, boolean deferred) { this.action = action; this.deferred = deferred; /* this is a potential cause for race conditions, * but we need to invalidate first so the interrupted threads * see the invalidation in poll() in their catch(InterruptedException) clause * and wait on the barrier instead of retrying their blocking action. */ assumption.invalidate(); interruptOtherThreads(); step(currentNode, true); }
@Override public void enter(Node node, VirtualFrame frame) { try { traceAssumption.check(); } catch (InvalidAssumptionException e) { traceAssumption = context.getTraceManager().getTraceAssumption(); traceFunc = context.getTraceManager().getTraceFunc(); if (traceFunc != null) { callNode = insert(Truffle.getRuntime().createDirectCallNode(traceFunc.getCallTarget())); } else { callNode = null; } } if (traceFunc != null) { if (!context.getTraceManager().isInTraceFunc()) { context.getTraceManager().setInTraceFunc(true); final Object[] args = new Object[] { event, file, line, NilPlaceholder.INSTANCE, new RubyBinding( context.getCoreLibrary().getBindingClass(), RubyArguments.getSelf(frame.getArguments()), frame.materialize()), NilPlaceholder.INSTANCE }; try { callNode.call( frame, RubyArguments.pack( traceFunc, traceFunc.getDeclarationFrame(), traceFunc.getSelfCapturedInScope(), traceFunc.getBlockCapturedInScope(), args)); } finally { context.getTraceManager().setInTraceFunc(false); } } } }
@Specialization(guards = "guardName") public Object dispatch( VirtualFrame frame, RubyNilClass methodReceiverObject, LexicalScope lexicalScope, RubySymbol receiverObject, Object methodName, Object blockObject, Object argumentsObjects, Dispatch.DispatchAction dispatchAction) { CompilerAsserts.compilationConstant(dispatchAction); // Check the class has not been modified try { unmodifiedAssumption.check(); } catch (InvalidAssumptionException e) { return resetAndDispatch( frame, methodReceiverObject, lexicalScope, receiverObject, methodName, CompilerDirectives.unsafeCast(blockObject, RubyProc.class, true, false), argumentsObjects, dispatchAction, "class modified"); } if (dispatchAction == Dispatch.DispatchAction.CALL_METHOD) { return callNode.call( frame, RubyArguments.pack( method, method.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 value; } else { throw new UnsupportedOperationException(); } }
@Specialization( guards = {"location != null", "object.getShape() == cachedShape"}, assumptions = {"newArray(cachedShape.getValidAssumption(), validLocation)"}, limit = "getCacheLimit()") public void writeExistingField( DynamicObject object, Object value, @Cached("object.getShape()") Shape cachedShape, @Cached("getLocation(object, value)") Location location, @Cached("createAssumption()") Assumption validLocation) { try { location.set(object, value, cachedShape); } catch (IncompatibleLocationException | FinalLocationException e) { // remove this entry validLocation.invalidate(); execute(object, value); } }
@Specialization( guards = {"!hasField", "object.getShape() == oldShape"}, assumptions = { "newArray(oldShape.getValidAssumption(), newShape.getValidAssumption(), validLocation)" }, limit = "getCacheLimit()") public void writeNewField( DynamicObject object, Object value, @Cached("hasField(object, value)") boolean hasField, @Cached("object.getShape()") Shape oldShape, @Cached("transitionWithNewField(oldShape, value)") Shape newShape, @Cached("getNewLocation(newShape)") Location location, @Cached("createAssumption()") Assumption validLocation) { try { location.set(object, value, oldShape, newShape); } catch (IncompatibleLocationException e) { // remove this entry validLocation.invalidate(); execute(object, value); } }
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); } } }