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