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