1.1 --- a/rt/emul/compact/src/main/java/sun/invoke/anon/ConstantPoolPatch.java Sun Aug 10 05:56:32 2014 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,503 +0,0 @@
1.4 -/*
1.5 - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
1.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 - *
1.8 - * This code is free software; you can redistribute it and/or modify it
1.9 - * under the terms of the GNU General Public License version 2 only, as
1.10 - * published by the Free Software Foundation. Oracle designates this
1.11 - * particular file as subject to the "Classpath" exception as provided
1.12 - * by Oracle in the LICENSE file that accompanied this code.
1.13 - *
1.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 - * version 2 for more details (a copy is included in the LICENSE file that
1.18 - * accompanied this code).
1.19 - *
1.20 - * You should have received a copy of the GNU General Public License version
1.21 - * 2 along with this work; if not, write to the Free Software Foundation,
1.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 - *
1.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 - * or visit www.oracle.com if you need additional information or have any
1.26 - * questions.
1.27 - */
1.28 -
1.29 -package sun.invoke.anon;
1.30 -
1.31 -import java.io.IOException;
1.32 -import java.io.OutputStream;
1.33 -import java.util.Arrays;
1.34 -import java.util.HashSet;
1.35 -import java.util.IdentityHashMap;
1.36 -import java.util.Map;
1.37 -
1.38 -import static sun.invoke.anon.ConstantPoolVisitor.*;
1.39 -
1.40 -/** A class and its patched constant pool.
1.41 - *
1.42 - * This class allow to modify (patch) a constant pool
1.43 - * by changing the value of its entry.
1.44 - * Entry are referenced using index that can be get
1.45 - * by parsing the constant pool using
1.46 - * {@link ConstantPoolParser#parse(ConstantPoolVisitor)}.
1.47 - *
1.48 - * @see ConstantPoolVisitor
1.49 - * @see ConstantPoolParser#createPatch()
1.50 - */
1.51 -public class ConstantPoolPatch {
1.52 - final ConstantPoolParser outer;
1.53 - final Object[] patchArray;
1.54 -
1.55 - ConstantPoolPatch(ConstantPoolParser outer) {
1.56 - this.outer = outer;
1.57 - this.patchArray = new Object[outer.getLength()];
1.58 - }
1.59 -
1.60 - /** Create a {@link ConstantPoolParser} and
1.61 - * a {@link ConstantPoolPatch} in one step.
1.62 - * Equivalent to {@code new ConstantPoolParser(classFile).createPatch()}.
1.63 - *
1.64 - * @param classFile an array of bytes containing a class.
1.65 - * @see #ConstantPoolParser(Class)
1.66 - */
1.67 - public ConstantPoolPatch(byte[] classFile) throws InvalidConstantPoolFormatException {
1.68 - this(new ConstantPoolParser(classFile));
1.69 - }
1.70 -
1.71 - /** Create a {@link ConstantPoolParser} and
1.72 - * a {@link ConstantPoolPatch} in one step.
1.73 - * Equivalent to {@code new ConstantPoolParser(templateClass).createPatch()}.
1.74 - *
1.75 - * @param templateClass the class to parse.
1.76 - * @see #ConstantPoolParser(Class)
1.77 - */
1.78 - public ConstantPoolPatch(Class<?> templateClass) throws IOException, InvalidConstantPoolFormatException {
1.79 - this(new ConstantPoolParser(templateClass));
1.80 - }
1.81 -
1.82 -
1.83 - /** Creates a patch from an existing patch.
1.84 - * All changes are copied from that patch.
1.85 - * @param patch a patch
1.86 - *
1.87 - * @see ConstantPoolParser#createPatch()
1.88 - */
1.89 - public ConstantPoolPatch(ConstantPoolPatch patch) {
1.90 - outer = patch.outer;
1.91 - patchArray = patch.patchArray.clone();
1.92 - }
1.93 -
1.94 - /** Which parser built this patch? */
1.95 - public ConstantPoolParser getParser() {
1.96 - return outer;
1.97 - }
1.98 -
1.99 - /** Report the tag at the given index in the constant pool. */
1.100 - public byte getTag(int index) {
1.101 - return outer.getTag(index);
1.102 - }
1.103 -
1.104 - /** Report the current patch at the given index of the constant pool.
1.105 - * Null means no patch will be made.
1.106 - * To observe the unpatched entry at the given index, use
1.107 - * {@link #getParser()}{@code .}@link ConstantPoolParser#parse(ConstantPoolVisitor)}
1.108 - */
1.109 - public Object getPatch(int index) {
1.110 - Object value = patchArray[index];
1.111 - if (value == null) return null;
1.112 - switch (getTag(index)) {
1.113 - case CONSTANT_Fieldref:
1.114 - case CONSTANT_Methodref:
1.115 - case CONSTANT_InterfaceMethodref:
1.116 - if (value instanceof String)
1.117 - value = stripSemis(2, (String) value);
1.118 - break;
1.119 - case CONSTANT_NameAndType:
1.120 - if (value instanceof String)
1.121 - value = stripSemis(1, (String) value);
1.122 - break;
1.123 - }
1.124 - return value;
1.125 - }
1.126 -
1.127 - /** Clear all patches. */
1.128 - public void clear() {
1.129 - Arrays.fill(patchArray, null);
1.130 - }
1.131 -
1.132 - /** Clear one patch. */
1.133 - public void clear(int index) {
1.134 - patchArray[index] = null;
1.135 - }
1.136 -
1.137 - /** Produce the patches as an array. */
1.138 - public Object[] getPatches() {
1.139 - return patchArray.clone();
1.140 - }
1.141 -
1.142 - /** Produce the original constant pool as an array. */
1.143 - public Object[] getOriginalCP() throws InvalidConstantPoolFormatException {
1.144 - return getOriginalCP(0, patchArray.length, -1);
1.145 - }
1.146 -
1.147 - /** Walk the constant pool, applying patches using the given map.
1.148 - *
1.149 - * @param utf8Map Utf8 strings to modify, if encountered
1.150 - * @param classMap Classes (or their names) to modify, if encountered
1.151 - * @param valueMap Constant values to modify, if encountered
1.152 - * @param deleteUsedEntries if true, delete map entries that are used
1.153 - */
1.154 - public void putPatches(final Map<String,String> utf8Map,
1.155 - final Map<String,Object> classMap,
1.156 - final Map<Object,Object> valueMap,
1.157 - boolean deleteUsedEntries) throws InvalidConstantPoolFormatException {
1.158 - final HashSet<String> usedUtf8Keys;
1.159 - final HashSet<String> usedClassKeys;
1.160 - final HashSet<Object> usedValueKeys;
1.161 - if (deleteUsedEntries) {
1.162 - usedUtf8Keys = (utf8Map == null) ? null : new HashSet<String>();
1.163 - usedClassKeys = (classMap == null) ? null : new HashSet<String>();
1.164 - usedValueKeys = (valueMap == null) ? null : new HashSet<Object>();
1.165 - } else {
1.166 - usedUtf8Keys = null;
1.167 - usedClassKeys = null;
1.168 - usedValueKeys = null;
1.169 - }
1.170 -
1.171 - outer.parse(new ConstantPoolVisitor() {
1.172 -
1.173 - @Override
1.174 - public void visitUTF8(int index, byte tag, String utf8) {
1.175 - putUTF8(index, utf8Map.get(utf8));
1.176 - if (usedUtf8Keys != null) usedUtf8Keys.add(utf8);
1.177 - }
1.178 -
1.179 - @Override
1.180 - public void visitConstantValue(int index, byte tag, Object value) {
1.181 - putConstantValue(index, tag, valueMap.get(value));
1.182 - if (usedValueKeys != null) usedValueKeys.add(value);
1.183 - }
1.184 -
1.185 - @Override
1.186 - public void visitConstantString(int index, byte tag, String name, int nameIndex) {
1.187 - if (tag == CONSTANT_Class) {
1.188 - putConstantValue(index, tag, classMap.get(name));
1.189 - if (usedClassKeys != null) usedClassKeys.add(name);
1.190 - } else {
1.191 - assert(tag == CONSTANT_String);
1.192 - visitConstantValue(index, tag, name);
1.193 - }
1.194 - }
1.195 - });
1.196 - if (usedUtf8Keys != null) utf8Map.keySet().removeAll(usedUtf8Keys);
1.197 - if (usedClassKeys != null) classMap.keySet().removeAll(usedClassKeys);
1.198 - if (usedValueKeys != null) valueMap.keySet().removeAll(usedValueKeys);
1.199 - }
1.200 -
1.201 - Object[] getOriginalCP(final int startIndex,
1.202 - final int endIndex,
1.203 - final int tagMask) throws InvalidConstantPoolFormatException {
1.204 - final Object[] cpArray = new Object[endIndex - startIndex];
1.205 - outer.parse(new ConstantPoolVisitor() {
1.206 -
1.207 - void show(int index, byte tag, Object value) {
1.208 - if (index < startIndex || index >= endIndex) return;
1.209 - if (((1 << tag) & tagMask) == 0) return;
1.210 - cpArray[index - startIndex] = value;
1.211 - }
1.212 -
1.213 - @Override
1.214 - public void visitUTF8(int index, byte tag, String utf8) {
1.215 - show(index, tag, utf8);
1.216 - }
1.217 -
1.218 - @Override
1.219 - public void visitConstantValue(int index, byte tag, Object value) {
1.220 - assert(tag != CONSTANT_String);
1.221 - show(index, tag, value);
1.222 - }
1.223 -
1.224 - @Override
1.225 - public void visitConstantString(int index, byte tag,
1.226 - String value, int j) {
1.227 - show(index, tag, value);
1.228 - }
1.229 -
1.230 - @Override
1.231 - public void visitMemberRef(int index, byte tag,
1.232 - String className, String memberName,
1.233 - String signature,
1.234 - int j, int k) {
1.235 - show(index, tag, new String[]{ className, memberName, signature });
1.236 - }
1.237 -
1.238 - @Override
1.239 - public void visitDescriptor(int index, byte tag,
1.240 - String memberName, String signature,
1.241 - int j, int k) {
1.242 - show(index, tag, new String[]{ memberName, signature });
1.243 - }
1.244 - });
1.245 - return cpArray;
1.246 - }
1.247 -
1.248 - /** Write the head (header plus constant pool)
1.249 - * of the patched class file to the indicated stream.
1.250 - */
1.251 - void writeHead(OutputStream out) throws IOException {
1.252 - outer.writePatchedHead(out, patchArray);
1.253 - }
1.254 -
1.255 - /** Write the tail (everything after the constant pool)
1.256 - * of the patched class file to the indicated stream.
1.257 - */
1.258 - void writeTail(OutputStream out) throws IOException {
1.259 - outer.writeTail(out);
1.260 - }
1.261 -
1.262 - private void checkConstantTag(byte tag, Object value) {
1.263 - if (value == null)
1.264 - throw new IllegalArgumentException(
1.265 - "invalid null constant value");
1.266 - if (classForTag(tag) != value.getClass())
1.267 - throw new IllegalArgumentException(
1.268 - "invalid constant value"
1.269 - + (tag == CONSTANT_None ? ""
1.270 - : " for tag "+tagName(tag))
1.271 - + " of class "+value.getClass());
1.272 - }
1.273 -
1.274 - private void checkTag(int index, byte putTag) {
1.275 - byte tag = outer.tags[index];
1.276 - if (tag != putTag)
1.277 - throw new IllegalArgumentException(
1.278 - "invalid put operation"
1.279 - + " for " + tagName(putTag)
1.280 - + " at index " + index + " found " + tagName(tag));
1.281 - }
1.282 -
1.283 - private void checkTagMask(int index, int tagBitMask) {
1.284 - byte tag = outer.tags[index];
1.285 - int tagBit = ((tag & 0x1F) == tag) ? (1 << tag) : 0;
1.286 - if ((tagBit & tagBitMask) == 0)
1.287 - throw new IllegalArgumentException(
1.288 - "invalid put operation"
1.289 - + " at index " + index + " found " + tagName(tag));
1.290 - }
1.291 -
1.292 - private static void checkMemberName(String memberName) {
1.293 - if (memberName.indexOf(';') >= 0)
1.294 - throw new IllegalArgumentException("memberName " + memberName + " contains a ';'");
1.295 - }
1.296 -
1.297 - /** Set the entry of the constant pool indexed by index to
1.298 - * a new string.
1.299 - *
1.300 - * @param index an index to a constant pool entry containing a
1.301 - * {@link ConstantPoolVisitor#CONSTANT_Utf8} value.
1.302 - * @param utf8 a string
1.303 - *
1.304 - * @see ConstantPoolVisitor#visitUTF8(int, byte, String)
1.305 - */
1.306 - public void putUTF8(int index, String utf8) {
1.307 - if (utf8 == null) { clear(index); return; }
1.308 - checkTag(index, CONSTANT_Utf8);
1.309 - patchArray[index] = utf8;
1.310 - }
1.311 -
1.312 - /** Set the entry of the constant pool indexed by index to
1.313 - * a new value, depending on its dynamic type.
1.314 - *
1.315 - * @param index an index to a constant pool entry containing a
1.316 - * one of the following structures:
1.317 - * {@link ConstantPoolVisitor#CONSTANT_Integer},
1.318 - * {@link ConstantPoolVisitor#CONSTANT_Float},
1.319 - * {@link ConstantPoolVisitor#CONSTANT_Long},
1.320 - * {@link ConstantPoolVisitor#CONSTANT_Double},
1.321 - * {@link ConstantPoolVisitor#CONSTANT_String}, or
1.322 - * {@link ConstantPoolVisitor#CONSTANT_Class}
1.323 - * @param value a boxed int, float, long or double; or a string or class object
1.324 - * @throws IllegalArgumentException if the type of the constant does not
1.325 - * match the constant pool entry type,
1.326 - * as reported by {@link #getTag(int)}
1.327 - *
1.328 - * @see #putConstantValue(int, byte, Object)
1.329 - * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object)
1.330 - * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int)
1.331 - */
1.332 - public void putConstantValue(int index, Object value) {
1.333 - if (value == null) { clear(index); return; }
1.334 - byte tag = tagForConstant(value.getClass());
1.335 - checkConstantTag(tag, value);
1.336 - checkTag(index, tag);
1.337 - patchArray[index] = value;
1.338 - }
1.339 -
1.340 - /** Set the entry of the constant pool indexed by index to
1.341 - * a new value.
1.342 - *
1.343 - * @param index an index to a constant pool entry matching the given tag
1.344 - * @param tag one of the following values:
1.345 - * {@link ConstantPoolVisitor#CONSTANT_Integer},
1.346 - * {@link ConstantPoolVisitor#CONSTANT_Float},
1.347 - * {@link ConstantPoolVisitor#CONSTANT_Long},
1.348 - * {@link ConstantPoolVisitor#CONSTANT_Double},
1.349 - * {@link ConstantPoolVisitor#CONSTANT_String}, or
1.350 - * {@link ConstantPoolVisitor#CONSTANT_Class}
1.351 - * @param value a boxed number, string, or class object
1.352 - * @throws IllegalArgumentException if the type of the constant does not
1.353 - * match the constant pool entry type, or if a class name contains
1.354 - * '/' or ';'
1.355 - *
1.356 - * @see #putConstantValue(int, Object)
1.357 - * @see ConstantPoolVisitor#visitConstantValue(int, byte, Object)
1.358 - * @see ConstantPoolVisitor#visitConstantString(int, byte, String, int)
1.359 - */
1.360 - public void putConstantValue(int index, byte tag, Object value) {
1.361 - if (value == null) { clear(index); return; }
1.362 - checkTag(index, tag);
1.363 - if (tag == CONSTANT_Class && value instanceof String) {
1.364 - checkClassName((String) value);
1.365 - } else if (tag == CONSTANT_String) {
1.366 - // the JVM accepts any object as a patch for a string
1.367 - } else {
1.368 - // make sure the incoming value is the right type
1.369 - checkConstantTag(tag, value);
1.370 - }
1.371 - checkTag(index, tag);
1.372 - patchArray[index] = value;
1.373 - }
1.374 -
1.375 - /** Set the entry of the constant pool indexed by index to
1.376 - * a new {@link ConstantPoolVisitor#CONSTANT_NameAndType} value.
1.377 - *
1.378 - * @param index an index to a constant pool entry containing a
1.379 - * {@link ConstantPoolVisitor#CONSTANT_NameAndType} value.
1.380 - * @param memberName a memberName
1.381 - * @param signature a signature
1.382 - * @throws IllegalArgumentException if memberName contains the character ';'
1.383 - *
1.384 - * @see ConstantPoolVisitor#visitDescriptor(int, byte, String, String, int, int)
1.385 - */
1.386 - public void putDescriptor(int index, String memberName, String signature) {
1.387 - checkTag(index, CONSTANT_NameAndType);
1.388 - checkMemberName(memberName);
1.389 - patchArray[index] = addSemis(memberName, signature);
1.390 - }
1.391 -
1.392 - /** Set the entry of the constant pool indexed by index to
1.393 - * a new {@link ConstantPoolVisitor#CONSTANT_Fieldref},
1.394 - * {@link ConstantPoolVisitor#CONSTANT_Methodref}, or
1.395 - * {@link ConstantPoolVisitor#CONSTANT_InterfaceMethodref} value.
1.396 - *
1.397 - * @param index an index to a constant pool entry containing a member reference
1.398 - * @param className a class name
1.399 - * @param memberName a field or method name
1.400 - * @param signature a field or method signature
1.401 - * @throws IllegalArgumentException if memberName contains the character ';'
1.402 - * or signature is not a correct signature
1.403 - *
1.404 - * @see ConstantPoolVisitor#visitMemberRef(int, byte, String, String, String, int, int)
1.405 - */
1.406 - public void putMemberRef(int index, byte tag,
1.407 - String className, String memberName, String signature) {
1.408 - checkTagMask(tag, CONSTANT_MemberRef_MASK);
1.409 - checkTag(index, tag);
1.410 - checkClassName(className);
1.411 - checkMemberName(memberName);
1.412 - if (signature.startsWith("(") == (tag == CONSTANT_Fieldref))
1.413 - throw new IllegalArgumentException("bad signature: "+signature);
1.414 - patchArray[index] = addSemis(className, memberName, signature);
1.415 - }
1.416 -
1.417 - static private final int CONSTANT_MemberRef_MASK =
1.418 - CONSTANT_Fieldref
1.419 - | CONSTANT_Methodref
1.420 - | CONSTANT_InterfaceMethodref;
1.421 -
1.422 - private static final Map<Class<?>, Byte> CONSTANT_VALUE_CLASS_TAG
1.423 - = new IdentityHashMap<Class<?>, Byte>();
1.424 - private static final Class<?>[] CONSTANT_VALUE_CLASS = new Class<?>[16];
1.425 - static {
1.426 - Object[][] values = {
1.427 - {Integer.class, CONSTANT_Integer},
1.428 - {Long.class, CONSTANT_Long},
1.429 - {Float.class, CONSTANT_Float},
1.430 - {Double.class, CONSTANT_Double},
1.431 - {String.class, CONSTANT_String},
1.432 - {Class.class, CONSTANT_Class}
1.433 - };
1.434 - for (Object[] value : values) {
1.435 - Class<?> cls = (Class<?>)value[0];
1.436 - Byte tag = (Byte) value[1];
1.437 - CONSTANT_VALUE_CLASS_TAG.put(cls, tag);
1.438 - CONSTANT_VALUE_CLASS[(byte)tag] = cls;
1.439 - }
1.440 - }
1.441 -
1.442 - static Class<?> classForTag(byte tag) {
1.443 - if ((tag & 0xFF) >= CONSTANT_VALUE_CLASS.length)
1.444 - return null;
1.445 - return CONSTANT_VALUE_CLASS[tag];
1.446 - }
1.447 -
1.448 - static byte tagForConstant(Class<?> cls) {
1.449 - Byte tag = CONSTANT_VALUE_CLASS_TAG.get(cls);
1.450 - return (tag == null) ? CONSTANT_None : (byte)tag;
1.451 - }
1.452 -
1.453 - private static void checkClassName(String className) {
1.454 - if (className.indexOf('/') >= 0 || className.indexOf(';') >= 0)
1.455 - throw new IllegalArgumentException("invalid class name " + className);
1.456 - }
1.457 -
1.458 - static String addSemis(String name, String... names) {
1.459 - StringBuilder buf = new StringBuilder(name.length() * 5);
1.460 - buf.append(name);
1.461 - for (String name2 : names) {
1.462 - buf.append(';').append(name2);
1.463 - }
1.464 - String res = buf.toString();
1.465 - assert(stripSemis(names.length, res)[0].equals(name));
1.466 - assert(stripSemis(names.length, res)[1].equals(names[0]));
1.467 - assert(names.length == 1 ||
1.468 - stripSemis(names.length, res)[2].equals(names[1]));
1.469 - return res;
1.470 - }
1.471 -
1.472 - static String[] stripSemis(int count, String string) {
1.473 - String[] res = new String[count+1];
1.474 - int pos = 0;
1.475 - for (int i = 0; i < count; i++) {
1.476 - int pos2 = string.indexOf(';', pos);
1.477 - if (pos2 < 0) pos2 = string.length(); // yuck
1.478 - res[i] = string.substring(pos, pos2);
1.479 - pos = pos2;
1.480 - }
1.481 - res[count] = string.substring(pos);
1.482 - return res;
1.483 - }
1.484 -
1.485 - public String toString() {
1.486 - StringBuilder buf = new StringBuilder(this.getClass().getName());
1.487 - buf.append("{");
1.488 - Object[] origCP = null;
1.489 - for (int i = 0; i < patchArray.length; i++) {
1.490 - if (patchArray[i] == null) continue;
1.491 - if (origCP != null) {
1.492 - buf.append(", ");
1.493 - } else {
1.494 - try {
1.495 - origCP = getOriginalCP();
1.496 - } catch (InvalidConstantPoolFormatException ee) {
1.497 - origCP = new Object[0];
1.498 - }
1.499 - }
1.500 - Object orig = (i < origCP.length) ? origCP[i] : "?";
1.501 - buf.append(orig).append("=").append(patchArray[i]);
1.502 - }
1.503 - buf.append("}");
1.504 - return buf.toString();
1.505 - }
1.506 -}