public CachedBoxedSymbolDispatchNode( RubyContext context, Object cachedName, DispatchNode next, Object value, InternalMethod method, boolean indirect, DispatchAction dispatchAction) { super(context, cachedName, next, indirect, dispatchAction); unmodifiedAssumption = context.getCoreLibrary().getSymbolClass().getUnmodifiedAssumption(); this.value = value; this.method = method; if (method != null) { if (indirect) { indirectCallNode = Truffle.getRuntime().createIndirectCallNode(); } else { callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget()); if (callNode.isCallTargetCloningAllowed() && method.getSharedMethodInfo().shouldAlwaysSplit()) { insert(callNode); callNode.cloneCallTarget(); } } } }
@TruffleBoundary private SafepointAction step(Node currentNode, boolean isDrivingThread) { final DynamicObject thread = context.getThreadManager().getCurrentThread(); // wait other threads to reach their safepoint phaser.arriveAndAwaitAdvance(); if (isDrivingThread) { assumption = Truffle.getRuntime().createAssumption("SafepointManager"); } // wait the assumption to be renewed phaser.arriveAndAwaitAdvance(); // Read these while in the safepoint. SafepointAction deferredAction = deferred ? action : null; try { if (!deferred && thread != null && Layouts.THREAD.getStatus(thread) != Status.ABORTING) { action.run(thread, currentNode); } } finally { // wait other threads to finish their action phaser.arriveAndAwaitAdvance(); } return deferredAction; }
@Override public Object execute( TranslatorDriver.ParserContext parserContext, Object self, MaterializedFrame parentFrame, org.jruby.ast.RootNode rootNode) { try { final RubyParserResult parseResult = truffleContext .getTranslator() .parse( truffleContext, truffleContext.getSourceManager().get(rootNode.getPosition().getFile()), parserContext, parentFrame, rootNode); final CallTarget callTarget = Truffle.getRuntime().createCallTarget(parseResult.getRootNode()); return callTarget.call(RubyArguments.pack(parentFrame, self, null)); } catch (ThrowException e) { throw new RaiseException(truffleContext.getCoreLibrary().nameErrorUncaughtThrow(e.getTag())); } catch (RaiseException | BreakShellException | QuitException e) { throw e; } catch (Throwable e) { e.printStackTrace(); throw new RaiseException(ExceptionTranslator.translateException(truffleContext, e)); } }
@Override public TruffleMethod truffelize(DynamicMethod originalMethod, ArgsNode argsNode, Node bodyNode) { final MethodDefinitionNode methodDefinitionNode = truffleContext.getTranslator().parse(truffleContext, null, argsNode, bodyNode); return new TruffleMethod( originalMethod, Truffle.getRuntime().createCallTarget(methodDefinitionNode.getMethodRootNode())); }
@Specialization public RubyString fullTree() { notDesignedForCompilation(); return getContext() .makeString( NodeUtil.printTreeToString( Truffle.getRuntime().getCallerFrame().getCallNode().getRootNode())); }
@Test public void test() { TruffleRuntime runtime = Truffle.getRuntime(); TestRootNode rootNode = new TestRootNode(new TestArgumentNode[] {new TestArgumentNode(0), new TestArgumentNode(1)}); CallTarget target = runtime.createCallTarget(rootNode); Object result = target.call(new TestArguments(20, 22)); Assert.assertEquals(42, 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"); }
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; if (method != null) { callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget()); } }
public OpenModuleNode( RubyContext context, SourceSection sourceSection, RubyNode definingModule, MethodDefinitionNode definitionMethod, LexicalScope lexicalScope) { super(context, sourceSection); this.definingModule = definingModule; this.definitionMethod = definitionMethod; this.lexicalScope = lexicalScope; callModuleDefinitionNode = Truffle.getRuntime().createIndirectCallNode(); }
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; } }
@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); } } } }
private boolean lazyUpdatedImpl(VirtualFrame frame) { Node nextChain = instrumenter.installBindings(ProbeNode.this); if (nextChain == null) { // chain is null -> remove wrapper; // Note: never set child nodes to null, can cause races InstrumentationHandler.removeWrapper(ProbeNode.this); return false; } EventChainNode oldChain = this.chain; if (oldChain != null) { oldChain.onDispose(context, frame); } this.chain = (EventChainNode) insert(nextChain); this.version = Truffle.getRuntime().createAssumption("Instrumentations unchanged"); return true; }
public CachedYieldDispatchNode(RubyContext context, RubyProc block, YieldDispatchNode next) { super(context); callNode = Truffle.getRuntime().createDirectCallNode(block.getCallTargetForBlocks()); insert(callNode); if (INLINER_ALWAYS_CLONE_YIELD && callNode.isCallTargetCloningAllowed()) { callNode.cloneCallTarget(); } if (INLINER_ALWAYS_INLINE_YIELD && callNode.isInlinable()) { callNode.forceInlining(); } this.next = next; }
public CachedSingletonDispatchNode( RubyContext context, Object cachedName, DispatchNode next, DynamicObject expectedReceiver, DynamicObject expectedClass, InternalMethod method, DispatchAction dispatchAction) { super(context, cachedName, next, dispatchAction); this.expectedReceiver = expectedReceiver; this.unmodifiedAssumption = Layouts.MODULE.getFields(expectedClass).getUnmodifiedAssumption(); this.next = next; this.method = method; this.callNode = Truffle.getRuntime().createDirectCallNode(method.getCallTarget()); applySplittingInliningStrategy(callNode, method); }
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(); } } }
/** * Slow-path code for a call, used when the polymorphic inline cache exceeded its maximum size. Such * calls are not optimized any further, e.g., no method inlining is performed. */ final class LlvmGenericDispatchNode extends LlvmAbstractDispatchNode { /** * {@link IndirectCallNode} is part of the Truffle API and handles all the steps necessary for * calling a megamorphic call-site. The Graal specific version of this node performs additional * optimizations for the fast access of the SimpleLanguage stack trace. */ @Child private IndirectCallNode callNode = Truffle.getRuntime().createIndirectCallNode(); @Override protected Object executeDispatch(VirtualFrame frame, LlvmFunction function, Object[] arguments) { /* * Llvm has a quite simple call lookup: just ask the function for the current call target, * and call it. */ return callNode.call(frame, function.getCallTarget(), arguments); } }
public MethodDefinitionNode compileMethodNode( SourceSection sourceSection, String methodName, org.jruby.ast.Node bodyNode, SharedMethodInfo sharedMethodInfo) { final RubyNode body = compileMethodBody(sourceSection, methodName, bodyNode, sharedMethodInfo); final RubyRootNode rootNode = new RubyRootNode( context, considerExtendingMethodToCoverEnd(body.getSourceSection()), environment.getFrameDescriptor(), environment.getSharedMethodInfo(), body, environment.needsDeclarationFrame()); final CallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode); return new MethodDefinitionNode( context, sourceSection, methodName, environment.getSharedMethodInfo(), callTarget); }
@Override public void init() { if (RubyContext.PRINT_RUNTIME) { runtime .getInstanceConfig() .getError() .println("jruby: using " + Truffle.getRuntime().getName()); } // Bring in core method nodes CoreMethodNodeManager.addStandardMethods(truffleContext.getCoreLibrary().getObjectClass()); // Give the core library manager a chance to tweak some of those methods truffleContext.getCoreLibrary().initializeAfterMethodsAdded(); // Set program arguments for (IRubyObject arg : ((org.jruby.RubyArray) runtime.getObject().getConstant("ARGV")).toJavaArray()) { assert arg != null; truffleContext.getCoreLibrary().getArgv().slowPush(truffleContext.makeString(arg.toString())); } // Set the load path final RubyArray loadPath = (RubyArray) truffleContext.getCoreLibrary().getGlobalVariablesObject().getInstanceVariable("$:"); for (IRubyObject path : ((org.jruby.RubyArray) runtime.getLoadService().getLoadPath()).toJavaArray()) { loadPath.slowPush(truffleContext.makeString(path.toString())); } // Hook if (truffleContext.getHooks() != null) { truffleContext.getHooks().afterInit(truffleContext); } }
public static PGenerator create( String name, RootCallTarget callTarget, FrameDescriptor frameDescriptor, MaterializedFrame declarationFrame, Object[] arguments, int numOfActiveFlags, int numOfGeneratorBlockNode, int numOfGeneratorForNode) { /** Setting up the persistent frame in {@link #arguments}. */ GeneratorControlData generatorArgs = new GeneratorControlData(numOfActiveFlags, numOfGeneratorBlockNode, numOfGeneratorForNode); MaterializedFrame generatorFrame = Truffle.getRuntime().createMaterializedFrame(PArguments.create(), frameDescriptor); PArguments.setDeclarationFrame(arguments, declarationFrame); PArguments.setGeneratorFrame(arguments, generatorFrame); PArguments.setControlData(arguments, generatorArgs); return new PGenerator(name, callTarget, frameDescriptor, arguments); }
public CallTarget compile(String format) { if (format.length() > context.getOptions().PACK_RECOVER_LOOP_MIN) { format = LoopRecovery.recoverLoop(format); } final SimpleUnpackTreeBuilder builder = new SimpleUnpackTreeBuilder(context, currentNode); builder.enterSequence(); final SimplePackParser parser = new SimplePackParser(builder, format.getBytes(StandardCharsets.US_ASCII)); parser.parse(); builder.exitSequence(); return Truffle.getRuntime() .createCallTarget( new UnpackRootNode( context, currentNode.getEncapsulatingSourceSection(), builder.getNode())); }
public Status run(String[] args) { try { if (Options.TRUFFLE_PRINT_RUNTIME.load()) { config.getError().println("jruby: using " + Truffle.getRuntime().getName()); } config.processArguments(args); return internalRun(); } catch (MainExitException mee) { return handleMainExit(mee); } catch (OutOfMemoryError oome) { return handleOutOfMemory(oome); } catch (StackOverflowError soe) { return handleStackOverflow(soe); } catch (UnsupportedClassVersionError ucve) { return handleUnsupportedClassVersion(ucve); } catch (ThreadKill kill) { return new Status(); } }
public static CallTarget getIndirectCallTarget( LLVMContext context, LLVMFunction function, LLVMExpressionNode[] args) { CallTarget callTarget = context.getFunction(function); if (callTarget == null) { final NativeFunctionHandle nativeHandle = context.getNativeHandle(function, args); if (nativeHandle == null) { throw new IllegalStateException("could not find function " + function.getName()); } else { return Truffle.getRuntime() .createCallTarget( new RootNode(LLVMLanguage.class, null, null) { @Override public Object execute(VirtualFrame frame) { return nativeHandle.call(frame.getArguments()); } }); } } else { return callTarget; } }
public class SafepointManager { private final RubyContext context; private final Set<Thread> runningThreads = Collections.newSetFromMap(new ConcurrentHashMap<Thread, Boolean>()); @CompilationFinal private Assumption assumption = Truffle.getRuntime().createAssumption("SafepointManager"); private final ReentrantLock lock = new ReentrantLock(); private final Phaser phaser = new Phaser(); private volatile SafepointAction action; private volatile boolean deferred; public SafepointManager(RubyContext context) { this.context = context; } public void enterThread() { CompilerAsserts.neverPartOfCompilation(); lock.lock(); try { phaser.register(); runningThreads.add(Thread.currentThread()); } finally { lock.unlock(); } } public void leaveThread() { CompilerAsserts.neverPartOfCompilation(); phaser.arriveAndDeregister(); runningThreads.remove(Thread.currentThread()); } public void poll(Node currentNode) { poll(currentNode, false); } public void pollFromBlockingCall(Node currentNode) { poll(currentNode, true); } private void poll(Node currentNode, boolean fromBlockingCall) { try { assumption.check(); } catch (InvalidAssumptionException e) { assumptionInvalidated(currentNode, fromBlockingCall); } } @TruffleBoundary private void assumptionInvalidated(Node currentNode, boolean fromBlockingCall) { final DynamicObject thread = context.getThreadManager().getCurrentThread(); final InterruptMode interruptMode = Layouts.THREAD.getInterruptMode(thread); final boolean interruptible = (interruptMode == InterruptMode.IMMEDIATE) || (fromBlockingCall && interruptMode == InterruptMode.ON_BLOCKING); if (!interruptible) { Thread.currentThread().interrupt(); // keep the interrupt flag return; // interrupt me later } SafepointAction deferredAction = step(currentNode, false); // We're now running again normally and can run deferred actions if (deferredAction != null) { deferredAction.run(thread, currentNode); } } @TruffleBoundary private SafepointAction step(Node currentNode, boolean isDrivingThread) { final DynamicObject thread = context.getThreadManager().getCurrentThread(); // wait other threads to reach their safepoint phaser.arriveAndAwaitAdvance(); if (isDrivingThread) { assumption = Truffle.getRuntime().createAssumption("SafepointManager"); } // wait the assumption to be renewed phaser.arriveAndAwaitAdvance(); // Read these while in the safepoint. SafepointAction deferredAction = deferred ? action : null; try { if (!deferred && thread != null && Layouts.THREAD.getStatus(thread) != Status.ABORTING) { action.run(thread, currentNode); } } finally { // wait other threads to finish their action phaser.arriveAndAwaitAdvance(); } return deferredAction; } private void interruptOtherThreads() { Thread current = Thread.currentThread(); for (Thread thread : runningThreads) { if (thread != current) { thread.interrupt(); } } } 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); } // Variants for all threads @TruffleBoundary public void pauseAllThreadsAndExecute( Node currentNode, boolean deferred, SafepointAction action) { if (lock.isHeldByCurrentThread()) { throw new IllegalStateException("Re-entered SafepointManager"); } // Need to lock interruptibly since we are in the registered threads. while (!lock.tryLock()) { poll(currentNode); } try { pauseAllThreadsAndExecute(currentNode, true, action, deferred); } finally { lock.unlock(); } // Run deferred actions after leaving the SafepointManager lock. if (deferred) { action.run(context.getThreadManager().getCurrentThread(), currentNode); } } @TruffleBoundary public void pauseAllThreadsAndExecuteFromNonRubyThread(boolean deferred, SafepointAction action) { if (lock.isHeldByCurrentThread()) { throw new IllegalStateException("Re-entered SafepointManager"); } assert !runningThreads.contains(Thread.currentThread()); // Just wait to grab the lock, since we are not in the registered threads. lock.lock(); try { enterThread(); try { pauseAllThreadsAndExecute(null, false, action, deferred); } finally { leaveThread(); } } finally { lock.unlock(); } } // Variants for a single thread @TruffleBoundary public void pauseThreadAndExecute( final Thread thread, Node currentNode, final SafepointAction action) { if (Thread.currentThread() == thread) { // fast path if we are already the right thread DynamicObject rubyThread = context.getThreadManager().getCurrentThread(); action.run(rubyThread, currentNode); } else { pauseAllThreadsAndExecute( currentNode, false, new SafepointAction() { @Override public void run(DynamicObject rubyThread, Node currentNode) { if (Thread.currentThread() == thread) { action.run(rubyThread, currentNode); } } }); } } @TruffleBoundary public void pauseThreadAndExecuteLater( final Thread thread, Node currentNode, final SafepointAction action) { if (Thread.currentThread() == thread) { // fast path if we are already the right thread DynamicObject rubyThread = context.getThreadManager().getCurrentThread(); action.run(rubyThread, currentNode); } else { pauseAllThreadsAndExecute( currentNode, true, new SafepointAction() { @Override public void run(DynamicObject rubyThread, Node currentNode) { if (Thread.currentThread() == thread) { action.run(rubyThread, currentNode); } } }); } } @TruffleBoundary public void pauseThreadAndExecuteLaterFromNonRubyThread( final Thread thread, final SafepointAction action) { pauseAllThreadsAndExecuteFromNonRubyThread( true, new SafepointAction() { @Override public void run(DynamicObject rubyThread, Node currentNode) { if (Thread.currentThread() == thread) { action.run(rubyThread, currentNode); } } }); } }
protected Assumption createAssumption() { return Truffle.getRuntime().createAssumption(); }
public LLVMResolvedDirectCallNode(CallTarget callTarget, LLVMExpressionNode[] args) { this.callNode = Truffle.getRuntime().createDirectCallNode(callTarget); this.args = args; }
public IntDownToDoMessageNode(final ExpressionNode orignialNode, final SBlock block) { super(orignialNode.getSourceSection()); blockMethod = block.getMethod(); valueSend = Truffle.getRuntime().createDirectCallNode(blockMethod.getCallTarget()); }
public GeneralYieldDispatchNode(RubyContext context) { super(context); callNode = Truffle.getRuntime().createIndirectCallNode(); }
GenericObjectAccessNode(Message access) { this.access = access; indirectCallNode = Truffle.getRuntime().createIndirectCallNode(); }
public class RContext { public static final boolean DEBUG = Utils.getProperty("RConsole.debug.gui", false); private static boolean debuggingFormat = false; private static boolean usesTruffleOptimizer = Truffle.getRuntime().equals("Default Truffle Runtime"); private static ManageError errorManager = new ManageError(System.err); private static Truffleize truffleize = new Truffleize(); private static final int NCONNECTIONS = 128; private static final Connection[] connections = new Connection[NCONNECTIONS]; static { Arrays.fill(connections, null); } public static boolean usesTruffleOptimizer() { return usesTruffleOptimizer; } public static boolean debuggingFormat() { return debuggingFormat; } public static boolean debuggingFormat(boolean useDebuggingFormat) { boolean previous = debuggingFormat; debuggingFormat = useDebuggingFormat; return previous; } public static RAny eval(ASTNode expr, boolean useDebuggingFormat) { debuggingFormat(useDebuggingFormat); return eval(expr); // NOTE: cannot reset to the original value of debuggingFormat here, because usually the pretty // printer is // invoked on the results afterwards by the caller of eval; the pretty printer still depends on // the correct // setting of debugging format } public static RAny eval(ASTNode expr) { try { return (RAny) truffleize.createLazyRootTree(expr).execute(null); // null means top-level } catch (RError e) { if (DEBUG) { e.printStackTrace(); } error(e); // throws an error } throw new Error("Never reached"); } public static RNode createNode(ASTNode expr) { return truffleize.createTree(expr); } public static RNode createRootNode(ASTNode expr, final RFunction rootEnclosingFunction) { return new BaseR(expr) { @Child RNode node = adoptChild(truffleize.createTree(ast, rootEnclosingFunction)); @Override public Object execute(Frame frame) { return node.execute(frame); } }; } public static void warning(ASTNode expr, String msg, Object... args) { errorManager.warning(expr, String.format(msg, args)); } public static void warning(ASTNode expr, String msg) { errorManager.warning(expr, msg); } public static void warning(RError err) { errorManager.warning(err); } public static void error(ASTNode expr, String msg) { errorManager.error(expr, msg); } public static void error(RError err) { errorManager.error(err); } public static int allocateConnection(Connection connection) { for (int i = 0; i < NCONNECTIONS; i++) { if (connections[i] == null) { connections[i] = connection; return i; } } return -1; } /** Release a connection currently in use. */ public static void freeConnection(int i) { assert Utils.check(connections[i] != null); connections[i] = null; } /** Return a connection or null. */ public static Connection getConnection(int i) { return i >= 0 && i < NCONNECTIONS ? connections[i] : null; } // note: GNUR currently means not only the GNU-R library, but also some other native code, under // licenses compatible with GPL private static int hasGNUR = -1; public static boolean hasGNUR() { if (hasGNUR == -1) { try { System.loadLibrary("gnurglue"); hasGNUR = 1; } catch (Throwable t) { hasGNUR = 0; } } return hasGNUR == 1; } public static ASTNode parseFile(ANTLRStringStream inputStream) { CommonTokenStream tokens = new CommonTokenStream(); RLexer lexer = new RLexer(inputStream); tokens.setTokenSource(lexer); RParser parser = new RParser(tokens); try { return parser.script(); } catch (RecognitionException e) { Console.parseError(parser, e); return null; } } }
public GeneralDispatchNode(RubyContext context, String name) { super(context); assert name != null; this.name = name; callNode = Truffle.getRuntime().createIndirectCallNode(); }