Mon, 18 Feb 2013 16:00:15 +0100
8008371: Fix Dynalink compiler warnings and whitespace
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.codegen.CompilerConstants.LITERAL_PREFIX;
29 import static jdk.nashorn.internal.codegen.CompilerConstants.TEMP_PREFIX;
30 import static jdk.nashorn.internal.ir.Symbol.IS_CONSTANT;
31 import static jdk.nashorn.internal.ir.Symbol.IS_TEMP;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.EnumSet;
36 import java.util.LinkedList;
37 import java.util.List;
38 import java.util.Stack;
39 import jdk.nashorn.internal.codegen.CompileUnit;
40 import jdk.nashorn.internal.codegen.Compiler;
41 import jdk.nashorn.internal.codegen.Frame;
42 import jdk.nashorn.internal.codegen.MethodEmitter;
43 import jdk.nashorn.internal.codegen.Namespace;
44 import jdk.nashorn.internal.codegen.types.Type;
45 import jdk.nashorn.internal.ir.annotations.Ignore;
46 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
47 import jdk.nashorn.internal.parser.Parser;
48 import jdk.nashorn.internal.runtime.Source;
49 import jdk.nashorn.internal.runtime.UserAccessorProperty;
50 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
52 /**
53 * IR representation for function (or script.)
54 *
55 */
56 public class FunctionNode extends Block {
58 /** Function kinds */
59 public enum Kind {
60 /** a normal function - nothing special */
61 NORMAL,
62 /** a script function */
63 SCRIPT,
64 /** a getter, @see {@link UserAccessorProperty} */
65 GETTER,
66 /** a setter, @see {@link UserAccessorProperty} */
67 SETTER
68 }
70 /** Compilation states available */
71 public enum CompilationState {
72 /** compiler is ready */
73 INITIALIZED,
74 /** method has been parsed */
75 PARSED,
76 /** method has been parsed */
77 PARSE_ERROR,
78 /** constant folding pass */
79 CONSTANT_FOLDED,
80 /** method has been lowered */
81 LOWERED,
82 /** method hass been attributed */
83 ATTR,
84 /** method has been split */
85 SPLIT,
86 /** method has had its types finalized */
87 FINALIZED,
88 /** method has been emitted to bytecode */
89 EMITTED
90 }
92 /** External function identifier. */
93 @Ignore
94 private IdentNode ident;
96 /** Internal function name. */
97 private String name;
99 /** Compilation unit. */
100 private CompileUnit compileUnit;
102 /** Method emitter for current method. */
103 private MethodEmitter method;
105 /** Function kind. */
106 private Kind kind;
108 /** List of parameters. */
109 private List<IdentNode> parameters;
111 /** List of nested functions. */
112 private List<FunctionNode> functions;
114 /** First token of function. **/
115 private long firstToken;
117 /** Last token of function. **/
118 private long lastToken;
120 /** Variable frames. */
121 private Frame frames;
123 /** Method's namespace. */
124 private final Namespace namespace;
126 /** Node representing current this. */
127 @Ignore
128 private IdentNode thisNode;
130 /** Node representing current scope. */
131 @Ignore
132 private IdentNode scopeNode;
134 /** Node representing return value. */
135 @Ignore
136 private IdentNode resultNode;
138 /** Node representing current arguments. */
139 @Ignore
140 private IdentNode argumentsNode;
142 /** Node representing callee */
143 @Ignore
144 private IdentNode calleeNode;
146 /** Node representing varargs */
147 @Ignore
148 private IdentNode varArgsNode;
150 /** Pending label list. */
151 private final Stack<LabelNode> labelStack;
153 /** Pending control list. */
154 private final Stack<Node> controlStack;
156 /** Variable declarations in the function's scope */
157 @Ignore
158 private final List<VarNode> declarations;
160 /** VarNode for this function statement */
161 @Ignore //this is explicit code anyway and should not be traversed after lower
162 private VarNode funcVarNode;
164 /** Line number for function declaration */
165 @Ignore
166 private LineNumberNode funcVarLineNumberNode;
168 /** Initializer var func = __callee__, where applicable */
169 @Ignore
170 private Node selfSymbolInit;
172 /** Current compilation state */
173 @Ignore
174 private final EnumSet<CompilationState> compilationState;
176 /** Function flags. */
177 private int flags;
179 /** Is anonymous function flag. */
180 private static final int IS_ANONYMOUS = 0b0000_0000_0000_0001;
181 /** Is statement flag */
182 private static final int IS_STATEMENT = 0b0000_0000_0000_0010;
183 /** is this a strict mode function? */
184 private static final int IS_STRICT_MODE = 0b0000_0000_0000_0100;
185 /** Does the function use the "arguments" identifier ? */
186 private static final int USES_ARGUMENTS = 0b0000_0000_0000_1000;
187 /** Are we lowered ? */
188 private static final int IS_LOWERED = 0b0000_0000_0001_0000;
189 /** Has this node been split because it was too large? */
190 private static final int IS_SPLIT = 0b0000_0000_0010_0000;
191 /** Is this function lazily compiled? */
192 private static final int IS_LAZY = 0b0000_0000_0100_0000;
193 /** Does the function call eval? */
194 private static final int HAS_EVAL = 0b0000_0000_1000_0000;
195 /** Does the function contain a with block ? */
196 private static final int HAS_WITH = 0b0000_0001_0000_0000;
197 /** Does a descendant function contain a with or eval? */
198 private static final int HAS_DESCENDANT_WITH_OR_EVAL = 0b0000_0010_0000_0000;
199 /** Does the function define "arguments" identifier as a parameter of nested function name? */
200 private static final int DEFINES_ARGUMENTS = 0b0000_0100_0000_0000;
201 /** Does the function need a self symbol? */
202 private static final int NEEDS_SELF_SYMBOL = 0b0000_1000_0000_0000;
203 /** Does this function or any of its descendants use variables from an ancestor function's scope (incl. globals)? */
204 private static final int USES_ANCESTOR_SCOPE = 0b0001_0000_0000_0000;
206 /** Does this function or any nested functions contain a with or an eval? */
207 private static final int HAS_DEEP_WITH_OR_EVAL = HAS_EVAL | HAS_WITH | HAS_DESCENDANT_WITH_OR_EVAL;
208 /** Does this function need to store all its variables in scope? */
209 private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_WITH_OR_EVAL | IS_SPLIT;
210 /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
211 private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
212 /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep with or eval. */
213 private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_WITH_OR_EVAL;
215 /** What is the return type of this function? */
216 private Type returnType = Type.UNKNOWN;
218 /**
219 * Used to keep track of a function's parent blocks.
220 * This is needed when a (finally body) block is cloned than contains inner functions.
221 * Does not include function.getParent().
222 */
223 @Ignore
224 private List<Block> referencingParentBlocks;
226 /**
227 * Constructor
228 *
229 * @param source the source
230 * @param token token
231 * @param finish finish
232 * @param namespace the namespace
233 * @param parent the parent block
234 * @param ident the identifier
235 * @param name the name of the function
236 */
237 @SuppressWarnings("LeakingThisInConstructor")
238 public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final Block parent, final IdentNode ident, final String name) {
239 super(source, token, finish, parent, null);
241 this.ident = ident;
242 this.name = name;
243 this.kind = Kind.NORMAL;
244 this.parameters = new ArrayList<>();
245 this.functions = new ArrayList<>();
246 this.firstToken = token;
247 this.lastToken = token;
248 this.namespace = namespace;
249 this.labelStack = new Stack<>();
250 this.controlStack = new Stack<>();
251 this.declarations = new ArrayList<>();
252 // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies
253 // it as such a leak - this is a false positive as we're setting this into a field of the object being
254 // constructed, so it can't be seen from other threads.
255 this.function = this;
256 this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
257 }
259 @SuppressWarnings("LeakingThisInConstructor")
260 private FunctionNode(final FunctionNode functionNode, final CopyState cs) {
261 super(functionNode, cs);
263 this.ident = (IdentNode)cs.existingOrCopy(functionNode.ident);
264 this.name = functionNode.name;
265 this.kind = functionNode.kind;
267 this.parameters = new ArrayList<>();
268 for (final IdentNode param : functionNode.getParameters()) {
269 this.parameters.add((IdentNode) cs.existingOrCopy(param));
270 }
272 this.functions = new ArrayList<>();
273 this.firstToken = functionNode.firstToken;
274 this.lastToken = functionNode.lastToken;
275 this.namespace = functionNode.getNamespace();
276 this.thisNode = (IdentNode)cs.existingOrCopy(functionNode.thisNode);
277 this.scopeNode = (IdentNode)cs.existingOrCopy(functionNode.scopeNode);
278 this.resultNode = (IdentNode)cs.existingOrCopy(functionNode.resultNode);
279 this.argumentsNode = (IdentNode)cs.existingOrCopy(functionNode.argumentsNode);
280 this.varArgsNode = (IdentNode)cs.existingOrCopy(functionNode.varArgsNode);
281 this.calleeNode = (IdentNode)cs.existingOrCopy(functionNode.calleeNode);
282 this.labelStack = new Stack<>();
283 this.controlStack = new Stack<>();
284 this.declarations = new ArrayList<>();
286 for (final VarNode decl : functionNode.getDeclarations()) {
287 declarations.add((VarNode) cs.existingOrCopy(decl)); //TODO same?
288 }
290 this.flags = functionNode.flags;
292 this.funcVarNode = (VarNode)cs.existingOrCopy(functionNode.funcVarNode);
293 /** VarNode for this function statement */
295 // my block -> function is this. We added @SuppressWarnings("LeakingThisInConstructor") as NetBeans identifies
296 // it as such a leak - this is a false positive as we're setting this into a field of the object being
297 // constructed, so it can't be seen from other threads.
298 this.function = this;
300 this.compilationState = EnumSet.copyOf(functionNode.compilationState);
301 }
303 @Override
304 protected Node copy(final CopyState cs) {
305 // deep clone all parent blocks
306 return fixBlockChain(new FunctionNode(this, cs));
307 }
309 @Override
310 public Node accept(final NodeVisitor visitor) {
311 final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode();
312 final Block saveBlock = visitor.getCurrentBlock();
314 visitor.setCurrentFunctionNode(this);
315 visitor.setCurrentCompileUnit(getCompileUnit());
316 visitor.setCurrentMethodEmitter(getMethodEmitter());
317 visitor.setCurrentBlock(this);
319 try {
320 if (visitor.enter(this) != null) {
321 if (ident != null) {
322 ident = (IdentNode)ident.accept(visitor);
323 }
325 for (int i = 0, count = parameters.size(); i < count; i++) {
326 parameters.set(i, (IdentNode)parameters.get(i).accept(visitor));
327 }
329 for (int i = 0, count = functions.size(); i < count; i++) {
330 functions.set(i, (FunctionNode)functions.get(i).accept(visitor));
331 }
333 for (int i = 0, count = statements.size(); i < count; i++) {
334 statements.set(i, statements.get(i).accept(visitor));
335 }
337 return visitor.leave(this);
338 }
339 } finally {
340 visitor.setCurrentBlock(saveBlock);
341 visitor.setCurrentFunctionNode(saveFunctionNode);
342 visitor.setCurrentCompileUnit(saveFunctionNode != null ? saveFunctionNode.getCompileUnit() : null);
343 visitor.setCurrentMethodEmitter(saveFunctionNode != null ? saveFunctionNode.getMethodEmitter() : null);
344 }
346 return this;
347 }
349 /**
350 * Locate the parent function.
351 *
352 * @return Parent function.
353 */
354 public FunctionNode findParentFunction() {
355 return getParent() != null ? getParent().getFunction() : null;
356 }
358 /**
359 * Add parent name to the builder.
360 *
361 * @param sb String builder.
362 */
363 @Override
364 public void addParentName(final StringBuilder sb) {
365 if (!isScript()) {
366 sb.append(getName());
367 sb.append("$");
368 }
369 }
371 @Override
372 public boolean needsScope() {
373 return super.needsScope() || isScript();
374 }
376 /**
377 * Check whether this FunctionNode has reached a give CompilationState.
378 *
379 * @param state the state to check for
380 * @return true of the node is in the given state
381 */
382 public boolean hasState(final EnumSet<CompilationState> state) {
383 return compilationState.equals(state);
384 }
386 /**
387 * Check whether the state of this FunctionNode contains a given compilation
388 * state.
389 *
390 * A node can be in many states at once, e.g. both lowered and initialized.
391 * To check for an exact state, use {FunctionNode{@link #hasState(EnumSet)}
392 *
393 * @param state state to check for
394 * @return true if state is present in the total compilation state of this FunctionNode
395 */
396 public boolean hasState(final CompilationState state) {
397 return compilationState.contains(state);
398 }
400 /**
401 * Add a state to the total CompilationState of this node, e.g. if
402 * FunctionNode has been lowered, the compiler will add
403 * {@code CompilationState#LOWERED} to the state vector
404 *
405 * @param state {@link CompilationState} to add
406 */
407 public void setState(final CompilationState state) {
408 compilationState.add(state);
409 }
411 /*
412 * Frame management.
413 */
415 /**
416 * Push a new block frame.
417 *
418 * @return the new frame
419 */
420 public final Frame pushFrame() {
421 frames = new Frame(frames);
422 return frames;
423 }
425 /**
426 * Pop a block frame.
427 */
428 public final void popFrame() {
429 frames = frames.getPrevious();
430 }
432 /**
433 * Create a temporary variable to the current frame.
434 *
435 * @param currentFrame Frame to add to - defaults to current function frame
436 * @param type Strong type of symbol.
437 * @param node Primary node to use symbol.
438 *
439 * @return Symbol used.
440 */
441 public Symbol newTemporary(final Frame currentFrame, final Type type, final Node node) {
442 assert currentFrame != null;
443 Symbol symbol = node.getSymbol();
445 // If no symbol already present.
446 if (symbol == null) {
447 final String uname = uniqueName(TEMP_PREFIX.tag());
448 symbol = new Symbol(uname, IS_TEMP, type);
449 symbol.setNode(node);
450 }
452 // Assign a slot if it doesn't have one.
453 if (!symbol.hasSlot()) {
454 currentFrame.addSymbol(symbol);
455 }
457 // Set symbol to node.
458 node.setSymbol(symbol);
460 return symbol;
461 }
463 /**
464 * Create a unique name in the namespace of this FunctionNode
465 * @param base prefix for name
466 * @return base if no collision exists, otherwise a name prefix with base
467 */
468 public String uniqueName(final String base) {
469 return namespace.uniqueName(base);
470 }
472 /**
473 * Add a new temporary variable to the current frame
474 *
475 * @param type Strong type of symbol
476 * @param node Primary node to use symbol
477 *
478 * @return symbol used
479 */
480 public Symbol newTemporary(final Type type, final Node node) {
481 return newTemporary(frames, type, node);
482 }
484 /**
485 * Create a virtual symbol for a literal.
486 *
487 * @param literalNode Primary node to use symbol.
488 *
489 * @return Symbol used.
490 */
491 public Symbol newLiteral(final LiteralNode<?> literalNode) {
492 final String uname = uniqueName(LITERAL_PREFIX.tag());
493 final Symbol symbol = new Symbol(uname, IS_CONSTANT, literalNode.getType());
494 symbol.setNode(literalNode);
495 literalNode.setSymbol(symbol);
497 return symbol;
498 }
500 @Override
501 public void toString(final StringBuilder sb) {
502 sb.append('[');
503 sb.append(returnType);
504 sb.append(']');
505 sb.append(' ');
507 sb.append("function");
509 if (ident != null) {
510 sb.append(' ');
511 ident.toString(sb);
512 }
514 sb.append('(');
515 boolean first = true;
517 for (final IdentNode parameter : parameters) {
518 if (!first) {
519 sb.append(", ");
520 } else {
521 first = false;
522 }
524 parameter.toString(sb);
525 }
527 sb.append(')');
528 }
530 /**
531 * Determine if script function.
532 *
533 * @return True if script function.
534 */
535 public boolean isScript() {
536 return getParent() == null;
537 }
539 /**
540 * Get the control stack. Used when parsing to establish nesting depths of
541 * different control structures
542 *
543 * @return the control stack
544 */
545 public Stack<Node> getControlStack() {
546 return controlStack;
547 }
549 /**
550 * Should this function node be lazily code generated, i.e. first at link time
551 * @return true if lazy
552 */
553 public boolean isLazy() {
554 return (flags & IS_LAZY) != 0;
555 }
557 /**
558 * Set if this function should be lazily generated
559 * @param isLazy is lazy
560 */
561 public void setIsLazy(final boolean isLazy) {
562 this.flags = isLazy ? flags | IS_LAZY : flags & ~IS_LAZY;
563 }
565 /**
566 * Check if the {@code with} keyword is used in this function
567 *
568 * @return true if {@code with} is used
569 */
570 public boolean hasWith() {
571 return (flags & HAS_WITH) != 0;
572 }
574 /**
575 * Flag this function as using the {@code with} keyword
576 */
577 public void setHasWith() {
578 if(!hasWith()) {
579 this.flags |= HAS_WITH;
580 // with requires scope in parents.
581 // TODO: refine this. with should not force all variables in parents to be in scope, only those that are
582 // actually referenced as identifiers by name
583 markParentForWithOrEval();
584 }
585 }
587 private void markParentForWithOrEval() {
588 // If this is invoked, then either us or a descendant uses with or eval, meaning we must have our own scope.
589 setNeedsScope();
591 final FunctionNode parentFunction = findParentFunction();
592 if(parentFunction != null) {
593 parentFunction.setDescendantHasWithOrEval();
594 }
595 }
597 private void setDescendantHasWithOrEval() {
598 if((flags & HAS_DESCENDANT_WITH_OR_EVAL) == 0) {
599 flags |= HAS_DESCENDANT_WITH_OR_EVAL;
600 markParentForWithOrEval();
601 }
602 }
604 /**
605 * Check if the {@code eval} keyword is used in this function
606 *
607 * @return true if {@code eval} is used
608 */
609 public boolean hasEval() {
610 return (flags & HAS_EVAL) != 0;
611 }
613 /**
614 * Flag this function as calling the {@code eval} function
615 */
616 public void setHasEval() {
617 if(!hasEval()) {
618 this.flags |= HAS_EVAL;
619 markParentForWithOrEval();
620 }
621 }
623 /**
624 * Test whether this function or any of its nested functions contains a <tt>with</tt> statement
625 * or an <tt>eval</tt> call.
626 *
627 * @see #hasWith()
628 * @see #hasEval()
629 * @return true if this or a nested function contains with or eval
630 */
631 public boolean hasDeepWithOrEval() {
632 return (flags & HAS_DEEP_WITH_OR_EVAL) != 0;
633 }
635 /**
636 * Get the first token for this function
637 * @return the first token
638 */
639 public long getFirstToken() {
640 return firstToken;
641 }
643 /**
644 * Set the first token for this function
645 * @param firstToken the first token
646 */
647 public void setFirstToken(final long firstToken) {
648 this.firstToken = firstToken;
649 }
651 /**
652 * Get all nested functions
653 * @return list of nested functions in this function
654 */
655 public List<FunctionNode> getFunctions() {
656 return Collections.unmodifiableList(functions);
657 }
659 /**
660 * Get the label stack. This is used by the parser to establish
661 * label nesting depth
662 *
663 * @return the label stack
664 */
665 public Stack<LabelNode> getLabelStack() {
666 return labelStack;
667 }
669 /**
670 * If this function needs to use var args, return the identifier to the node used
671 * for the var args structure
672 *
673 * @return IdentNode representing the var args structure
674 */
675 public IdentNode getVarArgsNode() {
676 return varArgsNode;
677 }
679 /**
680 * Set the identifier to the node used for the var args structure
681 *
682 * @param varArgsNode IdentNode representing the var args
683 */
684 public void setVarArgsNode(final IdentNode varArgsNode) {
685 this.varArgsNode = varArgsNode;
686 }
688 /**
689 * If this function uses the {@code callee} variable, return the node used
690 * as this variable
691 *
692 * @return an IdentNode representing the {@code callee} variable
693 */
694 public IdentNode getCalleeNode() {
695 return calleeNode;
696 }
698 /**
699 * If this function uses the {@code callee} variable, set the node representing the
700 * callee
701 * @param calleeNode an IdentNode representing the callee
702 */
703 public void setCalleeNode(final IdentNode calleeNode) {
704 this.calleeNode = calleeNode;
705 }
707 /**
708 * Check if this function's generated Java method needs a {@code callee} parameter. Functions that need access to
709 * their parent scope, functions that reference themselves, and non-strict functions that need an Arguments object
710 * (since it exposes {@code arguments.callee} property) will need to have a callee parameter.
711 * @return true if the function's generated Java method needs a {@code callee} parameter.
712 */
713 public boolean needsCallee() {
714 return needsParentScope() || needsSelfSymbol() || (needsArguments() && !isStrictMode());
715 }
717 /**
718 * If this is a function where {@code arguments} is used, return the node used as the {@code arguments}
719 * variable
720 * @return an IdentNode representing {@code arguments}
721 */
722 public IdentNode getArgumentsNode() {
723 return argumentsNode;
724 }
726 /**
727 * If this is a Function where {@code arguments} is used, an identifier to the node representing
728 * the {@code arguments} value has to be supplied by the compiler
729 *
730 * @param argumentsNode IdentNode that represents {@code arguments}
731 */
732 public void setArgumentsNode(final IdentNode argumentsNode) {
733 this.argumentsNode = argumentsNode;
734 }
736 /**
737 * Get the identifier for this function
738 * @return the identifier as an IdentityNode
739 */
740 public IdentNode getIdent() {
741 return ident;
742 }
744 /**
745 * Reset the identifier for this function
746 * @param ident IdentNode for new identifier
747 */
748 public void setIdent(final IdentNode ident) {
749 this.ident = ident;
750 }
752 /**
753 * Does this function's method needs to be variable arity (gather all script-declared parameters in a final
754 * {@code Object[]} parameter. Functions that need to have the "arguments" object as well as functions that simply
755 * declare too many arguments for JVM to handle with fixed arity will need to be variable arity.
756 * @return true if the Java method in the generated code that implements this function needs to be variable arity.
757 * @see #needsArguments()
758 * @see LinkerCallSite#ARGLIMIT
759 */
760 public boolean isVarArg() {
761 return needsArguments() || parameters.size() > LinkerCallSite.ARGLIMIT;
762 }
764 /**
765 * Flag this function as one that defines the identifier "arguments" as a function parameter or nested function
766 * name. This precludes it from needing to have an Arguments object defined as "arguments" local variable. Note that
767 * defining a local variable named "arguments" still requires construction of the Arguments object (see
768 * ECMAScript 5.1 Chapter 10.5).
769 * @see #needsArguments()
770 */
771 public void setDefinesArguments() {
772 this.flags |= DEFINES_ARGUMENTS;
773 }
775 /**
776 * Returns true if this function needs to have an Arguments object defined as a local variable named "arguments".
777 * Functions that use "arguments" as identifier and don't define it as a name of a parameter or a nested function
778 * (see ECMAScript 5.1 Chapter 10.5), as well as any function that uses eval or with, or has a nested function that
779 * does the same, will have an "arguments" object. Also, if this function is a script, it will not have an
780 * "arguments" object, because it does not have local variables; rather the Global object will have an explicit
781 * "arguments" property that provides command-line arguments for the script.
782 * @return true if this function needs an arguments object.
783 */
784 public boolean needsArguments() {
785 // uses "arguments" or calls eval, but it does not redefine "arguments", and finally, it's not a script, since
786 // for top-level script, "arguments" is picked up from Context by Global.init() instead.
787 return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isScript();
788 }
790 /**
791 * Flags this function as one that uses the "arguments" identifier.
792 * @see #needsArguments()
793 */
794 public void setUsesArguments() {
795 flags |= USES_ARGUMENTS;
796 }
798 /**
799 * Returns true if this function needs access to its parent scope. Functions referencing variables outside their
800 * scope (including global variables), as well as functions that call eval or have a with block, or have nested
801 * functions that call eval or have a with block, will need a parent scope. Top-level script functions also need a
802 * parent scope since they might be used from within eval, and eval will need an externally passed scope.
803 * @return true if the function needs parent scope.
804 */
805 public boolean needsParentScope() {
806 return (flags & NEEDS_PARENT_SCOPE) != 0 || isScript();
807 }
809 /**
810 * Return the kind of this function
811 * @see FunctionNode.Kind
812 * @return the kind
813 */
814 public Kind getKind() {
815 return kind;
816 }
818 /**
819 * Set the kind of this function
820 * @see FunctionNode.Kind
821 * @param kind the kind
822 */
823 public void setKind(final Kind kind) {
824 this.kind = kind;
825 }
827 /**
828 * Return the last token for this function's code
829 * @return last token
830 */
831 public long getLastToken() {
832 return lastToken;
833 }
835 /**
836 * Set the last token for this function's code
837 * @param lastToken the last token
838 */
839 public void setLastToken(final long lastToken) {
840 this.lastToken = lastToken;
841 }
843 /**
844 * Get the name of this function
845 * @return the name
846 */
847 public String getName() {
848 return name;
849 }
851 /**
852 * Set the name of this function
853 * @param name the name
854 */
855 public void setName(final String name) {
856 this.name = name;
857 }
859 /**
860 * Check if this function should have all its variables in its own scope. Scripts, split sub-functions, and
861 * functions having with and/or eval blocks are such.
862 *
863 * @return true if all variables should be in scope
864 */
865 public boolean varsInScope() {
866 return isScript() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0;
867 }
869 /**
870 * Checks if this function is a sub-function generated by splitting a larger one
871 *
872 * @return true if this function is split from a larger one
873 */
874 public boolean isSplit() {
875 return (flags & IS_SPLIT) != 0;
876 }
878 /**
879 * Flag this function node as being a sub-function generated by the splitter
880 */
881 public void setIsSplit() {
882 this.flags |= IS_SPLIT;
883 setNeedsScope();
884 }
886 /**
887 * Get the parameters to this function
888 * @return a list of IdentNodes which represent the function parameters, in order
889 */
890 public List<IdentNode> getParameters() {
891 return Collections.unmodifiableList(parameters);
892 }
894 /**
895 * Set the paremeters to this function
896 * @param parameters a list of IdentNodes representing parameters in left to right order
897 */
898 public void setParameters(final List<IdentNode> parameters) {
899 this.parameters = parameters;
900 }
902 /**
903 * Get the identifier for the variable in which the function return value
904 * should be stored
905 * @return an IdentNode representing the return value
906 */
907 public IdentNode getResultNode() {
908 return resultNode;
909 }
911 /**
912 * Set the identifier representing the variable in which the function return
913 * value should be stored
914 * @param resultNode an IdentNode representing the return value
915 */
916 public void setResultNode(final IdentNode resultNode) {
917 this.resultNode = resultNode;
918 }
920 /**
921 * Get the identifier representing this function's scope
922 * @return an IdentNode representing this function's scope
923 */
924 public IdentNode getScopeNode() {
925 return scopeNode;
926 }
928 /**
929 * Set the identifier representing this function's scope
930 * @param scopeNode an IdentNode representing this function's scope
931 */
932 public void setScopeNode(final IdentNode scopeNode) {
933 this.scopeNode = scopeNode;
934 }
936 /**
937 * Check if this function is a statement
938 * @return true if function is a statement
939 */
940 public boolean isStatement() {
941 return (flags & IS_STATEMENT) != 0;
942 }
944 /**
945 * Flag this function as a statement
946 * @see Parser
947 */
948 public void setIsStatement() {
949 this.flags |= IS_STATEMENT;
950 }
952 /**
953 * Check if this function is anonymous
954 * @return true if function is anonymous
955 */
956 public boolean isAnonymous() {
957 return (flags & IS_ANONYMOUS) != 0;
958 }
960 /**
961 * Flag this function as an anonymous function.
962 * @see Parser
963 */
964 public void setIsAnonymous() {
965 this.flags |= IS_ANONYMOUS;
966 }
968 /**
969 * Does this function need a self symbol - this is needed only for self
970 * referring functions
971 * @return true if function needs a symbol for self
972 */
973 public boolean needsSelfSymbol() {
974 return (flags & NEEDS_SELF_SYMBOL) != 0;
975 }
977 /**
978 * Get the initializer statement for the __callee__ variable, where applicable
979 * for self references
980 * @return initialization
981 */
982 public Node getSelfSymbolInit() {
983 return this.selfSymbolInit;
984 }
986 /**
987 * Flag the function as needing a self symbol. This is needed only for
988 * self referring functions
989 * @param selfSymbolInit initialization expression for self symbol
990 */
991 public void setNeedsSelfSymbol(final Node selfSymbolInit) {
992 this.flags |= NEEDS_SELF_SYMBOL;
993 this.selfSymbolInit = selfSymbolInit;
994 }
996 /**
997 * Marks this function as one using any global symbol. The function and all its parent functions will all be marked
998 * as needing parent scope.
999 * @see #needsParentScope()
1000 */
1001 public void setUsesGlobalSymbol() {
1002 this.flags |= USES_ANCESTOR_SCOPE;
1003 final FunctionNode parentFn = findParentFunction();
1004 if(parentFn != null) {
1005 parentFn.setUsesGlobalSymbol();
1006 }
1007 }
1009 /**
1010 * Marks this function as using a specified scoped symbol. The function and its parent functions up to but not
1011 * including the function defining the symbol will be marked as needing parent scope. The function defining the
1012 * symbol will be marked as one that needs to have its own scope.
1013 * @param symbol the symbol being used.
1014 * @see #needsParentScope()
1015 */
1016 public void setUsesScopeSymbol(final Symbol symbol) {
1017 if(symbol.getBlock() == this) {
1018 setNeedsScope();
1019 } else {
1020 this.flags |= USES_ANCESTOR_SCOPE;
1021 final FunctionNode parentFn = findParentFunction();
1022 if(parentFn != null) {
1023 parentFn.setUsesScopeSymbol(symbol);
1024 }
1025 }
1026 }
1028 /**
1029 * Return the node representing {@code this} in this function
1030 * @return IdentNode representing {@code this}
1031 */
1032 public IdentNode getThisNode() {
1033 return thisNode;
1034 }
1036 /**
1037 * Set the node representing {@code this} in this function
1038 * @param thisNode identifier representing {@code this}
1039 */
1040 public void setThisNode(final IdentNode thisNode) {
1041 this.thisNode = thisNode;
1042 }
1044 /**
1045 * Every function declared as {@code function x()} is internally hoisted
1046 * and represented as {@code var x = function() ... }. This getter returns
1047 * the VarNode representing this virtual assignment
1048 *
1049 * @return the var node emitted for setting this function symbol
1050 */
1051 public VarNode getFunctionVarNode() {
1052 return funcVarNode;
1053 }
1055 /**
1056 * Set the virtual VarNode assignment for this function.
1057 * @see FunctionNode#getFunctionVarNode()
1058 *
1059 * @param varNode the virtual var node assignment
1060 */
1061 public void setFunctionVarNode(final VarNode varNode) {
1062 funcVarNode = varNode;
1063 }
1065 /**
1066 * The line number information where the function was declared must be propagated
1067 * to the virtual {@code var x = function() ... } assignment described in
1068 * {@link FunctionNode#getFunctionVarNode()}
1069 * This maintains the line number of the declaration
1070 *
1071 * @return a line number node representing the line this function was declared
1072 */
1073 public LineNumberNode getFunctionVarLineNumberNode() {
1074 return funcVarLineNumberNode;
1075 }
1077 /**
1078 * Set the virtual VarNode assignment for this function, along with
1079 * a line number node for tracking the original start line of the function
1080 * declaration
1081 *
1082 * @param varNode the virtual var node assignment
1083 * @param lineNumber the line number node for the function declaration
1084 */
1085 public void setFunctionVarNode(final VarNode varNode, final LineNumberNode lineNumber) {
1086 funcVarNode = varNode;
1087 funcVarLineNumberNode = lineNumber;
1088 }
1090 /**
1091 * Get the namespace this function uses for its symbols
1092 * @return the namespace
1093 */
1094 public Namespace getNamespace() {
1095 return namespace;
1096 }
1098 @Override
1099 public Type getType() {
1100 return getReturnType();
1101 }
1103 /**
1104 * Get the return type for this function. Return types can be specialized
1105 * if the compiler knows them, but parameters cannot, as they need to go through
1106 * appropriate object conversion
1107 *
1108 * @return the return type
1109 */
1110 public Type getReturnType() {
1111 return returnType;
1112 }
1114 /**
1115 * Set the function return type
1116 *
1117 * @param returnType new return type
1118 */
1119 public void setReturnType(final Type returnType) {
1120 //we never bother with object types narrower than objects, that will lead to byte code verification errors
1121 //as for instance even if we know we are returning a string from a method, the code generator will always
1122 //treat it as an object, at least for now
1123 this.returnType = Type.widest(this.returnType, returnType.isObject() ? Type.OBJECT : returnType);
1124 }
1126 /**
1127 * Set strict mode on or off for this function
1128 *
1129 * @param isStrictMode true if strict mode should be enabled
1130 */
1131 public void setStrictMode(final boolean isStrictMode) {
1132 flags = isStrictMode ? flags | IS_STRICT_MODE : flags & ~IS_STRICT_MODE;
1133 }
1135 /**
1136 * Check if the function is generated in strict mode
1137 * @return true if strict mode enabled for function
1138 */
1139 public boolean isStrictMode() {
1140 return (flags & IS_STRICT_MODE) != 0;
1141 }
1143 /**
1144 * Set the lowered state
1145 */
1146 public void setIsLowered() {
1147 flags |= IS_LOWERED;
1148 }
1150 /**
1151 * Get the lowered state
1152 *
1153 * @return true if function is lowered
1154 */
1155 public boolean isLowered() {
1156 return (flags & IS_LOWERED) != 0;
1157 }
1159 /**
1160 * Add a new function to the function list.
1161 *
1162 * @param functionNode Function node to add.
1163 */
1164 @Override
1165 public void addFunction(final FunctionNode functionNode) {
1166 assert functionNode != null;
1167 functions.add(functionNode);
1168 }
1170 /**
1171 * Add a list of functions to the function list.
1172 *
1173 * @param functionNodes Function nodes to add.
1174 */
1175 @Override
1176 public void addFunctions(final List<FunctionNode> functionNodes) {
1177 functions.addAll(functionNodes);
1178 }
1180 /**
1181 * Set a function list
1182 *
1183 * @param functionNodes to set
1184 */
1185 @Override
1186 public void setFunctions(final List<FunctionNode> functionNodes) {
1187 this.functions = functionNodes;
1188 }
1190 /**
1191 * Add a variable declaration that should be visible to the entire function
1192 * scope. Parser does this.
1193 *
1194 * @param varNode a var node
1195 */
1196 public void addDeclaration(final VarNode varNode) {
1197 declarations.add(varNode);
1198 }
1200 /**
1201 * Return all variable declarations from this function scope
1202 *
1203 * @return all VarNodes in scope
1204 */
1205 public List<VarNode> getDeclarations() {
1206 return Collections.unmodifiableList(declarations);
1207 }
1209 /**
1210 * Get the compile unit used to compile this function
1211 * @see Compiler
1212 * @return the compile unit
1213 */
1214 public CompileUnit getCompileUnit() {
1215 return compileUnit;
1216 }
1218 /**
1219 * Reset the compile unit used to compile this function
1220 * @see Compiler
1221 * @param compileUnit the compile unit
1222 */
1223 public void setCompileUnit(final CompileUnit compileUnit) {
1224 this.compileUnit = compileUnit;
1225 }
1227 /**
1228 * Return the method emitter used to write bytecode for this function
1229 * @return the method emitter
1230 */
1231 public MethodEmitter getMethodEmitter() {
1232 return method;
1233 }
1235 /**
1236 * Set the method emitter that is to be used to write bytecode for this function
1237 * @param method a method emitter
1238 */
1239 public void setMethodEmitter(final MethodEmitter method) {
1240 this.method = method;
1241 }
1243 /**
1244 * Each FunctionNode maintains a list of reference to its parent blocks.
1245 * Add a parent block to this function.
1246 *
1247 * @param parentBlock a block to remember as parent
1248 */
1249 public void addReferencingParentBlock(final Block parentBlock) {
1250 assert parentBlock.getFunction() == function.findParentFunction(); // all parent blocks must be in the same function
1251 if (parentBlock != function.getParent()) {
1252 if (referencingParentBlocks == null) {
1253 referencingParentBlocks = new LinkedList<>();
1254 }
1255 referencingParentBlocks.add(parentBlock);
1256 }
1257 }
1259 /**
1260 * Get the known parent blocks to this function
1261 *
1262 * @return list of parent blocks
1263 */
1264 public List<Block> getReferencingParentBlocks() {
1265 if (referencingParentBlocks == null) {
1266 return Collections.emptyList();
1267 }
1268 return Collections.unmodifiableList(referencingParentBlocks);
1269 }
1270 }