Skip to content

Commit 2de5366

Browse files
committed
GH-397 logical value for TruffleString
1 parent 816514c commit 2de5366

File tree

1 file changed

+148
-1
lines changed

1 file changed

+148
-1
lines changed

visualvm/heapviewer.truffle/src/org/graalvm/visualvm/heapviewer/truffle/details/TruffleDetailsProvider.java

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,16 @@
2424
*/
2525
package org.graalvm.visualvm.heapviewer.truffle.details;
2626

27+
import java.io.UnsupportedEncodingException;
28+
import java.util.Collections;
29+
import java.util.HashMap;
30+
import java.util.List;
31+
import java.util.Map;
32+
import java.util.WeakHashMap;
33+
import org.graalvm.visualvm.lib.jfluid.heap.Heap;
2734
import org.graalvm.visualvm.lib.jfluid.heap.Instance;
35+
import org.graalvm.visualvm.lib.jfluid.heap.JavaClass;
36+
import org.graalvm.visualvm.lib.jfluid.heap.PrimitiveArrayInstance;
2837
import org.graalvm.visualvm.lib.profiler.heapwalk.details.api.DetailsSupport;
2938
import org.graalvm.visualvm.lib.profiler.heapwalk.details.spi.DetailsProvider;
3039
import org.graalvm.visualvm.lib.profiler.heapwalk.details.spi.DetailsUtils;
@@ -48,12 +57,19 @@ public class TruffleDetailsProvider extends DetailsProvider.Basic {
4857
private static final String INSTRUMENT_INFO_MASK = "com.oracle.truffle.api.InstrumentInfo"; // NOI18N
4958
private static final String NATIVE_ROOT_MASK = "com.oracle.truffle.nfi.LibFFIFunctionMessageResolutionForeign$ExecuteLibFFIFunctionSubNode$EXECUTERootNode"; // NOI18N
5059
private static final String NODE_MASK = "com.oracle.truffle.api.nodes.Node+"; // NOI18N
60+
private static final String TSTRING_MASK = "com.oracle.truffle.api.strings.AbstractTruffleString+"; // NOI18N
61+
private static final String TS_LONG_MASK = "com.oracle.truffle.api.strings.AbstractTruffleString$LazyLong"; // NOI18N
62+
private static final String TS_CONCAT_MASK = "com.oracle.truffle.api.strings.AbstractTruffleString$LazyConcat"; // NOI18N
63+
64+
private static final String TS_ENCODING_CLASS = "com.oracle.truffle.api.strings.TruffleString$Encoding"; // NOI18N
65+
private static final Object CACHE_LOCK = new Object();
66+
private static WeakHashMap<Heap,Map<Byte,Encoding>> CACHE;
5167

5268
public TruffleDetailsProvider() {
5369
super(DEFAULT_CALL_TARGET_MASK, OPTIMIZED_CALL_TARGET_MASK, OPTIMIZED_CALL_TARGET1_MASK,
5470
ENT_OPTIMIZED_CALL_TARGET_MASK, LANG_INFO_MASK, LANG_CACHE_MASK,
5571
LANG_CACHE1_MASK, POLYGLOT_MASK, INSTRUMENT_INFO_MASK, NATIVE_ROOT_MASK,
56-
NODE_MASK);
72+
NODE_MASK, TSTRING_MASK, TS_LONG_MASK, TS_CONCAT_MASK);
5773
}
5874

5975
public String getDetailsString(String className, Instance instance) {
@@ -115,6 +131,61 @@ public String getDetailsString(String className, Instance instance) {
115131
if (NODE_MASK.equals(className)) {
116132
return DetailsUtils.getInstanceFieldString(instance, "sourceSection");
117133
}
134+
if (TSTRING_MASK.equals(className)) {
135+
Instance next = instance;
136+
do {
137+
String str = getString(next);
138+
if (str != null) {
139+
return str;
140+
}
141+
next = (Instance) next.getValueOfField("next"); // NOI18N
142+
} while (next != null && !instance.equals(next));
143+
144+
Object data = instance.getValueOfField("data");
145+
if (data instanceof PrimitiveArrayInstance) {
146+
Encoding encoding = getEncoding(instance);
147+
Byte stride = (Byte)instance.getValueOfField("stride"); // NOI18N
148+
if (stride != null && encoding != null) {
149+
byte[] bytes = convertBytes((PrimitiveArrayInstance)data, encoding.naturalStride, stride);
150+
try {
151+
if ("BYTES".equals(encoding.name)) {
152+
return new String(bytes, "ISO-8859-1");
153+
}
154+
return new String(bytes, encoding.name);
155+
} catch (UnsupportedEncodingException ex) {
156+
try {
157+
return new String(bytes, encoding.name.replace('_', '-'));
158+
} catch (UnsupportedEncodingException ex1) {
159+
return new String(bytes);
160+
}
161+
}
162+
}
163+
} else {
164+
return DetailsUtils.getInstanceString((Instance) data);
165+
}
166+
}
167+
if (TS_LONG_MASK.equals(className)) {
168+
return String.valueOf(DetailsUtils.getLongFieldValue(instance, "value", 0)); // NOI18N
169+
}
170+
if (TS_CONCAT_MASK.equals(className)) {
171+
Object vall = instance.getValueOfField("left"); // NOI18N
172+
Object valr = instance.getValueOfField("right"); // NOI18N
173+
174+
String left = DetailsUtils.getInstanceString((Instance)vall);
175+
176+
if (left == null) {
177+
return DetailsUtils.getInstanceString((Instance)valr);
178+
}
179+
if (valr == null || left.length() > DetailsUtils.MAX_ARRAY_LENGTH) {
180+
return left;
181+
}
182+
String value = left + DetailsUtils.getInstanceString((Instance)valr);
183+
184+
if (value.length() > DetailsUtils.MAX_ARRAY_LENGTH) {
185+
return value.substring(0, DetailsUtils.MAX_ARRAY_LENGTH) + "..."; // NOI18N
186+
}
187+
return value;
188+
}
118189
return null;
119190
}
120191

@@ -128,4 +199,80 @@ public View getDetailsView(String className, Instance instance) {
128199
}
129200
return null;
130201
}
202+
203+
private String getString(Instance truffleString) {
204+
Object data = truffleString.getValueOfField("data"); // NOI18N
205+
if (data instanceof Instance) {
206+
Instance idata = (Instance) data;
207+
if (idata.getJavaClass().getName().equals(String.class.getName())) {
208+
return DetailsUtils.getInstanceString(idata);
209+
}
210+
}
211+
return null;
212+
}
213+
214+
private Encoding getEncoding(Instance truffleString) {
215+
Byte encodingId = (Byte) truffleString.getValueOfField("encoding"); // NOI18N
216+
217+
Map<Byte, Encoding> heapCache = getEncodingCache(truffleString);
218+
Encoding cachedEncoding = heapCache.get(encodingId);
219+
if (cachedEncoding == null && encodingId != null) {
220+
Heap heap = truffleString.getJavaClass().getHeap();
221+
JavaClass encodingClass = heap.getJavaClassByName(TS_ENCODING_CLASS);
222+
for (Instance encoding : encodingClass.getInstances()) {
223+
Byte id = (Byte) encoding.getValueOfField("id"); // NOI18N
224+
225+
if (id.equals(encodingId)) {
226+
cachedEncoding = new Encoding(encoding);
227+
heapCache.put(encodingId, cachedEncoding);
228+
}
229+
}
230+
}
231+
return cachedEncoding;
232+
}
233+
234+
private Map<Byte, Encoding> getEncodingCache(Instance truffleString) {
235+
synchronized (CACHE_LOCK) {
236+
if (CACHE == null) {
237+
CACHE = new WeakHashMap();
238+
}
239+
Heap heap = truffleString.getJavaClass().getHeap();
240+
Map<Byte, Encoding> heapCache = CACHE.get(heap);
241+
if (heapCache == null) {
242+
heapCache = Collections.synchronizedMap(new HashMap<>());
243+
CACHE.put(heap, heapCache);
244+
}
245+
return heapCache;
246+
}
247+
}
248+
249+
private byte[] convertBytes(PrimitiveArrayInstance data, byte naturalStride, byte stride) {
250+
int inCharSize = 1 << stride;
251+
int outCharSize = 1 << naturalStride;
252+
int padding = outCharSize - inCharSize;
253+
byte[] bytes = new byte[(data.getLength() / inCharSize) * outCharSize];
254+
List<String> values = data.getValues();
255+
int op = 0;
256+
257+
for (int ip = 0; ip < values.size();) {
258+
for (int j = 0; j < inCharSize; j++) {
259+
bytes[op++] = Byte.valueOf(values.get(ip++));
260+
}
261+
op += padding;
262+
}
263+
return bytes;
264+
}
265+
266+
private static class Encoding {
267+
268+
byte encId;
269+
String name;
270+
byte naturalStride;
271+
272+
Encoding(Instance encoding) {
273+
encId = (Byte) encoding.getValueOfField("id"); // NOI18N
274+
name = DetailsUtils.getInstanceFieldString(encoding, "name"); // NOI18N
275+
naturalStride = (Byte) encoding.getValueOfField("naturalStride"); // NOI18N
276+
}
277+
}
131278
}

0 commit comments

Comments
 (0)