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