src/jdk/nashorn/internal/ir/FunctionNode.java

Tue, 26 Aug 2014 15:52:55 +0200

author
attila
date
Tue, 26 Aug 2014 15:52:55 +0200
changeset 980
44b69fb3b031
parent 963
e2497b11a021
child 991
b7a2db4de254
permissions
-rw-r--r--

8056025: CompilationPhase.setStates() is hot in class installation phase
Reviewed-by: jlaskey, sundar

     1 /*
     2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package jdk.nashorn.internal.ir;
    28 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROFILE;
    29 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT;
    30 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE;
    31 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_ENTEREXIT;
    32 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_MISSES;
    33 import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_TRACE_VALUES;
    35 import java.util.Collections;
    36 import java.util.EnumSet;
    37 import java.util.HashSet;
    38 import java.util.Iterator;
    39 import java.util.List;
    40 import java.util.Set;
    41 import java.util.function.Function;
    42 import jdk.nashorn.internal.AssertsEnabled;
    43 import jdk.nashorn.internal.codegen.CompileUnit;
    44 import jdk.nashorn.internal.codegen.Compiler;
    45 import jdk.nashorn.internal.codegen.CompilerConstants;
    46 import jdk.nashorn.internal.codegen.Namespace;
    47 import jdk.nashorn.internal.codegen.types.Type;
    48 import jdk.nashorn.internal.ir.annotations.Ignore;
    49 import jdk.nashorn.internal.ir.annotations.Immutable;
    50 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
    51 import jdk.nashorn.internal.runtime.ScriptFunction;
    52 import jdk.nashorn.internal.runtime.Source;
    53 import jdk.nashorn.internal.runtime.UserAccessorProperty;
    54 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
    56 /**
    57  * IR representation for function (or script.)
    58  */
    59 @Immutable
    60 public final class FunctionNode extends LexicalContextExpression implements Flags<FunctionNode> {
    61     /** Type used for all FunctionNodes */
    62     public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
    64     /** Function kinds */
    65     public enum Kind {
    66         /** a normal function - nothing special */
    67         NORMAL,
    68         /** a script function */
    69         SCRIPT,
    70         /** a getter, @see {@link UserAccessorProperty} */
    71         GETTER,
    72         /** a setter, @see {@link UserAccessorProperty} */
    73         SETTER
    74     }
    76     /** Compilation states available */
    77     public enum CompilationState {
    78         /** compiler is ready */
    79         INITIALIZED,
    80         /** method has been parsed */
    81         PARSED,
    82         /** method has been parsed */
    83         PARSE_ERROR,
    84         /** constant folding pass */
    85         CONSTANT_FOLDED,
    86         /** method has been lowered */
    87         LOWERED,
    88         /** program points have been assigned to unique locations */
    89         PROGRAM_POINTS_ASSIGNED,
    90         /** any transformations of builtins have taken place, e.g. apply=&gt;call */
    91         BUILTINS_TRANSFORMED,
    92         /** method has been split */
    93         SPLIT,
    94         /** method has had symbols assigned */
    95         SYMBOLS_ASSIGNED,
    96         /** computed scope depths for symbols */
    97         SCOPE_DEPTHS_COMPUTED,
    98         /** method has had types calculated*/
    99         OPTIMISTIC_TYPES_ASSIGNED,
   100         /** method has had types calculated */
   101         LOCAL_VARIABLE_TYPES_CALCULATED,
   102         /** compile units reused (optional) */
   103         COMPILE_UNITS_REUSED,
   104         /** method has been emitted to bytecode */
   105         BYTECODE_GENERATED,
   106         /** method has been installed */
   107         BYTECODE_INSTALLED
   108     }
   110     /** Source of entity. */
   111     private final Source source;
   113     /** Unique ID used for recompilation among other things */
   114     private final int id;
   116     /** External function identifier. */
   117     @Ignore
   118     private final IdentNode ident;
   120     /** The body of the function node */
   121     private final Block body;
   123     /** Internal function name. */
   124     private final String name;
   126     /** Compilation unit. */
   127     private final CompileUnit compileUnit;
   129     /** Function kind. */
   130     private final Kind kind;
   132     /** List of parameters. */
   133     private final List<IdentNode> parameters;
   135     /** First token of function. **/
   136     private final long firstToken;
   138     /** Last token of function. **/
   139     private final long lastToken;
   141     /** Declared symbols in this function node */
   142     @Ignore
   143     private final Set<Symbol> declaredSymbols;
   145     /** Method's namespace. */
   146     private final Namespace namespace;
   148     /** Current compilation state */
   149     @Ignore
   150     private final EnumSet<CompilationState> compilationState;
   152     /** Number of properties of "this" object assigned in this function */
   153     @Ignore
   154     private final int thisProperties;
   156     /** Function flags. */
   157     private final int flags;
   159     /** Line number of function start */
   160     private final int lineNumber;
   162     /** Root class for function */
   163     private final Class<?> rootClass;
   165     /** Is anonymous function flag. */
   166     public static final int IS_ANONYMOUS                = 1 << 0;
   168     /** Is the function created in a function declaration (as opposed to a function expression) */
   169     public static final int IS_DECLARED                 = 1 << 1;
   171     /** is this a strict mode function? */
   172     public static final int IS_STRICT                   = 1 << 2;
   174     /** Does the function use the "arguments" identifier ? */
   175     public static final int USES_ARGUMENTS              = 1 << 3;
   177     /** Has this function been split because it was too large? */
   178     public static final int IS_SPLIT                    = 1 << 4;
   180     /** Does the function call eval? If it does, then all variables in this function might be get/set by it and it can
   181      * introduce new variables into this function's scope too.*/
   182     public static final int HAS_EVAL                    = 1 << 5;
   184     /** Does a nested function contain eval? If it does, then all variables in this function might be get/set by it. */
   185     public static final int HAS_NESTED_EVAL             = 1 << 6;
   187     /** Does this function have any blocks that create a scope? This is used to determine if the function needs to
   188      * have a local variable slot for the scope symbol. */
   189     public static final int HAS_SCOPE_BLOCK             = 1 << 7;
   191     /**
   192      * Flag this function as one that defines the identifier "arguments" as a function parameter or nested function
   193      * name. This precludes it from needing to have an Arguments object defined as "arguments" local variable. Note that
   194      * defining a local variable named "arguments" still requires construction of the Arguments object (see
   195      * ECMAScript 5.1 Chapter 10.5).
   196      * @see #needsArguments()
   197      */
   198     public static final int DEFINES_ARGUMENTS           = 1 << 8;
   200     /** Does this function or any of its descendants use variables from an ancestor function's scope (incl. globals)? */
   201     public static final int USES_ANCESTOR_SCOPE         = 1 << 9;
   203     /** Does this function have nested declarations? */
   204     public static final int HAS_FUNCTION_DECLARATIONS   = 1 << 10;
   206     /** Does this function have optimistic expressions? (If it does, it can undergo deoptimizing recompilation.) */
   207     public static final int IS_DEOPTIMIZABLE            = 1 << 11;
   209     /** Are we vararg, but do we just pass the arguments along to apply or call */
   210     public static final int HAS_APPLY_TO_CALL_SPECIALIZATION = 1 << 12;
   212     /** Does this function explicitly use the {@link CompilerConstants#RETURN} symbol? Some functions are known to
   213      * always use the return symbol, namely a function that is a program (as it must track its last executed expression
   214      * statement's value) as well as functions that are split (to communicate return values from inner to outer
   215      * partitions). Other functions normally don't use the return symbol (so we optimize away its slot), except in some
   216      * very special cases, e.g. when containing a return statement in a finally block. These special cases set this
   217      * flag. */
   218     public static final int USES_RETURN_SYMBOL = 1 << 13;
   220     /**
   221      * Is this function the top-level program?
   222      */
   223     public static final int IS_PROGRAM = 1 << 14;
   225     /**
   226      * Flag indicating whether this function uses the local variable symbol for itself. Only named function expressions
   227      * can have this flag set if they reference themselves (e.g. "(function f() { return f })". Declared functions will
   228      * use the symbol in their parent scope instead when they reference themselves by name.
   229      */
   230     public static final int USES_SELF_SYMBOL = 1 << 15;
   232     /** Does this function use the "this" keyword? */
   233     public static final int USES_THIS = 1 << 16;
   235     /** Is this declared in a dynamic context */
   236     public static final int IN_DYNAMIC_CONTEXT = 1 << 17;
   238     /**
   239      * The following flags are derived from directive comments within this function.
   240      * Note that even IS_STRICT is one such flag but that requires special handling.
   241      */
   243     // parser, lower debugging this function
   244     public static final int IS_PRINT_PARSE       = 1 << 18;
   245     public static final int IS_PRINT_LOWER_PARSE = 1 << 19;
   246     public static final int IS_PRINT_AST         = 1 << 20;
   247     public static final int IS_PRINT_LOWER_AST   = 1 << 21;
   248     public static final int IS_PRINT_SYMBOLS     = 1 << 22;
   250     /** profile callsites in this function? */
   251     public static final int IS_PROFILE         = 1 << 23;
   253     // callsite tracing, profiling within this function
   254     /** trace callsite enterexit in this function? */
   255     public static final int IS_TRACE_ENTEREXIT = 1 << 24;
   257     /** trace callsite misses in this function? */
   258     public static final int IS_TRACE_MISSES    = 1 << 25;
   260     /** trace callsite values in this function? */
   261     public static final int IS_TRACE_VALUES    = 1 << 26;
   263     /** extension callsite flags mask */
   264     public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
   265         IS_PRINT_LOWER_PARSE | IS_PRINT_AST | IS_PRINT_LOWER_AST |
   266         IS_PRINT_SYMBOLS | IS_PROFILE | IS_TRACE_ENTEREXIT |
   267         IS_TRACE_MISSES | IS_TRACE_VALUES;
   269     /** Does this function or any nested functions contain an eval? */
   270     private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
   272     /** Does this function need to store all its variables in scope? */
   273     private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_EVAL;
   275     /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
   276     private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
   278     /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval.
   279      *  We also pessimistically need a parent scope if we have lazy children that have not yet been compiled */
   280     private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL;
   282     /** Used to signify "null", e.g. if someone asks for the parent of the program node */
   283     public static final int NO_FUNCTION_ID = 0;
   285     /** Where to start assigning global and unique function node ids */
   286     public static final int FIRST_FUNCTION_ID = NO_FUNCTION_ID + 1;
   288     /** What is the return type of this function? */
   289     private Type returnType = Type.UNKNOWN;
   291     /**
   292      * Constructor
   293      *
   294      * @param source     the source
   295      * @param id         unique id
   296      * @param lineNumber line number
   297      * @param token      token
   298      * @param finish     finish
   299      * @param firstToken first token of the funtion node (including the function declaration)
   300      * @param namespace  the namespace
   301      * @param ident      the identifier
   302      * @param name       the name of the function
   303      * @param parameters parameter list
   304      * @param kind       kind of function as in {@link FunctionNode.Kind}
   305      * @param flags      initial flags
   306      */
   307     public FunctionNode(
   308         final Source source,
   309         final int id,
   310         final int lineNumber,
   311         final long token,
   312         final int finish,
   313         final long firstToken,
   314         final Namespace namespace,
   315         final IdentNode ident,
   316         final String name,
   317         final List<IdentNode> parameters,
   318         final FunctionNode.Kind kind,
   319         final int flags) {
   320         super(token, finish);
   322         this.source           = source;
   323         this.id               = id;
   324         this.lineNumber       = lineNumber;
   325         this.ident            = ident;
   326         this.name             = name;
   327         this.kind             = kind;
   328         this.parameters       = parameters;
   329         this.firstToken       = firstToken;
   330         this.lastToken        = token;
   331         this.namespace        = namespace;
   332         this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
   333         this.declaredSymbols  = new HashSet<>();
   334         this.flags            = flags;
   335         this.compileUnit      = null;
   336         this.body             = null;
   337         this.thisProperties   = 0;
   338         this.rootClass        = null;
   339     }
   341     private FunctionNode(
   342         final FunctionNode functionNode,
   343         final long lastToken,
   344         final int flags,
   345         final String name,
   346         final Type returnType,
   347         final CompileUnit compileUnit,
   348         final EnumSet<CompilationState> compilationState,
   349         final Block body,
   350         final List<IdentNode> parameters,
   351         final int thisProperties,
   352         final Class<?> rootClass) {
   353         super(functionNode);
   355         this.lineNumber       = functionNode.lineNumber;
   356         this.flags            = flags;
   357         this.name             = name;
   358         this.returnType       = returnType;
   359         this.compileUnit      = compileUnit;
   360         this.lastToken        = lastToken;
   361         this.compilationState = compilationState;
   362         this.body             = body;
   363         this.parameters       = parameters;
   364         this.thisProperties   = thisProperties;
   365         this.rootClass        = rootClass;
   367         // the fields below never change - they are final and assigned in constructor
   368         this.source          = functionNode.source;
   369         this.id              = functionNode.id;
   370         this.ident           = functionNode.ident;
   371         this.namespace       = functionNode.namespace;
   372         this.declaredSymbols = functionNode.declaredSymbols;
   373         this.kind            = functionNode.kind;
   374         this.firstToken      = functionNode.firstToken;
   375     }
   377     @Override
   378     public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
   379         if (visitor.enterFunctionNode(this)) {
   380             return visitor.leaveFunctionNode(setBody(lc, (Block)body.accept(visitor)));
   381         }
   382         return this;
   383     }
   385     /**
   386      * Visits the parameter nodes of this function. Parameters are normally not visited automatically.
   387      * @param visitor the visitor to apply to the nodes.
   388      * @return a list of parameter nodes, potentially modified from original ones by the visitor.
   389      */
   390     public List<IdentNode> visitParameters(final NodeVisitor<? extends LexicalContext> visitor) {
   391         return Node.accept(visitor, parameters);
   392     }
   394     /**
   395      * Get additional callsite flags to be used specific to this function.
   396      *
   397      * @return callsite flags
   398      */
   399     public int getCallSiteFlags() {
   400         int callsiteFlags = 0;
   401         if (getFlag(IS_STRICT)) {
   402             callsiteFlags |= CALLSITE_STRICT;
   403         }
   405         // quick check for extension callsite flags turned on by directives.
   406         if ((flags & EXTENSION_CALLSITE_FLAGS) == 0) {
   407             return callsiteFlags;
   408         }
   410         if (getFlag(IS_PROFILE)) {
   411             callsiteFlags |= CALLSITE_PROFILE;
   412         }
   414         if (getFlag(IS_TRACE_MISSES)) {
   415             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_MISSES;
   416         }
   418         if (getFlag(IS_TRACE_VALUES)) {
   419             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT | CALLSITE_TRACE_VALUES;
   420         }
   422         if (getFlag(IS_TRACE_ENTEREXIT)) {
   423             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT;
   424         }
   426         return callsiteFlags;
   427     }
   429     /**
   430      * Get the source for this function
   431      * @return the source
   432      */
   433     public Source getSource() {
   434         return source;
   435     }
   437     /**
   438      * Get the unique ID for this function
   439      * @return the id
   440      */
   441     public int getId() {
   442         return id;
   443     }
   445     /**
   446      * get source name - sourceURL or name derived from Source.
   447      *
   448      * @return name for the script source
   449      */
   450     public String getSourceName() {
   451         return getSourceName(source);
   452     }
   454     /**
   455      * Static source name getter
   456      *
   457      * @param source the source
   458      * @return source name
   459      */
   460     public static String getSourceName(final Source source) {
   461         final String explicitURL = source.getExplicitURL();
   462         return explicitURL != null ? explicitURL : source.getName();
   463     }
   465     /**
   466      * Function to parse nashorn per-function extension directive comments.
   467      *
   468      * @param directive nashorn extension directive string
   469      * @return integer flag for the given directive.
   470      */
   471     public static int getDirectiveFlag(final String directive) {
   472         switch (directive) {
   473             case "nashorn callsite trace enterexit":
   474                 return IS_TRACE_ENTEREXIT;
   475             case "nashorn callsite trace misses":
   476                 return IS_TRACE_MISSES;
   477             case "nashorn callsite trace objects":
   478                 return IS_TRACE_VALUES;
   479             case "nashorn callsite profile":
   480                 return IS_PROFILE;
   481             case "nashorn print parse":
   482                 return IS_PRINT_PARSE;
   483             case "nashorn print lower parse":
   484                 return IS_PRINT_LOWER_PARSE;
   485             case "nashorn print ast":
   486                 return IS_PRINT_AST;
   487             case "nashorn print lower ast":
   488                 return IS_PRINT_LOWER_AST;
   489             case "nashorn print symbols":
   490                 return IS_PRINT_SYMBOLS;
   491             default:
   492                 // unknown/unsupported directive
   493                 return 0;
   494         }
   495     }
   497     /**
   498      * Returns the line number.
   499      * @return the line number.
   500      */
   501     public int getLineNumber() {
   502         return lineNumber;
   503     }
   505     /**
   506      * Get the compilation state of this function
   507      * @return the compilation state
   508      */
   509     public EnumSet<CompilationState> getState() {
   510         return compilationState;
   511     }
   513     /**
   514      * Check whether this FunctionNode has reached a give CompilationState.
   515      *
   516      * @param state the state to check for
   517      * @return true of the node is in the given state
   518      */
   519     public boolean hasState(final EnumSet<CompilationState> state) {
   520         return !AssertsEnabled.assertsEnabled() || compilationState.containsAll(state);
   521     }
   523     /**
   524      * Add a state to the total CompilationState of this node, e.g. if
   525      * FunctionNode has been lowered, the compiler will add
   526      * {@code CompilationState#LOWERED} to the state vector
   527      *
   528      * @param lc lexical context
   529      * @param state {@link CompilationState} to add
   530      * @return function node or a new one if state was changed
   531      */
   532     public FunctionNode setState(final LexicalContext lc, final CompilationState state) {
   533         if (!AssertsEnabled.assertsEnabled() || this.compilationState.contains(state)) {
   534             return this;
   535         }
   536         final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
   537         newState.add(state);
   538         return Node.replaceInLexicalContext(
   539                 lc,
   540                 this,
   541                 new FunctionNode(
   542                         this,
   543                         lastToken,
   544                         flags,
   545                         name,
   546                         returnType,
   547                         compileUnit,
   548                         newState,
   549                         body,
   550                         parameters,
   551                         thisProperties,
   552                         rootClass));
   553     }
   555     /**
   556      * Create a unique name in the namespace of this FunctionNode
   557      * @param base prefix for name
   558      * @return base if no collision exists, otherwise a name prefix with base
   559      */
   560     public String uniqueName(final String base) {
   561         return namespace.uniqueName(base);
   562     }
   564     @Override
   565     public void toString(final StringBuilder sb, final boolean printTypes) {
   566         sb.append('[').
   567             append(returnType).
   568             append(']').
   569             append(' ');
   571         sb.append("function");
   573         if (ident != null) {
   574             sb.append(' ');
   575             ident.toString(sb, printTypes);
   576         }
   578         sb.append('(');
   580         for (final Iterator<IdentNode> iter = parameters.iterator(); iter.hasNext(); ) {
   581             final IdentNode parameter = iter.next();
   582             if (parameter.getSymbol() != null) {
   583                 sb.append('[').append(parameter.getType()).append(']').append(' ');
   584             }
   585             parameter.toString(sb, printTypes);
   586             if (iter.hasNext()) {
   587                 sb.append(", ");
   588             }
   589         }
   591         sb.append(')');
   592     }
   594     @Override
   595     public int getFlags() {
   596         return flags;
   597     }
   599     @Override
   600     public boolean getFlag(final int flag) {
   601         return (flags & flag) != 0;
   602     }
   604     @Override
   605     public FunctionNode setFlags(final LexicalContext lc, final int flags) {
   606         if (this.flags == flags) {
   607             return this;
   608         }
   609         return Node.replaceInLexicalContext(
   610                 lc,
   611                 this,
   612                 new FunctionNode(
   613                         this,
   614                         lastToken,
   615                         flags,
   616                         name,
   617                         returnType,
   618                         compileUnit,
   619                         compilationState,
   620                         body,
   621                         parameters,
   622                         thisProperties,
   623                         rootClass));
   624     }
   626     @Override
   627     public FunctionNode clearFlag(final LexicalContext lc, final int flag) {
   628         return setFlags(lc, flags & ~flag);
   629     }
   631     @Override
   632     public FunctionNode setFlag(final LexicalContext lc, final int flag) {
   633         return setFlags(lc, flags | flag);
   634     }
   636     /**
   637      * Returns true if the function is the top-level program.
   638      * @return True if this function node represents the top-level program.
   639      */
   640     public boolean isProgram() {
   641         return getFlag(IS_PROGRAM);
   642     }
   644     /**
   645      * Returns true if the function contains at least one optimistic operation (and thus can be deoptimized).
   646      * @return true if the function contains at least one optimistic operation (and thus can be deoptimized).
   647      */
   648     public boolean canBeDeoptimized() {
   649         return getFlag(IS_DEOPTIMIZABLE);
   650     }
   652     /**
   653      * Check if the {@code eval} keyword is used in this function
   654      *
   655      * @return true if {@code eval} is used
   656      */
   657     public boolean hasEval() {
   658         return getFlag(HAS_EVAL);
   659     }
   661     /**
   662      * Get the first token for this function
   663      * @return the first token
   664      */
   665     public long getFirstToken() {
   666         return firstToken;
   667     }
   669     /**
   670      * Check whether this function has nested function declarations
   671      * @return true if nested function declarations exist
   672      */
   673     public boolean hasDeclaredFunctions() {
   674         return getFlag(HAS_FUNCTION_DECLARATIONS);
   675     }
   677     /**
   678      * Check if this function's generated Java method needs a {@code callee} parameter. Functions that need access to
   679      * their parent scope, functions that reference themselves, and non-strict functions that need an Arguments object
   680      * (since it exposes {@code arguments.callee} property) will need to have a callee parameter. We also return true
   681      * for split functions to make sure symbols slots are the same in the main and split methods.
   682      *
   683      * A function that has had an apply(this,arguments) turned into a call doesn't need arguments anymore, but still
   684      * has to fit the old callsite, thus, we require a dummy callee parameter for those functions as well
   685      *
   686      * @return true if the function's generated Java method needs a {@code callee} parameter.
   687      */
   688     public boolean needsCallee() {
   689         return needsParentScope() || usesSelfSymbol() || isSplit() || (needsArguments() && !isStrict()) || hasOptimisticApplyToCall();
   690     }
   692     /**
   693      * Check if this function uses the return symbol
   694      * @return true if uses the return symbol
   695      */
   696     public boolean usesReturnSymbol() {
   697         return isProgram() || isSplit() || getFlag(USES_RETURN_SYMBOL);
   698     }
   700     /**
   701      * Return {@code true} if this function makes use of the {@code this} object.
   702      *
   703      * @return true if function uses {@code this} object
   704      */
   705     public boolean usesThis() {
   706         return getFlag(USES_THIS);
   707     }
   710     /**
   711      * Return true if function contains an apply to call transform
   712      * @return true if this function has transformed apply to call
   713      */
   714     public boolean hasOptimisticApplyToCall() {
   715         return getFlag(HAS_APPLY_TO_CALL_SPECIALIZATION);
   716     }
   718     /**
   719      * Get the identifier for this function, this is its symbol.
   720      * @return the identifier as an IdentityNode
   721      */
   722     public IdentNode getIdent() {
   723         return ident;
   724     }
   726     /**
   727      * Return a set of symbols declared in this function node. This
   728      * is only relevant after Attr, otherwise it will be an empty
   729      * set as no symbols have been introduced
   730      * @return set of declared symbols in function
   731      */
   732     public Set<Symbol> getDeclaredSymbols() {
   733         return Collections.unmodifiableSet(declaredSymbols);
   734     }
   736     /**
   737      * Add a declared symbol to this function node
   738      * @param symbol symbol that is declared
   739      */
   740     public void addDeclaredSymbol(final Symbol symbol) {
   741         declaredSymbols.add(symbol);
   742     }
   744     /**
   745      * Get the function body
   746      * @return the function body
   747      */
   748     public Block getBody() {
   749         return body;
   750     }
   752     /**
   753      * Reset the function body
   754      * @param lc lexical context
   755      * @param body new body
   756      * @return new function node if body changed, same if not
   757      */
   758     public FunctionNode setBody(final LexicalContext lc, final Block body) {
   759         if (this.body == body) {
   760             return this;
   761         }
   762         return Node.replaceInLexicalContext(
   763                 lc,
   764                 this,
   765                 new FunctionNode(
   766                         this,
   767                         lastToken,
   768                         flags |
   769                             (body.needsScope() ?
   770                                     FunctionNode.HAS_SCOPE_BLOCK :
   771                                     0),
   772                         name,
   773                         returnType,
   774                         compileUnit,
   775                         compilationState,
   776                         body,
   777                         parameters,
   778                         thisProperties,
   779                         rootClass));
   780     }
   782     /**
   783      * Does this function's method needs to be variable arity (gather all script-declared parameters in a final
   784      * {@code Object[]} parameter. Functions that need to have the "arguments" object as well as functions that simply
   785      * declare too many arguments for JVM to handle with fixed arity will need to be variable arity.
   786      * @return true if the Java method in the generated code that implements this function needs to be variable arity.
   787      * @see #needsArguments()
   788      * @see LinkerCallSite#ARGLIMIT
   789      */
   790     public boolean isVarArg() {
   791         return needsArguments() || parameters.size() > LinkerCallSite.ARGLIMIT;
   792     }
   794     /**
   795      * Was this function declared in a dynamic context, i.e. in a with or eval style
   796      * chain
   797      * @return true if in dynamic context
   798      */
   799     public boolean inDynamicContext() {
   800         return getFlag(IN_DYNAMIC_CONTEXT);
   801     }
   803     /**
   804      * Check whether a function would need dynamic scope, which is does if it has
   805      * evals and isn't strict.
   806      * @return true if dynamic scope is needed
   807      */
   808     public boolean needsDynamicScope() {
   809         // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new
   810         // variable into the function's scope), and it isn't strict (as evals in strict functions get an
   811         // isolated scope).
   812         return hasEval() && !isStrict();
   813     }
   815     /**
   816      * Flag this function as declared in a dynamic context
   817      * @param lc lexical context
   818      * @return new function node, or same if unmodified
   819      */
   820     public FunctionNode setInDynamicContext(final LexicalContext lc) {
   821         return setFlag(lc, IN_DYNAMIC_CONTEXT);
   822     }
   824     /**
   825      * Returns true if this function needs to have an Arguments object defined as a local variable named "arguments".
   826      * Functions that use "arguments" as identifier and don't define it as a name of a parameter or a nested function
   827      * (see ECMAScript 5.1 Chapter 10.5), as well as any function that uses eval or with, or has a nested function that
   828      * does the same, will have an "arguments" object. Also, if this function is a script, it will not have an
   829      * "arguments" object, because it does not have local variables; rather the Global object will have an explicit
   830      * "arguments" property that provides command-line arguments for the script.
   831      * @return true if this function needs an arguments object.
   832      */
   833     public boolean needsArguments() {
   834         // uses "arguments" or calls eval, but it does not redefine "arguments", and finally, it's not a script, since
   835         // for top-level script, "arguments" is picked up from Context by Global.init() instead.
   836         return getFlag(MAYBE_NEEDS_ARGUMENTS) && !getFlag(DEFINES_ARGUMENTS) && !isProgram();
   837     }
   839     /**
   840      * Returns true if this function needs access to its parent scope. Functions referencing variables outside their
   841      * scope (including global variables), as well as functions that call eval or have a with block, or have nested
   842      * functions that call eval or have a with block, will need a parent scope. Top-level script functions also need a
   843      * parent scope since they might be used from within eval, and eval will need an externally passed scope.
   844      * @return true if the function needs parent scope.
   845      */
   846     public boolean needsParentScope() {
   847         return getFlag(NEEDS_PARENT_SCOPE) || isProgram();
   848     }
   850     /**
   851      * Set the number of properties assigned to the this object in this function.
   852      * @param lc the current lexical context.
   853      * @param thisProperties number of properties
   854      * @return a potentially modified function node
   855      */
   856     public FunctionNode setThisProperties(final LexicalContext lc, final int thisProperties) {
   857         if (this.thisProperties == thisProperties) {
   858             return this;
   859         }
   860         return Node.replaceInLexicalContext(
   861                 lc,
   862                 this,
   863                 new FunctionNode(
   864                         this,
   865                         lastToken,
   866                         flags,
   867                         name,
   868                         returnType,
   869                         compileUnit,
   870                         compilationState,
   871                         body,
   872                         parameters,
   873                         thisProperties,
   874                         rootClass));
   875     }
   877     /**
   878      * Get the number of properties assigned to the this object in this function.
   879      * @return number of properties
   880      */
   881     public int getThisProperties() {
   882         return thisProperties;
   883     }
   885     /**
   886      * Returns true if any of the blocks in this function create their own scope.
   887      * @return true if any of the blocks in this function create their own scope.
   888      */
   889     public boolean hasScopeBlock() {
   890         return getFlag(HAS_SCOPE_BLOCK);
   891     }
   893     /**
   894      * Return the kind of this function
   895      * @see FunctionNode.Kind
   896      * @return the kind
   897      */
   898     public Kind getKind() {
   899         return kind;
   900     }
   902     /**
   903      * Return the last token for this function's code
   904      * @return last token
   905      */
   906     public long getLastToken() {
   907         return lastToken;
   908     }
   910     /**
   911      * Set the last token for this function's code
   912      * @param lc lexical context
   913      * @param lastToken the last token
   914      * @return function node or a new one if state was changed
   915      */
   916     public FunctionNode setLastToken(final LexicalContext lc, final long lastToken) {
   917         if (this.lastToken == lastToken) {
   918             return this;
   919         }
   920         return Node.replaceInLexicalContext(
   921                 lc,
   922                 this,
   923                 new FunctionNode(
   924                         this,
   925                         lastToken,
   926                         flags,
   927                         name,
   928                         returnType,
   929                         compileUnit,
   930                         compilationState,
   931                         body,
   932                         parameters,
   933                         thisProperties,
   934                         rootClass));
   935     }
   937     /**
   938      * Get the name of this function
   939      * @return the name
   940      */
   941     public String getName() {
   942         return name;
   943     }
   945     /**
   946      * Set the internal name for this function
   947      * @param lc    lexical context
   948      * @param name new name
   949      * @return new function node if changed, otherwise the same
   950      */
   951     public FunctionNode setName(final LexicalContext lc, final String name) {
   952         if (this.name.equals(name)) {
   953             return this;
   954         }
   955         return Node.replaceInLexicalContext(
   956                 lc,
   957                 this,
   958                 new FunctionNode(
   959                         this,
   960                         lastToken,
   961                         flags,
   962                         name,
   963                         returnType,
   964                         compileUnit,
   965                         compilationState,
   966                         body,
   967                         parameters,
   968                         thisProperties,
   969                         rootClass));
   970     }
   972     /**
   973      * Check if this function should have all its variables in its own scope. Scripts, split sub-functions, and
   974      * functions having with and/or eval blocks are such.
   975      *
   976      * @return true if all variables should be in scope
   977      */
   978     public boolean allVarsInScope() {
   979         return isProgram() || getFlag(HAS_ALL_VARS_IN_SCOPE);
   980     }
   982     /**
   983      * Checks if this function is a sub-function generated by splitting a larger one
   984      *
   985      * @return true if this function is split from a larger one
   986      */
   987     public boolean isSplit() {
   988         return getFlag(IS_SPLIT);
   989     }
   991     /**
   992      * Get the parameters to this function
   993      * @return a list of IdentNodes which represent the function parameters, in order
   994      */
   995     public List<IdentNode> getParameters() {
   996         return Collections.unmodifiableList(parameters);
   997     }
   999     /**
  1000      * Returns the identifier for a named parameter at the specified position in this function's parameter list.
  1001      * @param index the parameter's position.
  1002      * @return the identifier for the requested named parameter.
  1003      * @throws IndexOutOfBoundsException if the index is invalid.
  1004      */
  1005     public IdentNode getParameter(final int index) {
  1006         return parameters.get(index);
  1009     /**
  1010      * Reset the compile unit used to compile this function
  1011      * @see Compiler
  1012      * @param  lc lexical context
  1013      * @param  parameters the compile unit
  1014      * @return function node or a new one if state was changed
  1015      */
  1016     public FunctionNode setParameters(final LexicalContext lc, final List<IdentNode> parameters) {
  1017         if (this.parameters == parameters) {
  1018             return this;
  1020         return Node.replaceInLexicalContext(
  1021                 lc,
  1022                 this,
  1023                 new FunctionNode(
  1024                         this,
  1025                         lastToken,
  1026                         flags,
  1027                         name,
  1028                         returnType,
  1029                         compileUnit,
  1030                         compilationState,
  1031                         body,
  1032                         parameters,
  1033                         thisProperties,
  1034                         rootClass));
  1037     /**
  1038      * Check if this function is created as a function declaration (as opposed to function expression)
  1039      * @return true if function is declared.
  1040      */
  1041     public boolean isDeclared() {
  1042         return getFlag(IS_DECLARED);
  1045     /**
  1046      * Check if this function is anonymous
  1047      * @return true if function is anonymous
  1048      */
  1049     public boolean isAnonymous() {
  1050         return getFlag(IS_ANONYMOUS);
  1053     /**
  1054      * Does this function use its self symbol - this is needed only for self-referencing named function expressions.
  1055      * Self-referencing declared functions won't have this flag set, as they can access their own symbol through the
  1056      * scope (since they're bound to the symbol with their name in their enclosing scope).
  1057      * @return true if this function node is a named function expression that uses the symbol for itself.
  1058      */
  1059     public boolean usesSelfSymbol() {
  1060         return getFlag(USES_SELF_SYMBOL);
  1063     @Override
  1064     public Type getType(final Function<Symbol, Type> localVariableTypes) {
  1065         return FUNCTION_TYPE;
  1068     @Override
  1069     public Type getWidestOperationType() {
  1070         return FUNCTION_TYPE;
  1073     /**
  1074      * Get the return type for this function. Return types can be specialized
  1075      * if the compiler knows them, but parameters cannot, as they need to go through
  1076      * appropriate object conversion
  1078      * @return the return type
  1079      */
  1080     public Type getReturnType() {
  1081         return returnType;
  1084     /**
  1085      * Set the function return type
  1086      * @param lc lexical context
  1087      * @param returnType new return type
  1088      * @return function node or a new one if state was changed
  1089      */
  1090     public FunctionNode setReturnType(final LexicalContext lc, final Type returnType) {
  1091         //we never bother with object types narrower than objects, that will lead to byte code verification errors
  1092         //as for instance even if we know we are returning a string from a method, the code generator will always
  1093         //treat it as an object, at least for now
  1094         final Type type = returnType.isObject() ? Type.OBJECT : returnType;
  1095         if (this.returnType == type) {
  1096             return this;
  1098         return Node.replaceInLexicalContext(
  1099             lc,
  1100             this,
  1101             new FunctionNode(
  1102                 this,
  1103                 lastToken,
  1104                 flags,
  1105                 name,
  1106                 type,
  1107                 compileUnit,
  1108                 compilationState,
  1109                 body,
  1110                 parameters,
  1111                 thisProperties,
  1112                 rootClass
  1113                 ));
  1116     /**
  1117      * Check if the function is generated in strict mode
  1118      * @return true if strict mode enabled for function
  1119      */
  1120     public boolean isStrict() {
  1121         return getFlag(IS_STRICT);
  1124     /**
  1125      * Get the compile unit used to compile this function
  1126      * @see Compiler
  1127      * @return the compile unit
  1128      */
  1129     public CompileUnit getCompileUnit() {
  1130         return compileUnit;
  1133     /**
  1134      * Reset the compile unit used to compile this function
  1135      * @see Compiler
  1136      * @param lc lexical context
  1137      * @param compileUnit the compile unit
  1138      * @return function node or a new one if state was changed
  1139      */
  1140     public FunctionNode setCompileUnit(final LexicalContext lc, final CompileUnit compileUnit) {
  1141         if (this.compileUnit == compileUnit) {
  1142             return this;
  1144         return Node.replaceInLexicalContext(
  1145                 lc,
  1146                 this,
  1147                 new FunctionNode(
  1148                         this,
  1149                         lastToken,
  1150                         flags,
  1151                         name,
  1152                         returnType,
  1153                         compileUnit,
  1154                         compilationState,
  1155                         body,
  1156                         parameters,
  1157                         thisProperties,
  1158                         rootClass));
  1161     /**
  1162      * Create a temporary variable to the current frame.
  1164      * @param block that needs the temporary
  1165      * @param type  Strong type of symbol.
  1166      * @param node  Primary node to use symbol.
  1168      * @return Symbol used.
  1169      */
  1171     /**
  1172      * Get the symbol for a compiler constant, or null if not available (yet)
  1173      * @param cc compiler constant
  1174      * @return symbol for compiler constant, or null if not defined yet (for example in Lower)
  1175      */
  1176     public Symbol compilerConstant(final CompilerConstants cc) {
  1177         return body.getExistingSymbol(cc.symbolName());
  1180     /**
  1181      * Get the root class that this function node compiles to
  1182      * @return root class
  1183      */
  1184     public Class<?> getRootClass() {
  1185         return rootClass;
  1188     /**
  1189      * Reset the root class that this function is compiled to
  1190      * @see Compiler
  1191      * @param lc lexical context
  1192      * @param rootClass root class
  1193      * @return function node or a new one if state was changed
  1194      */
  1195     public FunctionNode setRootClass(final LexicalContext lc, final Class<?> rootClass) {
  1196         if (this.rootClass == rootClass) {
  1197             return this;
  1199         return Node.replaceInLexicalContext(
  1200                 lc,
  1201                 this,
  1202                 new FunctionNode(
  1203                         this,
  1204                         lastToken,
  1205                         flags,
  1206                         name,
  1207                         returnType,
  1208                         compileUnit,
  1209                         compilationState,
  1210                         body,
  1211                         parameters,
  1212                         thisProperties,
  1213                         rootClass));

mercurial