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