changeset 19288:3a37116ef37f

Truffle-DSL: added @Cached annotation, added limit property and updated @Specialization javadoc.
author Christian Humer <christian.humer@gmail.com>
date Mon, 29 Dec 2014 18:32:03 +0100
parents 19c6359c6191
children 62c43fcf5be2
files graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Cached.java graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java
diffstat 2 files changed, 538 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Cached.java	Mon Dec 29 18:32:03 2014 +0100
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 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 java.lang.annotation.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+
+/**
+ * <p>
+ * A parameter annotated with {@link Cached} in a {@link Specialization} refers to a <b>cached</b>
+ * 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()}.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * 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 (==, !=, <, <=,
+ * >, >=) 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:
+ * <ol>
+ * <li>Dynamic and cached parameters of the enclosing specialization.</li>
+ * <li>Fields defined using {@link NodeField} for the enclosing node.</li>
+ * <li>Public constructors of the type of the annotated parameter using the <code>new</code> keyword
+ * as method name.</li>
+ * <li>Public and static methods or fields of the type of the annotated parameter.</li>
+ * <li>Non-private, static or virtual methods or fields of enclosing node.</li>
+ * <li>Non-private, static or virtual methods or fields of super types of the enclosing node.</li>
+ * <li>Public and static methods or fields imported using {@link ImportStatic}.</li>
+ * </ol>
+ *
+ * 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:
+ * </p>
+ *
+ * <pre>
+ * @NodeChild("operand")
+ * abstract TestNode extends Node {
+ *   abstract void execute(Object operandValue);
+ *   // ... example here ...
+ * }
+ * </pre>
+ *
+ * <ol>
+ * <li>
+ * 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).
+ *
+ * <pre>
+ *  &#064;Specialization
+ *  void doCached(int operand, @Local(&quot;operand&quot;) 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)
+ *
+ * </pre>
+ *
+ * </li>
+ * <li>
+ * 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 <code>int</code> values and for each
+ * individual <code>int</code> 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 <code>3</code>.
+ *
+ * <pre>
+ * &#064;Specialization(guards = &quot;==(operand, cachedOperand)&quot;)
+ * void doCached(int operand, @Cached(&quot;operand&quot;) 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
+ *
+ * </pre>
+ *
+ * </li>
+ * <li>
+ * To handle the limit overflow we extend our example by an additional specialization named
+ * <code>doNormal</code>. This specialization has the same type restrictions but does not have local
+ * state nor the operand identity guard. It is also declared after <code>doCached</code> therefore
+ * it is only instantiated if the limit of the <code>doCached</code> specialization has been
+ * reached. In other words <code>doNormal</code> is more generic than <code>doCached</code> . The
+ * <code>doNormal</code> specialization uses <code>contains=&quot;doCached&quot;</code> to specify
+ * that all instantiations of <code>doCached</code> get removed if <code>doNormal</code> is
+ * instantiated. Alternatively if the <code>contains</code> relation is omitted then all
+ * <code>doCached</code> instances remain but no new instances are created.
+ *
+ * <pre>
+ * &#064;Specialization(guards = &quot;==(operand, cachedOperand)&quot;)
+ * void doCached(int operand, @Cached(&quot;operand&quot;) int cachedOperand) {
+ *    CompilerAsserts.compilationConstant(cachedOperand);
+ *    ...
+ * }
+ * 
+ * &#064;Specialization(contains = &quot;doCached&quot;)
+ * void doNormal(int operand) {...}
+ * 
+ * Example executions with contains = &quot;doCached&quot;:
+ * 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 contains = &quot;doCached&quot;:
+ * 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)
+ *
+ * </pre>
+ *
+ * </li>
+ * <li>
+ * 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 <code>private</code>.
+ *
+ * <pre>
+ * &#064;Specialization
+ * void s(int operand, @Cached(&quot;transformLocal(operand)&quot;) int cachedOperand) {
+ * }
+ * 
+ * int transformLocal(int operand) {
+ *     return operand & 0x42;
+ * }
+ *
+ * </li>
+ * </pre>
+ * <li>
+ * The <code>new</code> keyword can be used to initialize a cached parameter using a constructor of
+ * the parameter type.
+ *
+ * <pre>
+ * &#064;Specialization
+ * void s(Object operand, @Cached(&quot;new()&quot;) OtherNode someNode) {
+ *     someNode.execute(operand);
+ * }
+ * 
+ * static class OtherNode extends Node {
+ * 
+ *     public String execute(Object value) {
+ *         throw new UnsupportedOperationException();
+ *     }
+ * }
+ *
+ * </pre>
+ *
+ * </li>
+ * <li>
+ * 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 BranchProfile#create()} is used to instantiate the {@link BranchProfile} instance.
+ *
+ * <pre>
+ * &#064;Specialization
+ * void s(int operand, @Local(&quot;create()&quot;) BranchProfile profile) {
+ * }
+ * </pre>
+ *
+ * </li>
+ * </ol>
+ *
+ * @see Specialization#guards()
+ * @see Specialization#contains()
+ * @see Specialization#limit()
+ * @see ImportStatic
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface Cached {
+
+    /**
+     * Defines the initializer expression of the cached parameter value.
+     *
+     * @see Cached
+     */
+    String value();
+
+}
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java	Wed Feb 11 12:13:43 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java	Mon Dec 29 18:32:03 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -26,6 +26,91 @@
 
 import java.lang.annotation.*;
 
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * The supported kind of input values for a specialization are declared using guards. A
+ * specialization may provide declarative specifications for four kinds of guards:
+ * <ul>
+ * <li><b>Type guards</b> 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.</li>
+ *
+ * <li><b>Expression guards</b> optimistically assume the return value of a user-defined expression
+ * to be <code>true</code>. Expression guards are modeled using Java expressions that return a
+ * <code>boolean</code> value. If the guard expression returns <code>false</code>, the
+ * specialization is no longer applicable and the operation is re-specialized. Guard expressions are
+ * declared using the {@link #guards()} attribute.</li>
+ *
+ * <li><b>Event guards</b> 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.</li>
+ *
+ * <li><b>Assumption guards</b> optimistically assume that the state of an {@link Assumption}
+ * remains <code>true</code>. Assumptions can be assigned to specializations using the
+ * {@link #assumptions()} attribute.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The enclosing {@link Node} of a specialization method must have at least one <code>public</code>
+ * and non-<code>final</code> 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.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @see NodeChild
+ * @see ShortCircuit
+ * @see Fallback
+ * @see Cached
+ * @see TypeSystem
+ * @see TypeSystemReference
+ * @see UnsupportedSpecializationException
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD})
 public @interface Specialization {
@@ -36,39 +121,242 @@
     @Deprecated int DEFAULT_ORDER = -1;
 
     /**
-     * The order has no effect anymore. The declaration order specialization methods is used
-     * instead.
-     *
      * @deprecated use declaration order instead. Will get removed in the next release.
      */
     @Deprecated
     int order() default DEFAULT_ORDER;
 
     /**
-     * Inserts this and all specializations that are declared after this specialization before a
-     * specialization in the superclass. By default all specializations of the subclass are appended
-     * to the specializations of the superclass.
+     * 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 "";
 
+    /**
+     * <p>
+     * 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.
+     * </p>
+     *
+     * <p>
+     * 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.
+     * </p>
+     *
+     * <b>Example usage:</b>
+     *
+     * <pre>
+     * &#064;Specialization(rewriteOn = ArithmeticException.class)
+     * int doAddNoOverflow(int a, int b) {
+     *     return ExactMath.addExact(a, b);
+     * }
+     * 
+     * &#064;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)
+     * </pre>
+     *
+     * </p>
+     *
+     * @see ExactMath#addExact(int, int)
+     */
     Class<? extends Throwable>[] rewriteOn() default {};
 
     /**
-     * The contains attribute declares all specializations that are contained by this
-     * specialization. A containing specialization must be strictly generic as the contained
-     * specialization.
+     * <p>
+     * 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.
+     * </p>
+     * <b>Example usage:</b>
+     *
+     * <pre>
+     * &#064;Specialization(guards = "b == 2")
+     * void doDivPowerTwo(int a, int b) {
+     *     return a >> 1;
+     * }
+     * 
+     * &#064;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)
+     * </pre>
+     *
+     * </p>
+     *
+     * @see #guards()
      */
     String[] contains() default {};
 
+    /**
+     * <p>
+     * Declares <code>boolean</code> 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.
+     * </p>
+     * <p>
+     * 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).
+     * </p>
+     * <p>
+     * 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 <code>boolean</code>. Bound elements without receivers are resolved using
+     * the following order:
+     * <ol>
+     * <li>Dynamic and cached parameters of the enclosing specialization.</li>
+     * <li>Fields defined using {@link NodeField} for the enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of super types of the enclosing node.</li>
+     * <li>Public and static methods or fields imported using {@link ImportStatic}.</li>
+     * </ol>
+     * </p>
+     * <p>
+     * <b>Example usage:</b>
+     *
+     * <pre>
+     * static boolean acceptOperand(int operand) {
+     *     assert operand <= 42;
+     *     return operand & 1 == 1;
+     * }
+     * 
+     * &#064;Specialization(guards = {"operand <= 42", "acceptOperand(operand)"})
+     * void doSpecialization(int operand) {...}
+     * </pre>
+     *
+     * </p>
+     *
+     * @see Cached
+     * @see ImportStatic
+     */
     String[] guards() default {};
 
     /**
-     * Defines the assumptions to check for this specialization. When the specialization method is
-     * invoked it is guaranteed that these assumptions still hold. It is not guaranteed that they
-     * are checked before the {@link #guards()} methods. They may be checked before after or in
-     * between {@link #guards()}. To declare assumptions use the {@link NodeAssumptions} annotation
-     * at class level.
+     * <p>
+     * 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.
+     * An assumption expression may return different assumptions per specialization instance. The
+     * returned assumption instance must not be <code>null</code>.
+     * </p>
+     * <p>
+     * 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}. Assumption expressions are not allowed to bind to
+     * dynamic parameter values of the specialization. Bound elements without receivers are resolved
+     * using the following order:
+     * <ol>
+     * <li>Cached parameters of the enclosing specialization.</li>
+     * <li>Fields defined using {@link NodeField} for the enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of super types of the enclosing node.</li>
+     * <li>Public and static methods or fields imported using {@link ImportStatic}.</li>
+     * </ol>
+     * </p>
+     *
+     * <p>
+     * <b>Example usage:</b>
+     *
+     * <pre>
+     * static abstract class DynamicObject() {
+     *      abstract Shape getShape();
+     *      ...
+     * }
+     * static abstract class Shape() {
+     *      abstract Assumption getUnmodifiedAssuption();
+     *      ...
+     * }
+     * 
+     * &#064;Specialization(guards = "operand.getShape() == cachedShape", assumptions = "cachedShape.getUnmodifiedAssumption()")
+     * void doAssumeUnmodifiedShape(DynamicObject operand, @Cached("operand.getShape()") Shape cachedShape) {...}
+     * </pre>
+     *
+     * </p>
+     *
+     * @see Cached
+     * @see ImportStatic
      */
     String[] assumptions() default {};
 
+    /**
+     * <p>
+     * Declares the expression that limits the number of specialization instantiations. The default
+     * limit for specialization instantiations is defined as <code>"3"</code>. If the limit is
+     * exceeded no more instantiations of the enclosing specialization method are created. Please
+     * note that the existing specialization instantiations are <b>not</b> removed from the
+     * specialization chain. You can use {@link #contains()} to remove unnecessary specializations
+     * instances.
+     * </p>
+     * <p>
+     * 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 <code>int</code>. Limit expressions are not allowed to bind to dynamic
+     * parameter values of the specialization. Bound elements without receivers are resolved using
+     * the following order:
+     * <ol>
+     * <li>Cached parameters of the enclosing specialization.</li>
+     * <li>Fields defined using {@link NodeField} for the enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of super types of the enclosing node.</li>
+     * <li>Public and static methods or fields imported using {@link ImportStatic}.</li>
+     * </ol>
+     * </p>
+     *
+     * <p>
+     * <b>Example usage:</b>
+     *
+     * <pre>
+     * static int getCacheLimit() {
+     *     return Integer.parseInt(System.getProperty("language.cacheLimit"));
+     * }
+     * 
+     * &#064;Specialization(guards = "operand == cachedOperand", limit = "getCacheLimit()")
+     * void doCached(Object operand, @Cached("operand") Object cachedOperand) {...}
+     * </pre>
+     *
+     * </p>
+     *
+     * @see #guards()
+     * @see #contains()
+     * @see Cached
+     * @see ImportStatic
+     */
+    String limit() default "";
+
 }