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