1 /*
2  * Copyright (c) 2000, 2020, 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 
25 package sun.jvm.hotspot.oops;
26 
27 import java.io.*;
28 import java.util.*;
29 import sun.jvm.hotspot.debugger.*;
30 import sun.jvm.hotspot.runtime.*;
31 import sun.jvm.hotspot.types.*;
32 import sun.jvm.hotspot.utilities.*;
33 import sun.jvm.hotspot.utilities.Observable;
34 import sun.jvm.hotspot.utilities.Observer;
35 
36 // A Symbol is a canonicalized string.
37 // All Symbols reside in global symbolTable.
38 
39 public class Symbol extends VMObject {
40   static {
VM.registerVMInitializedObserver(new Observer() { public void update(Observable o, Object data) { initialize(VM.getVM().getTypeDataBase()); } })41     VM.registerVMInitializedObserver(new Observer() {
42         public void update(Observable o, Object data) {
43           initialize(VM.getVM().getTypeDataBase());
44         }
45       });
46   }
47 
initialize(TypeDataBase db)48   private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
49     Type type  = db.lookupType("Symbol");
50     lengthField = type.getCIntegerField("_length");
51     baseOffset = type.getField("_body").getOffset();
52     idHashAndRefcount = type.getCIntegerField("_hash_and_refcount");
53   }
54 
create(Address addr)55   public static Symbol create(Address addr) {
56     if (addr == null) {
57       return null;
58     }
59     return new Symbol(addr);
60   }
61 
Symbol(Address addr)62   Symbol(Address addr) {
63     super(addr);
64   }
65 
isSymbol()66   public boolean isSymbol()            { return true; }
67 
68   private static long baseOffset; // tells where the array part starts
69 
70   // Fields
71   private static CIntegerField lengthField;
72   // idHash is a short packed into the high bits of a 32-bit integer with refcount
73   private static CIntegerField idHashAndRefcount;
74 
75   // Accessors for declared fields
getLength()76   public long getLength() {
77     return lengthField.getValue(this.addr);
78   }
79 
getByteAt(long index)80   public byte getByteAt(long index) {
81     return addr.getJByteAt(baseOffset + index);
82   }
83 
identityHash()84   public long identityHash() {
85     long addr_value = getAddress().asLongValue();
86     long addr_bits =
87       (addr_value >> (VM.getVM().getLogMinObjAlignmentInBytes() + 3)) & 0xffffffffL;
88     int  length = (int)getLength();
89     int  byte0 = getByteAt(0);
90     int  byte1 = getByteAt(1);
91     long id_hash = (long)idHashAndRefcount.getValue(this.addr);
92     id_hash = (id_hash >> 16) & 0xffff;
93     return (id_hash |
94       ((addr_bits ^ (length << 8) ^ ((byte0 << 8) | byte1)) << 16)) & 0xffffffffL;
95   }
96 
equals(byte[] modUTF8Chars)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 
equals(String string)109   public boolean equals(String string) {
110     return asString().equals(string);
111   }
112 
asByteArray()113   public byte[] asByteArray() {
114     int length = (int) getLength();
115     byte [] result = new byte [length];
116     for (int index = 0; index < length; index++) {
117       result[index] = getByteAt(index);
118     }
119     return result;
120   }
121 
asString()122   public String asString() {
123     // Decode the byte array and return the string.
124     try {
125       return readModifiedUTF8(asByteArray());
126     } catch(Exception e) {
127       System.err.println(addr);
128       e.printStackTrace();
129       return null;
130     }
131   }
132 
startsWith(String str)133   public boolean startsWith(String str) {
134     return asString().startsWith(str);
135   }
136 
printValueOn(PrintStream tty)137   public void printValueOn(PrintStream tty) {
138     tty.print("#" + asString());
139   }
140 
141   /** Note: this comparison is used for vtable sorting only; it
142       doesn't matter what order it defines, as long as it is a total,
143       time-invariant order Since Symbol* are in C_HEAP, their
144       relative order in memory never changes, so use address
145       comparison for speed. */
fastCompare(Symbol other)146   public long fastCompare(Symbol other) {
147     return addr.minus(other.addr);
148   }
149 
readModifiedUTF8(byte[] buf)150   private static String readModifiedUTF8(byte[] buf) throws IOException {
151     final int len = buf.length;
152     byte[] tmp = new byte[len + 2];
153     // write modified UTF-8 length as short in big endian
154     tmp[0] = (byte) ((len >>> 8) & 0xFF);
155     tmp[1] = (byte) ((len >>> 0) & 0xFF);
156     // copy the data
157     System.arraycopy(buf, 0, tmp, 2, len);
158     DataInputStream dis = new DataInputStream(new ByteArrayInputStream(tmp));
159     return dis.readUTF();
160   }
161 }
162