8037082: java/lang/instrument/NativeMethodPrefixAgent.java failing
Reviewed-by: sla
--- a/jdk/test/ProblemList.txt Tue Aug 26 16:42:31 2014 +0800
+++ b/jdk/test/ProblemList.txt Mon Aug 25 18:17:24 2014 +0200
@@ -274,9 +274,6 @@
# jdk_instrument
-# 8037082
-java/lang/instrument/NativeMethodPrefixAgent.java generic-all
-
############################################################################
# svc_tools
--- a/jdk/test/java/lang/instrument/MakeJAR2.sh Tue Aug 26 16:42:31 2014 +0800
+++ b/jdk/test/java/lang/instrument/MakeJAR2.sh Mon Aug 25 18:17:24 2014 +0200
@@ -75,9 +75,9 @@
cp ${TESTSRC}/${AGENT}.java .
cp ${TESTSRC}/${APP}.java .
-rm -rf ilib
-mkdir ilib
-cp ${TESTSRC}/ilib/*.java ilib
+rm -rf asmlib
+mkdir asmlib
+cp ${TESTSRC}/asmlib/*.java asmlib
rm -rf bootpath
mkdir -p bootpath/bootreporter
cp ${TESTSRC}/bootreporter/*.java bootpath/bootreporter
@@ -86,7 +86,7 @@
${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} bootreporter/*.java
cd ..
-${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${AGENT}.java ilib/*.java
+${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -XDignore.symbol.file ${AGENT}.java asmlib/*.java
${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -classpath .${PATHSEP}bootpath ${APP}.java
echo "Manifest-Version: 1.0" > ${AGENT}.mf
@@ -98,6 +98,6 @@
shift
done
-${JAR} ${TESTTOOLVMOPTS} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class ilib/*.class
+${JAR} ${TESTTOOLVMOPTS} cvfm ${AGENT}.jar ${AGENT}.mf ${AGENT}*.class asmlib/*.class
-# rm -rf ${AGENT}.java ilib ${AGENT}.mf ${AGENT}*.class
+# rm -rf ${AGENT}.java asmlib ${AGENT}.mf ${AGENT}*.class
--- a/jdk/test/java/lang/instrument/NativeMethodPrefixAgent.java Tue Aug 26 16:42:31 2014 +0800
+++ b/jdk/test/java/lang/instrument/NativeMethodPrefixAgent.java Mon Aug 25 18:17:24 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,7 @@
import java.security.ProtectionDomain;
import java.io.*;
-import ilib.*;
+import asmlib.*;
class NativeMethodPrefixAgent {
@@ -62,14 +62,25 @@
System.out.println(trname + ": " +
(redef? "Retransforming " : "Loading ") + className);
if (className != null) {
- Options opt = new Options();
- opt.shouldInstrumentNativeMethods = true;
- opt.trackerClassName = "bootreporter/StringIdCallbackReporter";
- opt.wrappedTrackerMethodName = "tracker";
- opt.fixedIndex = transformId;
- opt.wrappedPrefix = "wrapped_" + trname + "_";
try {
- byte[] newcf = Inject.instrumentation(opt, loader, className, classfileBuffer);
+ byte[] newcf = Instrumentor.instrFor(classfileBuffer)
+ .addNativeMethodTrackingInjection(
+ "wrapped_" + trname + "_",
+ (h)->{
+ h.push(h.getName());
+ h.push(transformId);
+ h.invokeStatic("bootreporter/StringIdCallbackReporter", "tracker", "(Ljava/lang/String;I)V", false);
+ })
+ .apply();
+ /*** debugging ...
+ if (newcf != null) {
+ String fname = trname + (redef?"_redef" : "") + "/" + className;
+ System.err.println("dumping to: " + fname);
+ write_buffer(fname + "_before.class", classfileBuffer);
+ write_buffer(fname + "_instr.class", newcf);
+ }
+ ***/
+
return redef? null : newcf;
} catch (Throwable ex) {
System.err.println("ERROR: Injection failure: " + ex);
@@ -86,10 +97,14 @@
// for debugging
static void write_buffer(String fname, byte[]buffer) {
try {
- FileOutputStream outStream = new FileOutputStream(fname);
- outStream.write(buffer, 0, buffer.length);
- outStream.close();
- } catch (Exception ex) {
+ File f = new File(fname);
+ if (!f.getParentFile().exists()) {
+ f.getParentFile().mkdirs();
+ }
+ try (FileOutputStream outStream = new FileOutputStream(f)) {
+ outStream.write(buffer, 0, buffer.length);
+ }
+ } catch (IOException ex) {
System.err.println("EXCEPTION in write_buffer: " + ex);
}
}
--- a/jdk/test/java/lang/instrument/RetransformAgent.java Tue Aug 26 16:42:31 2014 +0800
+++ b/jdk/test/java/lang/instrument/RetransformAgent.java Mon Aug 25 18:17:24 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,8 +34,7 @@
import java.lang.instrument.*;
import java.security.ProtectionDomain;
import java.io.*;
-
-import ilib.*;
+import asmlib.*;
class RetransformAgent {
@@ -75,20 +74,25 @@
// System.err.println("hook " + trname + ": " + className +
// (redef? " REDEF" : " LOAD"));
if ((redef? onRedef : onLoad) && className != null && className.equals(cname)) {
- Options opt = new Options();
- opt.shouldInstrumentIndexed = true;
- opt.shouldInstrumentCall = true;
- opt.targetMethod = nname;
- opt.fixedIndex = redef? redefIndex : loadIndex;
- opt.trackerClassName = "RetransformAgent";
+ int fixedIndex = redef ? redefIndex : loadIndex;
try {
- byte[] newcf = Inject.instrumentation(opt, loader, className, classfileBuffer);
+ byte[] newcf = Instrumentor.instrFor(classfileBuffer)
+ .addMethodEntryInjection(
+ nname,
+ (h)->{
+ h.push(fixedIndex);
+ h.invokeStatic("RetransformAgent", "callTracker", "(I)V", false);
+ })
+ .apply();
/*** debugging ...
- String fname = trname + (redef?"_redef" : "");
- write_buffer(fname + "_before.class", classfileBuffer);
- write_buffer(fname + "_instr.class", newcf);
+ if (newcf != null) {
+ String fname = trname + (redef?"_redef" : "") + "/" + className;
+ System.err.println("dumping to: " + fname);
+ write_buffer(fname + "_before.class", classfileBuffer);
+ write_buffer(fname + "_instr.class", newcf);
+ }
***/
- System.err.println(trname + ": " + className + " index: " + opt.fixedIndex +
+ System.err.println(trname + ": " + className + " index: " + fixedIndex +
(redef? " REDEF" : " LOAD") +
" len before: " + classfileBuffer.length +
" after: " + newcf.length);
@@ -104,10 +108,14 @@
static void write_buffer(String fname, byte[]buffer) {
try {
- FileOutputStream outStream = new FileOutputStream(fname);
- outStream.write(buffer, 0, buffer.length);
- outStream.close();
- } catch (Exception ex) {
+ File f = new File(fname);
+ if (!f.getParentFile().exists()) {
+ f.getParentFile().mkdirs();
+ }
+ try (FileOutputStream outStream = new FileOutputStream(f)) {
+ outStream.write(buffer, 0, buffer.length);
+ }
+ } catch (IOException ex) {
System.err.println("EXCEPTION in write_buffer: " + ex);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/instrument/asmlib/Instrumentor.java Mon Aug 25 18:17:24 2014 +0200
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package asmlib;
+
+import java.io.PrintStream;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+import java.util.function.Consumer;
+import jdk.internal.org.objectweb.asm.Type;
+
+public class Instrumentor {
+ public static class InstrHelper {
+ private final MethodVisitor mv;
+ private final String name;
+
+ InstrHelper(MethodVisitor mv, String name) {
+ this.mv = mv;
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void invokeStatic(String owner, String name, String desc, boolean itf) {
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf);
+ }
+
+ public void invokeSpecial(String owner, String name, String desc) {
+ mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false);
+ }
+
+ public void invokeVirtual(String owner, String name, String desc) {
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, false);
+ }
+
+ public void push(int val) {
+ if (val >= -1 && val <= 5) {
+ mv.visitInsn(Opcodes.ICONST_0 + val);
+ } else if (val >= Byte.MIN_VALUE && val <= Byte.MAX_VALUE) {
+ mv.visitIntInsn(Opcodes.BIPUSH, val);
+ } else if (val >= Short.MIN_VALUE && val <= Short.MAX_VALUE) {
+ mv.visitIntInsn(Opcodes.SIPUSH, val);
+ } else {
+ mv.visitLdcInsn(val);
+ }
+ }
+
+ public void push(Object val) {
+ mv.visitLdcInsn(val);
+ }
+
+ public void println(String s) {
+ mv.visitFieldInsn(Opcodes.GETSTATIC, Type.getInternalName(System.class), "out", Type.getDescriptor(PrintStream.class));
+ mv.visitLdcInsn(s);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(PrintStream.class), "println", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)), false);
+ }
+ }
+
+ public static Instrumentor instrFor(byte[] classData) {
+ return new Instrumentor(classData);
+ }
+
+
+ private final ClassReader cr;
+ private final ClassWriter output;
+ private ClassVisitor instrumentingVisitor = null;
+ private final AtomicInteger matches = new AtomicInteger(0);
+
+ private Instrumentor(byte[] classData) {
+ cr = new ClassReader(classData);
+ output = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ instrumentingVisitor = output;
+ }
+
+ public synchronized Instrumentor addMethodEntryInjection(String methodName, Consumer<InstrHelper> injector) {
+ instrumentingVisitor = new ClassVisitor(Opcodes.ASM5, instrumentingVisitor) {
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+
+ if (name.equals(methodName)) {
+ matches.getAndIncrement();
+
+ mv = new MethodVisitor(Opcodes.ASM5, mv) {
+ @Override
+ public void visitCode() {
+ injector.accept(new InstrHelper(mv, name));
+ }
+ };
+ }
+ return mv;
+ }
+ };
+ return this;
+ }
+
+ public synchronized Instrumentor addNativeMethodTrackingInjection(String prefix, Consumer<InstrHelper> injector) {
+ instrumentingVisitor = new ClassVisitor(Opcodes.ASM5, instrumentingVisitor) {
+ private final Set<Consumer<ClassVisitor>> wmGenerators = new HashSet<>();
+ private String className;
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ this.className = name;
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ if ((access & Opcodes.ACC_NATIVE) != 0) {
+ matches.getAndIncrement();
+
+ String newName = prefix + name;
+ wmGenerators.add((v)->{
+ MethodVisitor mv = v.visitMethod(access & ~Opcodes.ACC_NATIVE, name, desc, signature, exceptions);
+ mv.visitCode();
+ injector.accept(new InstrHelper(mv, name));
+ Type[] argTypes = Type.getArgumentTypes(desc);
+ Type retType = Type.getReturnType(desc);
+
+ boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
+ if (!isStatic) {
+ mv.visitIntInsn(Opcodes.ALOAD, 0); // load "this"
+ }
+
+ // load the method parameters
+ if (argTypes.length > 0) {
+ int ptr = isStatic ? 0 : 1;
+ for(Type argType : argTypes) {
+ mv.visitIntInsn(argType.getOpcode(Opcodes.ILOAD), ptr);
+ ptr += argType.getSize();
+ }
+ }
+
+ mv.visitMethodInsn(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKESPECIAL, className, newName, desc, false);
+ mv.visitInsn(retType.getOpcode(Opcodes.IRETURN));
+
+ mv.visitMaxs(1, 1); // dummy call; let ClassWriter to deal with this
+ mv.visitEnd();
+ });
+ return super.visitMethod(access, newName, desc, signature, exceptions);
+ }
+ return super.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ @Override
+ public void visitEnd() {
+ wmGenerators.stream().forEach((e) -> {
+ e.accept(cv);
+ });
+ super.visitEnd();
+ }
+ };
+
+ return this;
+ }
+
+ public synchronized byte[] apply() {
+ cr.accept(instrumentingVisitor, ClassReader.SKIP_DEBUG + ClassReader.EXPAND_FRAMES);
+
+ return matches.get() == 0 ? null : output.toByteArray();
+ }
+}
--- a/jdk/test/java/lang/instrument/ilib/ClassDump.java Tue Aug 26 16:42:31 2014 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,273 +0,0 @@
-/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package ilib;
-
-import java.io.IOException;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.DataOutputStream;
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.io.CharArrayWriter;
-import java.util.List;
-import java.util.Iterator;
-import java.util.ArrayList;
-
-public class ClassDump implements RuntimeConstants {
-
- public static void dump(Options opt,
- ClassLoader loader,
- String className,
- byte[] classfileBuffer) {
- ClassReaderWriter c = new ClassReaderWriter(classfileBuffer);
- (new ClassDump(className, c)).doit();
- }
-
- static boolean verbose = true;
-
- final String className;
- final ClassReaderWriter c;
- private final PrintStream output;
-
- int constantPoolCount;
- int methodsCount;
-
- ClassDump(String className, ClassReaderWriter c) {
- this.className = className;
- this.c = c;
- this.output = System.err;
- }
-
- void doit() {
- int i;
- c.copy(4 + 2 + 2); // magic min/maj version
- constantPoolCount = c.copyU2();
- // copy old constant pool
- c.copyConstantPool(constantPoolCount);
-
- traceln("ConstantPool size: " + constantPoolCount);
-
- c.copy(2 + 2 + 2); // access, this, super
- int interfaceCount = c.copyU2();
- traceln("interfaceCount: " + interfaceCount);
- c.copy(interfaceCount * 2);
- copyFields(); // fields
- copyMethods(); // methods
- int attrCount = c.copyU2();
- traceln("class attrCount: " + attrCount);
- // copy the class attributes
- copyAttrs(attrCount);
- }
-
-
- void copyFields() {
- int count = c.copyU2();
- if (verbose) {
- System.out.println("fields count: " + count);
- }
- for (int i = 0; i < count; ++i) {
- c.copy(6); // access, name, descriptor
- int attrCount = c.copyU2();
- if (verbose) {
- System.out.println("field attr count: " + attrCount);
- }
- copyAttrs(attrCount);
- }
- }
-
- void copyMethods() {
- methodsCount = c.copyU2();
- if (verbose) {
- System.out.println("methods count: " + methodsCount);
- }
- for (int i = 0; i < methodsCount; ++i) {
- copyMethod();
- }
- }
-
- void copyMethod() {
- int accessFlags = c.copyU2();// access flags
- int nameIndex = c.copyU2(); // name
- checkIndex(nameIndex, "Method name");
- String methodName = c.constantPoolString(nameIndex);
- traceln("method: " + methodName);
- int descriptorIndex = c.copyU2(); // descriptor
- checkIndex(descriptorIndex, "Method descriptor");
- int attrCount = c.copyU2(); // attribute count
- if (verbose) {
- System.out.println("method attr count: " + attrCount);
- }
- for (int i = 0; i < attrCount; ++i) {
- copyAttrForMethod(methodName, accessFlags);
- }
- }
-
- void copyAttrs(int attrCount) {
- for (int i = 0; i < attrCount; ++i) {
- copyAttr();
- }
- }
-
- void copyAttr() {
- c.copy(2); // name
- int len = c.copyU4(); // attr len
- if (verbose) {
- System.out.println("attr len: " + len);
- }
- c.copy(len); // attribute info
- }
-
- void copyAttrForMethod(String methodName, int accessFlags) {
- int nameIndex = c.copyU2(); // name
- // check for Code attr
- checkIndex(nameIndex, "Method attr name");
- if (nameIndex == c.codeAttributeIndex) {
- try {
- copyCodeAttr(methodName);
- } catch (IOException exc) {
- System.err.println("Code Exception - " + exc);
- System.exit(1);
- }
- } else {
- int len = c.copyU4(); // attr len
- traceln("method attr len: " + len);
- c.copy(len); // attribute info
- }
- }
-
- void copyAttrForCode() throws IOException {
- int nameIndex = c.copyU2(); // name
-
- checkIndex(nameIndex, "Code attr name");
- int len = c.copyU4(); // attr len
- traceln("code attr len: " + len);
- c.copy(len); // attribute info
- }
-
- void copyCodeAttr(String methodName) throws IOException {
- traceln("Code attr found");
- int attrLength = c.copyU4(); // attr len
- checkLength(attrLength, "Code attr length");
- int maxStack = c.readU2(); // max stack
- c.copyU2(); // max locals
- int codeLength = c.copyU4(); // code length
- checkLength(codeLength, "Code length");
-
- copyExceptionTable();
-
- int attrCount = c.copyU2();
- checkLength(attrCount, "Code attr count");
- for (int i = 0; i < attrCount; ++i) {
- copyAttrForCode();
- }
- }
-
- /**
- * Copy the exception table for this method code
- */
- void copyExceptionTable() throws IOException {
- int tableLength = c.copyU2(); // exception table len
- checkLength(tableLength, "Exception Table length");
- if (tableLength > 0) {
- traceln();
- traceln("Exception table:");
- traceln(" from:old/new to:old/new target:old/new type");
- for (int tcnt = tableLength; tcnt > 0; --tcnt) {
- int startPC = c.readU2();
- int endPC = c.readU2();
- int handlerPC = c.readU2();
- int catchType = c.copyU2();
- if (verbose) {
- traceFixedWidthInt(startPC, 6);
- traceFixedWidthInt(endPC, 6);
- traceFixedWidthInt(handlerPC, 6);
- trace(" ");
- if (catchType == 0)
- traceln("any");
- else {
- traceln("" + catchType);
- }
- }
- }
- }
- }
-
- private void checkIndex(int index, String comment) {
- if (index > constantPoolCount) {
- output.println("ERROR BAD INDEX " + comment + " : " + index);
- } else {
- traceln(comment + " : " + index);
- }
- }
-
- private void checkLength(int length, String comment) {
- if (length > c.inputBytes().length) {
- output.println("ERROR BAD LENGTH " + comment + " : " + length);
- } else {
- traceln(comment + " : " + length);
- }
- }
-
- private void trace(String str) {
- if (verbose) {
- output.print(str);
- }
- }
-
- private void traceln(String str) {
- if (verbose) {
- output.println(str);
- }
- }
-
- private void traceln() {
- if (verbose) {
- output.println();
- }
- }
-
- private void trace(int i) {
- if (verbose) {
- output.print(i);
- }
- }
-
- /**
- * Print an integer so that it takes 'length' characters in
- * the output. Temporary until formatting code is stable.
- */
- private void traceFixedWidthInt(int x, int length) {
- if (verbose) {
- CharArrayWriter baStream = new CharArrayWriter();
- PrintWriter pStream = new PrintWriter(baStream);
- pStream.print(x);
- String str = baStream.toString();
- for (int cnt = length - str.length(); cnt > 0; --cnt)
- trace(" ");
- trace(str);
- }
- }
-
-
-}
--- a/jdk/test/java/lang/instrument/ilib/ClassReaderWriter.java Tue Aug 26 16:42:31 2014 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,263 +0,0 @@
-/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package ilib;
-
-class ClassReaderWriter implements RuntimeConstants {
-
- int codeAttributeIndex;
- int lineNumberAttributeIndex;
- int localVarAttributeIndex;
-
- private final byte[] orig;
- private final byte[] gen;
- private final int sectionLength;
-
- private static final int GROWTH_FACTOR = 2;
- private static final int SECTIONS = 2;
- private static final String codeAttributeName = "Code";
- private static final String lineNumberAttributeName = "LineNumberTable";
- private static final String localVarAttributeName = "LocalVariableTable";
-
- private int[] genSectionPos = new int[SECTIONS];
-
- private int inputPos = 0;
- private int genPos = 0;
- private int markPos = 0;
- private int currentSection = 0;
-
- private String[] constantPool;
-
- ClassReaderWriter(byte[] orig) {
- this.orig = orig;
- sectionLength = orig.length * GROWTH_FACTOR;
- gen = new byte[sectionLength * SECTIONS];
- for (int section = 0; section < SECTIONS; ++section) {
- genSectionPos[section] = section * sectionLength;
- }
- }
-
- int setSection(int section) {
- int prevSection = currentSection;
- genSectionPos[prevSection] = genPos;
- genPos = genSectionPos[section];
- currentSection = section;
- return prevSection;
- }
-
- byte[] result() {
- int section;
- int totalLength = 0;
-
- setSection(0); // save current section
-
- for (section = 0; section < SECTIONS; ++section) {
- int sectionStart = section * sectionLength;
- int sectionGenLength = genSectionPos[section] - sectionStart;
- totalLength += sectionGenLength;
- }
-
- byte[] newcf = new byte[totalLength];
- int written = 0;
- for (section = 0; section < SECTIONS; ++section) {
- int sectionStart = section * sectionLength;
- int sectionGenLength = genSectionPos[section] - sectionStart;
- System.arraycopy(gen, sectionStart, newcf, written, sectionGenLength);
- written += sectionGenLength;
- }
-
- return newcf;
- }
-
- int readU1() {
- return ((int)orig[inputPos++]) & 0xFF;
- }
-
- int readU2() {
- int res = readU1();
- return (res << 8) + readU1();
- }
-
- short readS2() {
- int res = readU1();
- return (short)((res << 8) + readU1());
- }
-
- int readU4() {
- int res = readU2();
- return (res << 16) + readU2();
- }
-
- void writeU1(int val) {
- gen[genPos++] = (byte)val;
- }
-
- void writeU2(int val) {
- writeU1(val >> 8);
- writeU1(val & 0xFF);
- }
-
- void writeU4(int val) {
- writeU2(val >> 16);
- writeU2(val & 0xFFFF);
- }
-
- int copyU1() {
- int value = readU1();
- writeU1(value);
- return value;
- }
-
- int copyU2() {
- int value = readU2();
- writeU2(value);
- return value;
- }
-
- int copyU4() {
- int value = readU4();
- writeU4(value);
- return value;
- }
-
- void copy(int count) {
- for (int i = 0; i < count; ++i) {
- gen[genPos++] = orig[inputPos++];
- }
- }
-
- void skip(int count) {
- inputPos += count;
- }
-
- byte[] readBytes(int count) {
- byte[] bytes = new byte[count];
- for (int i = 0; i < count; ++i) {
- bytes[i] = orig[inputPos++];
- }
- return bytes;
- }
-
- void writeBytes(byte[] bytes) {
- for (int i = 0; i < bytes.length; ++i) {
- gen[genPos++] = bytes[i];
- }
- }
-
- byte[] inputBytes() {
- return orig;
- }
-
- int inputPosition() {
- return inputPos;
- }
-
- void setInputPosition(int pos) {
- inputPos = pos;
- }
-
- void markLocalPositionStart() {
- markPos = inputPos;
- }
-
- int localPosition() {
- return inputPos - markPos;
- }
-
- void rewind() {
- setInputPosition(markPos);
- }
-
- int generatedPosition() {
- return genPos;
- }
-
- void randomAccessWriteU2(int pos, int val) {
- int savePos = genPos;
- genPos = pos;
- writeU2(val);
- genPos = savePos;
- }
-
- void randomAccessWriteU4(int pos, int val) {
- int savePos = genPos;
- genPos = pos;
- writeU4(val);
- genPos = savePos;
- }
-
- String constantPoolString(int index) {
- return constantPool[index];
- }
-
- void copyConstantPool(int constantPoolCount){
- // copy const pool
- constantPool = new String[constantPoolCount];
- // index zero not in class file
- for (int i = 1; i < constantPoolCount; ++i) {
- int tag = readU1();
- writeU1(tag);
- switch (tag) {
- case CONSTANT_CLASS:
- case CONSTANT_STRING:
- copy(2);
- break;
- case CONSTANT_FIELD:
- case CONSTANT_METHOD:
- case CONSTANT_INTERFACEMETHOD:
- case CONSTANT_INTEGER:
- case CONSTANT_FLOAT:
- case CONSTANT_NAMEANDTYPE:
- copy(4);
- break;
- case CONSTANT_LONG:
- case CONSTANT_DOUBLE:
- copy(8);
- ++i; // these take two CP entries - duh!
- break;
- case CONSTANT_UTF8:
- int len = copyU2();
- byte[] utf8 = readBytes(len);
- String str = null; // null to shut the compiler up
- try {
- str = new String(utf8, "UTF-8");
- } catch (Exception exc) {
- throw new Error("CP exception: " + exc);
- }
- constantPool[i] = str;
- if (str.equals(codeAttributeName)) {
- codeAttributeIndex = i;
- } else if (str.equals(lineNumberAttributeName)) {
- lineNumberAttributeIndex = i;
- } else if (str.equals(localVarAttributeName)) {
- localVarAttributeIndex = i;
- }
- writeBytes(utf8);
- break;
- default:
- throw new Error(i + " unexpected CP tag: " + tag);
- }
- }
- }
-
-}
--- a/jdk/test/java/lang/instrument/ilib/Info.java Tue Aug 26 16:42:31 2014 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package ilib;
-
-public class Info {
- final int counter;
- final String className;
- final String methodName;
- final int location;
-
- Info(int counter, String className, String methodName, int location) {
- this.counter = counter;
- this.className = className;
- this.methodName = methodName;
- this.location = location;
- }
-}
--- a/jdk/test/java/lang/instrument/ilib/Inject.java Tue Aug 26 16:42:31 2014 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,746 +0,0 @@
-/*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package ilib;
-
-import java.io.IOException;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.DataOutputStream;
-import java.util.List;
-import java.util.Iterator;
-import java.util.ArrayList;
-
-public class Inject implements RuntimeConstants {
-
- public static byte[] instrumentation(Options opt,
- ClassLoader loader,
- String className,
- byte[] classfileBuffer) {
- ClassReaderWriter c = new ClassReaderWriter(classfileBuffer);
- (new Inject(className, c, loader == null, opt)).doit();
- return c.result();
- }
-
- static boolean verbose = false;
-
- final String className;
- final ClassReaderWriter c;
- final boolean isSystem;
- final Options options;
-
- int constantPoolCount;
- int methodsCount;
- int methodsCountPos;
- int profiler;
- int wrappedTrackerIndex = 0;
- int thisClassIndex = 0;
-
- TrackerInjector callInjector;
- TrackerInjector allocInjector;
- TrackerInjector defaultInjector;
-
- static interface TrackerInjector extends Injector {
- void reinit(int tracker);
- int stackSize(int currentSize);
- }
-
- static class SimpleInjector implements TrackerInjector {
- byte[] injection;
-
- public int stackSize(int currentSize) {
- return currentSize;
- }
-
- public void reinit(int tracker) {
- injection = new byte[3];
- injection[0] = (byte)opc_invokestatic;
- injection[1] = (byte)(tracker >> 8);
- injection[2] = (byte)tracker;
- }
-
- public byte[] bytecodes(String className, String methodName, int location) {
- return injection;
- }
- }
-
- static class ObjectInjector implements TrackerInjector {
- byte[] injection;
-
- public int stackSize(int currentSize) {
- return currentSize + 1;
- }
-
- public void reinit(int tracker) {
- injection = new byte[4];
- injection[0] = (byte)opc_dup;
- injection[1] = (byte)opc_invokestatic;
- injection[2] = (byte)(tracker >> 8);
- injection[3] = (byte)tracker;
- }
-
- public byte[] bytecodes(String className, String methodName, int location) {
- return injection;
- }
- }
-
- class IndexedInjector implements TrackerInjector {
- int counter = 0;
- int tracker;
- List<Info> infoList = new ArrayList<>();
-
- public int stackSize(int currentSize) {
- return currentSize + 1;
- }
-
- public void reinit(int tracker) {
- this.tracker = tracker;
- }
-
- void dump(File outDir, String filename) throws IOException {
- try (FileOutputStream fileOut =
- new FileOutputStream(new File(outDir, filename));
- DataOutputStream dataOut = new DataOutputStream(fileOut))
- {
- String currentClassName = null;
-
- dataOut.writeInt(infoList.size());
- for (Iterator<Info> it = infoList.iterator(); it.hasNext(); ) {
- Info info = it.next();
- if (!info.className.equals(currentClassName)) {
- dataOut.writeInt(123456); // class name marker
- currentClassName = info.className;
- dataOut.writeUTF(currentClassName);
- }
- dataOut.writeInt(info.location);
- dataOut.writeUTF(info.methodName);
- }
- }
- }
-
- public byte[] bytecodes(String className, String methodName, int location) {
- byte[] injection = new byte[6];
- int injectedIndex = options.fixedIndex != 0? options.fixedIndex : ++counter;
- infoList.add(new Info(counter, className, methodName, location));
- injection[0] = (byte)opc_sipush;
- injection[1] = (byte)(injectedIndex >> 8);
- injection[2] = (byte)injectedIndex;
- injection[3] = (byte)opc_invokestatic;
- injection[4] = (byte)(tracker >> 8);
- injection[5] = (byte)tracker;
- return injection;
- }
- }
-
- Inject(String className, ClassReaderWriter c, boolean isSystem, Options options) {
- this.className = className;
- this.c = c;
- this.isSystem = isSystem;
- this.options = options;
- }
-
- void doit() {
- int i;
- c.copy(4 + 2 + 2); // magic min/maj version
- int constantPoolCountPos = c.generatedPosition();
- constantPoolCount = c.copyU2();
- // copy old constant pool
- c.copyConstantPool(constantPoolCount);
-
- if (verbose) {
- System.out.println("ConstantPool expanded from: " +
- constantPoolCount);
- }
-
- profiler = addClassToConstantPool(options.trackerClassName);
- if (options.shouldInstrumentNew || options.shouldInstrumentObjectInit) {
- if (options.shouldInstrumentIndexed) {
- if (allocInjector == null) {
- // first time - create it
- allocInjector = new IndexedInjector();
- }
- int allocTracker = addMethodToConstantPool(profiler,
- options.allocTrackerMethodName,
- "(I)V");
- allocInjector.reinit(allocTracker);
- } else if (options.shouldInstrumentObject) {
- if (allocInjector == null) {
- // first time - create it
- allocInjector = new ObjectInjector();
- }
- int allocTracker = addMethodToConstantPool(profiler,
- options.allocTrackerMethodName,
- "(Ljava/lang/Object;)V");
- allocInjector.reinit(allocTracker);
- } else {
- if (allocInjector == null) {
- // first time - create it
- allocInjector = new SimpleInjector();
- }
- int allocTracker = addMethodToConstantPool(profiler,
- options.allocTrackerMethodName,
- "()V");
- allocInjector.reinit(allocTracker);
- }
- defaultInjector = allocInjector;
- }
- if (options.shouldInstrumentCall) {
- if (options.shouldInstrumentIndexed) {
- if (callInjector == null) {
- // first time - create it
- callInjector = new IndexedInjector();
- }
- int callTracker = addMethodToConstantPool(profiler,
- options.callTrackerMethodName,
- "(I)V");
- callInjector.reinit(callTracker);
- } else {
- if (callInjector == null) {
- // first time - create it
- callInjector = new SimpleInjector();
- }
- int callTracker = addMethodToConstantPool(profiler,
- options.callTrackerMethodName,
- "()V");
- callInjector.reinit(callTracker);
- }
- defaultInjector = callInjector;
- }
-
- if (verbose) {
- System.out.println("To: " + constantPoolCount);
- }
-
- c.setSection(1);
-
- c.copy(2 + 2 + 2); // access, this, super
- int interfaceCount = c.copyU2();
- if (verbose) {
- System.out.println("interfaceCount: " + interfaceCount);
- }
- c.copy(interfaceCount * 2);
- copyFields(); // fields
- copyMethods(); // methods
- int attrCountPos = c.generatedPosition();
- int attrCount = c.copyU2();
- if (verbose) {
- System.out.println("class attrCount: " + attrCount);
- }
- // copy the class attributes
- copyAttrs(attrCount);
-
- c.randomAccessWriteU2(constantPoolCountPos, constantPoolCount);
- }
-
-
- void copyFields() {
- int count = c.copyU2();
- if (verbose) {
- System.out.println("fields count: " + count);
- }
- for (int i = 0; i < count; ++i) {
- c.copy(6); // access, name, descriptor
- int attrCount = c.copyU2();
- if (verbose) {
- System.out.println("field attr count: " + attrCount);
- }
- copyAttrs(attrCount);
- }
- }
-
- void copyMethods() {
- methodsCountPos = c.generatedPosition();
- methodsCount = c.copyU2();
- int initialMethodsCount = methodsCount;
- if (verbose) {
- System.out.println("methods count: " + methodsCount);
- }
- for (int i = 0; i < initialMethodsCount; ++i) {
- copyMethod();
- }
- }
-
- void copyMethod() {
- int accessFlags = c.copyU2();// access flags
- if (options.shouldInstrumentNativeMethods && (accessFlags & ACC_NATIVE) != 0) {
- wrapNativeMethod(accessFlags);
- return;
- }
- int nameIndex = c.copyU2(); // name
- String methodName = c.constantPoolString(nameIndex);
- c.copyU2(); // descriptor
- int attrCount = c.copyU2(); // attribute count
- if (verbose) {
- System.out.println("methods attr count: " + attrCount);
- }
- for (int i = 0; i < attrCount; ++i) {
- copyAttrForMethod(methodName, accessFlags);
- }
- }
-
- void wrapNativeMethod(int accessFlags) {
- // first, copy the native method with the name changed
- // accessFlags have already been copied
- int nameIndex = c.readU2(); // name
- String methodName = c.constantPoolString(nameIndex);
- String wrappedMethodName = options.wrappedPrefix + methodName;
- int wrappedNameIndex = writeCPEntryUtf8(wrappedMethodName);
- c.writeU2(wrappedNameIndex); // change to the wrapped name
-
- int descriptorIndex = c.copyU2(); // descriptor index
-
- int attrCount = c.copyU2(); // attribute count
- // need to replicate these attributes (esp Exceptions) in wrapper
- // so mark this location so we can rewind
- c.markLocalPositionStart();
- for (int i = 0; i < attrCount; ++i) {
- copyAttrForMethod(methodName, accessFlags);
- }
- if (true) {
- System.err.println(" wrapped: " + methodName);
- }
-
- // now write the wrapper method
- c.writeU2(accessFlags & ~ACC_NATIVE);
- c.writeU2(nameIndex); // original unwrapped name
- c.writeU2(descriptorIndex); // descriptor is the same
-
- c.writeU2(attrCount + 1); // wrapped plus a code attribute
- // rewind to wrapped attributes
- c.rewind();
- for (int i = 0; i < attrCount; ++i) {
- copyAttrForMethod(methodName, accessFlags);
- }
-
- // generate a Code attribute for the wrapper method
- int wrappedIndex = addMethodToConstantPool(getThisClassIndex(),
- wrappedNameIndex,
- descriptorIndex);
- String descriptor = c.constantPoolString(descriptorIndex);
- createWrapperCodeAttr(nameIndex, accessFlags, descriptor, wrappedIndex);
-
- // increment method count
- c.randomAccessWriteU2(methodsCountPos, ++methodsCount);
- }
-
- void copyAttrs(int attrCount) {
- for (int i = 0; i < attrCount; ++i) {
- copyAttr();
- }
- }
-
- void copyAttr() {
- c.copy(2); // name
- int len = c.copyU4(); // attr len
- if (verbose) {
- System.out.println("attr len: " + len);
- }
- c.copy(len); // attribute info
- }
-
- void copyAttrForMethod(String methodName, int accessFlags) {
- int nameIndex = c.copyU2(); // name
- // check for Code attr
- if (nameIndex == c.codeAttributeIndex) {
- try {
- copyCodeAttr(methodName);
- } catch (IOException exc) {
- System.err.println("Code Exception - " + exc);
- System.exit(1);
- }
- } else {
- int len = c.copyU4(); // attr len
- if (verbose) {
- System.out.println("method attr len: " + len);
- }
- c.copy(len); // attribute info
- }
- }
-
- void copyAttrForCode(InjectBytecodes ib) throws IOException {
- int nameIndex = c.copyU2(); // name
-
- // check for Code attr
- if (nameIndex == c.lineNumberAttributeIndex) {
- ib.copyLineNumberAttr();
- } else if (nameIndex == c.localVarAttributeIndex) {
- ib.copyLocalVarAttr();
- } else {
- int len = c.copyU4(); // attr len
- if (verbose) {
- System.out.println("code attr len: " + len);
- }
- c.copy(len); // attribute info
- }
- }
-
- void copyCodeAttr(String methodName) throws IOException {
- if (verbose) {
- System.out.println("Code attr found");
- }
- int attrLengthPos = c.generatedPosition();
- int attrLength = c.copyU4(); // attr len
- int maxStack = c.readU2(); // max stack
- c.writeU2(defaultInjector == null? maxStack :
- defaultInjector.stackSize(maxStack)); // big enough for injected code
- c.copyU2(); // max locals
- int codeLengthPos = c.generatedPosition();
- int codeLength = c.copyU4(); // code length
- if (options.targetMethod != null && !options.targetMethod.equals(methodName)) {
- c.copy(attrLength - 8); // copy remainder minus already copied
- return;
- }
- if (isSystem) {
- if (codeLength == 1 && methodName.equals("finalize")) {
- if (verbose) {
- System.out.println("empty system finalizer not instrumented");
- }
- c.copy(attrLength - 8); // copy remainder minus already copied
- return;
- }
- if (codeLength == 1 && methodName.equals("<init>")) {
- if (verbose) {
- System.out.println("empty system constructor not instrumented");
- }
- if (!options.shouldInstrumentObjectInit) {
- c.copy(attrLength - 8); // copy remainder minus already copied
- return;
- }
- }
- if (methodName.equals("<clinit>")) {
- if (verbose) {
- System.out.println("system class initializer not instrumented");
- }
- c.copy(attrLength - 8); // copy remainder minus already copied
- return;
- }
- }
- if (options.shouldInstrumentObjectInit
- && (!className.equals("java/lang/Object")
- || !methodName.equals("<init>"))) {
- c.copy(attrLength - 8); // copy remainder minus already copied
- return;
- }
-
- InjectBytecodes ib = new InjectBytecodes(c, codeLength, className, methodName);
-
- if (options.shouldInstrumentNew) {
- ib.injectAfter(opc_new, allocInjector);
- ib.injectAfter(opc_newarray, allocInjector);
- ib.injectAfter(opc_anewarray, allocInjector);
- ib.injectAfter(opc_multianewarray, allocInjector);
- }
- if (options.shouldInstrumentCall) {
- ib.inject(0, callInjector.bytecodes(className, methodName, 0));
- }
- if (options.shouldInstrumentObjectInit) {
- ib.inject(0, allocInjector.bytecodes(className, methodName, 0));
- }
-
- ib.adjustOffsets();
-
- // fix up code length
- int newCodeLength = c.generatedPosition() - (codeLengthPos + 4);
- c.randomAccessWriteU4(codeLengthPos, newCodeLength);
- if (verbose) {
- System.out.println("code length old: " + codeLength +
- ", new: " + newCodeLength);
- }
-
- ib.copyExceptionTable();
-
- int attrCount = c.copyU2();
- for (int i = 0; i < attrCount; ++i) {
- copyAttrForCode(ib);
- }
-
- // fix up attr length
- int newAttrLength = c.generatedPosition() - (attrLengthPos + 4);
- c.randomAccessWriteU4(attrLengthPos, newAttrLength);
- if (verbose) {
- System.out.println("attr length old: " + attrLength +
- ", new: " + newAttrLength);
- }
- }
-
- int nextDescriptorIndex(String descriptor, int index) {
- switch (descriptor.charAt(index)) {
- case 'B': // byte
- case 'C': // char
- case 'I': // int
- case 'S': // short
- case 'Z': // boolean
- case 'F': // float
- case 'D': // double
- case 'J': // long
- return index + 1;
- case 'L': // object
- int i = index + 1;
- while (descriptor.charAt(i) != ';') {
- ++i;
- }
- return i + 1;
- case '[': // array
- return nextDescriptorIndex(descriptor, index + 1);
- }
- throw new InternalError("should not reach here");
- }
-
- int getWrappedTrackerIndex() {
- if (wrappedTrackerIndex == 0) {
- wrappedTrackerIndex = addMethodToConstantPool(profiler,
- options.wrappedTrackerMethodName,
- "(Ljava/lang/String;I)V");
- }
- return wrappedTrackerIndex;
- }
-
- int getThisClassIndex() {
- if (thisClassIndex == 0) {
- thisClassIndex = addClassToConstantPool(className);
- }
- return thisClassIndex;
- }
-
- int computeMaxLocals(String descriptor, int accessFlags) {
- int index = 1;
- int slot = 0;
-
- if ((accessFlags & ACC_STATIC) == 0) {
- ++slot;
- }
- char type;
- while ((type = descriptor.charAt(index)) != ')') {
- switch (type) {
- case 'B': // byte
- case 'C': // char
- case 'I': // int
- case 'S': // short
- case 'Z': // boolean
- case 'F': // float
- case 'L': // object
- case '[': // array
- ++slot;
- break;
- case 'D': // double
- case 'J': // long
- slot += 2;
- break;
- }
- index = nextDescriptorIndex(descriptor, index);
- }
-
- return slot;
- }
-
-
- void createWrapperCodeAttr(int methodNameIndex, int accessFlags,
- String descriptor, int wrappedIndex) {
- int maxLocals = computeMaxLocals(descriptor, accessFlags);
-
- c.writeU2(c.codeAttributeIndex); //
- int attrLengthPos = c.generatedPosition();
- c.writeU4(0); // attr len -- fix up below
- c.writeU2(maxLocals + 4); // max stack
- c.writeU2(maxLocals); // max locals
- int codeLengthPos = c.generatedPosition();
- c.writeU4(0); // code length -- fix up below
-
- int methodStringIndex = writeCPEntryString(methodNameIndex);
-
- c.writeU1(opc_ldc_w);
- c.writeU2(methodStringIndex); // send the method name
- c.writeU1(opc_sipush);
- c.writeU2(options.fixedIndex);
- c.writeU1(opc_invokestatic);
- c.writeU2(getWrappedTrackerIndex());
-
- // set-up args
- int index = 1;
- int slot = 0;
- if ((accessFlags & ACC_STATIC) == 0) {
- c.writeU1(opc_aload_0); // this
- ++slot;
- }
- char type;
- while ((type = descriptor.charAt(index)) != ')') {
- switch (type) {
- case 'B': // byte
- case 'C': // char
- case 'I': // int
- case 'S': // short
- case 'Z': // boolean
- c.writeU1(opc_iload);
- c.writeU1(slot);
- ++slot;
- break;
- case 'F': // float
- c.writeU1(opc_fload);
- c.writeU1(slot);
- ++slot;
- break;
- case 'D': // double
- c.writeU1(opc_dload);
- c.writeU1(slot);
- slot += 2;
- break;
- case 'J': // long
- c.writeU1(opc_lload);
- c.writeU1(slot);
- slot += 2;
- break;
- case 'L': // object
- case '[': // array
- c.writeU1(opc_aload);
- c.writeU1(slot);
- ++slot;
- break;
- }
- index = nextDescriptorIndex(descriptor, index);
- }
-
- // call the wrapped version
- if ((accessFlags & ACC_STATIC) == 0) {
- c.writeU1(opc_invokevirtual);
- } else {
- c.writeU1(opc_invokestatic);
- }
- c.writeU2(wrappedIndex);
-
- // return correct type
- switch (descriptor.charAt(index+1)) {
- case 'B': // byte
- case 'C': // char
- case 'I': // int
- case 'S': // short
- case 'Z': // boolean
- c.writeU1(opc_ireturn);
- break;
- case 'F': // float
- c.writeU1(opc_freturn);
- break;
- case 'D': // double
- c.writeU1(opc_dreturn);
- break;
- case 'J': // long
- c.writeU1(opc_lreturn);
- break;
- case 'L': // object
- case '[': // array
- c.writeU1(opc_areturn);
- break;
- case 'V': // void
- c.writeU1(opc_return);
- break;
- }
-
- // end of code
-
- // fix up code length
- int newCodeLength = c.generatedPosition() - (codeLengthPos + 4);
- c.randomAccessWriteU4(codeLengthPos, newCodeLength);
-
- c.writeU2(0); // exception table length
- c.writeU2(0); // attribute count
-
- // fix up attr length
- int newAttrLength = c.generatedPosition() - (attrLengthPos + 4);
- c.randomAccessWriteU4(attrLengthPos, newAttrLength);
- }
-
-
- int addClassToConstantPool(String className) {
- int prevSection = c.setSection(0);
- int classNameIndex = writeCPEntryUtf8(className);
- int classIndex = writeCPEntryClass(classNameIndex);
- c.setSection(prevSection);
- return classIndex;
- }
-
- int addMethodToConstantPool(int classIndex,
- String methodName,
- String descr) {
- int prevSection = c.setSection(0);
- int methodNameIndex = writeCPEntryUtf8(methodName);
- int descrIndex = writeCPEntryUtf8(descr);
- c.setSection(prevSection);
- return addMethodToConstantPool(classIndex, methodNameIndex, descrIndex);
- }
-
- int addMethodToConstantPool(int classIndex,
- int methodNameIndex,
- int descrIndex) {
- int prevSection = c.setSection(0);
- int nameAndTypeIndex = writeCPEntryNameAndType(methodNameIndex,
- descrIndex);
- int methodIndex = writeCPEntryMethodRef(classIndex, nameAndTypeIndex);
- c.setSection(prevSection);
- return methodIndex;
- }
-
- int writeCPEntryUtf8(String str) {
- int prevSection = c.setSection(0);
- int len = str.length();
- c.writeU1(CONSTANT_UTF8); // Utf8 tag
- c.writeU2(len);
- for (int i = 0; i < len; ++i) {
- c.writeU1(str.charAt(i));
- }
- c.setSection(prevSection);
- return constantPoolCount++;
- }
-
- int writeCPEntryString(int utf8Index) {
- int prevSection = c.setSection(0);
- c.writeU1(CONSTANT_STRING);
- c.writeU2(utf8Index);
- c.setSection(prevSection);
- return constantPoolCount++;
- }
-
- int writeCPEntryClass(int classNameIndex) {
- int prevSection = c.setSection(0);
- c.writeU1(CONSTANT_CLASS);
- c.writeU2(classNameIndex);
- c.setSection(prevSection);
- return constantPoolCount++;
- }
-
- int writeCPEntryNameAndType(int nameIndex, int descrIndex) {
- int prevSection = c.setSection(0);
- c.writeU1(CONSTANT_NAMEANDTYPE);
- c.writeU2(nameIndex);
- c.writeU2(descrIndex);
- c.setSection(prevSection);
- return constantPoolCount++;
- }
-
- int writeCPEntryMethodRef(int classIndex, int nameAndTypeIndex) {
- int prevSection = c.setSection(0);
- c.writeU1(CONSTANT_METHOD);
- c.writeU2(classIndex);
- c.writeU2(nameAndTypeIndex);
- c.setSection(prevSection);
- return constantPoolCount++;
- }
-}
--- a/jdk/test/java/lang/instrument/ilib/InjectBytecodes.java Tue Aug 26 16:42:31 2014 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,769 +0,0 @@
-/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * An extension of BinaryCode that allows code to be printed.
- * Includes printing of disassembled byte codes, exception info,
- * local variable and line number info.
- *
- */
-
-package ilib;
-
-import java.io.ByteArrayInputStream;
-import java.io.CharArrayWriter;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.PrintStream;
-import java.util.Map;
-import java.util.HashMap;
-
-class InjectBytecodes implements RuntimeConstants {
-
- private final ClassReaderWriter c;
- private final PrintStream output;
- private final int length;
- private final int[] map;
- private final byte[] widening;
- private final Injector[] before = new Injector[256];
- private final Injector[] after = new Injector[256];
- private final String className;
- private final String methodName;
- private final Map<Integer,byte[]> snippets = new HashMap<>();
-
- private int pos;
- private int newPos;
-
- private class Span {
- final int delta;
- final int target;
- final int newDelta;
- final int newTarget;
-
- Span(int delta) {
- this.delta = delta;
- this.target = pos + delta;
- this.newTarget = map[target];
- this.newDelta = newTarget - newPos;
- }
- }
-
- /**
- * Constructor
- */
- InjectBytecodes(ClassReaderWriter c, int length,
- String className, String methodName) {
- this.c = c;
- this.output = System.out;
- this.length = length;
- this.map = new int[length + 1];
- this.widening = new byte[length + 1];
- this.className = className;
- this.methodName = methodName;
- c.markLocalPositionStart();
- for (int i = 0; i <= length; ++i) {
- map[i] = i;
- }
- }
-
- public void inject(int at, byte[] newCode) {
- snippets.put(new Integer(at), newCode);
- trace("external ");
- inject(at, newCode.length);
- }
-
- private void inject(int at, int len) {
- if (Inject.verbose) {
- traceln("Injecting " + len + " at " + at);
- }
- for (int i = at; i <= length; ++i) {
- map[i] += len;
- }
- }
-
- private void widen(int at, int len) {
- int delta = len - widening[at];
- if (Inject.verbose) {
- traceln();
- traceln("Widening to " + len + " at " + at);
- }
- inject(c.localPosition(), delta); // inject at end of instruction
- widening[at] = (byte)len; // mark at beginning of instruction
- }
-
- public void injectBefore(int code, Injector inj) {
- before[code] = inj;
- }
-
- public void injectAfter(int code, Injector inj) {
- after[code] = inj;
- }
-
- private void trace(String str) {
- if (Inject.verbose) {
- output.print(str);
- }
- }
-
- private void traceln(String str) {
- if (Inject.verbose) {
- output.println(str);
- }
- }
-
- private void traceln() {
- if (Inject.verbose) {
- output.println();
- }
- }
-
- private void trace(int i) {
- if (Inject.verbose) {
- output.print(i);
- }
- }
-
- /**
- * Print an integer so that it takes 'length' characters in
- * the output. Temporary until formatting code is stable.
- */
- private void traceFixedWidthInt(int x, int length) {
- if (Inject.verbose) {
- CharArrayWriter baStream = new CharArrayWriter();
- PrintWriter pStream = new PrintWriter(baStream);
- pStream.print(x);
- String str = baStream.toString();
- for (int cnt = length - str.length(); cnt > 0; --cnt)
- trace(" ");
- trace(str);
- }
- }
-
- void adjustOffsets() throws IOException {
- if (Inject.verbose) {
- traceln();
- traceln("Method " + methodName);
- traceln();
- }
- c.rewind();
- while (c.localPosition() < length) {
- insertAtInstruction();
- }
- trace("Searching for adjustments...");
- c.rewind();
- while (c.localPosition() < length) {
- if (!adjustInstruction()) {
- c.rewind();
- traceln();
- traceln("Restarting adjustments after change...");
- }
- }
- // write the new bytecodes
- traceln();
- traceln();
- trace("Writing new code...");
- c.rewind();
- while (c.localPosition() < length) {
- writeInstruction();
- }
- if (!snippets.isEmpty()) {
- throw new Error("not all snippets written");
- }
- }
-
- /**
- * Walk one instruction inserting instrumentation at specified instructions
- */
- private void insertAtInstruction() throws IOException {
- pos = c.localPosition();
- int opcode = c.readU1();
- if (opcode == opc_wide) {
- // no support for instrumenting wide instructions
- int wopcode = c.readU1();
- int lvIndex = c.readU2();
- switch (wopcode) {
- case opc_aload: case opc_astore:
- case opc_fload: case opc_fstore:
- case opc_iload: case opc_istore:
- case opc_lload: case opc_lstore:
- case opc_dload: case opc_dstore:
- case opc_ret:
- break;
-
- case opc_iinc:
- c.readS2();
- break;
- default:
- throw new Error("Invalid wide opcode: " + wopcode);
- }
- } else {
- Injector inj;
-
- inj = before[opcode];
- if (inj != null) {
- inject(pos, inj.bytecodes(className, methodName, pos));
- }
-
- switch (opcode) {
- case opc_tableswitch:{
- int header = (pos+1+3) & (~3); // 4byte boundry
- c.skip(header - (pos+1)); // skip old padding
-
- c.readU4();
- int low = c.readU4();
- int high = c.readU4();
- c.skip((high+1-low) * 4);
- break;
- }
-
- case opc_lookupswitch:{
- int header = (pos+1+3) & (~3); // 4byte boundry
- c.skip(header - (pos+1)); // skip padding
-
- c.readU4();
- int npairs = c.readU4();
- c.skip(npairs * 8);
- break;
- }
-
- default: {
- int instrLen = opcLengths[opcode];
- c.skip(instrLen-1);
- }
- }
- inj = after[opcode];
- if (inj != null) {
- pos = c.localPosition();
- inject(pos, inj.bytecodes(className, methodName, pos));
- }
- }
- }
-
- /**
- * Walk one instruction adjusting for insertions
- */
- private boolean adjustInstruction() throws IOException {
- pos = c.localPosition();
- newPos = map[pos];
- int opcode = c.readU1();
- if (Inject.verbose) {
- traceln();
- traceFixedWidthInt(pos, 4);
- traceFixedWidthInt(newPos, 4);
- trace(" ");
- }
- if (opcode == opc_wide) {
- int wopcode = c.readU1();
- int lvIndex = c.readU2();
- if (Inject.verbose) {
- trace(opcNames[wopcode] + "_w ");
- }
- switch (wopcode) {
- case opc_aload: case opc_astore:
- case opc_fload: case opc_fstore:
- case opc_iload: case opc_istore:
- case opc_lload: case opc_lstore:
- case opc_dload: case opc_dstore:
- case opc_ret:
- trace(lvIndex);
- break;
-
- case opc_iinc:
- int constVal = c.readS2();
- if (Inject.verbose) {
- trace(lvIndex + " " + constVal);
- }
- break;
- default:
- throw new Error("Invalid wide opcode: " + wopcode);
- }
- } else {
- if (Inject.verbose) {
- trace(opcNames[opcode]);
- }
- switch (opcode) {
-
- case opc_tableswitch:{
- int widened = widening[pos];
- int header = (pos+1+3) & (~3); // 4byte boundry
- int newHeader = (newPos+1+3) & (~3); // 4byte boundry
-
- c.skip(header - (pos+1)); // skip old padding
-
- Span defaultSkip = new Span(c.readU4());
- int low = c.readU4();
- int high = c.readU4();
- if (Inject.verbose) {
- trace(" " + low + " to " + high);
- trace(": default= [was] " + defaultSkip.target);
- trace(" [now] " + defaultSkip.newTarget);
- for (int i = low; i <= high; ++i) {
- Span jump = new Span(c.readU4());
- traceln("");
- trace('\t');
- traceFixedWidthInt(i, 5);
- trace(": " + jump.newTarget);
- }
- } else {
- c.skip((high+1-low) * 4);
- }
- int newPadding = newHeader - newPos;
- int oldPadding = header - pos;
- int deltaPadding = newPadding - oldPadding;
- if (widened != deltaPadding) {
- widen(pos, deltaPadding);
- return false; // cause restart
- }
- break;
- }
-
- case opc_lookupswitch:{
- int widened = widening[pos];
- int header = (pos+1+3) & (~3); // 4byte boundry
- int newHeader = (newPos+1+3) & (~3); // 4byte boundry
-
- c.skip(header - (pos+1)); // skip old padding
-
- Span defaultSkip = new Span(c.readU4());
- int npairs = c.readU4();
- if (Inject.verbose) {
- trace(" npairs: " + npairs);
- trace(": default= [was] " + defaultSkip.target);
- trace(" [now] " + defaultSkip.newTarget);
- for (int i = 0; i< npairs; ++i) {
- int match = c.readU4();
- Span jump = new Span(c.readU4());
- traceln("");
- trace('\t');
- traceFixedWidthInt(match, 5);
- trace(": " + jump.newTarget);
- }
- } else {
- c.skip(npairs * 8);
- }
- int newPadding = newHeader - newPos;
- int oldPadding = header - pos;
- int deltaPadding = newPadding - oldPadding;
- if (widened != deltaPadding) {
- widen(pos, deltaPadding);
- return false; // cause restart
- }
- break;
- }
-
- case opc_jsr: case opc_goto:
- case opc_ifeq: case opc_ifge: case opc_ifgt:
- case opc_ifle: case opc_iflt: case opc_ifne:
- case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge:
- case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt:
- case opc_if_acmpeq: case opc_if_acmpne:
- case opc_ifnull: case opc_ifnonnull: {
- int widened = widening[pos];
- Span jump = new Span(c.readS2());
- if (widened == 0) { // not yet widened
- int newDelta = jump.newDelta;
- if ((newDelta < -32768) || (newDelta > 32767)) {
- switch (opcode) {
- case opc_jsr: case opc_goto:
- widen(pos, 2); // will convert to wide
- break;
- default:
- widen(pos, 5); // will inject goto_w
- break;
- }
- return false; // cause restart
- }
- }
- if (Inject.verbose) {
- trace(" [was] " + jump.target + " ==> " +
- " [now] " + jump.newTarget);
- }
- break;
- }
-
- case opc_jsr_w:
- case opc_goto_w: {
- Span jump = new Span(c.readU4());
- if (Inject.verbose) {
- trace(" [was] " + jump.target +
- " [now] " + jump.newTarget);
- }
- break;
- }
-
- default: {
- int instrLen = opcLengths[opcode];
- c.skip(instrLen-1);
- break;
- }
- }
- }
- return true; // successful return
- }
-
-
- /**
- * Walk one instruction writing the transformed instruction.
- */
- private void writeInstruction() throws IOException {
- pos = c.localPosition();
- newPos = map[pos];
- byte[] newCode = snippets.remove(new Integer(pos));
- if (newCode != null) {
- traceln();
- traceFixedWidthInt(pos, 4);
- trace(" ... -- Inserting new code");
- c.writeBytes(newCode);
- }
- int opcode = c.readU1();
- if (Inject.verbose) {
- traceln();
- traceFixedWidthInt(pos, 4);
- traceFixedWidthInt(newPos, 4);
- trace(" ");
- }
- if (opcode == opc_wide) {
- int wopcode = c.readU1();
- int lvIndex = c.readU2();
- if (Inject.verbose) {
- trace(opcNames[wopcode] + "_w ");
- }
- c.writeU1(opcode);
- c.writeU1(wopcode);
- c.writeU2(lvIndex);
- switch (wopcode) {
- case opc_aload: case opc_astore:
- case opc_fload: case opc_fstore:
- case opc_iload: case opc_istore:
- case opc_lload: case opc_lstore:
- case opc_dload: case opc_dstore:
- case opc_ret:
- trace(lvIndex);
- break;
-
- case opc_iinc:
- int constVal = c.readS2();
- c.writeU2(constVal); // ??? U vs S
- if (Inject.verbose) {
- trace(lvIndex + " " + constVal);
- }
- break;
- default:
- throw new Error("Invalid wide opcode: " + wopcode);
- }
- } else {
- if (Inject.verbose) {
- trace(opcNames[opcode]);
- }
- switch (opcode) {
-
- case opc_tableswitch:{
- int header = (pos+1+3) & (~3); // 4byte boundry
- int newHeader = (newPos+1+3) & (~3); // 4byte boundry
-
- c.skip(header - (pos+1)); // skip old padding
-
- Span defaultSkip = new Span(c.readU4());
- int low = c.readU4();
- int high = c.readU4();
-
- c.writeU1(opcode); // copy instruction
- for (int i = newPos+1; i < newHeader; ++i) {
- c.writeU1(0); // write new padding
- }
- c.writeU4(defaultSkip.newDelta);
- c.writeU4(low);
- c.writeU4(high);
-
- if (Inject.verbose) {
- trace(" " + low + " to " + high);
- trace(": default= [was] " + defaultSkip.target);
- trace(" [now] " + defaultSkip.newTarget);
- }
- for (int i = low; i <= high; ++i) {
- Span jump = new Span(c.readU4());
- c.writeU4(jump.newDelta);
- if (Inject.verbose) {
- traceln("");
- trace('\t');
- traceFixedWidthInt(i, 5);
- trace(": " + jump.newTarget);
- }
- }
- break;
- }
-
- case opc_lookupswitch:{
- int header = (pos+1+3) & (~3); // 4byte boundry
- int newHeader = (newPos+1+3) & (~3); // 4byte boundry
-
- c.skip(header - (pos+1)); // skip old padding
-
- Span defaultSkip = new Span(c.readU4());
- int npairs = c.readU4();
- if (Inject.verbose) {
- trace(" npairs: " + npairs);
- trace(": default= [was] " + defaultSkip.target);
- trace(" [now] " + defaultSkip.newTarget);
- }
- c.writeU1(opcode); // copy instruction
- for (int i = newPos+1; i < newHeader; ++i) {
- c.writeU1(0); // write new padding
- }
- c.writeU4(defaultSkip.newDelta);
- c.writeU4(npairs);
- for (int i = 0; i< npairs; ++i) {
- int match = c.readU4();
- Span jump = new Span(c.readU4());
- c.writeU4(match);
- c.writeU4(jump.newDelta);
- if (Inject.verbose) {
- traceln("");
- trace('\t');
- traceFixedWidthInt(match, 5);
- trace(": " + jump.newTarget);
- }
- }
- break;
- }
-
- case opc_jsr: case opc_goto:
- case opc_ifeq: case opc_ifge: case opc_ifgt:
- case opc_ifle: case opc_iflt: case opc_ifne:
- case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge:
- case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt:
- case opc_if_acmpeq: case opc_if_acmpne:
- case opc_ifnull: case opc_ifnonnull: {
- int widened = widening[pos];
- Span jump = new Span(c.readS2());
- int newOpcode = opcode; // default to unchanged
- if (widened == 0) { // not widened
- c.writeU1(opcode); // rewrite instruction
- c.writeU2(jump.newDelta);
- } else if (widened == 2) { // wide form
- switch (opcode) {
- case opc_jsr:
- newOpcode = opc_jsr_w;
- break;
- case opc_goto:
- newOpcode = opc_jsr_w;
- break;
- default:
- throw new Error("unexpected opcode: " +
- opcode);
- }
- c.writeU1(newOpcode); // write wide instruction
- c.writeU4(jump.newDelta); // write new and wide delta
- } else if (widened == 5) { // insert goto_w
- switch (opcode) {
- case opc_ifeq:
- newOpcode = opc_ifne;
- break;
- case opc_ifge:
- newOpcode = opc_iflt;
- break;
- case opc_ifgt:
- newOpcode = opc_ifle;
- break;
- case opc_ifle:
- newOpcode = opc_ifgt;
- break;
- case opc_iflt:
- newOpcode = opc_ifge;
- break;
- case opc_ifne:
- newOpcode = opc_ifeq;
- break;
- case opc_if_icmpeq:
- newOpcode = opc_if_icmpne;
- break;
- case opc_if_icmpne:
- newOpcode = opc_if_icmpeq;
- break;
- case opc_if_icmpge:
- newOpcode = opc_if_icmplt;
- break;
- case opc_if_icmpgt:
- newOpcode = opc_if_icmple;
- break;
- case opc_if_icmple:
- newOpcode = opc_if_icmpgt;
- break;
- case opc_if_icmplt:
- newOpcode = opc_if_icmpge;
- break;
- case opc_if_acmpeq:
- newOpcode = opc_if_acmpne;
- break;
- case opc_if_acmpne:
- newOpcode = opc_if_acmpeq;
- break;
- case opc_ifnull:
- newOpcode = opc_ifnonnull;
- break;
- case opc_ifnonnull:
- newOpcode = opc_ifnull;
- break;
- default:
- throw new Error("unexpected opcode: " +
- opcode);
- }
- c.writeU1(newOpcode); // write inverse branch
- c.writeU2(3 + 5); // beyond if and goto_w
- c.writeU1(opc_goto_w);// add a goto_w
- c.writeU4(jump.newDelta); // write new and wide delta
- } else {
- throw new Error("unexpected widening");
- }
-
- if (Inject.verbose) {
- trace(" [was] " + jump.target + " ==> " +
- opcNames[newOpcode] +
- " [now] " + jump.newTarget);
- }
- break;
- }
-
- case opc_jsr_w:
- case opc_goto_w: {
- Span jump = new Span(c.readU4());
- c.writeU1(opcode); // instruction itself
- c.writeU4(jump.newDelta);
- if (Inject.verbose) {
- trace(" [was] " + jump.target +
- " [now] " + jump.newTarget);
- }
- break;
- }
-
- default: {
- int instrLen = opcLengths[opcode];
- c.writeU1(opcode); // instruction itself
- c.copy(instrLen-1);
- }
- }
- }
- }
-
- /**
- * Copy the exception table for this method code
- */
- void copyExceptionTable() throws IOException {
- int tableLength = c.copyU2(); // exception table len
- if (tableLength > 0) {
- traceln();
- traceln("Exception table:");
- traceln(" from:old/new to:old/new target:old/new type");
- for (int tcnt = tableLength; tcnt > 0; --tcnt) {
- int startPC = c.readU2();
- int newStartPC = map[startPC];
- c.writeU2(newStartPC);
- int endPC = c.readU2();
- int newEndPC = map[endPC];
- c.writeU2(newEndPC);
- int handlerPC = c.readU2();
- int newHandlerPC = map[handlerPC];
- c.writeU2(newHandlerPC);
- int catchType = c.copyU2();
- if (Inject.verbose) {
- traceFixedWidthInt(startPC, 6);
- traceFixedWidthInt(newStartPC, 6);
- traceFixedWidthInt(endPC, 6);
- traceFixedWidthInt(newEndPC, 6);
- traceFixedWidthInt(handlerPC, 6);
- traceFixedWidthInt(newHandlerPC, 6);
- trace(" ");
- if (catchType == 0)
- traceln("any");
- else {
- traceln("" + catchType);
- }
- }
- }
- }
- }
-
- /**
- * Copy the line number table for this method code
- */
- void copyLineNumberAttr() throws IOException {
- // name index already read
- c.copy(4); // attr len
- int tableLength = c.copyU2(); // line table len
- if (tableLength > 0) {
- if (Inject.verbose) {
- traceln();
- traceln("Line numbers for method " + methodName);
- }
- for (int tcnt = tableLength; tcnt > 0; --tcnt) {
- int startPC = c.readU2();
- int newStartPC = map[startPC];
- c.writeU2(newStartPC);
- int lineNumber = c.copyU2();
- if (Inject.verbose) {
- traceln(" line " + lineNumber +
- ": [was] " + startPC +
- " [now] " + newStartPC);
- }
- }
- }
- }
-
- /**
- * Copy the local variable table for this method code
- */
- void copyLocalVarAttr() throws IOException {
- // name index already read
- c.copy(4); // attr len
- int tableLength = c.copyU2(); // local var table len
- if (tableLength > 0) {
- if (Inject.verbose) {
- traceln();
- traceln("Local variables for method " + methodName);
- }
- for (int tcnt = tableLength; tcnt > 0; --tcnt) {
- int startPC = c.readU2();
- int newStartPC = map[startPC];
- c.writeU2(newStartPC);
- int length = c.readU2();
- int endPC = startPC + length;
- int newEndPC = map[endPC];
- int newLength = newEndPC - newStartPC;
- c.writeU2(newLength);
- int nameIndex = c.copyU2();
- int descriptorIndex = c.copyU2();
- int index = c.copyU2();
- if (Inject.verbose) {
- trace(" ");
- trace(descriptorIndex);
- trace(" ");
- trace(nameIndex);
- traceln(" pc= [was] " + startPC + " [now] " + newStartPC +
- ", length= [was] " + length + " [now] " + newLength +
- ", slot=" + index);
- }
- }
- }
- }
-}
--- a/jdk/test/java/lang/instrument/ilib/Injector.java Tue Aug 26 16:42:31 2014 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package ilib;
-
-interface Injector {
- byte[] bytecodes(String className, String methodName, int location);
-}
--- a/jdk/test/java/lang/instrument/ilib/Options.java Tue Aug 26 16:42:31 2014 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package ilib;
-
-public class Options {
- public boolean shouldInstrumentNew = false;
- public boolean shouldInstrumentCall = false;
- public boolean shouldInstrumentIndexed = false;
- public boolean shouldInstrumentObject = false;
- public boolean shouldInstrumentObjectInit = false;
- public boolean shouldInstrumentNativeMethods = false;
- public String targetMethod = null;
- public int fixedIndex = 0;
- public String trackerClassName = "MyTracker";
- public String allocTrackerMethodName = "allocTracker";
- public String callTrackerMethodName = "callTracker";
- public String wrappedTrackerMethodName = "wrappedTracker";
- public String wrappedPrefix = "wrapped_up_";
-}
--- a/jdk/test/java/lang/instrument/ilib/RuntimeConstants.java Tue Aug 26 16:42:31 2014 +0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,732 +0,0 @@
-/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package ilib;
-
-public interface RuntimeConstants {
-
- /* Signature Characters */
- char SIGC_VOID = 'V';
- String SIG_VOID = "V";
- char SIGC_BOOLEAN = 'Z';
- String SIG_BOOLEAN = "Z";
- char SIGC_BYTE = 'B';
- String SIG_BYTE = "B";
- char SIGC_CHAR = 'C';
- String SIG_CHAR = "C";
- char SIGC_SHORT = 'S';
- String SIG_SHORT = "S";
- char SIGC_INT = 'I';
- String SIG_INT = "I";
- char SIGC_LONG = 'J';
- String SIG_LONG = "J";
- char SIGC_FLOAT = 'F';
- String SIG_FLOAT = "F";
- char SIGC_DOUBLE = 'D';
- String SIG_DOUBLE = "D";
- char SIGC_ARRAY = '[';
- String SIG_ARRAY = "[";
- char SIGC_CLASS = 'L';
- String SIG_CLASS = "L";
- char SIGC_METHOD = '(';
- String SIG_METHOD = "(";
- char SIGC_ENDCLASS = ';';
- String SIG_ENDCLASS = ";";
- char SIGC_ENDMETHOD = ')';
- String SIG_ENDMETHOD = ")";
- char SIGC_PACKAGE = '/';
- String SIG_PACKAGE = "/";
-
- /* Class File Constants */
- int JAVA_MAGIC = 0xcafebabe;
- int JAVA_MIN_SUPPORTED_VERSION = 45;
- int JAVA_MAX_SUPPORTED_VERSION = 48;
- int JAVA_MAX_SUPPORTED_MINOR_VERSION = 0;
-
- /* Generate class file version for 1.1 by default */
- int JAVA_DEFAULT_VERSION = 45;
- int JAVA_DEFAULT_MINOR_VERSION = 3;
-
- /* Constant table */
- int CONSTANT_UTF8 = 1;
- int CONSTANT_UNICODE = 2;
- int CONSTANT_INTEGER = 3;
- int CONSTANT_FLOAT = 4;
- int CONSTANT_LONG = 5;
- int CONSTANT_DOUBLE = 6;
- int CONSTANT_CLASS = 7;
- int CONSTANT_STRING = 8;
- int CONSTANT_FIELD = 9;
- int CONSTANT_METHOD = 10;
- int CONSTANT_INTERFACEMETHOD = 11;
- int CONSTANT_NAMEANDTYPE = 12;
-
- /* Access and modifier flags */
- int ACC_PUBLIC = 0x00000001;
- int ACC_PRIVATE = 0x00000002;
- int ACC_PROTECTED = 0x00000004;
- int ACC_STATIC = 0x00000008;
- int ACC_FINAL = 0x00000010;
- int ACC_SYNCHRONIZED = 0x00000020;
- int ACC_VOLATILE = 0x00000040;
- int ACC_TRANSIENT = 0x00000080;
- int ACC_NATIVE = 0x00000100;
- int ACC_INTERFACE = 0x00000200;
- int ACC_ABSTRACT = 0x00000400;
- int ACC_SUPER = 0x00000020;
- int ACC_STRICT = 0x00000800;
-
- /* Type codes */
- int T_CLASS = 0x00000002;
- int T_BOOLEAN = 0x00000004;
- int T_CHAR = 0x00000005;
- int T_FLOAT = 0x00000006;
- int T_DOUBLE = 0x00000007;
- int T_BYTE = 0x00000008;
- int T_SHORT = 0x00000009;
- int T_INT = 0x0000000a;
- int T_LONG = 0x0000000b;
-
- /* Opcodes */
- int opc_try = -3;
- int opc_dead = -2;
- int opc_label = -1;
- int opc_nop = 0;
- int opc_aconst_null = 1;
- int opc_iconst_m1 = 2;
- int opc_iconst_0 = 3;
- int opc_iconst_1 = 4;
- int opc_iconst_2 = 5;
- int opc_iconst_3 = 6;
- int opc_iconst_4 = 7;
- int opc_iconst_5 = 8;
- int opc_lconst_0 = 9;
- int opc_lconst_1 = 10;
- int opc_fconst_0 = 11;
- int opc_fconst_1 = 12;
- int opc_fconst_2 = 13;
- int opc_dconst_0 = 14;
- int opc_dconst_1 = 15;
- int opc_bipush = 16;
- int opc_sipush = 17;
- int opc_ldc = 18;
- int opc_ldc_w = 19;
- int opc_ldc2_w = 20;
- int opc_iload = 21;
- int opc_lload = 22;
- int opc_fload = 23;
- int opc_dload = 24;
- int opc_aload = 25;
- int opc_iload_0 = 26;
- int opc_iload_1 = 27;
- int opc_iload_2 = 28;
- int opc_iload_3 = 29;
- int opc_lload_0 = 30;
- int opc_lload_1 = 31;
- int opc_lload_2 = 32;
- int opc_lload_3 = 33;
- int opc_fload_0 = 34;
- int opc_fload_1 = 35;
- int opc_fload_2 = 36;
- int opc_fload_3 = 37;
- int opc_dload_0 = 38;
- int opc_dload_1 = 39;
- int opc_dload_2 = 40;
- int opc_dload_3 = 41;
- int opc_aload_0 = 42;
- int opc_aload_1 = 43;
- int opc_aload_2 = 44;
- int opc_aload_3 = 45;
- int opc_iaload = 46;
- int opc_laload = 47;
- int opc_faload = 48;
- int opc_daload = 49;
- int opc_aaload = 50;
- int opc_baload = 51;
- int opc_caload = 52;
- int opc_saload = 53;
- int opc_istore = 54;
- int opc_lstore = 55;
- int opc_fstore = 56;
- int opc_dstore = 57;
- int opc_astore = 58;
- int opc_istore_0 = 59;
- int opc_istore_1 = 60;
- int opc_istore_2 = 61;
- int opc_istore_3 = 62;
- int opc_lstore_0 = 63;
- int opc_lstore_1 = 64;
- int opc_lstore_2 = 65;
- int opc_lstore_3 = 66;
- int opc_fstore_0 = 67;
- int opc_fstore_1 = 68;
- int opc_fstore_2 = 69;
- int opc_fstore_3 = 70;
- int opc_dstore_0 = 71;
- int opc_dstore_1 = 72;
- int opc_dstore_2 = 73;
- int opc_dstore_3 = 74;
- int opc_astore_0 = 75;
- int opc_astore_1 = 76;
- int opc_astore_2 = 77;
- int opc_astore_3 = 78;
- int opc_iastore = 79;
- int opc_lastore = 80;
- int opc_fastore = 81;
- int opc_dastore = 82;
- int opc_aastore = 83;
- int opc_bastore = 84;
- int opc_castore = 85;
- int opc_sastore = 86;
- int opc_pop = 87;
- int opc_pop2 = 88;
- int opc_dup = 89;
- int opc_dup_x1 = 90;
- int opc_dup_x2 = 91;
- int opc_dup2 = 92;
- int opc_dup2_x1 = 93;
- int opc_dup2_x2 = 94;
- int opc_swap = 95;
- int opc_iadd = 96;
- int opc_ladd = 97;
- int opc_fadd = 98;
- int opc_dadd = 99;
- int opc_isub = 100;
- int opc_lsub = 101;
- int opc_fsub = 102;
- int opc_dsub = 103;
- int opc_imul = 104;
- int opc_lmul = 105;
- int opc_fmul = 106;
- int opc_dmul = 107;
- int opc_idiv = 108;
- int opc_ldiv = 109;
- int opc_fdiv = 110;
- int opc_ddiv = 111;
- int opc_irem = 112;
- int opc_lrem = 113;
- int opc_frem = 114;
- int opc_drem = 115;
- int opc_ineg = 116;
- int opc_lneg = 117;
- int opc_fneg = 118;
- int opc_dneg = 119;
- int opc_ishl = 120;
- int opc_lshl = 121;
- int opc_ishr = 122;
- int opc_lshr = 123;
- int opc_iushr = 124;
- int opc_lushr = 125;
- int opc_iand = 126;
- int opc_land = 127;
- int opc_ior = 128;
- int opc_lor = 129;
- int opc_ixor = 130;
- int opc_lxor = 131;
- int opc_iinc = 132;
- int opc_i2l = 133;
- int opc_i2f = 134;
- int opc_i2d = 135;
- int opc_l2i = 136;
- int opc_l2f = 137;
- int opc_l2d = 138;
- int opc_f2i = 139;
- int opc_f2l = 140;
- int opc_f2d = 141;
- int opc_d2i = 142;
- int opc_d2l = 143;
- int opc_d2f = 144;
- int opc_i2b = 145;
- int opc_i2c = 146;
- int opc_i2s = 147;
- int opc_lcmp = 148;
- int opc_fcmpl = 149;
- int opc_fcmpg = 150;
- int opc_dcmpl = 151;
- int opc_dcmpg = 152;
- int opc_ifeq = 153;
- int opc_ifne = 154;
- int opc_iflt = 155;
- int opc_ifge = 156;
- int opc_ifgt = 157;
- int opc_ifle = 158;
- int opc_if_icmpeq = 159;
- int opc_if_icmpne = 160;
- int opc_if_icmplt = 161;
- int opc_if_icmpge = 162;
- int opc_if_icmpgt = 163;
- int opc_if_icmple = 164;
- int opc_if_acmpeq = 165;
- int opc_if_acmpne = 166;
- int opc_goto = 167;
- int opc_jsr = 168;
- int opc_ret = 169;
- int opc_tableswitch = 170;
- int opc_lookupswitch = 171;
- int opc_ireturn = 172;
- int opc_lreturn = 173;
- int opc_freturn = 174;
- int opc_dreturn = 175;
- int opc_areturn = 176;
- int opc_return = 177;
- int opc_getstatic = 178;
- int opc_putstatic = 179;
- int opc_getfield = 180;
- int opc_putfield = 181;
- int opc_invokevirtual = 182;
- int opc_invokespecial = 183;
- int opc_invokestatic = 184;
- int opc_invokeinterface = 185;
- int opc_xxxunusedxxx = 186;
- int opc_new = 187;
- int opc_newarray = 188;
- int opc_anewarray = 189;
- int opc_arraylength = 190;
- int opc_athrow = 191;
- int opc_checkcast = 192;
- int opc_instanceof = 193;
- int opc_monitorenter = 194;
- int opc_monitorexit = 195;
- int opc_wide = 196;
- int opc_multianewarray = 197;
- int opc_ifnull = 198;
- int opc_ifnonnull = 199;
- int opc_goto_w = 200;
- int opc_jsr_w = 201;
- int opc_breakpoint = 202;
-
- /* Opcode Names */
- String opcNames[] = {
- "nop",
- "aconst_null",
- "iconst_m1",
- "iconst_0",
- "iconst_1",
- "iconst_2",
- "iconst_3",
- "iconst_4",
- "iconst_5",
- "lconst_0",
- "lconst_1",
- "fconst_0",
- "fconst_1",
- "fconst_2",
- "dconst_0",
- "dconst_1",
- "bipush",
- "sipush",
- "ldc",
- "ldc_w",
- "ldc2_w",
- "iload",
- "lload",
- "fload",
- "dload",
- "aload",
- "iload_0",
- "iload_1",
- "iload_2",
- "iload_3",
- "lload_0",
- "lload_1",
- "lload_2",
- "lload_3",
- "fload_0",
- "fload_1",
- "fload_2",
- "fload_3",
- "dload_0",
- "dload_1",
- "dload_2",
- "dload_3",
- "aload_0",
- "aload_1",
- "aload_2",
- "aload_3",
- "iaload",
- "laload",
- "faload",
- "daload",
- "aaload",
- "baload",
- "caload",
- "saload",
- "istore",
- "lstore",
- "fstore",
- "dstore",
- "astore",
- "istore_0",
- "istore_1",
- "istore_2",
- "istore_3",
- "lstore_0",
- "lstore_1",
- "lstore_2",
- "lstore_3",
- "fstore_0",
- "fstore_1",
- "fstore_2",
- "fstore_3",
- "dstore_0",
- "dstore_1",
- "dstore_2",
- "dstore_3",
- "astore_0",
- "astore_1",
- "astore_2",
- "astore_3",
- "iastore",
- "lastore",
- "fastore",
- "dastore",
- "aastore",
- "bastore",
- "castore",
- "sastore",
- "pop",
- "pop2",
- "dup",
- "dup_x1",
- "dup_x2",
- "dup2",
- "dup2_x1",
- "dup2_x2",
- "swap",
- "iadd",
- "ladd",
- "fadd",
- "dadd",
- "isub",
- "lsub",
- "fsub",
- "dsub",
- "imul",
- "lmul",
- "fmul",
- "dmul",
- "idiv",
- "ldiv",
- "fdiv",
- "ddiv",
- "irem",
- "lrem",
- "frem",
- "drem",
- "ineg",
- "lneg",
- "fneg",
- "dneg",
- "ishl",
- "lshl",
- "ishr",
- "lshr",
- "iushr",
- "lushr",
- "iand",
- "land",
- "ior",
- "lor",
- "ixor",
- "lxor",
- "iinc",
- "i2l",
- "i2f",
- "i2d",
- "l2i",
- "l2f",
- "l2d",
- "f2i",
- "f2l",
- "f2d",
- "d2i",
- "d2l",
- "d2f",
- "i2b",
- "i2c",
- "i2s",
- "lcmp",
- "fcmpl",
- "fcmpg",
- "dcmpl",
- "dcmpg",
- "ifeq",
- "ifne",
- "iflt",
- "ifge",
- "ifgt",
- "ifle",
- "if_icmpeq",
- "if_icmpne",
- "if_icmplt",
- "if_icmpge",
- "if_icmpgt",
- "if_icmple",
- "if_acmpeq",
- "if_acmpne",
- "goto",
- "jsr",
- "ret",
- "tableswitch",
- "lookupswitch",
- "ireturn",
- "lreturn",
- "freturn",
- "dreturn",
- "areturn",
- "return",
- "getstatic",
- "putstatic",
- "getfield",
- "putfield",
- "invokevirtual",
- "invokespecial",
- "invokestatic",
- "invokeinterface",
- "xxxunusedxxx",
- "new",
- "newarray",
- "anewarray",
- "arraylength",
- "athrow",
- "checkcast",
- "instanceof",
- "monitorenter",
- "monitorexit",
- "wide",
- "multianewarray",
- "ifnull",
- "ifnonnull",
- "goto_w",
- "jsr_w",
- "breakpoint"
- };
-
- /* Opcode Lengths */
- int opcLengths[] = {
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 2,
- 3,
- 2,
- 3,
- 3,
- 2,
- 2,
- 2,
- 2,
- 2,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 2,
- 2,
- 2,
- 2,
- 2,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 3,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 2,
- 99,
- 99,
- 1,
- 1,
- 1,
- 1,
- 1,
- 1,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 3,
- 5,
- 0,
- 3,
- 2,
- 3,
- 1,
- 1,
- 3,
- 3,
- 1,
- 1,
- 0,
- 4,
- 3,
- 3,
- 5,
- 5,
- 1
- };
-
-}