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