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