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