rev 1338 : 8066222: too strong assertion on function expression names
Reviewed-by: hannesw, lagergren

   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  */
  25 
  26 package jdk.nashorn.internal.ir;
  27 
  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;
  34 
  35 import java.util.Collections;
  36 import java.util.EnumSet;
  37 import java.util.Iterator;
  38 import java.util.List;
  39 import jdk.nashorn.internal.AssertsEnabled;
  40 import jdk.nashorn.internal.codegen.CompileUnit;
  41 import jdk.nashorn.internal.codegen.Compiler;
  42 import jdk.nashorn.internal.codegen.CompilerConstants;
  43 import jdk.nashorn.internal.codegen.Namespace;
  44 import jdk.nashorn.internal.codegen.types.Type;
  45 import jdk.nashorn.internal.ir.annotations.Ignore;
  46 import jdk.nashorn.internal.ir.annotations.Immutable;
  47 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
  48 import jdk.nashorn.internal.runtime.RecompilableScriptFunctionData;
  49 import jdk.nashorn.internal.runtime.ScriptFunction;
  50 import jdk.nashorn.internal.runtime.Source;
  51 import jdk.nashorn.internal.runtime.UserAccessorProperty;
  52 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
  53 
  54 /**
  55  * IR representation for function (or script.)
  56  */
  57 @Immutable
  58 public final class FunctionNode extends LexicalContextExpression implements Flags<FunctionNode>, CompileUnitHolder {
  59     private static final long serialVersionUID = 1L;
  60 
  61     /** Type used for all FunctionNodes */
  62     public static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
  63 
  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     }
  75 
  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     }
 109 
 110     /** Source of entity. */
 111     private transient final Source source;
 112 
 113     /**
 114      * Opaque object representing parser state at the end of the function. Used when reparsing outer functions
 115      * to skip parsing inner functions.
 116      */
 117     private final Object endParserState;
 118 
 119     /** External function identifier. */
 120     @Ignore
 121     private final IdentNode ident;
 122 
 123     /** The body of the function node */
 124     private final Block body;
 125 
 126     /** Internal function name. */
 127     private final String name;
 128 
 129     /** Compilation unit. */
 130     private final CompileUnit compileUnit;
 131 
 132     /** Function kind. */
 133     private final Kind kind;
 134 
 135     /** List of parameters. */
 136     private final List<IdentNode> parameters;
 137 
 138     /** First token of function. **/
 139     private final long firstToken;
 140 
 141     /** Last token of function. **/
 142     private final long lastToken;
 143 
 144     /** Method's namespace. */
 145     private transient final Namespace namespace;
 146 
 147     /** Current compilation state */
 148     @Ignore
 149     private final EnumSet<CompilationState> compilationState;
 150 
 151     /** Number of properties of "this" object assigned in this function */
 152     @Ignore
 153     private final int thisProperties;
 154 
 155     /** Function flags. */
 156     private final int flags;
 157 
 158     /** Line number of function start */
 159     private final int lineNumber;
 160 
 161     /** Root class for function */
 162     private final Class<?> rootClass;
 163 
 164     /** Is anonymous function flag. */
 165     public static final int IS_ANONYMOUS                = 1 << 0;
 166 
 167     /** Is the function created in a function declaration (as opposed to a function expression) */
 168     public static final int IS_DECLARED                 = 1 << 1;
 169 
 170     /** is this a strict mode function? */
 171     public static final int IS_STRICT                   = 1 << 2;
 172 
 173     /** Does the function use the "arguments" identifier ? */
 174     public static final int USES_ARGUMENTS              = 1 << 3;
 175 
 176     /** Has this function been split because it was too large? */
 177     public static final int IS_SPLIT                    = 1 << 4;
 178 
 179     /** Does the function call eval? If it does, then all variables in this function might be get/set by it and it can
 180      * introduce new variables into this function's scope too.*/
 181     public static final int HAS_EVAL                    = 1 << 5;
 182 
 183     /** Does a nested function contain eval? If it does, then all variables in this function might be get/set by it. */
 184     public static final int HAS_NESTED_EVAL             = 1 << 6;
 185 
 186     /** Does this function have any blocks that create a scope? This is used to determine if the function needs to
 187      * have a local variable slot for the scope symbol. */
 188     public static final int HAS_SCOPE_BLOCK             = 1 << 7;
 189 
 190     /**
 191      * Flag this function as one that defines the identifier "arguments" as a function parameter or nested function
 192      * name. This precludes it from needing to have an Arguments object defined as "arguments" local variable. Note that
 193      * defining a local variable named "arguments" still requires construction of the Arguments object (see
 194      * ECMAScript 5.1 Chapter 10.5).
 195      * @see #needsArguments()
 196      */
 197     public static final int DEFINES_ARGUMENTS           = 1 << 8;
 198 
 199     /** Does this function or any of its descendants use variables from an ancestor function's scope (incl. globals)? */
 200     public static final int USES_ANCESTOR_SCOPE         = 1 << 9;
 201 
 202     /** Does this function have nested declarations? */
 203     public static final int HAS_FUNCTION_DECLARATIONS   = 1 << 10;
 204 
 205     /** Does this function have optimistic expressions? (If it does, it can undergo deoptimizing recompilation.) */
 206     public static final int IS_DEOPTIMIZABLE            = 1 << 11;
 207 
 208     /** Are we vararg, but do we just pass the arguments along to apply or call */
 209     public static final int HAS_APPLY_TO_CALL_SPECIALIZATION = 1 << 12;
 210 
 211     /**
 212      * Is this function the top-level program?
 213      */
 214     public static final int IS_PROGRAM = 1 << 13;
 215 
 216     /**
 217      * Flag indicating whether this function uses the local variable symbol for itself. Only named function expressions
 218      * can have this flag set if they reference themselves (e.g. "(function f() { return f })". Declared functions will
 219      * use the symbol in their parent scope instead when they reference themselves by name.
 220      */
 221     public static final int USES_SELF_SYMBOL = 1 << 14;
 222 
 223     /** Does this function use the "this" keyword? */
 224     public static final int USES_THIS = 1 << 15;
 225 
 226     /** Is this declared in a dynamic context */
 227     public static final int IN_DYNAMIC_CONTEXT = 1 << 16;
 228 
 229     /**
 230      * The following flags are derived from directive comments within this function.
 231      * Note that even IS_STRICT is one such flag but that requires special handling.
 232      */
 233 
 234     /** parser, print parse tree */
 235     public static final int IS_PRINT_PARSE       = 1 << 17;
 236     /** parser, print lower parse tree */
 237     public static final int IS_PRINT_LOWER_PARSE = 1 << 18;
 238     /** parser, print AST */
 239     public static final int IS_PRINT_AST         = 1 << 19;
 240     /** parser, print lower AST */
 241     public static final int IS_PRINT_LOWER_AST   = 1 << 20;
 242     /** parser, print symbols */
 243     public static final int IS_PRINT_SYMBOLS     = 1 << 21;
 244 
 245     // callsite tracing, profiling within this function
 246     /** profile callsites in this function? */
 247     public static final int IS_PROFILE         = 1 << 22;
 248 
 249     /** trace callsite enterexit in this function? */
 250     public static final int IS_TRACE_ENTEREXIT = 1 << 23;
 251 
 252     /** trace callsite misses in this function? */
 253     public static final int IS_TRACE_MISSES    = 1 << 24;
 254 
 255     /** trace callsite values in this function? */
 256     public static final int IS_TRACE_VALUES    = 1 << 25;
 257 
 258     /**
 259      * Whether this function needs the callee {@link ScriptFunction} instance passed to its code as a
 260      * parameter on invocation. Note that we aren't, in fact using this flag in function nodes.
 261      * Rather, it is always calculated (see {@link #needsCallee()}). {@link RecompilableScriptFunctionData}
 262      * will, however, cache the value of this flag.
 263      */
 264     public static final int NEEDS_CALLEE       = 1 << 26;
 265 
 266     /** extension callsite flags mask */
 267     public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
 268         IS_PRINT_LOWER_PARSE | IS_PRINT_AST | IS_PRINT_LOWER_AST |
 269         IS_PRINT_SYMBOLS | IS_PROFILE | IS_TRACE_ENTEREXIT |
 270         IS_TRACE_MISSES | IS_TRACE_VALUES;
 271 
 272     /** Does this function or any nested functions contain an eval? */
 273     private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
 274 
 275     /** Does this function need to store all its variables in scope? */
 276     private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_EVAL;
 277 
 278     /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
 279     private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
 280 
 281     /** 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, or it's the program. */
 282     public static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL | IS_PROGRAM;
 283 
 284     /** What is the return type of this function? */
 285     private Type returnType = Type.UNKNOWN;
 286 
 287     /**
 288      * Constructor
 289      *
 290      * @param source     the source
 291      * @param lineNumber line number
 292      * @param token      token
 293      * @param finish     finish
 294      * @param firstToken first token of the function node (including the function declaration)
 295      * @param namespace  the namespace
 296      * @param ident      the identifier
 297      * @param name       the name of the function
 298      * @param parameters parameter list
 299      * @param kind       kind of function as in {@link FunctionNode.Kind}
 300      * @param flags      initial flags
 301      */
 302     public FunctionNode(
 303         final Source source,
 304         final int lineNumber,
 305         final long token,
 306         final int finish,
 307         final long firstToken,
 308         final Namespace namespace,
 309         final IdentNode ident,
 310         final String name,
 311         final List<IdentNode> parameters,
 312         final FunctionNode.Kind kind,
 313         final int flags) {
 314         super(token, finish);
 315 
 316         this.source           = source;
 317         this.lineNumber       = lineNumber;
 318         this.ident            = ident;
 319         this.name             = name;
 320         this.kind             = kind;
 321         this.parameters       = parameters;
 322         this.firstToken       = firstToken;
 323         this.lastToken        = token;
 324         this.namespace        = namespace;
 325         this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
 326         this.flags            = flags;
 327         this.compileUnit      = null;
 328         this.body             = null;
 329         this.thisProperties   = 0;
 330         this.rootClass        = null;
 331         this.endParserState    = null;
 332     }
 333 
 334     private FunctionNode(
 335         final FunctionNode functionNode,
 336         final long lastToken,
 337         final Object endParserState,
 338         final int flags,
 339         final String name,
 340         final Type returnType,
 341         final CompileUnit compileUnit,
 342         final EnumSet<CompilationState> compilationState,
 343         final Block body,
 344         final List<IdentNode> parameters,
 345         final int thisProperties,
 346         final Class<?> rootClass,
 347         final Source source, Namespace namespace) {
 348         super(functionNode);
 349 
 350         this.endParserState    = endParserState;
 351         this.lineNumber       = functionNode.lineNumber;
 352         this.flags            = flags;
 353         this.name             = name;
 354         this.returnType       = returnType;
 355         this.compileUnit      = compileUnit;
 356         this.lastToken        = lastToken;
 357         this.compilationState = compilationState;
 358         this.body             = body;
 359         this.parameters       = parameters;
 360         this.thisProperties   = thisProperties;
 361         this.rootClass        = rootClass;
 362         this.source           = source;
 363         this.namespace        = namespace;
 364 
 365         // the fields below never change - they are final and assigned in constructor
 366         this.ident           = functionNode.ident;
 367         this.kind            = functionNode.kind;
 368         this.firstToken      = functionNode.firstToken;
 369     }
 370 
 371     @Override
 372     public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
 373         if (visitor.enterFunctionNode(this)) {
 374             return visitor.leaveFunctionNode(setBody(lc, (Block)body.accept(visitor)));
 375         }
 376         return this;
 377     }
 378 
 379     /**
 380      * Visits the parameter nodes of this function. Parameters are normally not visited automatically.
 381      * @param visitor the visitor to apply to the nodes.
 382      * @return a list of parameter nodes, potentially modified from original ones by the visitor.
 383      */
 384     public List<IdentNode> visitParameters(final NodeVisitor<? extends LexicalContext> visitor) {
 385         return Node.accept(visitor, parameters);
 386     }
 387 
 388     /**
 389      * Get additional callsite flags to be used specific to this function.
 390      *
 391      * @return callsite flags
 392      */
 393     public int getCallSiteFlags() {
 394         int callsiteFlags = 0;
 395         if (getFlag(IS_STRICT)) {
 396             callsiteFlags |= CALLSITE_STRICT;
 397         }
 398 
 399         // quick check for extension callsite flags turned on by directives.
 400         if ((flags & EXTENSION_CALLSITE_FLAGS) == 0) {
 401             return callsiteFlags;
 402         }
 403 
 404         if (getFlag(IS_PROFILE)) {
 405             callsiteFlags |= CALLSITE_PROFILE;
 406         }
 407 
 408         if (getFlag(IS_TRACE_MISSES)) {
 409             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_MISSES;
 410         }
 411 
 412         if (getFlag(IS_TRACE_VALUES)) {
 413             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT | CALLSITE_TRACE_VALUES;
 414         }
 415 
 416         if (getFlag(IS_TRACE_ENTEREXIT)) {
 417             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT;
 418         }
 419 
 420         return callsiteFlags;
 421     }
 422 
 423     /**
 424      * Get the source for this function
 425      * @return the source
 426      */
 427     public Source getSource() {
 428         return source;
 429     }
 430 
 431     /**
 432      * Sets the source and namespace for this function. It can only set a non-null source and namespace for a function
 433      * that currently has both a null source and a null namespace. This is used to re-set the source and namespace for
 434      * a deserialized function node.
 435      * @param source the source for the function.
 436      * @param namespace the namespace for the function
 437      * @return a new function node with the set source and namespace
 438      * @throws IllegalArgumentException if the specified source or namespace is null
 439      * @throws IllegalStateException if the function already has either a source or namespace set.
 440      */
 441     public FunctionNode initializeDeserialized(final Source source, final Namespace namespace) {
 442         if (source == null || namespace == null) {
 443             throw new IllegalArgumentException();
 444         } else if (this.source == source && this.namespace == namespace) {
 445             return this;
 446         } else if (this.source != null || this.namespace != null) {
 447             throw new IllegalStateException();
 448         }
 449         return new FunctionNode(
 450             this,
 451             lastToken,
 452             endParserState,
 453             flags,
 454             name,
 455             returnType,
 456             compileUnit,
 457             compilationState,
 458             body,
 459             parameters,
 460             thisProperties,
 461             rootClass, source, namespace);
 462     }
 463 
 464     /**
 465      * Get the unique ID for this function within the script file.
 466      * @return the id
 467      */
 468     public int getId() {
 469         return position();
 470     }
 471 
 472     /**
 473      * get source name - sourceURL or name derived from Source.
 474      *
 475      * @return name for the script source
 476      */
 477     public String getSourceName() {
 478         return getSourceName(source);
 479     }
 480 
 481     /**
 482      * Static source name getter
 483      *
 484      * @param source the source
 485      * @return source name
 486      */
 487     public static String getSourceName(final Source source) {
 488         final String explicitURL = source.getExplicitURL();
 489         return explicitURL != null ? explicitURL : source.getName();
 490     }
 491 
 492     /**
 493      * Function to parse nashorn per-function extension directive comments.
 494      *
 495      * @param directive nashorn extension directive string
 496      * @return integer flag for the given directive.
 497      */
 498     public static int getDirectiveFlag(final String directive) {
 499         switch (directive) {
 500             case "nashorn callsite trace enterexit":
 501                 return IS_TRACE_ENTEREXIT;
 502             case "nashorn callsite trace misses":
 503                 return IS_TRACE_MISSES;
 504             case "nashorn callsite trace objects":
 505                 return IS_TRACE_VALUES;
 506             case "nashorn callsite profile":
 507                 return IS_PROFILE;
 508             case "nashorn print parse":
 509                 return IS_PRINT_PARSE;
 510             case "nashorn print lower parse":
 511                 return IS_PRINT_LOWER_PARSE;
 512             case "nashorn print ast":
 513                 return IS_PRINT_AST;
 514             case "nashorn print lower ast":
 515                 return IS_PRINT_LOWER_AST;
 516             case "nashorn print symbols":
 517                 return IS_PRINT_SYMBOLS;
 518             default:
 519                 // unknown/unsupported directive
 520                 return 0;
 521         }
 522     }
 523 
 524     /**
 525      * Returns the line number.
 526      * @return the line number.
 527      */
 528     public int getLineNumber() {
 529         return lineNumber;
 530     }
 531 
 532     /**
 533      * Get the compilation state of this function
 534      * @return the compilation state
 535      */
 536     public EnumSet<CompilationState> getState() {
 537         return compilationState;
 538     }
 539 
 540     /**
 541      * Check whether this FunctionNode has reached a give CompilationState.
 542      *
 543      * @param state the state to check for
 544      * @return true of the node is in the given state
 545      */
 546     public boolean hasState(final EnumSet<CompilationState> state) {
 547         return !AssertsEnabled.assertsEnabled() || compilationState.containsAll(state);
 548     }
 549 
 550     /**
 551      * Add a state to the total CompilationState of this node, e.g. if
 552      * FunctionNode has been lowered, the compiler will add
 553      * {@code CompilationState#LOWERED} to the state vector
 554      *
 555      * @param lc lexical context
 556      * @param state {@link CompilationState} to add
 557      * @return function node or a new one if state was changed
 558      */
 559     public FunctionNode setState(final LexicalContext lc, final CompilationState state) {
 560         if (!AssertsEnabled.assertsEnabled() || this.compilationState.contains(state)) {
 561             return this;
 562         }
 563         final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
 564         newState.add(state);
 565         return setCompilationState(lc, newState);
 566     }
 567 
 568     /**
 569      * Copy a compilation state from an original function to this function. Used when creating synthetic
 570      * function nodes by the splitter.
 571      *
 572      * @param lc lexical context
 573      * @param original the original function node to copy compilation state from
 574      * @return function node or a new one if state was changed
 575      */
 576     public FunctionNode copyCompilationState(final LexicalContext lc, final FunctionNode original) {
 577         final EnumSet<CompilationState> origState = original.compilationState;
 578         if (!AssertsEnabled.assertsEnabled() || this.compilationState.containsAll(origState)) {
 579             return this;
 580         }
 581         final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
 582         newState.addAll(origState);
 583         return setCompilationState(lc, newState);
 584     }
 585 
 586     private FunctionNode setCompilationState(final LexicalContext lc, final EnumSet<CompilationState> compilationState) {
 587         return Node.replaceInLexicalContext(
 588                 lc,
 589                 this,
 590                 new FunctionNode(
 591                         this,
 592                         lastToken,
 593                         endParserState,
 594                         flags,
 595                         name,
 596                         returnType,
 597                         compileUnit,
 598                         compilationState,
 599                         body,
 600                         parameters,
 601                         thisProperties,
 602                         rootClass, source, namespace));
 603     }
 604 
 605 
 606     /**
 607      * Create a unique name in the namespace of this FunctionNode
 608      * @param base prefix for name
 609      * @return base if no collision exists, otherwise a name prefix with base
 610      */
 611     public String uniqueName(final String base) {
 612         return namespace.uniqueName(base);
 613     }
 614 
 615     @Override
 616     public void toString(final StringBuilder sb, final boolean printTypes) {
 617         sb.append('[').
 618             append(returnType).
 619             append(']').
 620             append(' ');
 621 
 622         sb.append("function");
 623 
 624         if (ident != null) {
 625             sb.append(' ');
 626             ident.toString(sb, printTypes);
 627         }
 628 
 629         sb.append('(');
 630 
 631         for (final Iterator<IdentNode> iter = parameters.iterator(); iter.hasNext(); ) {
 632             final IdentNode parameter = iter.next();
 633             if (parameter.getSymbol() != null) {
 634                 sb.append('[').append(parameter.getType()).append(']').append(' ');
 635             }
 636             parameter.toString(sb, printTypes);
 637             if (iter.hasNext()) {
 638                 sb.append(", ");
 639             }
 640         }
 641 
 642         sb.append(')');
 643     }
 644 
 645     @Override
 646     public int getFlags() {
 647         return flags;
 648     }
 649 
 650     @Override
 651     public boolean getFlag(final int flag) {
 652         return (flags & flag) != 0;
 653     }
 654 
 655     @Override
 656     public FunctionNode setFlags(final LexicalContext lc, final int flags) {
 657         if (this.flags == flags) {
 658             return this;
 659         }
 660         return Node.replaceInLexicalContext(
 661                 lc,
 662                 this,
 663                 new FunctionNode(
 664                         this,
 665                         lastToken,
 666                         endParserState,
 667                         flags,
 668                         name,
 669                         returnType,
 670                         compileUnit,
 671                         compilationState,
 672                         body,
 673                         parameters,
 674                         thisProperties,
 675                         rootClass, source, namespace));
 676     }
 677 
 678     @Override
 679     public FunctionNode clearFlag(final LexicalContext lc, final int flag) {
 680         return setFlags(lc, flags & ~flag);
 681     }
 682 
 683     @Override
 684     public FunctionNode setFlag(final LexicalContext lc, final int flag) {
 685         return setFlags(lc, flags | flag);
 686     }
 687 
 688     /**
 689      * Returns true if the function is the top-level program.
 690      * @return True if this function node represents the top-level program.
 691      */
 692     public boolean isProgram() {
 693         return getFlag(IS_PROGRAM);
 694     }
 695 
 696     /**
 697      * Returns true if the function contains at least one optimistic operation (and thus can be deoptimized).
 698      * @return true if the function contains at least one optimistic operation (and thus can be deoptimized).
 699      */
 700     public boolean canBeDeoptimized() {
 701         return getFlag(IS_DEOPTIMIZABLE);
 702     }
 703 
 704     /**
 705      * Check if this function has a call expression for the identifier "eval" (that is, {@code eval(...)}).
 706      *
 707      * @return true if {@code eval} is called.
 708      */
 709     public boolean hasEval() {
 710         return getFlag(HAS_EVAL);
 711     }
 712 
 713     /**
 714      * Returns true if a function nested (directly or transitively) within this function {@link #hasEval()}.
 715      *
 716      * @return true if a nested function calls {@code eval}.
 717      */
 718     public boolean hasNestedEval() {
 719         return getFlag(HAS_NESTED_EVAL);
 720     }
 721 
 722     /**
 723      * Get the first token for this function
 724      * @return the first token
 725      */
 726     public long getFirstToken() {
 727         return firstToken;
 728     }
 729 
 730     /**
 731      * Check whether this function has nested function declarations
 732      * @return true if nested function declarations exist
 733      */
 734     public boolean hasDeclaredFunctions() {
 735         return getFlag(HAS_FUNCTION_DECLARATIONS);
 736     }
 737 
 738     /**
 739      * Check if this function's generated Java method needs a {@code callee} parameter. Functions that need access to
 740      * their parent scope, functions that reference themselves, and non-strict functions that need an Arguments object
 741      * (since it exposes {@code arguments.callee} property) will need to have a callee parameter. We also return true
 742      * for split functions to make sure symbols slots are the same in the main and split methods.
 743      *
 744      * A function that has had an apply(this,arguments) turned into a call doesn't need arguments anymore, but still
 745      * has to fit the old callsite, thus, we require a dummy callee parameter for those functions as well
 746      *
 747      * @return true if the function's generated Java method needs a {@code callee} parameter.
 748      */
 749     public boolean needsCallee() {
 750         // NOTE: we only need isSplit() here to ensure that :scope can never drop below slot 2 for splitting array units.
 751         return needsParentScope() || usesSelfSymbol() || isSplit() || (needsArguments() && !isStrict()) || hasOptimisticApplyToCall();
 752     }
 753 
 754     /**
 755      * Return {@code true} if this function makes use of the {@code this} object.
 756      *
 757      * @return true if function uses {@code this} object
 758      */
 759     public boolean usesThis() {
 760         return getFlag(USES_THIS);
 761     }
 762 
 763 
 764     /**
 765      * Return true if function contains an apply to call transform
 766      * @return true if this function has transformed apply to call
 767      */
 768     public boolean hasOptimisticApplyToCall() {
 769         return getFlag(HAS_APPLY_TO_CALL_SPECIALIZATION);
 770     }
 771 
 772     /**
 773      * Get the identifier for this function, this is its symbol.
 774      * @return the identifier as an IdentityNode
 775      */
 776     public IdentNode getIdent() {
 777         return ident;
 778     }
 779 
 780     /**
 781      * Get the function body
 782      * @return the function body
 783      */
 784     public Block getBody() {
 785         return body;
 786     }
 787 
 788     /**
 789      * Reset the function body
 790      * @param lc lexical context
 791      * @param body new body
 792      * @return new function node if body changed, same if not
 793      */
 794     public FunctionNode setBody(final LexicalContext lc, final Block body) {
 795         if (this.body == body) {
 796             return this;
 797         }
 798         return Node.replaceInLexicalContext(
 799                 lc,
 800                 this,
 801                 new FunctionNode(
 802                         this,
 803                         lastToken,
 804                         endParserState,
 805                         flags |
 806                             (body.needsScope() ?
 807                                     FunctionNode.HAS_SCOPE_BLOCK :
 808                                     0),
 809                         name,
 810                         returnType,
 811                         compileUnit,
 812                         compilationState,
 813                         body,
 814                         parameters,
 815                         thisProperties,
 816                         rootClass, source, namespace));
 817     }
 818 
 819     /**
 820      * Does this function's method needs to be variable arity (gather all script-declared parameters in a final
 821      * {@code Object[]} parameter. Functions that need to have the "arguments" object as well as functions that simply
 822      * declare too many arguments for JVM to handle with fixed arity will need to be variable arity.
 823      * @return true if the Java method in the generated code that implements this function needs to be variable arity.
 824      * @see #needsArguments()
 825      * @see LinkerCallSite#ARGLIMIT
 826      */
 827     public boolean isVarArg() {
 828         return needsArguments() || parameters.size() > LinkerCallSite.ARGLIMIT;
 829     }
 830 
 831     /**
 832      * Was this function declared in a dynamic context, i.e. in a with or eval style
 833      * chain
 834      * @return true if in dynamic context
 835      */
 836     public boolean inDynamicContext() {
 837         return getFlag(IN_DYNAMIC_CONTEXT);
 838     }
 839 
 840     /**
 841      * Check whether a function would need dynamic scope, which is does if it has
 842      * evals and isn't strict.
 843      * @return true if dynamic scope is needed
 844      */
 845     public boolean needsDynamicScope() {
 846         // Function has a direct eval in it (so a top-level "var ..." in the eval code can introduce a new
 847         // variable into the function's scope), and it isn't strict (as evals in strict functions get an
 848         // isolated scope).
 849         return hasEval() && !isStrict();
 850     }
 851 
 852     /**
 853      * Flag this function as declared in a dynamic context
 854      * @param lc lexical context
 855      * @return new function node, or same if unmodified
 856      */
 857     public FunctionNode setInDynamicContext(final LexicalContext lc) {
 858         return setFlag(lc, IN_DYNAMIC_CONTEXT);
 859     }
 860 
 861     /**
 862      * Returns true if this function needs to have an Arguments object defined as a local variable named "arguments".
 863      * Functions that use "arguments" as identifier and don't define it as a name of a parameter or a nested function
 864      * (see ECMAScript 5.1 Chapter 10.5), as well as any function that uses eval or with, or has a nested function that
 865      * does the same, will have an "arguments" object. Also, if this function is a script, it will not have an
 866      * "arguments" object, because it does not have local variables; rather the Global object will have an explicit
 867      * "arguments" property that provides command-line arguments for the script.
 868      * @return true if this function needs an arguments object.
 869      */
 870     public boolean needsArguments() {
 871         // uses "arguments" or calls eval, but it does not redefine "arguments", and finally, it's not a script, since
 872         // for top-level script, "arguments" is picked up from Context by Global.init() instead.
 873         return getFlag(MAYBE_NEEDS_ARGUMENTS) && !getFlag(DEFINES_ARGUMENTS) && !isProgram();
 874     }
 875 
 876     /**
 877      * Returns true if this function needs access to its parent scope. Functions referencing variables outside their
 878      * scope (including global variables), as well as functions that call eval or have a with block, or have nested
 879      * functions that call eval or have a with block, will need a parent scope. Top-level script functions also need a
 880      * parent scope since they might be used from within eval, and eval will need an externally passed scope.
 881      * @return true if the function needs parent scope.
 882      */
 883     public boolean needsParentScope() {
 884         return getFlag(NEEDS_PARENT_SCOPE);
 885     }
 886 
 887     /**
 888      * Set the number of properties assigned to the this object in this function.
 889      * @param lc the current lexical context.
 890      * @param thisProperties number of properties
 891      * @return a potentially modified function node
 892      */
 893     public FunctionNode setThisProperties(final LexicalContext lc, final int thisProperties) {
 894         if (this.thisProperties == thisProperties) {
 895             return this;
 896         }
 897         return Node.replaceInLexicalContext(
 898                 lc,
 899                 this,
 900                 new FunctionNode(
 901                         this,
 902                         lastToken,
 903                         endParserState,
 904                         flags,
 905                         name,
 906                         returnType,
 907                         compileUnit,
 908                         compilationState,
 909                         body,
 910                         parameters,
 911                         thisProperties,
 912                         rootClass, source, namespace));
 913     }
 914 
 915     /**
 916      * Get the number of properties assigned to the this object in this function.
 917      * @return number of properties
 918      */
 919     public int getThisProperties() {
 920         return thisProperties;
 921     }
 922 
 923     /**
 924      * Returns true if any of the blocks in this function create their own scope.
 925      * @return true if any of the blocks in this function create their own scope.
 926      */
 927     public boolean hasScopeBlock() {
 928         return getFlag(HAS_SCOPE_BLOCK);
 929     }
 930 
 931     /**
 932      * Return the kind of this function
 933      * @see FunctionNode.Kind
 934      * @return the kind
 935      */
 936     public Kind getKind() {
 937         return kind;
 938     }
 939 
 940     /**
 941      * Return the last token for this function's code
 942      * @return last token
 943      */
 944     public long getLastToken() {
 945         return lastToken;
 946     }
 947 
 948     /**
 949      * Set the last token for this function's code
 950      * @param lc lexical context
 951      * @param lastToken the last token
 952      * @return function node or a new one if state was changed
 953      */
 954     public FunctionNode setLastToken(final LexicalContext lc, final long lastToken) {
 955         if (this.lastToken == lastToken) {
 956             return this;
 957         }
 958         return Node.replaceInLexicalContext(
 959                 lc,
 960                 this,
 961                 new FunctionNode(
 962                         this,
 963                         lastToken,
 964                         endParserState,
 965                         flags,
 966                         name,
 967                         returnType,
 968                         compileUnit,
 969                         compilationState,
 970                         body,
 971                         parameters,
 972                         thisProperties,
 973                         rootClass, source, namespace));
 974     }
 975 
 976     /**
 977      * Returns the end parser state for this function.
 978      * @return the end parser state for this function.
 979      */
 980     public Object getEndParserState() {
 981         return endParserState;
 982     }
 983 
 984     /**
 985      * Set the end parser state for this function.
 986      * @param lc lexical context
 987      * @param endParserState the parser state to set
 988      * @return function node or a new one if state was changed
 989      */
 990     public FunctionNode setEndParserState(final LexicalContext lc, final Object endParserState) {
 991         if (this.endParserState == endParserState) {
 992             return this;
 993         }
 994         return Node.replaceInLexicalContext(
 995                 lc,
 996                 this,
 997                 new FunctionNode(
 998                         this,
 999                         lastToken,
1000                         endParserState,
1001                         flags,
1002                         name,
1003                         returnType,
1004                         compileUnit,
1005                         compilationState,
1006                         body,
1007                         parameters,
1008                         thisProperties,
1009                         rootClass,
1010                         source,
1011                         namespace));
1012     }
1013 
1014     /**
1015      * Get the name of this function
1016      * @return the name
1017      */
1018     public String getName() {
1019         return name;
1020     }
1021 
1022     /**
1023      * Set the internal name for this function
1024      * @param lc    lexical context
1025      * @param name new name
1026      * @return new function node if changed, otherwise the same
1027      */
1028     public FunctionNode setName(final LexicalContext lc, final String name) {
1029         if (this.name.equals(name)) {
1030             return this;
1031         }
1032         return Node.replaceInLexicalContext(
1033                 lc,
1034                 this,
1035                 new FunctionNode(
1036                         this,
1037                         lastToken,
1038                         endParserState,
1039                         flags,
1040                         name,
1041                         returnType,
1042                         compileUnit,
1043                         compilationState,
1044                         body,
1045                         parameters,
1046                         thisProperties,
1047                         rootClass,
1048                         source,
1049                         namespace));
1050     }
1051 
1052     /**
1053      * Check if this function should have all its variables in its own scope. Split sub-functions, and
1054      * functions having with and/or eval blocks are such.
1055      *
1056      * @return true if all variables should be in scope
1057      */
1058     public boolean allVarsInScope() {
1059         return getFlag(HAS_ALL_VARS_IN_SCOPE);
1060     }
1061 
1062     /**
1063      * Checks if this function is split into several smaller fragments.
1064      *
1065      * @return true if this function is split into several smaller fragments.
1066      */
1067     public boolean isSplit() {
1068         return getFlag(IS_SPLIT);
1069     }
1070 
1071     /**
1072      * Get the parameters to this function
1073      * @return a list of IdentNodes which represent the function parameters, in order
1074      */
1075     public List<IdentNode> getParameters() {
1076         return Collections.unmodifiableList(parameters);
1077     }
1078 
1079     /**
1080      * Returns the identifier for a named parameter at the specified position in this function's parameter list.
1081      * @param index the parameter's position.
1082      * @return the identifier for the requested named parameter.
1083      * @throws IndexOutOfBoundsException if the index is invalid.
1084      */
1085     public IdentNode getParameter(final int index) {
1086         return parameters.get(index);
1087     }
1088 
1089     /**
1090      * Reset the compile unit used to compile this function
1091      * @see Compiler
1092      * @param  lc lexical context
1093      * @param  parameters the compile unit
1094      * @return function node or a new one if state was changed
1095      */
1096     public FunctionNode setParameters(final LexicalContext lc, final List<IdentNode> parameters) {
1097         if (this.parameters == parameters) {
1098             return this;
1099         }
1100         return Node.replaceInLexicalContext(
1101                 lc,
1102                 this,
1103                 new FunctionNode(
1104                         this,
1105                         lastToken,
1106                         endParserState,
1107                         flags,
1108                         name,
1109                         returnType,
1110                         compileUnit,
1111                         compilationState,
1112                         body,
1113                         parameters,
1114                         thisProperties,
1115                         rootClass, source, namespace));
1116     }
1117 
1118     /**
1119      * Check if this function is created as a function declaration (as opposed to function expression)
1120      * @return true if function is declared.
1121      */
1122     public boolean isDeclared() {
1123         return getFlag(IS_DECLARED);
1124     }
1125 
1126     /**
1127      * Check if this function is anonymous
1128      * @return true if function is anonymous
1129      */
1130     public boolean isAnonymous() {
1131         return getFlag(IS_ANONYMOUS);
1132     }
1133 
1134     /**
1135      * Does this function use its self symbol - this is needed only for self-referencing named function expressions.
1136      * Self-referencing declared functions won't have this flag set, as they can access their own symbol through the
1137      * scope (since they're bound to the symbol with their name in their enclosing scope).
1138      * @return true if this function node is a named function expression that uses the symbol for itself.
1139      */
1140     public boolean usesSelfSymbol() {
1141         return getFlag(USES_SELF_SYMBOL);
1142     }
1143 
1144     /**
1145      * Returns true if this is a named function expression (that is, it isn't a declared function, it isn't an
1146      * anonymous function expression, and it isn't a program).
1147      * @return true if this is a named function expression
1148      */
1149     public boolean isNamedFunctionExpression() {
1150         return !getFlag(IS_PROGRAM | IS_ANONYMOUS | IS_DECLARED);
1151     }
1152 
1153     @Override
1154     public Type getType() {
1155         return FUNCTION_TYPE;
1156     }
1157 
1158     @Override
1159     public Type getWidestOperationType() {
1160         return FUNCTION_TYPE;
1161     }
1162 
1163     /**
1164      * Get the return type for this function. Return types can be specialized
1165      * if the compiler knows them, but parameters cannot, as they need to go through
1166      * appropriate object conversion
1167      *
1168      * @return the return type
1169      */
1170     public Type getReturnType() {
1171         return returnType;
1172     }
1173 
1174     /**
1175      * Set the function return type
1176      * @param lc lexical context
1177      * @param returnType new return type
1178      * @return function node or a new one if state was changed
1179      */
1180     public FunctionNode setReturnType(final LexicalContext lc, final Type returnType) {
1181         //we never bother with object types narrower than objects, that will lead to byte code verification errors
1182         //as for instance even if we know we are returning a string from a method, the code generator will always
1183         //treat it as an object, at least for now
1184         final Type type = returnType.isObject() ? Type.OBJECT : returnType;
1185         if (this.returnType == type) {
1186             return this;
1187         }
1188         return Node.replaceInLexicalContext(
1189             lc,
1190             this,
1191             new FunctionNode(
1192                 this,
1193                 lastToken,
1194                 endParserState,
1195                 flags,
1196                 name,
1197                 type,
1198                 compileUnit,
1199                 compilationState,
1200                 body,
1201                 parameters,
1202                 thisProperties,
1203                 rootClass, source, namespace
1204                 ));
1205    }
1206 
1207     /**
1208      * Check if the function is generated in strict mode
1209      * @return true if strict mode enabled for function
1210      */
1211     public boolean isStrict() {
1212         return getFlag(IS_STRICT);
1213     }
1214 
1215     /**
1216      * Get the compile unit used to compile this function
1217      * @see Compiler
1218      * @return the compile unit
1219      */
1220     @Override
1221     public CompileUnit getCompileUnit() {
1222         return compileUnit;
1223     }
1224 
1225     /**
1226      * Reset the compile unit used to compile this function
1227      * @see Compiler
1228      * @param lc lexical context
1229      * @param compileUnit the compile unit
1230      * @return function node or a new one if state was changed
1231      */
1232     public FunctionNode setCompileUnit(final LexicalContext lc, final CompileUnit compileUnit) {
1233         if (this.compileUnit == compileUnit) {
1234             return this;
1235         }
1236         return Node.replaceInLexicalContext(
1237                 lc,
1238                 this,
1239                 new FunctionNode(
1240                         this,
1241                         lastToken,
1242                         endParserState,
1243                         flags,
1244                         name,
1245                         returnType,
1246                         compileUnit,
1247                         compilationState,
1248                         body,
1249                         parameters,
1250                         thisProperties,
1251                         rootClass, source, namespace));
1252     }
1253 
1254     /**
1255      * Create a temporary variable to the current frame.
1256      *
1257      * @param block that needs the temporary
1258      * @param type  Strong type of symbol.
1259      * @param node  Primary node to use symbol.
1260      *
1261      * @return Symbol used.
1262      */
1263 
1264     /**
1265      * Get the symbol for a compiler constant, or null if not available (yet)
1266      * @param cc compiler constant
1267      * @return symbol for compiler constant, or null if not defined yet (for example in Lower)
1268      */
1269     public Symbol compilerConstant(final CompilerConstants cc) {
1270         return body.getExistingSymbol(cc.symbolName());
1271     }
1272 
1273     /**
1274      * Get the root class that this function node compiles to
1275      * @return root class
1276      */
1277     public Class<?> getRootClass() {
1278         return rootClass;
1279     }
1280 
1281     /**
1282      * Reset the root class that this function is compiled to
1283      * @see Compiler
1284      * @param lc lexical context
1285      * @param rootClass root class
1286      * @return function node or a new one if state was changed
1287      */
1288     public FunctionNode setRootClass(final LexicalContext lc, final Class<?> rootClass) {
1289         if (this.rootClass == rootClass) {
1290             return this;
1291         }
1292         return Node.replaceInLexicalContext(
1293                 lc,
1294                 this,
1295                 new FunctionNode(
1296                         this,
1297                         lastToken,
1298                         endParserState,
1299                         flags,
1300                         name,
1301                         returnType,
1302                         compileUnit,
1303                         compilationState,
1304                         body,
1305                         parameters,
1306                         thisProperties,
1307                         rootClass, source, namespace));
1308     }
1309 }
--- EOF ---