Sat, 23 Mar 2013 00:58:39 +0100
8010652: Eliminate non-child references in Block/FunctionNode, and make few node types immutable
Reviewed-by: jlaskey, lagergren
1 /*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
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.HashMap;
37 import java.util.Iterator;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Stack;
41 import jdk.nashorn.internal.codegen.CompileUnit;
42 import jdk.nashorn.internal.codegen.Compiler;
43 import jdk.nashorn.internal.codegen.Frame;
44 import jdk.nashorn.internal.codegen.MethodEmitter;
45 import jdk.nashorn.internal.codegen.Namespace;
46 import jdk.nashorn.internal.codegen.types.Type;
47 import jdk.nashorn.internal.ir.annotations.Ignore;
48 import jdk.nashorn.internal.ir.visitor.NodeVisitor;
49 import jdk.nashorn.internal.parser.Parser;
50 import jdk.nashorn.internal.runtime.ScriptFunction;
51 import jdk.nashorn.internal.runtime.Source;
52 import jdk.nashorn.internal.runtime.UserAccessorProperty;
53 import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
55 /**
56 * IR representation for function (or script.)
57 */
58 public class FunctionNode extends Block {
60 private static final Type FUNCTION_TYPE = Type.typeFor(ScriptFunction.class);
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 }
74 /** Compilation states available */
75 public enum CompilationState {
76 /** compiler is ready */
77 INITIALIZED,
78 /** method has been parsed */
79 PARSED,
80 /** method has been parsed */
81 PARSE_ERROR,
82 /** constant folding pass */
83 CONSTANT_FOLDED,
84 /** method has been lowered */
85 LOWERED,
86 /** method hass been attributed */
87 ATTR,
88 /** method has been split */
89 SPLIT,
90 /** method has had its types finalized */
91 FINALIZED,
92 /** method has been emitted to bytecode */
93 EMITTED,
94 /** code installed in a class loader */
95 INSTALLED
96 }
98 /** External function identifier. */
99 @Ignore
100 private IdentNode ident;
102 /** Internal function name. */
103 private String name;
105 /** Compilation unit. */
106 private CompileUnit compileUnit;
108 /** Method emitter for current method. */
109 private MethodEmitter method;
111 /** Function kind. */
112 private Kind kind;
114 /** List of parameters. */
115 private List<IdentNode> parameters;
117 /** First token of function. **/
118 private long firstToken;
120 /** Last token of function. **/
121 private long lastToken;
123 /** Variable frames. */
124 private Frame frames;
126 /** Method's namespace. */
127 private final Namespace namespace;
129 /** Node representing current this. */
130 @Ignore
131 private IdentNode thisNode;
133 /** Node representing current scope. */
134 @Ignore
135 private IdentNode scopeNode;
137 /** Node representing return value. */
138 @Ignore
139 private IdentNode resultNode;
141 /** Node representing current arguments. */
142 @Ignore
143 private IdentNode argumentsNode;
145 /** Node representing callee */
146 @Ignore
147 private IdentNode calleeNode;
149 /** Node representing varargs */
150 @Ignore
151 private IdentNode varArgsNode;
153 /** Pending label list. */
154 private final Stack<LabelNode> labelStack;
156 /** Pending control list. */
157 private final Stack<Node> controlStack;
159 /** VarNode for this function statement */
160 @Ignore //this is explicit code anyway and should not be traversed after lower
161 private VarNode funcVarNode;
163 /** Line number for function declaration */
164 @Ignore
165 private LineNumberNode funcVarLineNumberNode;
167 /** Initializer var func = __callee__, where applicable */
168 @Ignore
169 private Node selfSymbolInit;
171 /** Current compilation state */
172 @Ignore
173 private final EnumSet<CompilationState> compilationState;
175 /** Type hints, e.g based on parameters at call site */
176 private final Map<IdentNode, Type> specializedTypes;
178 /** Function flags. */
179 private int flags;
181 /** Is anonymous function flag. */
182 private static final int IS_ANONYMOUS = 1 << 0;
183 /** Is the function created in a function declaration (as opposed to a function expression) */
184 private static final int IS_DECLARED = 1 << 1;
185 /** is this a strict mode function? */
186 private static final int IS_STRICT_MODE = 1 << 2;
187 /** Does the function use the "arguments" identifier ? */
188 private static final int USES_ARGUMENTS = 1 << 3;
189 /** Are we lowered ? */
190 private static final int IS_LOWERED = 1 << 4;
191 /** Has this node been split because it was too large? */
192 private static final int IS_SPLIT = 1 << 5;
193 /** Does the function call eval? */
194 private static final int HAS_EVAL = 1 << 6;
195 /** Does the function contain a with block ? */
196 private static final int HAS_WITH = 1 << 7;
197 /** Does a descendant function contain a with or eval? */
198 private static final int HAS_DESCENDANT_WITH_OR_EVAL = 1 << 8;
199 /** Does the function define "arguments" identifier as a parameter of nested function name? */
200 private static final int DEFINES_ARGUMENTS = 1 << 9;
201 /** Does the function need a self symbol? */
202 private static final int NEEDS_SELF_SYMBOL = 1 << 10;
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 = 1 << 11;
205 /** Is this function lazily compiled? */
206 private static final int IS_LAZY = 1 << 12;
207 /** Does this function have lazy, yet uncompiled children */
208 private static final int HAS_LAZY_CHILDREN = 1 << 13;
209 /** Does this function have lazy, yet uncompiled children */
210 private static final int IS_PROGRAM = 1 << 14;
212 /** Does this function or any nested functions contain a with or an eval? */
213 private static final int HAS_DEEP_WITH_OR_EVAL = HAS_EVAL | HAS_WITH | HAS_DESCENDANT_WITH_OR_EVAL;
214 /** Does this function need to store all its variables in scope? */
215 private static final int HAS_ALL_VARS_IN_SCOPE = HAS_DEEP_WITH_OR_EVAL | IS_SPLIT | HAS_LAZY_CHILDREN;
216 /** Does this function potentially need "arguments"? Note that this is not a full test, as further negative check of REDEFINES_ARGS is needed. */
217 private static final int MAYBE_NEEDS_ARGUMENTS = USES_ARGUMENTS | HAS_EVAL;
218 /** 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.
219 * We also pessimistically need a parent scope if we have lazy children that have not yet been compiled */
220 private static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_WITH_OR_EVAL | HAS_LAZY_CHILDREN;
222 /** What is the return type of this function? */
223 private Type returnType = Type.UNKNOWN;
225 /**
226 * Constructor
227 *
228 * @param source the source
229 * @param token token
230 * @param finish finish
231 * @param namespace the namespace
232 * @param ident the identifier
233 * @param name the name of the function
234 */
235 public FunctionNode(final Source source, final long token, final int finish, final Namespace namespace, final IdentNode ident, final String name) {
236 super(source, token, finish);
238 this.ident = ident;
239 this.name = name;
240 this.kind = Kind.NORMAL;
241 this.parameters = new ArrayList<>();
242 this.firstToken = token;
243 this.lastToken = token;
244 this.namespace = namespace;
245 this.labelStack = new Stack<>();
246 this.controlStack = new Stack<>();
247 this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
248 this.specializedTypes = new HashMap<>();
249 }
251 private FunctionNode(final FunctionNode functionNode, final CopyState cs) {
252 super(functionNode, cs);
254 this.ident = (IdentNode)cs.existingOrCopy(functionNode.ident);
255 this.name = functionNode.name;
256 this.kind = functionNode.kind;
258 this.parameters = new ArrayList<>();
259 for (final IdentNode param : functionNode.getParameters()) {
260 this.parameters.add((IdentNode)cs.existingOrCopy(param));
261 }
263 this.firstToken = functionNode.firstToken;
264 this.lastToken = functionNode.lastToken;
265 this.namespace = functionNode.getNamespace();
266 this.thisNode = (IdentNode)cs.existingOrCopy(functionNode.thisNode);
267 this.scopeNode = (IdentNode)cs.existingOrCopy(functionNode.scopeNode);
268 this.resultNode = (IdentNode)cs.existingOrCopy(functionNode.resultNode);
269 this.argumentsNode = (IdentNode)cs.existingOrCopy(functionNode.argumentsNode);
270 this.varArgsNode = (IdentNode)cs.existingOrCopy(functionNode.varArgsNode);
271 this.calleeNode = (IdentNode)cs.existingOrCopy(functionNode.calleeNode);
272 this.labelStack = new Stack<>();
273 this.controlStack = new Stack<>();
275 this.flags = functionNode.flags;
277 this.funcVarNode = (VarNode)cs.existingOrCopy(functionNode.funcVarNode);
278 /** VarNode for this function statement */
280 this.compilationState = EnumSet.copyOf(functionNode.compilationState);
281 this.specializedTypes = new HashMap<>();
282 }
284 @Override
285 protected Node copy(final CopyState cs) {
286 // deep clone all parent blocks
287 return new FunctionNode(this, cs);
288 }
290 @Override
291 public Node accept(final NodeVisitor visitor) {
292 final FunctionNode saveFunctionNode = visitor.getCurrentFunctionNode();
293 final Block saveBlock = visitor.getCurrentBlock();
294 final MethodEmitter saveMethodEmitter = visitor.getCurrentMethodEmitter();
295 final CompileUnit saveCompileUnit = visitor.getCurrentCompileUnit();
297 visitor.setCurrentFunctionNode(this);
298 visitor.setCurrentBlock(this);
300 try {
301 if (visitor.enterFunctionNode(this) != null) {
302 if (ident != null) {
303 ident = (IdentNode)ident.accept(visitor);
304 }
306 for (int i = 0, count = parameters.size(); i < count; i++) {
307 parameters.set(i, (IdentNode)parameters.get(i).accept(visitor));
308 }
310 for (int i = 0, count = statements.size(); i < count; i++) {
311 statements.set(i, statements.get(i).accept(visitor));
312 }
314 return visitor.leaveFunctionNode(this);
315 }
316 } finally {
317 visitor.setCurrentBlock(saveBlock);
318 visitor.setCurrentFunctionNode(saveFunctionNode);
319 visitor.setCurrentCompileUnit(saveCompileUnit);
320 visitor.setCurrentMethodEmitter(saveMethodEmitter);
321 }
323 return this;
324 }
326 @Override
327 public boolean needsScope() {
328 return super.needsScope() || isProgram();
329 }
331 /**
332 * Check whether this FunctionNode has reached a give CompilationState.
333 *
334 * @param state the state to check for
335 * @return true of the node is in the given state
336 */
337 public boolean hasState(final EnumSet<CompilationState> state) {
338 return compilationState.equals(state);
339 }
341 /**
342 * Check whether the state of this FunctionNode contains a given compilation
343 * state.
344 *
345 * A node can be in many states at once, e.g. both lowered and initialized.
346 * To check for an exact state, use {FunctionNode{@link #hasState(EnumSet)}
347 *
348 * @param state state to check for
349 * @return true if state is present in the total compilation state of this FunctionNode
350 */
351 public boolean hasState(final CompilationState state) {
352 return compilationState.contains(state);
353 }
355 /**
356 * Add a state to the total CompilationState of this node, e.g. if
357 * FunctionNode has been lowered, the compiler will add
358 * {@code CompilationState#LOWERED} to the state vector
359 *
360 * @param state {@link CompilationState} to add
361 */
362 public void setState(final CompilationState state) {
363 compilationState.add(state);
364 }
366 /*
367 * Frame management.
368 */
370 /**
371 * Push a new block frame.
372 *
373 * @return the new frame
374 */
375 public final Frame pushFrame() {
376 frames = new Frame(frames);
377 return frames;
378 }
380 /**
381 * Pop a block frame.
382 */
383 public final void popFrame() {
384 frames = frames.getPrevious();
385 }
387 /**
388 * Create a temporary variable to the current frame.
389 *
390 * @param currentFrame Frame to add to - defaults to current function frame
391 * @param type Strong type of symbol.
392 * @param node Primary node to use symbol.
393 *
394 * @return Symbol used.
395 */
396 public Symbol newTemporary(final Frame currentFrame, final Type type, final Node node) {
397 assert currentFrame != null;
398 Symbol symbol = node.getSymbol();
400 // If no symbol already present.
401 if (symbol == null) {
402 final String uname = uniqueName(TEMP_PREFIX.tag());
403 symbol = new Symbol(uname, IS_TEMP, type);
404 symbol.setNode(node);
405 }
407 // Assign a slot if it doesn't have one.
408 if (!symbol.hasSlot()) {
409 currentFrame.addSymbol(symbol);
410 }
412 // Set symbol to node.
413 node.setSymbol(symbol);
415 return symbol;
416 }
418 /**
419 * Create a unique name in the namespace of this FunctionNode
420 * @param base prefix for name
421 * @return base if no collision exists, otherwise a name prefix with base
422 */
423 public String uniqueName(final String base) {
424 return namespace.uniqueName(base);
425 }
427 /**
428 * Add a new temporary variable to the current frame
429 *
430 * @param type Strong type of symbol
431 * @param node Primary node to use symbol
432 *
433 * @return symbol used
434 */
435 public Symbol newTemporary(final Type type, final Node node) {
436 return newTemporary(frames, type, node);
437 }
439 /**
440 * Create a virtual symbol for a literal.
441 *
442 * @param literalNode Primary node to use symbol.
443 *
444 * @return Symbol used.
445 */
446 public Symbol newLiteral(final LiteralNode<?> literalNode) {
447 final String uname = uniqueName(LITERAL_PREFIX.tag());
448 final Symbol symbol = new Symbol(uname, IS_CONSTANT, literalNode.getType());
449 symbol.setNode(literalNode);
450 literalNode.setSymbol(symbol);
452 return symbol;
453 }
455 @Override
456 public void toString(final StringBuilder sb) {
457 sb.append('[');
458 sb.append(returnType);
459 sb.append(']');
460 sb.append(' ');
462 sb.append("function");
464 if (ident != null) {
465 sb.append(' ');
466 ident.toString(sb);
467 }
469 sb.append('(');
470 boolean first = true;
472 for (final IdentNode parameter : parameters) {
473 if (!first) {
474 sb.append(", ");
475 } else {
476 first = false;
477 }
479 parameter.toString(sb);
480 }
482 sb.append(')');
483 }
485 /**
486 * Returns true if the function is the top-level program.
487 * @return True if this function node represents the top-level program.
488 */
489 public boolean isProgram() {
490 return (flags & IS_PROGRAM) != 0;
491 }
493 /**
494 * Marks the function as representing the top-level program.
495 */
496 public void setProgram() {
497 flags |= IS_PROGRAM;
498 }
500 /**
501 * Get the control stack. Used when parsing to establish nesting depths of
502 * different control structures
503 *
504 * @return the control stack
505 */
506 public Stack<Node> getControlStack() {
507 return controlStack;
508 }
510 /**
511 * Should this function node be lazily code generated, i.e. first at link time
512 * @return true if lazy
513 */
514 public boolean isLazy() {
515 return (flags & IS_LAZY) != 0;
516 }
518 /**
519 * Set if this function should be lazily generated
520 * @param isLazy is lazy
521 */
522 public void setIsLazy(final boolean isLazy) {
523 this.flags = isLazy ? flags | IS_LAZY : flags & ~IS_LAZY;
524 }
526 /**
527 * Check if the {@code with} keyword is used in this function
528 *
529 * @return true if {@code with} is used
530 */
531 public boolean hasWith() {
532 return (flags & HAS_WITH) != 0;
533 }
535 /**
536 * Flag this function as using the {@code with} keyword
537 * @param ancestors the iterator over functions in this functions's containing lexical context
538 */
539 public void setHasWith(final Iterator<FunctionNode> ancestors) {
540 if(!hasWith()) {
541 this.flags |= HAS_WITH;
542 // with requires scope in parents.
543 // TODO: refine this. with should not force all variables in parents to be in scope, only those that are
544 // actually referenced as identifiers by name
545 markParentForWithOrEval(ancestors);
546 }
547 }
549 private void markParentForWithOrEval(final Iterator<FunctionNode> ancestors) {
550 // If this is invoked, then either us or a descendant uses with or eval, meaning we must have our own scope.
551 setNeedsScope();
553 if(ancestors.hasNext()) {
554 ancestors.next().setDescendantHasWithOrEval(ancestors);
555 }
556 }
558 private void setDescendantHasWithOrEval(final Iterator<FunctionNode> ancestors) {
559 if((flags & HAS_DESCENDANT_WITH_OR_EVAL) == 0) {
560 flags |= HAS_DESCENDANT_WITH_OR_EVAL;
561 markParentForWithOrEval(ancestors);
562 }
563 }
565 /**
566 * Check if the {@code eval} keyword is used in this function
567 *
568 * @return true if {@code eval} is used
569 */
570 public boolean hasEval() {
571 return (flags & HAS_EVAL) != 0;
572 }
574 /**
575 * Flag this function as calling the {@code eval} function
576 * @param ancestors the iterator over functions in this functions's containing lexical context
577 */
578 public void setHasEval(final Iterator<FunctionNode> ancestors) {
579 if(!hasEval()) {
580 this.flags |= HAS_EVAL;
581 markParentForWithOrEval(ancestors);
582 }
583 }
585 /**
586 * Test whether this function or any of its nested functions contains a <tt>with</tt> statement
587 * or an <tt>eval</tt> call.
588 *
589 * @see #hasWith()
590 * @see #hasEval()
591 * @return true if this or a nested function contains with or eval
592 */
593 public boolean hasDeepWithOrEval() {
594 return (flags & HAS_DEEP_WITH_OR_EVAL) != 0;
595 }
597 /**
598 * Get the first token for this function
599 * @return the first token
600 */
601 public long getFirstToken() {
602 return firstToken;
603 }
605 /**
606 * Set the first token for this function
607 * @param firstToken the first token
608 */
609 public void setFirstToken(final long firstToken) {
610 this.firstToken = firstToken;
611 }
613 /**
614 * Returns a list of functions declared by this function. Only includes declared functions, and does not include any
615 * function expressions that might occur in its body.
616 * @return a list of functions declared by this function.
617 */
618 public List<FunctionNode> getDeclaredFunctions() {
619 // Note that the function does not have a dedicated list of declared functions, but rather relies on the
620 // invariant that all function declarations are at the beginning of the statement list as VarNode with a
621 // FunctionNode marked as statement with its variable initializer. Every VarNode is also preceded by a
622 // LineNumberNode. This invariant is established by the parser and has to be preserved in visitors.
623 final List<FunctionNode> fns = new ArrayList<>();
624 for (final Node stmt : statements) {
625 if(stmt instanceof LineNumberNode) {
626 continue;
627 } else if(stmt instanceof VarNode) {
628 final Node init = ((VarNode)stmt).getInit();
629 if(init instanceof FunctionNode) {
630 final FunctionNode fn = (FunctionNode)init;
631 if(fn.isDeclared()) {
632 fns.add(fn);
633 continue;
634 }
635 }
636 }
637 // Node is neither a LineNumberNode, nor a function declaration VarNode. Since all function declarations are
638 // at the start of the function, we've reached the end of function declarations.
639 break;
640 }
641 return fns;
642 }
644 /**
645 * Get the label stack. This is used by the parser to establish
646 * label nesting depth
647 *
648 * @return the label stack
649 */
650 public Stack<LabelNode> getLabelStack() {
651 return labelStack;
652 }
654 /**
655 * If this function needs to use var args, return the identifier to the node used
656 * for the var args structure
657 *
658 * @return IdentNode representing the var args structure
659 */
660 public IdentNode getVarArgsNode() {
661 return varArgsNode;
662 }
664 /**
665 * Set the identifier to the node used for the var args structure
666 *
667 * @param varArgsNode IdentNode representing the var args
668 */
669 public void setVarArgsNode(final IdentNode varArgsNode) {
670 this.varArgsNode = varArgsNode;
671 }
673 /**
674 * If this function uses the {@code callee} variable, return the node used
675 * as this variable
676 *
677 * @return an IdentNode representing the {@code callee} variable
678 */
679 public IdentNode getCalleeNode() {
680 return calleeNode;
681 }
683 /**
684 * If this function uses the {@code callee} variable, set the node representing the
685 * callee
686 * @param calleeNode an IdentNode representing the callee
687 */
688 public void setCalleeNode(final IdentNode calleeNode) {
689 this.calleeNode = calleeNode;
690 }
692 /**
693 * Check if this function's generated Java method needs a {@code callee} parameter. Functions that need access to
694 * their parent scope, functions that reference themselves, and non-strict functions that need an Arguments object
695 * (since it exposes {@code arguments.callee} property) will need to have a callee parameter.
696 *
697 * @return true if the function's generated Java method needs a {@code callee} parameter.
698 */
699 public boolean needsCallee() {
700 return needsParentScope() || needsSelfSymbol() || (needsArguments() && !isStrictMode());
701 }
703 /**
704 * If this is a function where {@code arguments} is used, return the node used as the {@code arguments}
705 * variable
706 * @return an IdentNode representing {@code arguments}
707 */
708 public IdentNode getArgumentsNode() {
709 return argumentsNode;
710 }
712 /**
713 * If this is a Function where {@code arguments} is used, an identifier to the node representing
714 * the {@code arguments} value has to be supplied by the compiler
715 *
716 * @param argumentsNode IdentNode that represents {@code arguments}
717 */
718 public void setArgumentsNode(final IdentNode argumentsNode) {
719 this.argumentsNode = argumentsNode;
720 }
722 /**
723 * Get the identifier for this function
724 * @return the identifier as an IdentityNode
725 */
726 public IdentNode getIdent() {
727 return ident;
728 }
730 /**
731 * Reset the identifier for this function
732 * @param ident IdentNode for new identifier
733 */
734 public void setIdent(final IdentNode ident) {
735 this.ident = ident;
736 }
738 /**
739 * Does this function's method needs to be variable arity (gather all script-declared parameters in a final
740 * {@code Object[]} parameter. Functions that need to have the "arguments" object as well as functions that simply
741 * declare too many arguments for JVM to handle with fixed arity will need to be variable arity.
742 * @return true if the Java method in the generated code that implements this function needs to be variable arity.
743 * @see #needsArguments()
744 * @see LinkerCallSite#ARGLIMIT
745 */
746 public boolean isVarArg() {
747 return needsArguments() || parameters.size() > LinkerCallSite.ARGLIMIT;
748 }
750 /**
751 * Flag this function as one that defines the identifier "arguments" as a function parameter or nested function
752 * name. This precludes it from needing to have an Arguments object defined as "arguments" local variable. Note that
753 * defining a local variable named "arguments" still requires construction of the Arguments object (see
754 * ECMAScript 5.1 Chapter 10.5).
755 * @see #needsArguments()
756 */
757 public void setDefinesArguments() {
758 this.flags |= DEFINES_ARGUMENTS;
759 }
761 /**
762 * Returns true if this function needs to have an Arguments object defined as a local variable named "arguments".
763 * Functions that use "arguments" as identifier and don't define it as a name of a parameter or a nested function
764 * (see ECMAScript 5.1 Chapter 10.5), as well as any function that uses eval or with, or has a nested function that
765 * does the same, will have an "arguments" object. Also, if this function is a script, it will not have an
766 * "arguments" object, because it does not have local variables; rather the Global object will have an explicit
767 * "arguments" property that provides command-line arguments for the script.
768 * @return true if this function needs an arguments object.
769 */
770 public boolean needsArguments() {
771 // uses "arguments" or calls eval, but it does not redefine "arguments", and finally, it's not a script, since
772 // for top-level script, "arguments" is picked up from Context by Global.init() instead.
773 return (flags & MAYBE_NEEDS_ARGUMENTS) != 0 && (flags & DEFINES_ARGUMENTS) == 0 && !isProgram();
774 }
776 /**
777 * Flags this function as one that uses the "arguments" identifier.
778 * @see #needsArguments()
779 */
780 public void setUsesArguments() {
781 flags |= USES_ARGUMENTS;
782 }
784 /**
785 * Returns true if this function needs access to its parent scope. Functions referencing variables outside their
786 * scope (including global variables), as well as functions that call eval or have a with block, or have nested
787 * functions that call eval or have a with block, will need a parent scope. Top-level script functions also need a
788 * parent scope since they might be used from within eval, and eval will need an externally passed scope.
789 * @return true if the function needs parent scope.
790 */
791 public boolean needsParentScope() {
792 return (flags & NEEDS_PARENT_SCOPE) != 0 || isProgram();
793 }
795 /**
796 * Return the kind of this function
797 * @see FunctionNode.Kind
798 * @return the kind
799 */
800 public Kind getKind() {
801 return kind;
802 }
804 /**
805 * Set the kind of this function
806 * @see FunctionNode.Kind
807 * @param kind the kind
808 */
809 public void setKind(final Kind kind) {
810 this.kind = kind;
811 }
813 /**
814 * Return the last token for this function's code
815 * @return last token
816 */
817 public long getLastToken() {
818 return lastToken;
819 }
821 /**
822 * Set the last token for this function's code
823 * @param lastToken the last token
824 */
825 public void setLastToken(final long lastToken) {
826 this.lastToken = lastToken;
827 }
829 /**
830 * Get the name of this function
831 * @return the name
832 */
833 public String getName() {
834 return name;
835 }
837 /**
838 * Set the name of this function
839 * @param name the name
840 */
841 public void setName(final String name) {
842 this.name = name;
843 }
845 /**
846 * Check if this function should have all its variables in its own scope. Scripts, split sub-functions, and
847 * functions having with and/or eval blocks are such.
848 *
849 * @return true if all variables should be in scope
850 */
851 public boolean allVarsInScope() {
852 return isProgram() || (flags & HAS_ALL_VARS_IN_SCOPE) != 0;
853 }
855 /**
856 * Checks if this function is a sub-function generated by splitting a larger one
857 *
858 * @return true if this function is split from a larger one
859 */
860 public boolean isSplit() {
861 return (flags & IS_SPLIT) != 0;
862 }
864 /**
865 * Flag this function node as being a sub-function generated by the splitter
866 */
867 public void setIsSplit() {
868 this.flags |= IS_SPLIT;
869 setNeedsScope();
870 }
872 /**
873 * Checks if this function has yet-to-be-generated child functions
874 *
875 * @return true if there are lazy child functions
876 */
877 public boolean hasLazyChildren() {
878 return (flags & HAS_LAZY_CHILDREN) != 0;
879 }
881 /**
882 * Flag this function node as having yet-to-be-generated child functions
883 */
884 public void setHasLazyChildren() {
885 this.flags |= HAS_LAZY_CHILDREN;
886 setNeedsScope();
887 }
889 /**
890 * Get the parameters to this function
891 * @return a list of IdentNodes which represent the function parameters, in order
892 */
893 public List<IdentNode> getParameters() {
894 return Collections.unmodifiableList(parameters);
895 }
897 /**
898 * Set the paremeters to this function
899 * @param parameters a list of IdentNodes representing parameters in left to right order
900 */
901 public void setParameters(final List<IdentNode> parameters) {
902 this.parameters = parameters;
903 }
905 /**
906 * Get a specialized type for an identity, if one exists
907 * @param node node to check specialized type for
908 * @return null if no specialization exists, otherwise type
909 */
910 public Type getSpecializedType(final IdentNode node) {
911 return specializedTypes.get(node);
912 }
914 /**
915 * Set parameter type hints for specialization.
916 * @param types types array of length equal to parameter list size
917 */
918 public void setParameterTypes(final Class<?>[] types) {
919 assert types.length == parameters.size() : "Type vector length doesn't correspond to parameter types";
920 //diff - skip the callee and this etc, they are not explicit params in the parse tree
921 for (int i = 0; i < types.length ; i++) {
922 specializedTypes.put(parameters.get(i), Type.typeFor(types[i]));
923 }
924 }
926 /**
927 * Get the identifier for the variable in which the function return value
928 * should be stored
929 * @return an IdentNode representing the return value
930 */
931 public IdentNode getResultNode() {
932 return resultNode;
933 }
935 /**
936 * Set the identifier representing the variable in which the function return
937 * value should be stored
938 * @param resultNode an IdentNode representing the return value
939 */
940 public void setResultNode(final IdentNode resultNode) {
941 this.resultNode = resultNode;
942 }
944 /**
945 * Get the identifier representing this function's scope
946 * @return an IdentNode representing this function's scope
947 */
948 public IdentNode getScopeNode() {
949 return scopeNode;
950 }
952 /**
953 * Set the identifier representing this function's scope
954 * @param scopeNode an IdentNode representing this function's scope
955 */
956 public void setScopeNode(final IdentNode scopeNode) {
957 this.scopeNode = scopeNode;
958 }
960 /**
961 * Check if this function is created as a function declaration (as opposed to function expression)
962 * @return true if function is declared.
963 */
964 public boolean isDeclared() {
965 return (flags & IS_DECLARED) != 0;
966 }
968 /**
969 * Flag this function as being created as a function declaration (as opposed to a function expression).
970 * @see Parser
971 */
972 public void setIsDeclared() {
973 this.flags |= IS_DECLARED;
974 }
976 /**
977 * Check if this function is anonymous
978 * @return true if function is anonymous
979 */
980 public boolean isAnonymous() {
981 return (flags & IS_ANONYMOUS) != 0;
982 }
984 /**
985 * Flag this function as an anonymous function.
986 * @see Parser
987 */
988 public void setIsAnonymous() {
989 this.flags |= IS_ANONYMOUS;
990 }
992 /**
993 * Does this function need a self symbol - this is needed only for self
994 * referring functions
995 * @return true if function needs a symbol for self
996 */
997 public boolean needsSelfSymbol() {
998 return (flags & NEEDS_SELF_SYMBOL) != 0;
999 }
1001 /**
1002 * Get the initializer statement for the __callee__ variable, where applicable
1003 * for self references
1004 * @return initialization
1005 */
1006 public Node getSelfSymbolInit() {
1007 return this.selfSymbolInit;
1008 }
1010 /**
1011 * Flag the function as needing a self symbol. This is needed only for
1012 * self referring functions
1013 * @param selfSymbolInit initialization expression for self symbol
1014 */
1015 public void setNeedsSelfSymbol(final Node selfSymbolInit) {
1016 this.flags |= NEEDS_SELF_SYMBOL;
1017 this.selfSymbolInit = selfSymbolInit;
1018 }
1020 /**
1021 * Marks this function as using any of its ancestors' scopes.
1022 */
1023 public void setUsesAncestorScope() {
1024 this.flags |= USES_ANCESTOR_SCOPE;
1025 }
1027 @Override
1028 void setUsesParentScopeSymbol(Symbol symbol, Iterator<Block> ancestors) {
1029 setUsesAncestorScope();
1030 super.setUsesParentScopeSymbol(symbol, ancestors);
1031 }
1033 /**
1034 * Return the node representing {@code this} in this function
1035 * @return IdentNode representing {@code this}
1036 */
1037 public IdentNode getThisNode() {
1038 return thisNode;
1039 }
1041 /**
1042 * Set the node representing {@code this} in this function
1043 * @param thisNode identifier representing {@code this}
1044 */
1045 public void setThisNode(final IdentNode thisNode) {
1046 this.thisNode = thisNode;
1047 }
1049 /**
1050 * Every function declared as {@code function x()} is internally hoisted
1051 * and represented as {@code var x = function() ... }. This getter returns
1052 * the VarNode representing this virtual assignment
1053 *
1054 * @return the var node emitted for setting this function symbol
1055 */
1056 public VarNode getFunctionVarNode() {
1057 return funcVarNode;
1058 }
1060 /**
1061 * Set the virtual VarNode assignment for this function.
1062 * @see FunctionNode#getFunctionVarNode()
1063 *
1064 * @param varNode the virtual var node assignment
1065 */
1066 public void setFunctionVarNode(final VarNode varNode) {
1067 funcVarNode = varNode;
1068 }
1070 /**
1071 * The line number information where the function was declared must be propagated
1072 * to the virtual {@code var x = function() ... } assignment described in
1073 * {@link FunctionNode#getFunctionVarNode()}
1074 * This maintains the line number of the declaration
1075 *
1076 * @return a line number node representing the line this function was declared
1077 */
1078 public LineNumberNode getFunctionVarLineNumberNode() {
1079 return funcVarLineNumberNode;
1080 }
1082 /**
1083 * Set the virtual VarNode assignment for this function, along with
1084 * a line number node for tracking the original start line of the function
1085 * declaration
1086 *
1087 * @param varNode the virtual var node assignment
1088 * @param lineNumber the line number node for the function declaration
1089 */
1090 public void setFunctionVarNode(final VarNode varNode, final LineNumberNode lineNumber) {
1091 funcVarNode = varNode;
1092 funcVarLineNumberNode = lineNumber;
1093 }
1095 /**
1096 * Get the namespace this function uses for its symbols
1097 * @return the namespace
1098 */
1099 public Namespace getNamespace() {
1100 return namespace;
1101 }
1103 @Override
1104 public Type getType() {
1105 return FUNCTION_TYPE;
1106 }
1108 /**
1109 * Get the return type for this function. Return types can be specialized
1110 * if the compiler knows them, but parameters cannot, as they need to go through
1111 * appropriate object conversion
1112 *
1113 * @return the return type
1114 */
1115 public Type getReturnType() {
1116 return returnType;
1117 }
1119 /**
1120 * Set the function return type
1121 *
1122 * @param returnType new return type
1123 */
1124 public void setReturnType(final Type returnType) {
1125 //we never bother with object types narrower than objects, that will lead to byte code verification errors
1126 //as for instance even if we know we are returning a string from a method, the code generator will always
1127 //treat it as an object, at least for now
1128 this.returnType = Type.widest(this.returnType, returnType.isObject() ? Type.OBJECT : returnType);
1129 }
1131 /**
1132 * Set strict mode on or off for this function
1133 *
1134 * @param isStrictMode true if strict mode should be enabled
1135 */
1136 public void setStrictMode(final boolean isStrictMode) {
1137 flags = isStrictMode ? flags | IS_STRICT_MODE : flags & ~IS_STRICT_MODE;
1138 }
1140 /**
1141 * Check if the function is generated in strict mode
1142 * @return true if strict mode enabled for function
1143 */
1144 public boolean isStrictMode() {
1145 return (flags & IS_STRICT_MODE) != 0;
1146 }
1148 /**
1149 * Set the lowered state
1150 */
1151 public void setIsLowered() {
1152 flags |= IS_LOWERED;
1153 }
1155 /**
1156 * Get the lowered state
1157 *
1158 * @return true if function is lowered
1159 */
1160 public boolean isLowered() {
1161 return (flags & IS_LOWERED) != 0;
1162 }
1164 /**
1165 * Get the compile unit used to compile this function
1166 * @see Compiler
1167 * @return the compile unit
1168 */
1169 public CompileUnit getCompileUnit() {
1170 return compileUnit;
1171 }
1173 /**
1174 * Reset the compile unit used to compile this function
1175 * @see Compiler
1176 * @param compileUnit the compile unit
1177 */
1178 public void setCompileUnit(final CompileUnit compileUnit) {
1179 this.compileUnit = compileUnit;
1180 }
1182 /**
1183 * Return the method emitter used to write bytecode for this function
1184 * @return the method emitter
1185 */
1186 public MethodEmitter getMethodEmitter() {
1187 return method;
1188 }
1190 /**
1191 * Set the method emitter that is to be used to write bytecode for this function
1192 * @param method a method emitter
1193 */
1194 public void setMethodEmitter(final MethodEmitter method) {
1195 this.method = method;
1196 }
1197 }