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

com.oracle.truffle.api.dsl.Specialization 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: 1.0.0-rc7
Show newest version
/*
 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.truffle.api.dsl;

import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.ExactMath;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 

* Defines a method of a node subclass to represent one specialization of an operation. Multiple * specializations can be defined in a node representing an operation. A specialization defines * which kind of input is expected using the method signature and the annotation attributes. The * specialized semantics of the operation are defined using the body of the annotated Java method. A * specialization method must be declared in a class that is derived from {@link Node} that * references a {@link TypeSystem}. At least one specialization must be defined per operation. If no * specialization is valid for the given set of input values then an * {@link UnsupportedSpecializationException} is thrown instead of invoking any specialization * method. *

*

* A specialization must have at least as many parameters as there are {@link NodeChild} annotations * declared for the enclosing operation node. These parameters are declared in the same order as the * {@link NodeChild} annotations (linear execution order). We call such parameters dynamic input * parameters. Every specialization that is declared within an operation must have an equal number * of dynamic input parameters. *

*

* The supported kind of input values for a specialization are declared using guards. A * specialization may provide declarative specifications for four kinds of guards: *

    *
  • Type guards optimistically assume the type of an input value. A value that matches the * type is cast to its expected type automatically. Type guards are modeled using the parameter type * of the specialization method. Types used for type guards must be defined in the * {@link TypeSystem}. If the type of the parameter is {@link Object} then no type guard is used for * the dynamic input parameter.
  • * *
  • Expression guards optimistically assume the return value of a user-defined expression * to be true. Expression guards are modeled using Java expressions that return a * boolean value. If the guard expression returns false, the * specialization is no longer applicable and the operation is re-specialized. Guard expressions are * declared using the {@link #guards()} attribute.
  • * *
  • Event guards trigger re-specialization in case an exception is thrown in the * specialization body. The {@link #rewriteOn()} attribute can be used to declare a list of such * exceptions. Guards of this kind are useful to avoid calculating a value twice when it is used in * the guard and its specialization.
  • * *
  • Assumption guards optimistically assume that the state of an {@link Assumption} * remains true. Assumptions can be assigned to specializations using the * {@link #assumptions()} attribute.
  • *
*

*

* The enclosing {@link Node} of a specialization method must have at least one public * and non-final execute method. An execute method is a method that starts with * 'execute'. If all execute methods declare the first parameter type as {@link Frame}, * {@link VirtualFrame} or {@link MaterializedFrame} then the same frame type can be used as * optional first parameter of the specialization. This parameter does not count to the number of * dynamic parameters. *

*

* A specialization method may declare multiple parameters annotated with {@link Cached}. Cached * parameters are initialized and stored once per specialization instantiation. For consistency * between specialization declarations cached parameters must be declared last in a specialization * method. *

*

* If the operation is re-specialized or if it is executed for the first time then all declared * specializations of the operation are tried in declaration order until the guards of the first * specialization accepts the current input values. The new specialization is then added to the * chain of current specialization instances which might consist of one (monomorph) or multiple * instances (polymorph). If an assumption of an instantiated specialization is violated then * re-specialization is triggered again. *

*

* With guards in combination with cached parameters it is possible that multiple instances of the * same specialization are created. The {@link #limit()} attribute can be used to limit the number * of instantiations per specialization. *

* * @see NodeChild * @see ShortCircuit * @see Fallback * @see Cached * @see TypeSystem * @see TypeSystemReference * @see UnsupportedSpecializationException * @since 0.8 or earlier */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Specialization { /** * References a specialization of a super class by its method name where this specialization is * inserted before. The declaration order of a specialization is not usable for nodes where * specializations are partly declared in the super class and partly declared in a derived * class. By default all specializations declared in the derived class are appended to those in * the super class. This attribute can be used to override the default behavior. */ String insertBefore() default ""; /** *

* Declares an event guards that trigger re-specialization in case an exception is thrown in the * specialization body. This attribute can be used to declare a list of such exceptions. Guards * of this kind are useful to avoid calculating a value twice when it is used in the guard and * its specialization. *

* *

* If an event guard exception is triggered then all instantiations of this specialization are * removed. If one of theses exceptions is thrown once then no further instantiations of this * specialization are going to be created for this node. A specialization that rewrites on an * exception must ensure that no non-repeatable side-effect is caused until the rewrite is * triggered. *

* * Example usage: * *
     * @Specialization(rewriteOn = ArithmeticException.class)
     * int doAddNoOverflow(int a, int b) {
     *     return ExactMath.addExact(a, b);
     * }
     * @Specialization
     * long doAddWithOverflow(int a, int b) {
     *     return a + b;
     * }
     * ...
     * Example executions:
     *   execute(Integer.MAX_VALUE - 1, 1) => doAddNoOverflow(Integer.MAX_VALUE - 1, 1)
     *   execute(Integer.MAX_VALUE, 1)     => doAddNoOverflow(Integer.MAX_VALUE, 1)
     *                                     => throws ArithmeticException
     *                                     => doAddWithOverflow(Integer.MAX_VALUE, 1)
     *   execute(Integer.MAX_VALUE - 1, 1) => doAddWithOverflow(Integer.MAX_VALUE - 1, 1)
     * 
* *

* * @see ExactMath#addExact(int, int) */ Class[] rewriteOn() default {}; /** *

* Declares other specializations of the same node to be contained by this specialization. Other * specializations are references using their unique method name. If this specialization is * instantiated then all contained specialization instances are removed and never instantiated * again for this node instance. Therefore this specialization should handle strictly more * inputs than which were handled by the contained specialization, otherwise the removal of the * contained specialization will lead to unspecialized types of input values. The contains * declaration is transitive for multiple involved specializations. *

* Example usage: * *
     * @Specialization(guards = "b == 2")
     * void doDivPowerTwo(int a, int b) {
     *     return a >> 1;
     * }
     * @Specialization(contains ="doDivPowerTwo", guards = "b > 0")
     * void doDivPositive(int a, int b) {
     *     return a / b;
     * }
     * ...
     * Example executions with contains="doDivPowerTwo":
     *   execute(4, 2) => doDivPowerTwo(4, 2)
     *   execute(9, 3) => doDivPositive(9, 3) // doDivPowerTwo instances get removed
     *   execute(4, 2) => doDivPositive(4, 2)
     * Same executions without contains="doDivPowerTwo"
     *   execute(4, 2) => doDivPowerTwo(4, 2)
     *   execute(9, 3) => doDivPositive(9, 3)
     *   execute(4, 2) => doDivPowerTwo(4, 2)
     * 
* *

* * @see #guards() */ String[] contains() default {}; /** *

* Declares boolean expressions that define whether or not input values are * applicable to this specialization instance. Guard expressions must always return the same * result for each combination of the enclosing node instance and the bound input values. *

*

* If a guard expression does not bind any dynamic input parameters then the DSL assumes that * the result will not change for this node after specialization instantiation. The DSL asserts * this assumption if assertions are enabled (-ea). *

*

* Guard expressions are defined using a subset of Java. This subset includes field/parameter * accesses, function calls, type exact infix comparisons (==, !=, <, <=, >, >=), logical * negation (!), logical disjunction (||) and integer literals. The return type of guard * expressions must be boolean. 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. Non-private, static or virtual methods or fields of enclosing node.
  6. *
  7. Non-private, static or virtual methods or fields of super types of the enclosing node. *
  8. *
  9. Public and static methods or fields imported using {@link ImportStatic}.
  10. *
*

*

* Example usage: * *

     * static boolean acceptOperand(int operand) { assert operand <= 42; return operand & 1 ==
     * 1; } @Specialization(guards = {"operand <= 42", "acceptOperand(operand)"}) void
     * doSpecialization(int operand) {...}
     * 
* *

* * @see Cached * @see ImportStatic */ String[] guards() default {}; /** *

* Declares assumption guards that optimistically assume that the state of an {@link Assumption} * remains valid. Assumption expressions are cached once per specialization instantiation. If * one of the returned assumptions gets invalidated then the specialization instance is removed. * If the assumption expression returns an array of assumptions then all assumptions of the * array are checked. This is limited to one-dimensional arrays. *

*

* Assumption expressions are defined using a subset of Java. This subset includes * field/parameter accesses, function calls, type exact infix comparisons (==, !=, <, <=, >, * >=), logical negation (!), logical disjunction (||) and integer literals. The return type of * the expression must be {@link Assumption} or an array of {@link Assumption} instances. * Assumption expressions are not allowed to bind to dynamic parameter values of the * specialization. Bound elements without receivers are resolved using the following order: *

    *
  1. Cached parameters of the enclosing specialization.
  2. *
  3. Fields defined using {@link NodeField} for the enclosing node.
  4. *
  5. Non-private, static or virtual methods or fields of enclosing node.
  6. *
  7. Non-private, static or virtual methods or fields of super types of the enclosing node. *
  8. *
  9. Public and static methods or fields imported using {@link ImportStatic}.
  10. *
*

* *

* Example usage: * *

     * static abstract class DynamicObject() { abstract Shape getShape(); ... } static
     * abstract class Shape() { abstract Assumption getUnmodifiedAssuption(); ... }
     * @Specialization(guards = "operand.getShape() == cachedShape", assumptions =
     * "cachedShape.getUnmodifiedAssumption()") void doAssumeUnmodifiedShape(DynamicObject
     * operand, @Cached("operand.getShape()") Shape cachedShape) {...}
     * 
* *

* * @see Cached * @see ImportStatic */ String[] assumptions() default {}; /** *

* Declares the expression that limits the number of specialization instantiations. The default * limit for specialization instantiations is defined as "3". If the limit is * exceeded no more instantiations of the enclosing specialization method are created. Please * note that the existing specialization instantiations are not removed from the * specialization chain. You can use {@link #contains()} to remove unnecessary specializations * instances. *

*

* The limit expression is defined using a subset of Java. This subset includes field/parameter * accesses, function calls, type exact infix comparisons (==, !=, <, <=, >, >=), logical * negation (!), logical disjunction (||) and integer literals. The return type of the limit * expression must be int. Limit expressions are not allowed to bind to dynamic * parameter values of the specialization. Bound elements without receivers are resolved using * the following order: *

    *
  1. Cached parameters of the enclosing specialization.
  2. *
  3. Fields defined using {@link NodeField} for the enclosing node.
  4. *
  5. Non-private, static or virtual methods or fields of enclosing node.
  6. *
  7. Non-private, static or virtual methods or fields of super types of the enclosing node. *
  8. *
  9. Public and static methods or fields imported using {@link ImportStatic}.
  10. *
*

* *

* Example usage: * *

     * static int getCacheLimit() { return
     * Integer.parseInt(System.getProperty("language.cacheLimit")); } @Specialization(guards =
     * "operand == cachedOperand", limit = "getCacheLimit()") void doCached(Object
     * operand, @Cached("operand") Object cachedOperand) {...}
     * 
* *

* * @see #guards() * @see #contains() * @see Cached * @see ImportStatic */ String limit() default ""; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy