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