1/*
2 * Copyright (c) 2000, 2016, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25package sun.jvm.hotspot.oops;
26
27import java.io.*;
28import java.util.*;
29import sun.jvm.hotspot.debugger.*;
30import sun.jvm.hotspot.runtime.*;
31import sun.jvm.hotspot.types.*;
32import sun.jvm.hotspot.utilities.*;
33
34// A Symbol is a canonicalized string.
35// All Symbols reside in global symbolTable.
36
37public class Symbol extends VMObject {
38  static {
39    VM.registerVMInitializedObserver(new Observer() {
40        public void update(Observable o, Object data) {
41          initialize(VM.getVM().getTypeDataBase());
42        }
43      });
44  }
45
46  private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
47    Type type  = db.lookupType("Symbol");
48    length     = type.getCIntegerField("_length");
49    baseOffset = type.getField("_body").getOffset();
50    idHash = type.getCIntegerField("_identity_hash");
51  }
52
53  // Format:
54  //   [header]
55  //   [klass ]
56  //   [length] byte size of uft8 string
57  //   ..body..
58
59  public static Symbol create(Address addr) {
60    if (addr == null) {
61      return null;
62    }
63    return new Symbol(addr);
64  }
65
66  Symbol(Address addr) {
67    super(addr);
68  }
69
70  public boolean isSymbol()            { return true; }
71
72  private static long baseOffset; // tells where the array part starts
73
74  // Fields
75  private static CIntegerField length;
76
77  // Accessors for declared fields
78  public long   getLength() { return          length.getValue(this.addr); }
79
80  public byte getByteAt(long index) {
81    return addr.getJByteAt(baseOffset + index);
82  }
83  // _identity_hash is a short
84  private static CIntegerField idHash;
85
86  public int identityHash() {
87    long addr_value = getAddress().asLongValue();
88    int  addr_bits = (int)(addr_value >> (VM.getVM().getLogMinObjAlignmentInBytes() + 3));
89    int  length = (int)getLength();
90    int  byte0 = getByteAt(0);
91    int  byte1 = getByteAt(1);
92    int  id_hash = (int)(0xffff & idHash.getValue(this.addr));
93    return id_hash |
94           ((addr_bits ^ (length << 8) ^ ((byte0 << 8) | byte1)) << 16);
95  }
96
97  public boolean equals(byte[] modUTF8Chars) {
98    int l = (int) getLength();
99    if (l != modUTF8Chars.length) return false;
100    while (l-- > 0) {
101      if (modUTF8Chars[l] != getByteAt(l)) return false;
102    }
103    if (Assert.ASSERTS_ENABLED) {
104      Assert.that(l == -1, "we should be at the beginning");
105    }
106    return true;
107  }
108
109  public byte[] asByteArray() {
110    int length = (int) getLength();
111    byte [] result = new byte [length];
112    for (int index = 0; index < length; index++) {
113      result[index] = getByteAt(index);
114    }
115    return result;
116  }
117
118  public String asString() {
119    // Decode the byte array and return the string.
120    try {
121      return readModifiedUTF8(asByteArray());
122    } catch(Exception e) {
123      System.err.println(addr);
124      e.printStackTrace();
125      return null;
126    }
127  }
128
129  public boolean startsWith(String str) {
130    return asString().startsWith(str);
131  }
132
133  public void printValueOn(PrintStream tty) {
134    tty.print("#" + asString());
135  }
136
137  /** Note: this comparison is used for vtable sorting only; it
138      doesn't matter what order it defines, as long as it is a total,
139      time-invariant order Since Symbol* are in C_HEAP, their
140      relative order in memory never changes, so use address
141      comparison for speed. */
142  public long fastCompare(Symbol other) {
143    return addr.minus(other.addr);
144  }
145
146  private static String readModifiedUTF8(byte[] buf) throws IOException {
147    final int len = buf.length;
148    byte[] tmp = new byte[len + 2];
149    // write modified UTF-8 length as short in big endian
150    tmp[0] = (byte) ((len >>> 8) & 0xFF);
151    tmp[1] = (byte) ((len >>> 0) & 0xFF);
152    // copy the data
153    System.arraycopy(buf, 0, tmp, 2, len);
154    DataInputStream dis = new DataInputStream(new ByteArrayInputStream(tmp));
155    return dis.readUTF();
156  }
157}
158