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

com.oracle.truffle.api.dsl.Cached Maven / Gradle / Ivy

Go to download

Truffle is a multi-language framework for executing dynamic languages that achieves high performance when combined with Graal.

There is a newer version: 24.1.1
Show newest version
/*
 * Copyright (c) 2015, 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 com.oracle.truffle.api.dsl;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.NodeInterface;

// Workaround for Eclipse formatter behaving different when running on JDK 9.
// @formatter:off
/**
 * 

* A parameter annotated with {@link Cached} in a {@link Specialization} refers to a cached * value of a specialization instance. A cached parameter value is initialized once using the * initializer expression at specialization instantiation. For each call of the specialization * method the cached value is provided by using the annotated parameter from the method body. Cache * initializers are potentially executed before guard expressions declared in * {@link Specialization#guards()}. *

*

* A typical specialization may define multiple dynamic and multiple cached parameters. Dynamic * parameter values are typically provided by executing child nodes of the operation. Cached * parameters are initialized and stored once per specialization instantiation. Cached parameters * are always constant at compile time. You may verify this by invoking * {@link CompilerAsserts#compilationConstant(Object)} on any cached parameter. For consistency * between specialization declarations cached parameters must be declared last in a specialization * method. *

*

* The initializer expression of a cached parameter is defined using a subset of Java. This subset * includes field/parameter accesses, function calls, type exact infix comparisons (==, !=, <, <=, * >, >=), logical negation (!), logical disjunction (||), null, true, false, and integer literals. * The return type of the initializer expression must be assignable to the parameter type. If the * annotated parameter type is derived from {@link Node} then the {@link Node} instance is allowed * to use the {@link Node#replace(Node)} method to replace itself. Bound elements without receivers * are resolved using the following order: *

    *
  1. Dynamic and cached parameters of the enclosing specialization.
  2. *
  3. Fields defined using {@link NodeField} for the enclosing node.
  4. *
  5. Public constructors of the type of the annotated parameter using the new keyword * as method name.
  6. *
  7. Public and static methods or fields of the type of the annotated parameter.
  8. *
  9. Non-private, static or virtual methods or fields of enclosing node.
  10. *
  11. Non-private, static or virtual methods or fields of super types of the enclosing node.
  12. *
  13. Public and static methods or fields imported using {@link ImportStatic}.
  14. *
* * The following examples explain the intended use of the {@link Cached} annotation. All of the * examples have to be enclosed in the following node declaration: *

* *
 * {@link NodeChild @NodeChild}("operand")
 * abstract TestNode extends Node {
 *   abstract void execute(Object operandValue);
 *   // ... example here ...
 * }
 * 
* *
    *
  1. This example defines one dynamic and one cached parameter. The operand parameter is * representing the dynamic value of the operand while the cachedOperand is initialized once at * first execution of the specialization (specialization instantiation time). * *
     *  @Specialization
     *  void doCached(int operand, {@code @Cached}("operand") int cachedOperand) {
     *      CompilerAsserts.compilationConstant(cachedOperand);
     *      ...
     *  }
     *
     *  Example executions:
     *  execute(1) => doCached(1, 1) // new instantiation, localOperand is bound to 1
     *  execute(0) => doCached(0, 1)
     *  execute(2) => doCached(2, 1)
     *
     * 
    * *
  2. *
  3. We extend the previous example by a guard for the cachedOperand value to be equal to the * dynamic operand value. This specifies that the specialization is instantiated for each individual * operand value that is provided. There are a lot of individual int values and for * each individual int value a new specialization would get instantiated. The * {@link Specialization#limit()} property defines a limit for the number of specializations that * can get instantiated. If the specialization instantiation limit is reached then no further * specializations are instantiated. Like for other specializations if there are no more * specializations defined an {@link UnsupportedSpecializationException} is thrown. The default * specialization instantiation limit is 3. * *
     * @Specialization(guards = "operand == cachedOperand")
     * void doCached(int operand, {@code @Cached}("operand") int cachedOperand) {
     *    CompilerAsserts.compilationConstant(cachedOperand);
     *    ...
     * }
     *
     * Example executions:
     * execute(0) => doCached(0, 0) // new instantiation, cachedOperand is bound to 0
     * execute(1) => doCached(1, 1) // new instantiation, cachedOperand is bound to 1
     * execute(1) => doCached(1, 1)
     * execute(2) => doCached(2, 2) // new instantiation, cachedOperand is bound to 2
     * execute(3) => throws UnsupportedSpecializationException // instantiation limit overflows
     *
     * 
    * *
  4. *
  5. To handle the limit overflow we extend our example by an additional specialization named * doNormal. This specialization has the same type restrictions but does not have local * state nor the operand identity guard. It is also declared after doCached therefore * it is only instantiated if the limit of the doCached specialization has been * reached. In other words doNormal is more generic than doCached . The * doNormal specialization uses replaces="doCached" to specify * that all instantiations of doCached get removed if doNormal is * instantiated. Alternatively if the replaces relation is omitted then all * doCached instances remain but no new instances are created. * *
     * @Specialization(guards = "operand == cachedOperand")
     * void doCached(int operand, {@code @Cached}("operand") int cachedOperand) {
     *    CompilerAsserts.compilationConstant(cachedOperand);
     *    ...
     * }
     *
     * @Specialization(replaces = "doCached")
     * void doNormal(int operand) {...}
     *
     * Example executions with replaces = "doCached":
     * execute(0) => doCached(0, 0) // new instantiation, cachedOperand is bound to 0
     * execute(1) => doCached(1, 1) // new instantiation, cachedOperand is bound to 1
     * execute(1) => doCached(1, 1)
     * execute(2) => doCached(2, 2) // new instantiation, cachedOperand is bound to 2
     * execute(3) => doNormal(3)    // new instantiation of doNormal due to limit overflow; doCached gets removed.
     * execute(1) => doNormal(1)
     *
     * Example executions without replaces = "doCached":
     * execute(0) => doCached(0, 0) // new instantiation, cachedOperand is bound to 0
     * execute(1) => doCached(1, 1) // new instantiation, cachedOperand is bound to 1
     * execute(1) => doCached(1, 1)
     * execute(2) => doCached(2, 2) // new instantiation, cachedOperand is bound to 2
     * execute(3) => doNormal(3)    // new instantiation of doNormal due to limit overflow
     * execute(1) => doCached(1, 1)
     *
     * 
    * *
  6. *
  7. This next example shows how methods from the enclosing node can be used to initialize cached * parameters. Please note that the visibility of transformLocal must not be private. * *
     * @Specialization
     * void s(int operand, {@code @Cached}("transformLocal(operand)") int cachedOperand) {
     * }
     *
     * int transformLocal(int operand) {
     *     return operand & 0x42;
     * }
     *
     * 
  8. *
* *
  • The new keyword can be used to initialize a cached parameter using a constructor * of the parameter type. * *
     * @Specialization
     * void s(Object operand, {@code @Cached}("new()") OtherNode someNode) {
     *     someNode.execute(operand);
     * }
     *
     * static class OtherNode extends Node {
     *
     *     public String execute(Object value) {
     *         throw new UnsupportedOperationException();
     *     }
     * }
     *
     * 
    * *
  • *
  • Java types without public constructor but with a static factory methods can be initialized by * just referencing its static factory method and its parameters. In this case * {@link com.oracle.truffle.api.profiles.BranchProfile#create()} is used to instantiate the * {@link com.oracle.truffle.api.profiles.BranchProfile} instance. * *
     * @Specialization
     * void s(int operand, {@code @Cached}("create()") BranchProfile profile) {
     * }
     * 
    * *
  • * * * @see Specialization#guards() * @see Specialization#replaces() * @see Specialization#limit() * @see ImportStatic * @since 0.8 or earlier */ // @formatter:on @Retention(RetentionPolicy.CLASS) @Target({ElementType.PARAMETER}) public @interface Cached { /** * Defines the initializer expression of the cached parameter value. * * @see Cached * @since 0.8 or earlier */ String value() default "create($parameters)"; /** * Defines the initializer that is used for {@link GenerateUncached uncached} nodes or uncached * versions of exported library messages. * * @see GenerateUncached * @since 19.0 */ String uncached() default "getUncached($parameters)"; /** * Specifies the number of array dimensions to be marked as {@link CompilationFinal compilation * final}. This value must be specified for all array-typed cached values except {@link Node * node} arrays and must be left unspecified in other cases where it has no meaning. * * The allowed range is from 0 to the number of declared array dimensions (inclusive). * Specifically, a {@code dimensions} value of 0 marks only the reference to the (outermost) * array as final but not its elements, a value of 1 marks the outermost array and all its * elements as final but not the elements of any nested arrays. * * If not specified and the cached value type is an array type then this will cause a warning * and in later releases an error. * * @since 0.26 * @see CompilationFinal#dimensions() */ int dimensions() default -1; /** * Allows the {@link #value()} to be used for {@link #uncached()}. This is useful if the * expression is the same for {@link #value()} and {@link #uncached()}. By setting * {@link #allowUncached()} to true it is not necessary to repeat the * {@link #value()} expression in the {@link #uncached()} expression. This flag cannot be set in * combination with {@link #uncached()}. * * @since 19.0 */ boolean allowUncached() default false; /** * Specifies the bindings used for the $parameters variable in cached or uncached initializers. * * @since 19.0 */ String[] parameters() default {}; /** * If set to true then weak references will be used to refer to this cached value * in the generated node. The default value is false. The weak cached parameter is * guaranteed to not become null in guards or specialization method invocations. If * a weak cached parameter gets collected by the GC, then any compiled code remain unaffected * and the specialization instance will not be removed. Specializations with collected cached * references continue to count to the specialization limit. This is necessary to provide an * upper bound for the number of invalidations that may happen for this specialization. *

    * A weak cached parameter implicitly adds a weakRef.get() != null guard that is * invoked before the cached value is referenced for the first time. This means that * specializations which previously did not result in fall-through behavior may now * fall-through. This is important if used in combination with {@link Fallback}. Weak cached * parameters that are used as part of {@link GenerateUncached uncached} nodes, execute the * cached initializer for each execution and therefore implicitly do not use a weak reference. *

    * Example usage: * *

         * @GenerateUncached
         * abstract class WeakInlineCacheNode extends Node {
         *
         *     abstract Object execute(Object arg0);
         *
         *     @Specialization(guards = "cachedArg.equals(arg)", limit = "3")
         *     Object s0(String arg,
         *                     @Cached(value = "arg", weak = true) String cachedArg) {
         *         assertNotNull(cachedStorage);
         *         return arg;
         *     }
         * }
         * 
    * * @see com.oracle.truffle.api.utilities.TruffleWeakReference * @since 20.2 */ boolean weak() default false; /** * Specifies whether the cached parameter values of type {@link NodeInterface} should be adopted * as its child by the current node. The default value is true, therefore all * cached values of type {@link NodeInterface} and arrays of the same type are adopted. If the * value is set to false, then no adoption is performed. It is useful to set adopt * to false when nodes need to be referenced more than once in the AST. *

    * If the type of the field is an {@link NodeInterface} array and adopt is set to * false, then the compilation final {@link Cached#dimensions() dimensions} * attribute needs to be specified explicitly. * * @since 20.2 */ boolean adopt() default true; /** * Allows sharing between multiple Cached parameters between multiple specializations or * exported library messages. If no sharing is desired then the {@link Cached cached} parameter * can be annotated with {@link Exclusive exclusive}. The DSL will indicate sharing * opportunities to the user by showing a warning. *

    * Shared caches with reference types must never return null for their initializer * when they are used in guards, because the null value is reserved for the * uninitialized state. An {@link AssertionError} will be thrown at runtime if that is the case. * Shared caches with primitive types must not be used at all in guards. * * @see Exclusive * @since 19.0 */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.PARAMETER}) public @interface Shared { /** * Specifies the sharing group of the shared cached element. * * @since 19.0 */ String value(); } /** * Disallows any sharing with other cached parameters. The DSL will indicate sharing * opportunities to the user by showing a warning. * * @since 19.0 */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.TYPE}) public @interface Exclusive { } }



    © 2015 - 2024 Weber Informatics LLC | Privacy Policy