001/* 002 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package jdk.internal.jvmci.hotspot; 024 025import static jdk.internal.jvmci.common.UnsafeAccess.*; 026import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; 027 028import java.io.*; 029import java.util.*; 030 031/** 032 * Represents a metaspace {@code Symbol}. 033 */ 034public class HotSpotSymbol { 035 036 private final long metaspaceSymbol; 037 038 public HotSpotSymbol(long metaspaceSymbol) { 039 assert metaspaceSymbol != 0; 040 this.metaspaceSymbol = metaspaceSymbol; 041 } 042 043 /** 044 * Decodes this {@code Symbol} and returns the symbol string as {@link java.lang.String}. 045 * 046 * @return the decoded string, or null if there was a decoding error 047 */ 048 public String asString() { 049 return readModifiedUTF8(asByteArray()); 050 } 051 052 /** 053 * Reads the modified UTF-8 string in {@code buf} and converts it to a {@link String}. The 054 * implementation is taken from {@link java.io.DataInputStream#readUTF(DataInput)} and adapted 055 * to operate on a {@code byte} array directly for performance reasons. 056 * 057 * @see java.io.DataInputStream#readUTF(DataInput) 058 */ 059 private static String readModifiedUTF8(byte[] buf) { 060 final int utflen = buf.length; 061 byte[] bytearr = null; 062 char[] chararr = new char[utflen]; 063 064 int c; 065 int char2; 066 int char3; 067 int count = 0; 068 int chararrCount = 0; 069 070 bytearr = buf; 071 072 while (count < utflen) { 073 c = bytearr[count] & 0xff; 074 if (c > 127) { 075 break; 076 } 077 count++; 078 chararr[chararrCount++] = (char) c; 079 } 080 081 while (count < utflen) { 082 c = bytearr[count] & 0xff; 083 switch (c >> 4) { 084 case 0: 085 case 1: 086 case 2: 087 case 3: 088 case 4: 089 case 5: 090 case 6: 091 case 7: 092 /* 0xxxxxxx */ 093 count++; 094 chararr[chararrCount++] = (char) c; 095 break; 096 case 12: 097 case 13: 098 /* 110x xxxx 10xx xxxx */ 099 count += 2; 100 if (count > utflen) { 101 // malformed input: partial character at end 102 return null; 103 } 104 char2 = bytearr[count - 1]; 105 if ((char2 & 0xC0) != 0x80) { 106 // malformed input around byte 107 return null; 108 } 109 chararr[chararrCount++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F)); 110 break; 111 case 14: 112 /* 1110 xxxx 10xx xxxx 10xx xxxx */ 113 count += 3; 114 if (count > utflen) { 115 // malformed input: partial character at end 116 return null; 117 } 118 char2 = bytearr[count - 2]; 119 char3 = bytearr[count - 1]; 120 if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) { 121 // malformed input around byte 122 return null; 123 } 124 chararr[chararrCount++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); 125 break; 126 default: 127 /* 10xx xxxx, 1111 xxxx */ 128 // malformed input around byte 129 return null; 130 } 131 } 132 // The number of chars produced may be less than utflen 133 char[] value = Arrays.copyOf(chararr, chararrCount); 134 return new String(value); 135 } 136 137 private byte[] asByteArray() { 138 final int length = getLength(); 139 byte[] result = new byte[length]; 140 for (int index = 0; index < length; index++) { 141 result[index] = getByteAt(index); 142 } 143 return result; 144 } 145 146 private int getLength() { 147 return unsafe.getShort(metaspaceSymbol + runtime().getConfig().symbolLengthOffset); 148 } 149 150 private byte getByteAt(int index) { 151 return unsafe.getByte(metaspaceSymbol + runtime().getConfig().symbolBodyOffset + index); 152 } 153}