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