Symbol.java revision 1399:eea9202e8930
11541Srgrimes/* 21541Srgrimes * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 41541Srgrimes * 51541Srgrimes * This code is free software; you can redistribute it and/or modify it 61541Srgrimes * under the terms of the GNU General Public License version 2 only, as 71541Srgrimes * published by the Free Software Foundation. Oracle designates this 81541Srgrimes * particular file as subject to the "Classpath" exception as provided 91541Srgrimes * by Oracle in the LICENSE file that accompanied this code. 101541Srgrimes * 111541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT 121541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 131541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 141541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that 151541Srgrimes * accompanied this code). 161541Srgrimes * 171541Srgrimes * You should have received a copy of the GNU General Public License version 181541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation, 191541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 201541Srgrimes * 211541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 221541Srgrimes * or visit www.oracle.com if you need additional information or have any 231541Srgrimes * questions. 241541Srgrimes */ 251541Srgrimes 261541Srgrimespackage jdk.nashorn.internal.ir; 271541Srgrimes 281541Srgrimesimport java.io.IOException; 291541Srgrimesimport java.io.ObjectInputStream; 301541Srgrimesimport java.io.PrintWriter; 311541Srgrimesimport java.io.Serializable; 321541Srgrimesimport java.util.HashSet; 3322521Sdysonimport java.util.Set; 3450477Speterimport java.util.StringTokenizer; 351541Srgrimesimport jdk.nashorn.internal.codegen.types.Type; 361541Srgrimesimport jdk.nashorn.internal.runtime.Context; 372165Spaulimport jdk.nashorn.internal.runtime.Debug; 382165Spaulimport jdk.nashorn.internal.runtime.options.Options; 392165Spaul 401541Srgrimes/** 411541Srgrimes * Symbol is a symbolic address for a value ("variable" if you wish). Identifiers in JavaScript source, as well as 4222521Sdyson * certain synthetic variables created by the compiler are represented by Symbol objects. Symbols can address either 431541Srgrimes * local variable slots in bytecode ("slotted symbol"), or properties in scope objects ("scoped symbol"). A symbol can 4422521Sdyson * also end up being defined but then not used during symbol assignment calculations; such symbol will be neither 451541Srgrimes * scoped, nor slotted; it represents a dead variable (it might be written to, but is never read). Finally, a symbol can 461541Srgrimes * be both slotted and in scope. This special case can only occur with bytecode method parameters. They all come in as 471541Srgrimes * slotted, but if they are used by a nested function (or eval) then they will be copied into the scope object, and used 481541Srgrimes * from there onwards. Two further special cases are parameters stored in {@code NativeArguments} objects and parameters 491541Srgrimes * stored in {@code Object[]} parameter to variable-arity functions. Those use the {@code #getFieldIndex()} property to 501541Srgrimes * refer to their location. 511541Srgrimes */ 521541Srgrimes 531541Srgrimespublic final class Symbol implements Comparable<Symbol>, Cloneable, Serializable { 541541Srgrimes private static final long serialVersionUID = 1L; 551541Srgrimes 561541Srgrimes /** Is this Global */ 571541Srgrimes public static final int IS_GLOBAL = 1; 581541Srgrimes /** Is this a variable */ 591541Srgrimes public static final int IS_VAR = 2; 601541Srgrimes /** Is this a parameter */ 611541Srgrimes public static final int IS_PARAM = 3; 6222521Sdyson /** Mask for kind flags */ 6322521Sdyson public static final int KINDMASK = (1 << 2) - 1; // Kinds are represented by lower two bits 641541Srgrimes 651541Srgrimes /** Is this symbol in scope */ 6618006Sdg public static final int IS_SCOPE = 1 << 2; 671541Srgrimes /** Is this a this symbol */ 681541Srgrimes public static final int IS_THIS = 1 << 3; 691541Srgrimes /** Is this a let */ 701541Srgrimes public static final int IS_LET = 1 << 4; 711541Srgrimes /** Is this a const */ 721541Srgrimes public static final int IS_CONST = 1 << 5; 731541Srgrimes /** Is this an internal symbol, never represented explicitly in source code */ 741541Srgrimes public static final int IS_INTERNAL = 1 << 6; 7518006Sdg /** Is this a function self-reference symbol */ 7641169Sbde public static final int IS_FUNCTION_SELF = 1 << 7; 7731132Sjulian /** Is this a function declaration? */ 7834266Sjulian public static final int IS_FUNCTION_DECLARATION = 1 << 8; 7934266Sjulian /** Is this a program level symbol? */ 8022521Sdyson public static final int IS_PROGRAM_LEVEL = 1 << 9; 811541Srgrimes /** Are this symbols' values stored in local variable slots? */ 821541Srgrimes public static final int HAS_SLOT = 1 << 10; 831541Srgrimes /** Is this symbol known to store an int value ? */ 841541Srgrimes public static final int HAS_INT_VALUE = 1 << 11; 851541Srgrimes /** Is this symbol known to store a long value ? */ 861541Srgrimes public static final int HAS_LONG_VALUE = 1 << 12; 871541Srgrimes /** Is this symbol known to store a double value ? */ 881541Srgrimes public static final int HAS_DOUBLE_VALUE = 1 << 13; 891541Srgrimes /** Is this symbol known to store an object value ? */ 901541Srgrimes public static final int HAS_OBJECT_VALUE = 1 << 14; 911541Srgrimes /** Is this symbol seen a declaration? Used for block scoped LET and CONST symbols only. */ 921541Srgrimes public static final int HAS_BEEN_DECLARED = 1 << 15; 9310027Sdg 941541Srgrimes /** Null or name identifying symbol. */ 9510027Sdg private final String name; 961541Srgrimes 9734266Sjulian /** Symbol flags. */ 981541Srgrimes private int flags; 9922521Sdyson 10031144Sjulian /** First bytecode method local variable slot for storing the value(s) of this variable. -1 indicates the variable 10131132Sjulian * is not stored in local variable slots or it is not yet known. */ 1021541Srgrimes private transient int firstSlot = -1; 1031541Srgrimes 1041541Srgrimes /** Field number in scope or property; array index in varargs when not using arguments object. */ 10510358Sjulian private transient int fieldIndex = -1; 1061541Srgrimes 1071541Srgrimes /** Number of times this symbol is used in code */ 1081541Srgrimes private int useCount; 10931144Sjulian 1101541Srgrimes /** Debugging option - dump info and stack trace when symbols with given names are manipulated */ 1111541Srgrimes private static final Set<String> TRACE_SYMBOLS; 1121541Srgrimes private static final Set<String> TRACE_SYMBOLS_STACKTRACE; 1131541Srgrimes 1141541Srgrimes static { 1151541Srgrimes final String stacktrace = Options.getStringProperty("nashorn.compiler.symbol.stacktrace", null); 1161541Srgrimes final String trace; 1171541Srgrimes if (stacktrace != null) { 11831346Sbde trace = stacktrace; //stacktrace always implies trace as well 11934266Sjulian TRACE_SYMBOLS_STACKTRACE = new HashSet<>(); 12035105Swosch for (final StringTokenizer st = new StringTokenizer(stacktrace, ","); st.hasMoreTokens(); ) { 12131346Sbde TRACE_SYMBOLS_STACKTRACE.add(st.nextToken()); 12231346Sbde } 12331346Sbde } else { 1241541Srgrimes trace = Options.getStringProperty("nashorn.compiler.symbol.trace", null); 1251541Srgrimes TRACE_SYMBOLS_STACKTRACE = null; 12631144Sjulian } 1271541Srgrimes 1281541Srgrimes if (trace != null) { 1291541Srgrimes TRACE_SYMBOLS = new HashSet<>(); 1301541Srgrimes for (final StringTokenizer st = new StringTokenizer(trace, ","); st.hasMoreTokens(); ) { 1311541Srgrimes TRACE_SYMBOLS.add(st.nextToken()); 1321541Srgrimes } 13327606Sbde } else { 1341541Srgrimes TRACE_SYMBOLS = null; 1351541Srgrimes } 13631144Sjulian } 13731144Sjulian 13831144Sjulian /** 1391541Srgrimes * Constructor 1401541Srgrimes * 1411541Srgrimes * @param name name of symbol 1421541Srgrimes * @param flags symbol flags 1431541Srgrimes */ 1441541Srgrimes public Symbol(final String name, final int flags) { 1451541Srgrimes this.name = name; 1461541Srgrimes this.flags = flags; 14731144Sjulian if(shouldTrace()) { 14831144Sjulian trace("CREATE SYMBOL " + name); 14931144Sjulian } 1501541Srgrimes } 15131144Sjulian 15231144Sjulian @Override 15331144Sjulian public Symbol clone() { 15431144Sjulian try { 15531144Sjulian return (Symbol)super.clone(); 15631144Sjulian } catch (final CloneNotSupportedException e) { 15734266Sjulian throw new AssertionError(e); 15834266Sjulian } 1591541Srgrimes } 16031144Sjulian 16131144Sjulian private static String align(final String string, final int max) { 16231144Sjulian final StringBuilder sb = new StringBuilder(); 1631541Srgrimes sb.append(string.substring(0, Math.min(string.length(), max))); 1641541Srgrimes 1651541Srgrimes while (sb.length() < max) { 1661541Srgrimes sb.append(' '); 1671541Srgrimes } 16831144Sjulian return sb.toString(); 16922521Sdyson } 17031144Sjulian 17122521Sdyson /** 17231144Sjulian * Debugging . 17322521Sdyson * 17422521Sdyson * @param stream Stream to print to. 17522521Sdyson */ 17631132Sjulian 17731132Sjulian void print(final PrintWriter stream) { 17831132Sjulian final StringBuilder sb = new StringBuilder(); 1791541Srgrimes 1801541Srgrimes sb.append(align(name, 20)). 18122521Sdyson append(": "). 18222521Sdyson append(", "). 18322521Sdyson append(align(firstSlot == -1 ? "none" : "" + firstSlot, 10)); 18423289Sbde 18523289Sbde switch (flags & KINDMASK) { 1862946Swollman case IS_GLOBAL: 18723289Sbde sb.append(" global"); 18822521Sdyson break; 18922521Sdyson case IS_VAR: 19022521Sdyson if (isConst()) { 19122521Sdyson sb.append(" const"); 19222521Sdyson } else if (isLet()) { 19322521Sdyson sb.append(" let"); 19422521Sdyson } else { 19522521Sdyson sb.append(" var"); 19622521Sdyson } 19722521Sdyson break; 19822521Sdyson case IS_PARAM: 19922521Sdyson sb.append(" param"); 20022521Sdyson break; 20122521Sdyson default: 20222521Sdyson break; 20334266Sjulian } 20434266Sjulian 20533122Sdyson if (isScope()) { 20622521Sdyson sb.append(" scope"); 20722521Sdyson } 20822521Sdyson 20922521Sdyson if (isInternal()) { 21022521Sdyson sb.append(" internal"); 21122521Sdyson } 21222521Sdyson 21322521Sdyson if (isThis()) { 21422521Sdyson sb.append(" this"); 21522521Sdyson } 21622521Sdyson 21722521Sdyson if (isProgramLevel()) { 21822521Sdyson sb.append(" program"); 21922521Sdyson } 22022521Sdyson 22122521Sdyson sb.append('\n'); 22222521Sdyson 22322521Sdyson stream.print(sb.toString()); 22422521Sdyson } 22522521Sdyson 22622521Sdyson /** 22727461Sdfr * Compare the the symbol kind with another. 22822521Sdyson * 22922521Sdyson * @param other Other symbol's flags. 23022521Sdyson * @return True if symbol has less kind. 23127461Sdfr */ 23227461Sdfr public boolean less(final int other) { 23327461Sdfr return (flags & KINDMASK) < (other & KINDMASK); 23427461Sdfr } 23527461Sdfr 23627461Sdfr /** 23727461Sdfr * Allocate a slot for this symbol. 23827461Sdfr * 23927461Sdfr * @param needsSlot True if symbol needs a slot. 24027461Sdfr * @return the symbol 24127461Sdfr */ 24222521Sdyson public Symbol setNeedsSlot(final boolean needsSlot) { 24322521Sdyson if(needsSlot) { 24422521Sdyson assert !isScope(); 24522521Sdyson flags |= HAS_SLOT; 2462946Swollman } else { 24722521Sdyson flags &= ~HAS_SLOT; 24822521Sdyson } 24922521Sdyson return this; 25022521Sdyson } 25122521Sdyson 25222521Sdyson /** 2532946Swollman * Return the number of slots required for the symbol. 2542946Swollman * 25523289Sbde * @return Number of slots. 25623289Sbde */ 25723289Sbde public int slotCount() { 25823289Sbde return ((flags & HAS_INT_VALUE) == 0 ? 0 : 1) + 25923289Sbde ((flags & HAS_LONG_VALUE) == 0 ? 0 : 2) + 26023289Sbde ((flags & HAS_DOUBLE_VALUE) == 0 ? 0 : 2) + 26123289Sbde ((flags & HAS_OBJECT_VALUE) == 0 ? 0 : 1); 26223289Sbde } 2637095Swollman 2647095Swollman private boolean isSlotted() { 2657095Swollman return firstSlot != -1 && ((flags & HAS_SLOT) != 0); 2667095Swollman } 26722521Sdyson 26822521Sdyson @Override 26922521Sdyson public String toString() { 27022521Sdyson final StringBuilder sb = new StringBuilder(); 27122521Sdyson 27222521Sdyson sb.append(name). 2737093Swollman append(' '); 27422521Sdyson 27522521Sdyson if (hasSlot()) { 27630354Sphk sb.append(' '). 27730354Sphk append('('). 27830354Sphk append("slot="). 27922521Sdyson append(firstSlot).append(' '); 28038866Sbde if((flags & HAS_INT_VALUE) != 0) { sb.append('I'); } 28122521Sdyson if((flags & HAS_LONG_VALUE) != 0) { sb.append('J'); } 28222521Sdyson if((flags & HAS_DOUBLE_VALUE) != 0) { sb.append('D'); } 2832946Swollman if((flags & HAS_OBJECT_VALUE) != 0) { sb.append('O'); } 2841541Srgrimes sb.append(')'); 2851541Srgrimes } 2861541Srgrimes 2871541Srgrimes if (isScope()) { 2881541Srgrimes if(isGlobal()) { 2891541Srgrimes sb.append(" G"); 2901541Srgrimes } else { 2911541Srgrimes sb.append(" S"); 2921541Srgrimes } 2931541Srgrimes } 2941541Srgrimes 2951541Srgrimes return sb.toString(); 2961541Srgrimes } 2971541Srgrimes 2981541Srgrimes @Override 2991541Srgrimes public int compareTo(final Symbol other) { 3001541Srgrimes return name.compareTo(other.name); 3011541Srgrimes } 3021541Srgrimes 3031541Srgrimes /** 3041541Srgrimes * Does this symbol have an allocated bytecode slot? Note that having an allocated bytecode slot doesn't necessarily 3051541Srgrimes * mean the symbol's value will be stored in it. Namely, a function parameter can have a bytecode slot, but if it is 3061541Srgrimes * in scope, then the bytecode slot will not be used. See {@link #isBytecodeLocal()}. 3071541Srgrimes * 30828270Swollman * @return true if this symbol has a local bytecode slot 3091541Srgrimes */ 3101541Srgrimes public boolean hasSlot() { 31122521Sdyson return (flags & HAS_SLOT) != 0; 31238757Sbde } 3131541Srgrimes 3141541Srgrimes /** 3151541Srgrimes * Is this symbol a local variable stored in bytecode local variable slots? This is true for a slotted variable that 3161541Srgrimes * is not in scope. (E.g. a parameter that is in scope is slotted, but it will not be a local variable). 3171541Srgrimes * @return true if this symbol is using bytecode local slots for its storage. 3181541Srgrimes */ 3191541Srgrimes public boolean isBytecodeLocal() { 3201541Srgrimes return hasSlot() && !isScope(); 3211541Srgrimes } 3221541Srgrimes 3231541Srgrimes /** 3241541Srgrimes * Returns true if this symbol is dead (it is a local variable that is statically proven to never be read in any type). 3251541Srgrimes * @return true if this symbol is dead 3261541Srgrimes */ 3272946Swollman public boolean isDead() { 32840435Speter return (flags & (HAS_SLOT | IS_SCOPE)) == 0; 32941056Speter } 33038909Sbde 33141056Speter /** 33241056Speter * Check if this is a symbol in scope. Scope symbols cannot, for obvious reasons 33341056Speter * be stored in byte code slots on the local frame 33441056Speter * 33541056Speter * @return true if this is scoped 33641056Speter */ 33741056Speter public boolean isScope() { 33841056Speter assert (flags & KINDMASK) != IS_GLOBAL || (flags & IS_SCOPE) == IS_SCOPE : "global without scope flag"; 33941056Speter return (flags & IS_SCOPE) != 0; 34041056Speter } 34141056Speter 34241056Speter /** 34340966Speter * Check if this symbol is a function declaration 34440435Speter * @return true if a function declaration 3451541Srgrimes */ 3461541Srgrimes public boolean isFunctionDeclaration() { 34739271Sphk return (flags & IS_FUNCTION_DECLARATION) != 0; 34834927Sbde } 3491541Srgrimes 3501541Srgrimes /** 3511541Srgrimes * Flag this symbol as scope as described in {@link Symbol#isScope()} 3521541Srgrimes * @return the symbol 3531541Srgrimes */ 3541541Srgrimes public Symbol setIsScope() { 3551541Srgrimes if (!isScope()) { 3561541Srgrimes if(shouldTrace()) { 3571541Srgrimes trace("SET IS SCOPE"); 3581541Srgrimes } 3591541Srgrimes flags |= IS_SCOPE; 3601541Srgrimes if(!isParam()) { 3611541Srgrimes flags &= ~HAS_SLOT; 3621541Srgrimes } 3631541Srgrimes } 3641541Srgrimes return this; 3651541Srgrimes } 36622521Sdyson 3671541Srgrimes /** 3681541Srgrimes * Mark this symbol as a function declaration. 3691541Srgrimes */ 3701541Srgrimes public void setIsFunctionDeclaration() { 3712213Sbde if (!isFunctionDeclaration()) { 37227461Sdfr if(shouldTrace()) { 37327461Sdfr trace("SET IS FUNCTION DECLARATION"); 37422521Sdyson } 37522521Sdyson flags |= IS_FUNCTION_DECLARATION; 37622521Sdyson } 37722521Sdyson } 3781541Srgrimes 3791541Srgrimes /** 3801541Srgrimes * Check if this symbol is a variable 38128270Swollman * @return true if variable 38234266Sjulian */ 38322521Sdyson public boolean isVar() { 38422521Sdyson return (flags & KINDMASK) == IS_VAR; 38541169Sbde } 3863151Sphk 38722521Sdyson /** 38822521Sdyson * Check if this symbol is a global (undeclared) variable 3897090Sbde * @return true if global 39040435Speter */ 39140435Speter public boolean isGlobal() { 39210027Sdg return (flags & KINDMASK) == IS_GLOBAL; 39322521Sdyson } 39427461Sdfr 3951541Srgrimes /** 39622521Sdyson * Check if this symbol is a function parameter 3971541Srgrimes * @return true if parameter 3981541Srgrimes */ 3991541Srgrimes public boolean isParam() { 4001541Srgrimes return (flags & KINDMASK) == IS_PARAM; 4011541Srgrimes } 4021541Srgrimes 4031541Srgrimes /** 4041541Srgrimes * Check if this is a program (script) level definition 40522521Sdyson * @return true if program level 4061541Srgrimes */ 4071541Srgrimes public boolean isProgramLevel() { 4082962Swollman return (flags & IS_PROGRAM_LEVEL) != 0; 4092962Swollman } 41032644Sbde 41123289Sbde /** 41223289Sbde * Check if this symbol is a constant 41323289Sbde * @return true if a constant 41432644Sbde */ 41532644Sbde public boolean isConst() { 4162962Swollman return (flags & IS_CONST) != 0; 4172962Swollman } 4182962Swollman 4191541Srgrimes /** 4201541Srgrimes * Check if this is an internal symbol, without an explicit JavaScript source 4212213Sbde * code equivalent 4222165Spaul * @return true if internal 4232213Sbde */ 424 public boolean isInternal() { 425 return (flags & IS_INTERNAL) != 0; 426 } 427 428 /** 429 * Check if this symbol represents {@code this} 430 * @return true if this 431 */ 432 public boolean isThis() { 433 return (flags & IS_THIS) != 0; 434 } 435 436 /** 437 * Check if this symbol is a let 438 * @return true if let 439 */ 440 public boolean isLet() { 441 return (flags & IS_LET) != 0; 442 } 443 444 /** 445 * Flag this symbol as a function's self-referencing symbol. 446 * @return true if this symbol as a function's self-referencing symbol. 447 */ 448 public boolean isFunctionSelf() { 449 return (flags & IS_FUNCTION_SELF) != 0; 450 } 451 452 /** 453 * Is this a block scoped symbol 454 * @return true if block scoped 455 */ 456 public boolean isBlockScoped() { 457 return isLet() || isConst(); 458 } 459 460 /** 461 * Has this symbol been declared 462 * @return true if declared 463 */ 464 public boolean hasBeenDeclared() { 465 return (flags & HAS_BEEN_DECLARED) != 0; 466 } 467 468 /** 469 * Mark this symbol as declared 470 */ 471 public void setHasBeenDeclared() { 472 if (!hasBeenDeclared()) { 473 flags |= HAS_BEEN_DECLARED; 474 } 475 } 476 477 /** 478 * Get the index of the field used to store this symbol, should it be an AccessorProperty 479 * and get allocated in a JO-prefixed ScriptObject subclass. 480 * 481 * @return field index 482 */ 483 public int getFieldIndex() { 484 assert fieldIndex != -1 : "fieldIndex must be initialized " + fieldIndex; 485 return fieldIndex; 486 } 487 488 /** 489 * Set the index of the field used to store this symbol, should it be an AccessorProperty 490 * and get allocated in a JO-prefixed ScriptObject subclass. 491 * 492 * @param fieldIndex field index - a positive integer 493 * @return the symbol 494 */ 495 public Symbol setFieldIndex(final int fieldIndex) { 496 if (this.fieldIndex != fieldIndex) { 497 this.fieldIndex = fieldIndex; 498 } 499 return this; 500 } 501 502 /** 503 * Get the symbol flags 504 * @return flags 505 */ 506 public int getFlags() { 507 return flags; 508 } 509 510 /** 511 * Set the symbol flags 512 * @param flags flags 513 * @return the symbol 514 */ 515 public Symbol setFlags(final int flags) { 516 if (this.flags != flags) { 517 this.flags = flags; 518 } 519 return this; 520 } 521 522 /** 523 * Set a single symbol flag 524 * @param flag flag to set 525 * @return the symbol 526 */ 527 public Symbol setFlag(final int flag) { 528 if ((this.flags & flag) == 0) { 529 this.flags |= flag; 530 } 531 return this; 532 } 533 534 /** 535 * Clears a single symbol flag 536 * @param flag flag to set 537 * @return the symbol 538 */ 539 public Symbol clearFlag(final int flag) { 540 if ((this.flags & flag) != 0) { 541 this.flags &= ~flag; 542 } 543 return this; 544 } 545 546 /** 547 * Get the name of this symbol 548 * @return symbol name 549 */ 550 public String getName() { 551 return name; 552 } 553 554 /** 555 * Get the index of the first bytecode slot for this symbol 556 * @return byte code slot 557 */ 558 public int getFirstSlot() { 559 assert isSlotted(); 560 return firstSlot; 561 } 562 563 /** 564 * Get the index of the bytecode slot for this symbol for storing a value of the specified type. 565 * @param type the requested type 566 * @return byte code slot 567 */ 568 public int getSlot(final Type type) { 569 assert isSlotted(); 570 int typeSlot = firstSlot; 571 if(type.isBoolean() || type.isInteger()) { 572 assert (flags & HAS_INT_VALUE) != 0; 573 return typeSlot; 574 } 575 typeSlot += ((flags & HAS_INT_VALUE) == 0 ? 0 : 1); 576 if(type.isLong()) { 577 assert (flags & HAS_LONG_VALUE) != 0; 578 return typeSlot; 579 } 580 typeSlot += ((flags & HAS_LONG_VALUE) == 0 ? 0 : 2); 581 if(type.isNumber()) { 582 assert (flags & HAS_DOUBLE_VALUE) != 0; 583 return typeSlot; 584 } 585 assert type.isObject(); 586 assert (flags & HAS_OBJECT_VALUE) != 0 : name; 587 return typeSlot + ((flags & HAS_DOUBLE_VALUE) == 0 ? 0 : 2); 588 } 589 590 /** 591 * Returns true if this symbol has a local variable slot for storing a value of specific type. 592 * @param type the type 593 * @return true if this symbol has a local variable slot for storing a value of specific type. 594 */ 595 public boolean hasSlotFor(final Type type) { 596 if(type.isBoolean() || type.isInteger()) { 597 return (flags & HAS_INT_VALUE) != 0; 598 } else if(type.isLong()) { 599 return (flags & HAS_LONG_VALUE) != 0; 600 } else if(type.isNumber()) { 601 return (flags & HAS_DOUBLE_VALUE) != 0; 602 } 603 assert type.isObject(); 604 return (flags & HAS_OBJECT_VALUE) != 0; 605 } 606 607 /** 608 * Marks this symbol as having a local variable slot for storing a value of specific type. 609 * @param type the type 610 */ 611 public void setHasSlotFor(final Type type) { 612 if(type.isBoolean() || type.isInteger()) { 613 setFlag(HAS_INT_VALUE); 614 } else if(type.isLong()) { 615 setFlag(HAS_LONG_VALUE); 616 } else if(type.isNumber()) { 617 setFlag(HAS_DOUBLE_VALUE); 618 } else { 619 assert type.isObject(); 620 setFlag(HAS_OBJECT_VALUE); 621 } 622 } 623 624 /** 625 * Increase the symbol's use count by one. 626 */ 627 public void increaseUseCount() { 628 if (isScope()) { // Avoid dirtying a cache line; we only need the use count for scoped symbols 629 useCount++; 630 } 631 } 632 633 /** 634 * Get the symbol's use count 635 * @return the number of times the symbol is used in code. 636 */ 637 public int getUseCount() { 638 return useCount; 639 } 640 641 /** 642 * Set the bytecode slot for this symbol 643 * @param firstSlot valid bytecode slot 644 * @return the symbol 645 */ 646 public Symbol setFirstSlot(final int firstSlot) { 647 assert firstSlot >= 0 && firstSlot <= 65535; 648 if (firstSlot != this.firstSlot) { 649 if(shouldTrace()) { 650 trace("SET SLOT " + firstSlot); 651 } 652 this.firstSlot = firstSlot; 653 } 654 return this; 655 } 656 657 /** 658 * From a lexical context, set this symbol as needing scope, which 659 * will set flags for the defining block that will be written when 660 * block is popped from the lexical context stack, used by codegen 661 * when flags need to be tagged, but block is in the 662 * middle of evaluation and cannot be modified. 663 * 664 * @param lc lexical context 665 * @param symbol symbol 666 * @return the symbol 667 */ 668 public static Symbol setSymbolIsScope(final LexicalContext lc, final Symbol symbol) { 669 symbol.setIsScope(); 670 if (!symbol.isGlobal()) { 671 lc.setBlockNeedsScope(lc.getDefiningBlock(symbol)); 672 } 673 return symbol; 674 } 675 676 private boolean shouldTrace() { 677 return TRACE_SYMBOLS != null && (TRACE_SYMBOLS.isEmpty() || TRACE_SYMBOLS.contains(name)); 678 } 679 680 private void trace(final String desc) { 681 Context.err(Debug.id(this) + " SYMBOL: '" + name + "' " + desc); 682 if (TRACE_SYMBOLS_STACKTRACE != null && (TRACE_SYMBOLS_STACKTRACE.isEmpty() || TRACE_SYMBOLS_STACKTRACE.contains(name))) { 683 new Throwable().printStackTrace(Context.getCurrentErr()); 684 } 685 } 686 687 private void readObject(final ObjectInputStream in) throws ClassNotFoundException, IOException { 688 in.defaultReadObject(); 689 firstSlot = -1; 690 fieldIndex = -1; 691 } 692} 693