All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pkl.thirdparty.truffle.api.TruffleSafepoint Maven / Gradle / Ivy

Go to download

Fat Jar containing pkl-cli, pkl-codegen-java, pkl-codegen-kotlin, pkl-config-java, pkl-core, pkl-doc, and their shaded third-party dependencies.

There is a newer version: 0.27.1
Show newest version
/*
 * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * The Universal Permissive License (UPL), Version 1.0
 *
 * Subject to the condition set forth below, permission is hereby granted to any
 * person obtaining a copy of this software, associated documentation and/or
 * data (collectively the "Software"), free of charge and under any and all
 * copyright rights in the Software, and any and all patent rights owned or
 * freely licensable by each licensor hereunder covering either (i) the
 * unmodified Software as contributed to or provided by such licensor, or (ii)
 * the Larger Works (as defined below), to deal in both
 *
 * (a) the Software, and
 *
 * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
 * one is included with the Software each a "Larger Work" to which the Software
 * is contributed by such licensors),
 *
 * without restriction, including without limitation the rights to copy, create
 * derivative works of, display, perform, and distribute the Software and make,
 * use, sell, offer for sale, import, export, have made, and have sold the
 * Software and the Larger Work(s), and to sublicense the foregoing rights on
 * either these or other terms.
 *
 * This license is subject to the following condition:
 *
 * The above copyright notice and either this complete permission notice or at a
 * minimum a reference to the UPL must be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.pkl.thirdparty.truffle.api;

import java.util.Objects;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.function.Consumer;

import org.pkl.thirdparty.graalvm.polyglot.Context;

import org.pkl.thirdparty.truffle.api.CompilerDirectives.TruffleBoundary;
import org.pkl.thirdparty.truffle.api.impl.Accessor.EngineSupport;
import org.pkl.thirdparty.truffle.api.impl.ThreadLocalHandshake;
import org.pkl.thirdparty.truffle.api.nodes.LoopNode;
import org.pkl.thirdparty.truffle.api.nodes.Node;
import org.pkl.thirdparty.truffle.api.nodes.RootNode;

/**
 * Truffle safepoints allow interrupting the guest language execution to execute thread-local
 * actions submitted by a language or tool. A safepoint is a location during the guest language
 * execution where the state is consistent, and other operations can read its state.
 * 

*

Supporting Safepoints in a Language

*

* Safepoints are explicitly polled by invoking the {@link #poll(Node)} method. Safepoints are * {@link #poll(Node) polled} with relaxed location or with {@link #pollHere(Node) exact location}. * A poll with a relaxed location is significantly more efficient than a poll with a precise * location as the compiler is able to move and combine the poll requests during compilation. A * Truffle guest language implementation must ensure that a safepoint is polled repeatedly within a * constant time interval. For example, a single arithmetic expression completes within a constant * number of CPU cycles. However, a loop that summarizes values over an array uses a non-constant * time dependent on the array size. This typically means that safepoints are best polled at the end * of loops and at the end of function or method calls to cover recursion. In addition, any guest * language code that blocks the execution, like guest language locks, need to use the * {@link #setBlockedWithException(Node, Interrupter, Interruptible, Object, Runnable, Consumer) * blocking API} to allow polling of safepoints while the thread is waiting. *

* Truffle's {@link LoopNode loop node} and {@link RootNode root node} support safepoint polling * automatically. No further calls to {@link #poll(Node)} are therefore necessary. Custom loops or * loops behind {@link TruffleBoundary boundary} annotated method calls are expected to be notified * by the guest language implementation manually. *

* Thread local actions optionally incur side-effects. By default side-effects are enabled. A * language implementation may disable side-effects temporarily for the current thread using * {@link #setAllowSideEffects(boolean)} method. *

* *

Submitting thread local actions

*

* See {@link ThreadLocalAction} for details on how to submit actions. *

* Further information can be found in the * safepoint * tutorial. * * @see ThreadLocalAction * @see Context#safepoint() * @since 21.1 */ public abstract class TruffleSafepoint { private static final ThreadLocalHandshake HANDSHAKE = LanguageAccessor.ACCESSOR.runtimeSupport().getThreadLocalHandshake(); /** * Do not extend this class. This class is intended to be implemented by a Truffle runtime * implementation. * * @since 21.1 */ protected TruffleSafepoint(EngineSupport support) { if (support == null) { throw new AssertionError("Only runtime is allowed create truffle safepoint instances."); } } /** * Polls a safepoint at the provided location. This allows to run thread local actions at this * location. A Truffle guest language implementation must ensure that a safepoint is polled * repeatedly within a constant time interval. See {@link TruffleSafepoint} for further details. *

* In compiled code calls to this method are removed. Instead the compiler inserts safepoints * automatically at loop ends and method exits. In this case the node location is approximated * by frame state of method ends and loop exits in the compiler IR. For method ends the parent * root node and for loop exits the loop node is passed as location. *

* Guest language exceptions may be thrown by this method. If * {@link #setAllowSideEffects(boolean) side-effects} are allowed then also guest language * exceptions may be thrown. Otherwise only internal or {@link ThreadDeath thread-death} * exceptions may be thrown. This method is safe to be used on compiled code paths. *

* Example usage with an unbounded loop sum behind a {@link TruffleBoundary}. * *

     * @TruffleBoundary
     * int sum(int[] array) {
     *     int sum = 0;
     *     for (int i = 0; i < array.length; i++) {
     *         sum += array[i];
     *
     *         TruffleSafepoint.poll();
     *     }
     *     return sum;
     * }
     * 
* * @param location the location of the poll. Must not be null. * @see TruffleSafepoint * @see #pollHere(Node) * @since 21.1 */ public static void poll(Node location) { if (location == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); throw new NullPointerException(); } HANDSHAKE.poll(location); } /** * Similar to {@link #poll(Node)} but with exact location. A poll with {@link #poll(Node) * relaxed location} is significantly more efficient than a poll with precise location as the * compiler is able to move and combine the poll requests during compilation. This method is * safe to be used on compiled code paths. *

* Usage example: * *

     * TruffleSafepoint safepoint = TruffleSafepoint.getCurrent();
     * boolean prev = safepoint.setAllowSideEffects(false);
     * try {
     *     // criticial section
     * } finally {
     *     safepoint.setAllowSideEffects(prev);
     *     TruffleSafepoint.pollHere(this);
     * }
     * 
* * @param location the location of the poll. Must not be null. * @see #poll(Node) * @since 21.1 */ @TruffleBoundary public static void pollHere(Node location) { Objects.requireNonNull(location); HANDSHAKE.poll(location); } /** * @see #setBlockedWithException(Node, Interrupter, Interruptible, Object, Runnable, Consumer) * @since 21.1 * @deprecated in 22.1. Use * {@link #setBlockedWithException(Node, Interrupter, Interruptible, Object, Runnable, Consumer)}. * Though similar in functionality, this method costs an additional lambda * expression, which may be unfavorable in partial evaluated code. */ @Deprecated(since = "22.1") public final void setBlocked(Node location, Interrupter interrupter, Interruptible interruptible, T object, Runnable beforeInterrupt, Runnable afterInterrupt) { setBlockedWithException(location, interrupter, interruptible, object, beforeInterrupt, // Runnable -> Consumer afterInterrupt == null ? null : (t) -> afterInterrupt.run()); } /** * Transitions the current thread into a blocked state and calls an interruptible functional * method. The blocked state is restored when the interruptible method returns. Setting the * blocked state allows safepoint notification while the current thread is blocked. This allows * Truffle to interrupt e.g. locks temporarily to perform a thread local action. *

* The location> parameter is used {@link #poll(Node) poll} all pending thread * local actions before transition to blocked state. *

* The interrupter parameter specifies how the blocked state can be interrupted * from another thread. The interrupter allows to interrupt the blocked state from other * threads. For most blocking java.util.concurrent primitives the * {@link Interrupter#THREAD_INTERRUPT thread interrupter} can be used. If the thread will be * blocked in native code, other ways of interrupting, like signals may be used by implementing * the {@link Interrupter} interface. *

* The interruptible parameter provides the method that calls the blocking method * which throws {@link InterruptedException} on interrupt. In order to avoid allocations of the * functional interface a single argument can be provided that is passed to the interface. This * is typically the {@link Lock lock} or {@link Semaphore semaphore} instance. The * implementation of this method is expected to throw an {@link InterruptedException} if the * {@link Interrupter#interrupt(Thread)} method is invoked for this thread. For most * java.util.concurrent primitives this is supported by using the interruptible blocking method * variant, for example {@link Lock#lockInterruptibly()}. *

* Since it is common to use this method with method reference syntax e.g. * Lock::lockInterruptibly for the interruptible parameter, we implicitlely apply a * {@link TruffleBoundary boundary} for the entire method call by default. If the interruptible * is called from a compiled code path and the interruptible should get partial evaluated, then * {@link CompiledInterruptible} should be used instead of {@link Interruptible}. In this case * the parameter must be a {@link CompilerDirectives#isPartialEvaluationConstant(Object) partial * evaluation constant}. *

* The beforeInterrupt {@link Runnable runnable} and afterInterrupt * {@link Consumer consumer} optional parameters allow to run code before and after a thread got * interrupted and safepoint events are processed. If null is provided then no * action will be performed. Arbitrary code may be executed in this runnable. Note that the * blocked state is temporarily reset to its previous state while the afterInterrupt is called. *

* If an exception is thrown during the processing of the safepoint, afterInterrupt * will receive the throwable as argument, or null if the safepoint successfully * completed. This exception will still be thrown after completion of * afterInterrupt, unless afterInterrupt throws an exception of its * own. * *

* Multiple recursive invocations of this method is supported. The previous blocked state will * be restored when the method completes or fails. *

* Example usage: *

* Note there is a short-cut method to achieve the same behavior as in this example * {@link #setBlockedThreadInterruptible(Node, Interruptible, Object)}. * *

     * Lock lock = new ReentrantLock();
     * TruffleSafepoint sp = TruffleSafepoint.getCurrent();
     * sp.setBlocked(location, Interrupter.THREAD_INTERRUPT, ReentrantLock::lockInterruptibly, lock, null, null);
     * 
* * @see TruffleSafepoint * @since 22.1 */ public abstract void setBlockedWithException(Node location, Interrupter interrupter, Interruptible interruptible, T object, Runnable beforeInterrupt, Consumer afterInterrupt); /** * Short-cut method to allow setting the blocked status for methods that throw * {@link InterruptedException} and support interrupting using {@link Thread#interrupt()}. * * @param location the location with which the safepoint should be polled. * @param interruptible the thread interruptable method to use for locking the object * @param object the instance to use the interruptable method with. * @since 21.1 */ public static void setBlockedThreadInterruptible(Node location, Interruptible interruptible, T object) { TruffleSafepoint safepoint = TruffleSafepoint.getCurrent(); safepoint.setBlockedWithException(location, Interrupter.THREAD_INTERRUPT, interruptible, object, null, (Consumer) null); } /** * Allows to temporarily delay all thread local actions on the current thread. It is recommended * to delay actions only for a constant period of time and while trusted and internal guest code * is running. Please consider using {@link #setAllowSideEffects(boolean)} before using this * method. While actions are disabled the value of {@link #setAllowSideEffects(boolean)} has no * effect. When {@link #setAllowActions(boolean) actions} are enabled again the value of * {@link #setAllowSideEffects(boolean)} will be interpreted again. *

* Currently this method may only be used during {@link TruffleLanguage#finalizeContext(Object) * context finalization}. This could be necessary to free up native resources through guest code * when a context is cancelled to avoid resource leakage. Any usage of this method should be * subject to a detailed security review to ensure only internal and well-known guest code is * executed. Disabling thread local actions may delay thread local actions like exit, * cancellation and interruption. *

* Example usage: * *

     * TruffleSafepoint sp = TruffleSafepoint.getCurrent();
     * boolean prev = sp.setAllowActions(false);
     * try {
     *     // critical section
     * } finally {
     *     sp.setAllowActions(prev);
     * }
     * 
* * @throws IllegalStateException if allow actions can currently not be set, for example outside * the scope of a {@link TruffleLanguage#finalizeContext(Object) context * finalization}. * @see TruffleLanguage#finalizeContext(Object) * @since 22.1 */ public abstract boolean setAllowActions(boolean enabled) throws IllegalStateException; /** * Allows to temporarily delay side-effecting thread local actions on the current thread. It is * recommended to delay side-effecting actions only for a short and constant period of time. *

* While side-effecting thread local actions are delayed on this thread, only non-side-effecting * thread local actions will be scheduled in this thread. Non-side-effecting thread local * actions do not mutate guest objects, run guest code or throw guest exceptions, but they might * still throw internal errors. *

* Example usage: * *

     * TruffleSafepoint sp = TruffleSafepoint.getCurrent();
     * boolean prev = sp.setAllowSideEffects(false);
     * try {
     *     // critical section
     * } finally {
     *     sp.setAllowSideEffects(prev);
     * }
     * 
* * @since 21.1 */ public abstract boolean setAllowSideEffects(boolean enabled); /** * Returns whether there is any pending side-effecting thread local action on this thread, due * to being in a critical section using {@link #setAllowSideEffects(boolean)}. When * side-effecting actions are allowed, this method always returns {@code false}. *

* This is useful if the language exposes a way to know if there are any pending side-effecting * thread local action due to using {@link #setAllowSideEffects(boolean)}. * * @since 21.1 */ public abstract boolean hasPendingSideEffectingActions(); /** * Returns the current safepoint configuration for the current thread. This method is useful to * access configuration methods like * {@link #setBlockedWithException(Node, Interrupter, Interruptible, Object, Runnable, Consumer)} * or {@link #setAllowSideEffects(boolean)}. *

* Important: The result of this method must not be stored or used on a different thread than * the current thread. * * @since 21.1 */ public static TruffleSafepoint getCurrent() { return HANDSHAKE.getCurrent(); } /** * Function interface that represent interruptable Java methods. Examples are * {@link Lock#lockInterruptibly() Lock::lockInterruptibly} or {@link Semaphore#acquire() * Semaphore::acquire}. If used directly implies a {@link TruffleBoundary boundary}. Use * {@link CompiledInterruptible} if you need partial evaluation for this functional interface. * * @see TruffleSafepoint#setBlockedThreadInterruptible(Node, Interruptible, Object) * @since 21.1 */ @FunctionalInterface public interface Interruptible { /** * Runs the interruptable method for a given object. * * @since 21.1 */ void apply(T arg) throws InterruptedException; } /** * Just like {@link Interruptible} but allows partial evaluation. * * @since 21.1 */ @FunctionalInterface public interface CompiledInterruptible extends Interruptible { /** * Runs the interruptable method for a given object. * * @since 21.1 */ @Override void apply(T arg) throws InterruptedException; } /** * An interrupter allows a foreign thread to interrupt the execution on a separate thread. Used * to allow the Truffle safepoint mechanism to interrupt a blocked thread and schedule a * safepoint. * * @see TruffleSafepoint#setBlockedWithException(Node, Interrupter, Interruptible, Object, * Runnable, Consumer) * @see Interrupter#THREAD_INTERRUPT * @since 21.1 */ public interface Interrupter { /** * Sets the interrupted state on a foreign thread. Internal locks are held while this method * is invoked, therefore this method must not block or run complex or guest language code * that could cause deadlocks. * * @param thread the thread to interrupt * @since 21.1 */ void interrupt(Thread thread); /** * Resets the interrupted state when executing on a thread after the thread was interrupted. * If a thread was interrupted it is guaranteed to be reset at least once, but might be * reset multiple times. Internal locks are held while this method is invoked, therefore * this method must not block or run complex or guest language code that could cause * deadlocks. * * @since 21.1 */ void resetInterrupted(); /** * A thread interrupter implementation that uses {@link Thread#interrupt()} and * {@link Thread#interrupted()} to clear the thread state. *

* *

         * THREAD_INTERRUPT = new Interrupter() {
         *
         *     @Override
         *     public void interrupt(Thread t) {
         *         t.interrupt();
         *     }
         *
         *     @Override
         *     public void interrupted() {
         *         Thread.interrupted();
         *     }
         *
         * };
         * 
* * @since 21.1 */ Interrupter THREAD_INTERRUPT = new Interrupter() { @Override public void resetInterrupted() { Thread.interrupted(); } @Override public void interrupt(Thread t) { t.interrupt(); } }; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy