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