src/jdk/nashorn/internal/ir/FunctionNode.java

Mon, 18 Feb 2013 16:00:15 +0100

author
attila
date
Mon, 18 Feb 2013 16:00:15 +0100
changeset 101
f8221ce53c2e
parent 89
43e32b36153c
child 108
a971adb68f38
permissions
-rw-r--r--

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();
  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);
  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;
  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;
  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
  1049      * @return the var node emitted for setting this function symbol
  1050      */
  1051     public VarNode getFunctionVarNode() {
  1052         return funcVarNode;
  1055     /**
  1056      * Set the virtual VarNode assignment for this function.
  1057      * @see FunctionNode#getFunctionVarNode()
  1059      * @param varNode the virtual var node assignment
  1060      */
  1061     public void setFunctionVarNode(final VarNode varNode) {
  1062         funcVarNode = varNode;
  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
  1071      * @return a line number node representing the line this function was declared
  1072      */
  1073     public LineNumberNode getFunctionVarLineNumberNode() {
  1074         return funcVarLineNumberNode;
  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
  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;
  1090     /**
  1091      * Get the namespace this function uses for its symbols
  1092      * @return the namespace
  1093      */
  1094     public Namespace getNamespace() {
  1095         return namespace;
  1098     @Override
  1099     public Type getType() {
  1100         return getReturnType();
  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
  1108      * @return the return type
  1109      */
  1110     public Type getReturnType() {
  1111         return returnType;
  1114     /**
  1115      * Set the function return type
  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);
  1126     /**
  1127      * Set strict mode on or off for this function
  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;
  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;
  1143     /**
  1144      * Set the lowered state
  1145      */
  1146     public void setIsLowered() {
  1147         flags |= IS_LOWERED;
  1150     /**
  1151      * Get the lowered state
  1153      * @return true if function is lowered
  1154      */
  1155     public boolean isLowered() {
  1156         return (flags & IS_LOWERED) != 0;
  1159     /**
  1160      * Add a new function to the function list.
  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);
  1170     /**
  1171      * Add a list of functions to the function list.
  1173      * @param functionNodes  Function nodes to add.
  1174      */
  1175     @Override
  1176     public void addFunctions(final List<FunctionNode> functionNodes) {
  1177         functions.addAll(functionNodes);
  1180     /**
  1181      * Set a function list
  1183      * @param functionNodes to set
  1184      */
  1185     @Override
  1186     public void setFunctions(final List<FunctionNode> functionNodes) {
  1187         this.functions = functionNodes;
  1190     /**
  1191      * Add a variable declaration that should be visible to the entire function
  1192      * scope. Parser does this.
  1194      * @param varNode a var node
  1195      */
  1196     public void addDeclaration(final VarNode varNode) {
  1197         declarations.add(varNode);
  1200     /**
  1201      * Return all variable declarations from this function scope
  1203      * @return all VarNodes in scope
  1204      */
  1205     public List<VarNode> getDeclarations() {
  1206         return Collections.unmodifiableList(declarations);
  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;
  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;
  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;
  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;
  1243     /**
  1244      * Each FunctionNode maintains a list of reference to its parent blocks.
  1245      * Add a parent block to this function.
  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<>();
  1255             referencingParentBlocks.add(parentBlock);
  1259     /**
  1260      * Get the known parent blocks to this function
  1262      * @return list of parent blocks
  1263      */
  1264     public List<Block> getReferencingParentBlocks() {
  1265         if (referencingParentBlocks == null) {
  1266             return Collections.emptyList();
  1268         return Collections.unmodifiableList(referencingParentBlocks);

mercurial