diff options
author | Yohann Roussel <yroussel@google.com> | 2014-02-06 15:24:30 +0100 |
---|---|---|
committer | Yohann Roussel <yroussel@google.com> | 2014-02-06 18:32:39 +0100 |
commit | e991948d20515a04e46524dbe1bf17222e872889 (patch) | |
tree | 63c7abc9002ff6054700beff5680d206701244b7 /asm4/examples | |
parent | 1b0adcc591ba181dce100b0ca70d5a63eae43807 (diff) | |
download | toolchain_jill-e991948d20515a04e46524dbe1bf17222e872889.tar.gz toolchain_jill-e991948d20515a04e46524dbe1bf17222e872889.tar.bz2 toolchain_jill-e991948d20515a04e46524dbe1bf17222e872889.zip |
Jack initial import.
Change-Id: I8d1fc53d705d25429514842aac2368d9b87c8c6f
Diffstat (limited to 'asm4/examples')
40 files changed, 5308 insertions, 0 deletions
diff --git a/asm4/examples/adapt/etc/execute.properties b/asm4/examples/adapt/etc/execute.properties new file mode 100644 index 0000000..e7fea9d --- /dev/null +++ b/asm4/examples/adapt/etc/execute.properties @@ -0,0 +1,32 @@ +############################################################################### +#ASM: a very small and fast Java bytecode manipulation framework +#Copyright (c) 2000-2011 INRIA, France Telecom +#All rights reserved. +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions +#are met: +#1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +#2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +#3. Neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +#THE POSSIBILITY OF SUCH DAMAGE. +############################################################################### + +run.classname Adapt +run.parameters ArraySet diff --git a/asm4/examples/adapt/src/Adapt.java b/asm4/examples/adapt/src/Adapt.java new file mode 100644 index 0000000..011f364 --- /dev/null +++ b/asm4/examples/adapt/src/Adapt.java @@ -0,0 +1,196 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +/** + * @author Eric Bruneton + */ +public class Adapt extends ClassLoader { + + @Override + protected synchronized Class<?> loadClass(final String name, + final boolean resolve) throws ClassNotFoundException { + if (name.startsWith("java.")) { + System.err.println("Adapt: loading class '" + name + + "' without on the fly adaptation"); + return super.loadClass(name, resolve); + } else { + System.err.println("Adapt: loading class '" + name + + "' with on the fly adaptation"); + } + + // gets an input stream to read the bytecode of the class + String resource = name.replace('.', '/') + ".class"; + InputStream is = getResourceAsStream(resource); + byte[] b; + + // adapts the class on the fly + try { + ClassReader cr = new ClassReader(is); + ClassWriter cw = new ClassWriter(0); + ClassVisitor cv = new TraceFieldClassAdapter(cw); + cr.accept(cv, 0); + b = cw.toByteArray(); + } catch (Exception e) { + throw new ClassNotFoundException(name, e); + } + + // optional: stores the adapted class on disk + try { + FileOutputStream fos = new FileOutputStream(resource + ".adapted"); + fos.write(b); + fos.close(); + } catch (IOException e) { + } + + // returns the adapted class + return defineClass(name, b, 0, b.length); + } + + public static void main(final String args[]) throws Exception { + // loads the application class (in args[0]) with an Adapt class loader + ClassLoader loader = new Adapt(); + Class<?> c = loader.loadClass(args[0]); + // calls the 'main' static method of this class with the + // application arguments (in args[1] ... args[n]) as parameter + Method m = c.getMethod("main", new Class<?>[] { String[].class }); + String[] applicationArgs = new String[args.length - 1]; + System.arraycopy(args, 1, applicationArgs, 0, applicationArgs.length); + m.invoke(null, new Object[] { applicationArgs }); + } +} + +class TraceFieldClassAdapter extends ClassVisitor implements Opcodes { + + private String owner; + + public TraceFieldClassAdapter(final ClassVisitor cv) { + super(Opcodes.ASM4, cv); + } + + @Override + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { + owner = name; + super.visit(version, access, name, signature, superName, interfaces); + } + + @Override + public FieldVisitor visitField(final int access, final String name, + final String desc, final String signature, final Object value) { + FieldVisitor fv = super + .visitField(access, name, desc, signature, value); + if ((access & ACC_STATIC) == 0) { + Type t = Type.getType(desc); + int size = t.getSize(); + + // generates getter method + String gDesc = "()" + desc; + MethodVisitor gv = cv.visitMethod(ACC_PRIVATE, "_get" + name, + gDesc, null, null); + gv.visitFieldInsn(GETSTATIC, "java/lang/System", "err", + "Ljava/io/PrintStream;"); + gv.visitLdcInsn("_get" + name + " called"); + gv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", + "(Ljava/lang/String;)V"); + gv.visitVarInsn(ALOAD, 0); + gv.visitFieldInsn(GETFIELD, owner, name, desc); + gv.visitInsn(t.getOpcode(IRETURN)); + gv.visitMaxs(1 + size, 1); + gv.visitEnd(); + + // generates setter method + String sDesc = "(" + desc + ")V"; + MethodVisitor sv = cv.visitMethod(ACC_PRIVATE, "_set" + name, + sDesc, null, null); + sv.visitFieldInsn(GETSTATIC, "java/lang/System", "err", + "Ljava/io/PrintStream;"); + sv.visitLdcInsn("_set" + name + " called"); + sv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", + "(Ljava/lang/String;)V"); + sv.visitVarInsn(ALOAD, 0); + sv.visitVarInsn(t.getOpcode(ILOAD), 1); + sv.visitFieldInsn(PUTFIELD, owner, name, desc); + sv.visitInsn(RETURN); + sv.visitMaxs(1 + size, 1 + size); + sv.visitEnd(); + } + return fv; + } + + @Override + public MethodVisitor visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { + MethodVisitor mv = cv.visitMethod(access, name, desc, signature, + exceptions); + return mv == null ? null : new TraceFieldCodeAdapter(mv, owner); + } +} + +class TraceFieldCodeAdapter extends MethodVisitor implements Opcodes { + + private String owner; + + public TraceFieldCodeAdapter(final MethodVisitor mv, final String owner) { + super(Opcodes.ASM4, mv); + this.owner = owner; + } + + @Override + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { + if (owner.equals(this.owner)) { + if (opcode == GETFIELD) { + // replaces GETFIELD f by INVOKESPECIAL _getf + String gDesc = "()" + desc; + visitMethodInsn(INVOKESPECIAL, owner, "_get" + name, gDesc); + return; + } else if (opcode == PUTFIELD) { + // replaces PUTFIELD f by INVOKESPECIAL _setf + String sDesc = "(" + desc + ")V"; + visitMethodInsn(INVOKESPECIAL, owner, "_set" + name, sDesc); + return; + } + } + super.visitFieldInsn(opcode, owner, name, desc); + } +} diff --git a/asm4/examples/adapt/src/ArraySet.java b/asm4/examples/adapt/src/ArraySet.java new file mode 100644 index 0000000..3548cd6 --- /dev/null +++ b/asm4/examples/adapt/src/ArraySet.java @@ -0,0 +1,94 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @author Eric Bruneton + */ +public class ArraySet { + + private int[] values = new int[3]; + + private int size; + + public boolean contains(final int v) { + for (int i = 0; i < size; ++i) { + if (values[i] == v) { + return true; + } + } + return false; + } + + public void add(final int v) { + if (!contains(v)) { + if (size == values.length) { + System.err.println("[enlarge]"); + int[] newValues = new int[values.length + 3]; + System.arraycopy(values, 0, newValues, 0, size); + values = newValues; + } + values[size++] = v; + } + } + + public void remove(final int v) { + int i = 0; + int j = 0; + while (i < size) { + int u = values[i]; + if (u != v) { + values[j++] = u; + } + ++i; + } + size = j; + } + + // test method + + public static void main(final String[] args) { + ArraySet s = new ArraySet(); + System.err.println("add 1"); + s.add(1); + System.err.println("add 1"); + s.add(1); + System.err.println("add 2"); + s.add(2); + System.err.println("add 4"); + s.add(4); + System.err.println("add 8"); + s.add(8); + System.err.println("contains 3 = " + s.contains(3)); + System.err.println("contains 1 = " + s.contains(1)); + System.err.println("remove 1"); + s.remove(1); + System.err.println("contains 1 = " + s.contains(1)); + } +} diff --git a/asm4/examples/analysis/etc/execute.properties b/asm4/examples/analysis/etc/execute.properties new file mode 100644 index 0000000..b560b40 --- /dev/null +++ b/asm4/examples/analysis/etc/execute.properties @@ -0,0 +1,32 @@ +############################################################################### +#ASM: a very small and fast Java bytecode manipulation framework +#Copyright (c) 2000-2011 INRIA, France Telecom +#All rights reserved. +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions +#are met: +#1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +#2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +#3. Neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +#THE POSSIBILITY OF SUCH DAMAGE. +############################################################################### + +run.classname Analysis +run.parameters diff --git a/asm4/examples/analysis/src/Analysis.java b/asm4/examples/analysis/src/Analysis.java new file mode 100644 index 0000000..3e319eb --- /dev/null +++ b/asm4/examples/analysis/src/Analysis.java @@ -0,0 +1,182 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.IincInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; +import org.objectweb.asm.tree.analysis.Analyzer; +import org.objectweb.asm.tree.analysis.BasicValue; +import org.objectweb.asm.tree.analysis.BasicVerifier; +import org.objectweb.asm.tree.analysis.Frame; +import org.objectweb.asm.tree.analysis.SourceInterpreter; +import org.objectweb.asm.tree.analysis.SourceValue; +import org.objectweb.asm.util.TraceMethodVisitor; +import org.objectweb.asm.util.Textifier; + +/** + * @author Eric Bruneton + */ +public class Analysis implements Opcodes { + + public static void main(final String[] args) throws Exception { + ClassReader cr = new ClassReader("Analysis"); + ClassNode cn = new ClassNode(); + cr.accept(cn, ClassReader.SKIP_DEBUG); + + List<MethodNode> methods = cn.methods; + for (int i = 0; i < methods.size(); ++i) { + MethodNode method = methods.get(i); + if (method.instructions.size() > 0) { + if (!analyze(cn, method)) { + Analyzer<?> a = new Analyzer<BasicValue>( + new BasicVerifier()); + try { + a.analyze(cn.name, method); + } catch (Exception ignored) { + } + final Frame<?>[] frames = a.getFrames(); + + Textifier t = new Textifier() { + @Override + public void visitMaxs(final int maxStack, + final int maxLocals) { + for (int i = 0; i < text.size(); ++i) { + StringBuffer s = new StringBuffer( + frames[i] == null ? "null" + : frames[i].toString()); + while (s.length() < Math.max(20, maxStack + + maxLocals + 1)) { + s.append(' '); + } + System.err.print(Integer.toString(i + 1000) + .substring(1) + + " " + + s + + " : " + + text.get(i)); + } + System.err.println(); + } + }; + MethodVisitor mv = new TraceMethodVisitor(t); + for (int j = 0; j < method.instructions.size(); ++j) { + Object insn = method.instructions.get(j); + ((AbstractInsnNode) insn).accept(mv); + } + mv.visitMaxs(0, 0); + } + } + } + } + + /* + * Detects unused xSTORE instructions, i.e. xSTORE instructions without at + * least one xLOAD corresponding instruction in their successor instructions + * (in the control flow graph). + */ + public static boolean analyze(final ClassNode c, final MethodNode m) + throws Exception { + Analyzer<SourceValue> a = new Analyzer<SourceValue>( + new SourceInterpreter()); + Frame<SourceValue>[] frames = a.analyze(c.name, m); + + // for each xLOAD instruction, we find the xSTORE instructions that can + // produce the value loaded by this instruction, and we put them in + // 'stores' + Set<AbstractInsnNode> stores = new HashSet<AbstractInsnNode>(); + for (int i = 0; i < m.instructions.size(); ++i) { + AbstractInsnNode insn = m.instructions.get(i); + int opcode = insn.getOpcode(); + if ((opcode >= ILOAD && opcode <= ALOAD) || opcode == IINC) { + int var = opcode == IINC ? ((IincInsnNode) insn).var + : ((VarInsnNode) insn).var; + Frame<SourceValue> f = frames[i]; + if (f != null) { + Set<AbstractInsnNode> s = f.getLocal(var).insns; + Iterator<AbstractInsnNode> j = s.iterator(); + while (j.hasNext()) { + insn = j.next(); + if (insn instanceof VarInsnNode) { + stores.add(insn); + } + } + } + } + } + + // we then find all the xSTORE instructions that are not in 'stores' + boolean ok = true; + for (int i = 0; i < m.instructions.size(); ++i) { + AbstractInsnNode insn = m.instructions.get(i); + int opcode = insn.getOpcode(); + if (opcode >= ISTORE && opcode <= ASTORE) { + if (!stores.contains(insn)) { + ok = false; + System.err.println("method " + m.name + ", instruction " + + i + ": useless store instruction"); + } + } + } + return ok; + } + + /* + * Test for the above method, with three useless xSTORE instructions. + */ + public int test(int i, int j) { + i = i + 1; // ok, because i can be read after this point + + if (j == 0) { + j = 1; // useless + } else { + try { + j = j - 1; // ok, because j can be accessed in the catch + int k = 0; + if (i > 0) { + k = i - 1; + } + return k; + } catch (Exception e) { // useless ASTORE (e is never used) + j = j + 1; // useless + } + } + + return 0; + } +} diff --git a/asm4/examples/annotations/build.xml b/asm4/examples/annotations/build.xml new file mode 100644 index 0000000..e149280 --- /dev/null +++ b/asm4/examples/annotations/build.xml @@ -0,0 +1,89 @@ +<!-- + ! ASM: a very small and fast Java bytecode manipulation framework + ! Copyright (c) 2000-2011 INRIA, France Telecom + ! All rights reserved. + ! + ! Redistribution and use in source and binary forms, with or without + ! modification, are permitted provided that the following conditions + ! are met: + ! 1. Redistributions of source code must retain the above copyright + ! notice, this list of conditions and the following disclaimer. + ! 2. Redistributions in binary form must reproduce the above copyright + ! notice, this list of conditions and the following disclaimer in the + ! documentation and/or other materials provided with the distribution. + ! 3. Neither the name of the copyright holders nor the names of its + ! contributors may be used to endorse or promote products derived from + ! this software without specific prior written permission. + ! + ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + ! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + ! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + ! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + ! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + ! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + ! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + ! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + ! THE POSSIBILITY OF SUCH DAMAGE. +--> + +<project name="Examples" default="compile"> + + <!-- directory definition --> + + <property name="src" value="${basedir}/src"/> + <property name="build" value="${basedir}/build"/> + + <property file="${basedir}/../etc/build.properties"/> + <property file="${basedir}/etc/build.properties"/> + <property file="${basedir}/etc/execute.properties"/> + + <!-- Building of a path which contains external jars --> + + <path id="classpath"> + <pathelement path="${asm.path}"/> + <pathelement path="${asm.tree.path}"/> + <pathelement path="${asm.analysis.path}"/> + <pathelement path="${asm.attrs.path}"/> + <pathelement path="${asm.util.path}"/> + <fileset dir="${basedir}"> + <include name="lib/**/*.jar"/> + </fileset> + <fileset dir="${basedir}/.."> + <include name="lib/**/*.jar"/> + </fileset> + <pathelement location="${build}"/> + </path> + + <!-- ================================== --> + <!-- EXECUTE --> + <!-- ================================== --> + + <target name="execute" depends="compile"> + <java classname="${run.classname}" + classpathref="classpath" fork="yes" failonerror="yes"> + <arg line="${run.parameters}"/> + </java> + </target> + + <!-- ================================== --> + <!-- COMPILE --> + <!-- ================================== --> + + <target name="compile"> + <mkdir dir="${build}"/> + <javac srcdir="${src}" destdir="${build}" debug="on" source="1.5" target="1.5"> + <classpath refid="classpath"/> + <include name="**/*.java"/> + </javac> + </target> + + <!-- ================================== --> + <!-- CLEAN --> + <!-- ================================== --> + + <target name="clean"> + <delete dir="${build}"/> + </target> +</project> diff --git a/asm4/examples/annotations/etc/execute.properties b/asm4/examples/annotations/etc/execute.properties new file mode 100644 index 0000000..06d0dec --- /dev/null +++ b/asm4/examples/annotations/etc/execute.properties @@ -0,0 +1,32 @@ +###############################################################################
+#ASM: a very small and fast Java bytecode manipulation framework
+#Copyright (c) 2000-2011 INRIA, France Telecom
+#All rights reserved.
+#
+#Redistribution and use in source and binary forms, with or without
+#modification, are permitted provided that the following conditions
+#are met:
+#1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#3. Neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+#THE POSSIBILITY OF SUCH DAMAGE.
+###############################################################################
+
+run.classname Annotations
+run.parameters
diff --git a/asm4/examples/annotations/src/Annotations.java b/asm4/examples/annotations/src/Annotations.java new file mode 100644 index 0000000..850b6f1 --- /dev/null +++ b/asm4/examples/annotations/src/Annotations.java @@ -0,0 +1,137 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +public class Annotations { + + public static void foo(final @NotNull String arg) { + System.out.println(arg); + } + + public static void main(final String[] args) throws Exception { + System.out + .println("Calling foo(null) results in a NullPointerException:"); + try { + foo(null); + } catch (Exception e) { + e.printStackTrace(System.out); + } + + final String n = Annotations.class.getName(); + final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + ClassReader cr = new ClassReader(n); + cr.accept(new ClassVisitor(Opcodes.ASM4, cw) { + + @Override + public MethodVisitor visitMethod(final int access, + final String name, final String desc, + final String signature, final String[] exceptions) { + final Type[] args = Type.getArgumentTypes(desc); + MethodVisitor v = cv.visitMethod(access, name, desc, signature, + exceptions); + return new MethodVisitor(Opcodes.ASM4, v) { + + private final List<Integer> params = new ArrayList<Integer>(); + + @Override + public AnnotationVisitor visitParameterAnnotation( + final int parameter, final String desc, + final boolean visible) { + AnnotationVisitor av; + av = mv.visitParameterAnnotation(parameter, desc, + visible); + if (desc.equals("LNotNull;")) { + params.add(new Integer(parameter)); + } + return av; + } + + @Override + public void visitCode() { + int var = (access & Opcodes.ACC_STATIC) == 0 ? 1 : 0; + for (int p = 0; p < params.size(); ++p) { + int param = params.get(p).intValue(); + for (int i = 0; i < param; ++i) { + var += args[i].getSize(); + } + String c = "java/lang/IllegalArgumentException"; + String d = "(Ljava/lang/String;)V"; + Label end = new Label(); + mv.visitVarInsn(Opcodes.ALOAD, var); + mv.visitJumpInsn(Opcodes.IFNONNULL, end); + mv.visitTypeInsn(Opcodes.NEW, c); + mv.visitInsn(Opcodes.DUP); + mv.visitLdcInsn("Argument " + param + + " must not be null"); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, c, + "<init>", d); + mv.visitInsn(Opcodes.ATHROW); + mv.visitLabel(end); + } + } + }; + } + }, 0); + + Class<?> c = new ClassLoader() { + @Override + public Class<?> loadClass(final String name) + throws ClassNotFoundException { + if (name.equals(n)) { + byte[] b = cw.toByteArray(); + return defineClass(name, b, 0, b.length); + } + return super.loadClass(name); + } + }.loadClass(n); + + System.out.println(); + System.out.println("Calling foo(null) on the transformed class results" + + " in an IllegalArgumentException:"); + Method m = c.getMethod("foo", new Class<?>[] { String.class }); + try { + m.invoke(null, new Object[] { null }); + } catch (InvocationTargetException e) { + e.getCause().printStackTrace(System.out); + } + } +} diff --git a/asm4/examples/annotations/src/NotNull.java b/asm4/examples/annotations/src/NotNull.java new file mode 100644 index 0000000..b16cf12 --- /dev/null +++ b/asm4/examples/annotations/src/NotNull.java @@ -0,0 +1,36 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.CLASS) +public @interface NotNull { + String value() default ""; +} diff --git a/asm4/examples/attributes/etc/execute.properties b/asm4/examples/attributes/etc/execute.properties new file mode 100644 index 0000000..f2027d4 --- /dev/null +++ b/asm4/examples/attributes/etc/execute.properties @@ -0,0 +1,32 @@ +############################################################################### +#ASM: a very small and fast Java bytecode manipulation framework +#Copyright (c) 2000-2011 INRIA, France Telecom +#All rights reserved. +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions +#are met: +#1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +#2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +#3. Neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +#THE POSSIBILITY OF SUCH DAMAGE. +############################################################################### + +run.classname Attributes +run.parameters diff --git a/asm4/examples/attributes/src/Attributes.java b/asm4/examples/attributes/src/Attributes.java new file mode 100644 index 0000000..b833042 --- /dev/null +++ b/asm4/examples/attributes/src/Attributes.java @@ -0,0 +1,144 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.util.Map; + +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ByteVector; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.util.Textifiable; +import org.objectweb.asm.util.TraceClassVisitor; + +/** + * @author Eric Bruneton + */ +public class Attributes extends ClassLoader { + + public static void main(final String args[]) throws Exception { + // loads the original class and adapts it + ClassReader cr = new ClassReader("CommentAttribute"); + ClassWriter cw = new ClassWriter(0); + ClassVisitor cv = new AddCommentClassAdapter(cw); + cr.accept(cv, new Attribute[] { new CommentAttribute("") }, 0); + byte[] b = cw.toByteArray(); + + // stores the adapted class on disk + FileOutputStream fos = new FileOutputStream( + "CommentAttribute.class.new"); + try { + fos.write(b); + } finally { + fos.close(); + } + + // "disassembles" the adapted class + cr = new ClassReader(b); + cv = new TraceClassVisitor(new PrintWriter(System.out)); + cr.accept(cv, new Attribute[] { new CommentAttribute("") }, 0); + } +} + +class AddCommentClassAdapter extends ClassVisitor implements Opcodes { + + public AddCommentClassAdapter(final ClassVisitor cv) { + super(Opcodes.ASM4, cv); + } + + @Override + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { + super.visit(version, access, name, signature, superName, interfaces); + visitAttribute(new CommentAttribute("this is a class comment")); + } + + @Override + public FieldVisitor visitField(final int access, final String name, + final String desc, final String signature, final Object value) { + FieldVisitor fv = super + .visitField(access, name, desc, signature, value); + fv.visitAttribute(new CommentAttribute("this is a field comment")); + return fv; + } + + @Override + public MethodVisitor visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { + MethodVisitor mv = cv.visitMethod(access, name, desc, signature, + exceptions); + if (mv != null) { + mv.visitAttribute(new CommentAttribute("this is a method comment")); + } + return mv; + } +} + +class CommentAttribute extends Attribute implements Textifiable { + + private String comment; + + public CommentAttribute(final String comment) { + super("Comment"); + this.comment = comment; + } + + public String getComment() { + return comment; + } + + @Override + public boolean isUnknown() { + return false; + } + + @Override + protected Attribute read(final ClassReader cr, final int off, + final int len, final char[] buf, final int codeOff, + final Label[] labels) { + return new CommentAttribute(cr.readUTF8(off, buf)); + } + + @Override + protected ByteVector write(final ClassWriter cw, final byte[] code, + final int len, final int maxStack, final int maxLocals) { + return new ByteVector().putShort(cw.newUTF8(comment)); + } + + public void textify(StringBuffer buf, Map<Label, String> labelNames) { + buf.append(": " + comment + "\n"); + } +} diff --git a/asm4/examples/common/README.txt b/asm4/examples/common/README.txt new file mode 100644 index 0000000..164705d --- /dev/null +++ b/asm4/examples/common/README.txt @@ -0,0 +1,43 @@ +******************************************************************************* +* ASM: a very small and fast Java bytecode manipulation framework +* Copyright (c) 2000-2011 INRIA, France Telecom +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holders nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +******************************************************************************* + +This directory contains the examples of the product. +It contains(*) the following items: + +- lib: jar files shared by all examples, +- etc: configuration files shared by all examples, +- README.txt: explains the organisation of the examples directory, +- all other directories contain(*) the following items: + - README.txt file: describes the example and its configuration, + - lib: jar files needed by the example, + - etc: configuration files needed by the example, + - src: source code of the example. + +(*) some items may not be present, depending on the product or example.
\ No newline at end of file diff --git a/asm4/examples/common/build.xml b/asm4/examples/common/build.xml new file mode 100644 index 0000000..950b028 --- /dev/null +++ b/asm4/examples/common/build.xml @@ -0,0 +1,97 @@ +<!-- + ! ASM: a very small and fast Java bytecode manipulation framework + ! Copyright (c) 2000-2011 INRIA, France Telecom + ! All rights reserved. + ! + ! Redistribution and use in source and binary forms, with or without + ! modification, are permitted provided that the following conditions + ! are met: + ! 1. Redistributions of source code must retain the above copyright + ! notice, this list of conditions and the following disclaimer. + ! 2. Redistributions in binary form must reproduce the above copyright + ! notice, this list of conditions and the following disclaimer in the + ! documentation and/or other materials provided with the distribution. + ! 3. Neither the name of the copyright holders nor the names of its + ! contributors may be used to endorse or promote products derived from + ! this software without specific prior written permission. + ! + ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + ! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + ! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + ! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + ! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + ! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + ! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + ! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + ! THE POSSIBILITY OF SUCH DAMAGE. +--> + +<project name="Examples" default="compile"> + + <!-- directory definition --> + + <property name="src" value="${basedir}/src"/> + <property name="build" value="${basedir}/build"/> + + <property file="${basedir}/../etc/build.properties"/> + <property file="${basedir}/etc/build.properties"/> + <property file="${basedir}/etc/execute.properties"/> + + <!-- Building of a path which contains external jars --> + + <path id="compile-classpath"> + <pathelement path="${asm.debug.path}"/> + <fileset dir="${basedir}"> + <include name="lib/*.jar"/> + </fileset> + <pathelement location="${build}"/> + </path> + + <path id="runtime-classpath"> + <pathelement path="${asm.path}"/> + <pathelement path="${asm.tree.path}"/> + <pathelement path="${asm.analysis.path}"/> + <pathelement path="${asm.attrs.path}"/> + <pathelement path="${asm.util.path}"/> + <pathelement path="${asm.commons.path}"/> + <fileset dir="${basedir}"> + <include name="lib/*.jar"/> + </fileset> + <pathelement location="${build}"/> + </path> + + + + <!-- ================================== --> + <!-- EXECUTE --> + <!-- ================================== --> + + <target name="execute" depends="compile"> + <java classname="${run.classname}" + classpathref="runtime-classpath" fork="yes" failonerror="yes"> + <arg line="${run.parameters}"/> + </java> + </target> + + <!-- ================================== --> + <!-- COMPILE --> + <!-- ================================== --> + + <target name="compile"> + <mkdir dir="${build}"/> + <javac srcdir="${src}" destdir="${build}" debug="on" source="1.5" target="1.5"> + <classpath refid="compile-classpath"/> + <include name="**/*.java"/> + </javac> + </target> + + <!-- ================================== --> + <!-- CLEAN --> + <!-- ================================== --> + + <target name="clean"> + <delete dir="${build}"/> + </target> +</project> diff --git a/asm4/examples/common/etc/build.properties b/asm4/examples/common/etc/build.properties new file mode 100644 index 0000000..c3eb187 --- /dev/null +++ b/asm4/examples/common/etc/build.properties @@ -0,0 +1,68 @@ +############################################################################### +#ASM: a very small and fast Java bytecode manipulation framework +#Copyright (c) 2000-2011 INRIA, France Telecom +#All rights reserved. +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions +#are met: +#1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +#2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +#3. Neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +#THE POSSIBILITY OF SUCH DAMAGE. +############################################################################### + +# Wich compiler do you want use ? + +# build.compiler jikes + +# Runtime class path for the ASM library (version @product.version@) +# See http://asm.objectweb.org + +asm.path ../../lib/asm-@product.version@.jar + +# Runtime class path for the ASM tree library (version @product.version@) +# See http://asm.objectweb.org + +asm.tree.path ../../lib/asm-tree-@product.version@.jar + +# Runtime class path for the ASM analysis library (version @product.version@) +# See http://asm.objectweb.org + +asm.analysis.path ../../lib/asm-analysis-@product.version@.jar + +# Runtime class path for the ASM attrs library (version @product.version@) +# See http://asm.objectweb.org + +asm.attrs.path ../../lib/asm-attrs-@product.version@.jar + +# Runtime class path for the ASM util library (version @product.version@) +# See http://asm.objectweb.org + +asm.util.path ../../lib/asm-util-@product.version@.jar + +# Runtime class path for the ASM commons library (version @product.version@) +# See http://asm.objectweb.org + +asm.commons.path ../../lib/asm-commons-@product.version@.jar + +# Compile time class path for the whole ASM library (version @product.version@) +# See http://asm.objectweb.org + +asm.debug.path ../../lib/all/asm-debug-all-@product.version@.jar diff --git a/asm4/examples/compile-indy/etc/execute.properties b/asm4/examples/compile-indy/etc/execute.properties new file mode 100644 index 0000000..a22cb1d --- /dev/null +++ b/asm4/examples/compile-indy/etc/execute.properties @@ -0,0 +1,32 @@ +############################################################################### +#ASM: a very small and fast Java bytecode manipulation framework +#Copyright (c) 2000-2011 INRIA, France Telecom +#All rights reserved. +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions +#are met: +#1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +#2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +#3. Neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +#THE POSSIBILITY OF SUCH DAMAGE. +############################################################################### + +run.classname IndyCompile +run.parameters diff --git a/asm4/examples/compile-indy/src/IndyCompile.java b/asm4/examples/compile-indy/src/IndyCompile.java new file mode 100644 index 0000000..cac146e --- /dev/null +++ b/asm4/examples/compile-indy/src/IndyCompile.java @@ -0,0 +1,368 @@ +/*** + * ASM examples: examples showing how ASM can be used + * This example is adapted from the example that you can find in examples/compile + * and use invokedynamic to implement all operations. + * + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static org.objectweb.asm.Opcodes.ACC_STATIC; +import static org.objectweb.asm.Opcodes.ALOAD; +import static org.objectweb.asm.Opcodes.ARETURN; +import static org.objectweb.asm.Opcodes.DUP; +import static org.objectweb.asm.Opcodes.H_INVOKESTATIC; +import static org.objectweb.asm.Opcodes.IFEQ; +import static org.objectweb.asm.Opcodes.IFNE; +import static org.objectweb.asm.Opcodes.POP; +import static org.objectweb.asm.Opcodes.V1_7; + +import java.io.FileOutputStream; +import java.lang.reflect.Method; + +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; + +/** + * @author Remi Forax + * @author Eric Bruneton + */ +public class IndyCompile extends ClassLoader { + + public static void main(final String[] args) throws Throwable { + // creates the expression tree corresponding to + // exp(i) = i > 3 && 6 > i + Exp exp = new And(new GT(new Var(0), new Cst(3)), new GT(new Cst(6), + new Var(0))); + + // compiles this expression into a generic static method in a class + IndyCompile main = new IndyCompile(); + byte[] b = exp.compile("Example"); + FileOutputStream fos = new FileOutputStream("Example.class"); + fos.write(b); + fos.close(); + Class<?> expClass = main.defineClass("Example", b, 0, b.length); + Method expMethod = expClass.getDeclaredMethods()[0]; + + // ... and use it to evaluate exp(0) to exp(9) + for (int i = 0; i < 10; ++i) { + boolean val = (Boolean) expMethod.invoke(null, i); + System.out.println(i + " > 3 && " + i + " < 6 = " + val); + } + + // ... more fun, test with strings !!! + for (int i = 0; i < 10; ++i) { + boolean val = (Boolean) expMethod.invoke(null, Integer.toString(i)); + System.out.println("\"" + i + "\" > 3 && 6 > \"" + i + "\" = " + + val); + } + } + + /** + * An abstract expression. + */ + static abstract class Exp { + + static final Handle CST = getHandle("cst", "Ljava/lang/Object;"); + + static final Handle UNARY = getHandle("unary", ""); + + static final Handle BINARY = getHandle("binary", ""); + + /** + * Returns the maximum variable index used in this expression. + * + * @return the maximum variable index used in this expression, or -1 if + * no variable is used. + */ + int getMaxVarIndex() { + return -1; + } + + /* + * Returns the byte code of a class corresponding to this expression. + */ + byte[] compile(final String name) { + // class header + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + cw.visit(V1_7, ACC_PUBLIC, name, null, "java/lang/Object", null); + + // eval method type + StringBuilder desc = new StringBuilder("("); + for (int i = 0; i <= getMaxVarIndex(); ++i) { + desc.append("Ljava/lang/Object;"); + } + desc.append(")Ljava/lang/Object;"); + + // eval method + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "eval", + desc.toString(), null, null); + compile(mv); + mv.visitInsn(ARETURN); + // max stack and max locals automatically computed + mv.visitMaxs(0, 0); + mv.visitEnd(); + + return cw.toByteArray(); + } + + /* + * Compile this expression. This method must append to the given code + * writer the byte code that evaluates and pushes on the stack the value + * of this expression. + */ + abstract void compile(MethodVisitor mv); + + private static Handle getHandle(final String name, final String optArgs) { + return new Handle( + H_INVOKESTATIC, + "RT", + name, + "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;" + + optArgs + ")Ljava/lang/invoke/CallSite;"); + } + } + + /** + * A constant expression. + */ + static class Cst extends Exp { + + private final Object value; + + Cst(final Object value) { + this.value = value; + } + + @Override + void compile(final MethodVisitor mv) { + if (value instanceof String) { + mv.visitLdcInsn(value); + return; + } + + // instead of pushing the constant and then box it, we use + // invokedynamic with the constant as bootstrap argument. The + // boxing will be performed by the VM when calling the bootstrap + // method + mv.visitInvokeDynamicInsn("cst", "()Ljava/lang/Object;", CST, value); + } + } + + /** + * A variable reference expression. + */ + static class Var extends Exp { + + final int index; + + Var(final int index) { + this.index = index; + } + + @Override + int getMaxVarIndex() { + return index; + } + + @Override + void compile(final MethodVisitor mv) { + // pushes the 'index' local variable onto the stack + mv.visitVarInsn(ALOAD, index); + } + } + + /** + * An abstract binary expression. + */ + static abstract class BinaryExp extends Exp { + + final Exp e1; + + final Exp e2; + + @Override + int getMaxVarIndex() { + return Math.max(e1.getMaxVarIndex(), e2.getMaxVarIndex()); + } + + BinaryExp(final Exp e1, final Exp e2) { + this.e1 = e1; + this.e2 = e2; + } + } + + /** + * An addition expression. + */ + static class Add extends BinaryExp { + + Add(final Exp e1, final Exp e2) { + super(e1, e2); + } + + @Override + void compile(final MethodVisitor mv) { + // compiles e1, e2, and adds an instruction to add the two values + e1.compile(mv); + e2.compile(mv); + mv.visitInvokeDynamicInsn("add", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + BINARY); + } + } + + /** + * A multiplication expression. + */ + static class Mul extends BinaryExp { + + Mul(final Exp e1, final Exp e2) { + super(e1, e2); + } + + @Override + void compile(final MethodVisitor mv) { + // compiles e1, e2, and adds an instruction to multiply the two + // values + e1.compile(mv); + e2.compile(mv); + mv.visitInvokeDynamicInsn("mul", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + BINARY); + } + } + + /** + * A "greater than" expression. + */ + static class GT extends BinaryExp { + + GT(final Exp e1, final Exp e2) { + super(e1, e2); + } + + @Override + void compile(final MethodVisitor mv) { + // compiles e1, e2, and adds the instructions to compare the two + // values + e1.compile(mv); + e2.compile(mv); + mv.visitInvokeDynamicInsn("gt", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + BINARY); + } + } + + /** + * A logical "and" expression. + */ + static class And extends BinaryExp { + + And(final Exp e1, final Exp e2) { + super(e1, e2); + } + + @Override + void compile(final MethodVisitor mv) { + // compiles e1 + e1.compile(mv); + // tests if e1 is false + mv.visitInsn(DUP); + // convert to a boolean + mv.visitInvokeDynamicInsn("asBoolean", "(Ljava/lang/Object;)Z", + UNARY); + + Label end = new Label(); + mv.visitJumpInsn(IFEQ, end); + // case where e1 is true : e1 && e2 is equal to e2 + mv.visitInsn(POP); + e2.compile(mv); + + // if e1 is false, e1 && e2 is equal to e1: + // we jump directly to this label, without evaluating e2 + mv.visitLabel(end); + } + } + + /** + * A logical "or" expression. + */ + static class Or extends BinaryExp { + + Or(final Exp e1, final Exp e2) { + super(e1, e2); + } + + @Override + void compile(final MethodVisitor mv) { + // compiles e1 + e1.compile(mv); + // tests if e1 is true + mv.visitInsn(DUP); + // convert to a boolean + mv.visitInvokeDynamicInsn("asBoolean", "(Ljava/lang/Object;)Z", + UNARY); + Label end = new Label(); + mv.visitJumpInsn(IFNE, end); + // case where e1 is false : e1 || e2 is equal to e2 + mv.visitInsn(POP); + e2.compile(mv); + // if e1 is true, e1 || e2 is equal to e1: + // we jump directly to this label, without evaluating e2 + mv.visitLabel(end); + } + } + + /** + * A logical "not" expression. + */ + static class Not extends Exp { + + private final Exp e; + + Not(final Exp e) { + this.e = e; + } + + @Override + int getMaxVarIndex() { + return e.getMaxVarIndex(); + } + + @Override + void compile(final MethodVisitor mv) { + // compiles e, and applies 'not' + e.compile(mv); + mv.visitInvokeDynamicInsn("not", + "(Ljava/lang/Object;)Ljava/lang/Object;", UNARY); + } + } +} diff --git a/asm4/examples/compile-indy/src/RT.java b/asm4/examples/compile-indy/src/RT.java new file mode 100644 index 0000000..fdf080a --- /dev/null +++ b/asm4/examples/compile-indy/src/RT.java @@ -0,0 +1,329 @@ +/*** + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.lang.invoke.CallSite; +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; +import java.lang.invoke.MutableCallSite; +import java.util.HashMap; + +/** + * There are 3 bootstrap methods: - one for the constant that are initialized + * once the first time the bootstrap method is called and after always reuse the + * same constant. It's almost equivalent to an LDC but here the constant are + * stored in boxed form e.g a java.lang.Integer containing 0 instead of an int + * containing 0. + * + * - one for the unary operation 'not' and 'asBoolean', here the semantics is + * hard coded, all primitive value are transformed as object by applying this + * operation: (v == 0)? false: true + * + * - one for the binary operation 'add', 'mul' and 'gt', here the semantics can + * be changed by adding more static methods in {@link BinaryOps}. This bootstrap + * method is a little more complex because it creates an inlining cache to avoid + * to recompute the binary method to call if the type of the two arguments + * doesn't change. Also, if the expression is used a lot and trigger the JIT, it + * will be able to inline the code of the operation directly at callsite. + * + * @author Remi Forax + */ +public class RT { + /** + * bootstrap method for constant + */ + public static CallSite cst(Lookup lookup, String name, MethodType type, + Object constant) { + return new ConstantCallSite(MethodHandles.constant(Object.class, + constant)); + } + + /** + * bootstrap method for unary operation 'asBoolean' and 'not' + */ + public static CallSite unary(Lookup lookup, String name, MethodType type) { + MethodHandle target; + if (name.equals("asBoolean")) { + target = MethodHandles.explicitCastArguments( + MethodHandles.identity(Object.class), + MethodType.methodType(boolean.class, Object.class)); + } else { // "not" + target = MethodHandles.explicitCastArguments(NOT, + MethodType.methodType(Object.class, Object.class)); + } + return new ConstantCallSite(target); + } + + /** + * bootstrap method for binary operation 'add', 'mul' and 'gt' + * + * This bootstrap method doesn't install the target method handle directly, + * because we want to install an inlining cache and we can't create an + * inlining cache without knowing the class of the arguments. So this method + * first installs a method handle that will call + * {@link BinaryOpCallSite#fallback(Object, Object)} and the fallback method + * will be called with the arguments and thus can install the inlining + * cache. Also, the fallback has to be bound to a specific callsite to be + * able to change its target after the first call, this part is done in the + * constructor of {@link BinaryOpCallSite}. + */ + public static CallSite binary(Lookup lookup, String name, MethodType type) { + BinaryOpCallSite callSite = new BinaryOpCallSite(name, type); + callSite.setTarget(callSite.fallback); + return callSite; + } + + /** + * Garbage class containing the method used to apply 'not' on a boolean. See + * {@link RT#unary(Lookup, String, MethodType)} + */ + public static class UnayOps { + + public static Object not(boolean b) { + return !b; + } + } + + private static final MethodHandle NOT; + + static { + try { + NOT = MethodHandles.publicLookup().findStatic(UnayOps.class, "not", + MethodType.methodType(Object.class, boolean.class)); + } catch (ReflectiveOperationException e) { + throw new LinkageError(e.getMessage(), e); + } + } + + /** + * A specific callsite that will install an 'inlining cache'. Because we + * don't know until runtime which method handle to call, the lookup + * depending on the dynamic type of the argument will be done at runtime + * when the method {@link #fallback(Object, Object)} is called. To avoid to + * do this dynamic lookup at each call, the fallback install two guards in + * front of dispatch call that will check if the arguments class change or + * not. If the arguments class don't change, the previously computed method + * handle will be called again. Otherwise, a new method handle will be + * computed and two new guards will be installed. + */ + static class BinaryOpCallSite extends MutableCallSite { + + private final String opName; + + final MethodHandle fallback; + + public BinaryOpCallSite(String opName, MethodType type) { + super(type); + this.opName = opName; + this.fallback = FALLBACK.bindTo(this); + } + + Object fallback(Object v1, Object v2) throws Throwable { + // when you debug with this message + // don't forget that && and || are lazy !! + // System.out.println("fallback called with "+opName+'('+v1.getClass()+','+v2.getClass()+')'); + + Class<? extends Object> class1 = v1.getClass(); + Class<? extends Object> class2 = v2.getClass(); + MethodHandle op = lookupBinaryOp(opName, class1, class2); + + // convert arguments + MethodType type = type(); + MethodType opType = op.type(); + if (opType.parameterType(0) == String.class) { + if (opType.parameterType(1) == String.class) { + op = MethodHandles.filterArguments(op, 0, TO_STRING, + TO_STRING); + } else { + op = MethodHandles.filterArguments(op, 0, TO_STRING); + op = MethodHandles.explicitCastArguments(op, type); + } + } else { + if (opType.parameterType(1) == String.class) { + op = MethodHandles.filterArguments(op, 1, TO_STRING); + } + op = MethodHandles.explicitCastArguments(op, type); + } + + // prepare guard + MethodHandle guard = MethodHandles.guardWithTest(TEST1 + .bindTo(class1), MethodHandles.guardWithTest( + TEST2.bindTo(class2), op, fallback), fallback); + + // install the inlining cache + setTarget(guard); + return op.invokeWithArguments(v1, v2); + } + + public static boolean test1(Class<?> v1Class, Object v1, Object v2) { + return v1.getClass() == v1Class; + } + + public static boolean test2(Class<?> v2Class, Object v1, Object v2) { + return v2.getClass() == v2Class; + } + + private static final MethodHandle TO_STRING; + + private static final MethodHandle TEST1; + + private static final MethodHandle TEST2; + + private static final MethodHandle FALLBACK; + + static { + Lookup lookup = MethodHandles.lookup(); + try { + TO_STRING = lookup.findVirtual(Object.class, "toString", + MethodType.methodType(String.class)); + MethodType testType = MethodType.methodType(boolean.class, + Class.class, Object.class, Object.class); + TEST1 = lookup.findStatic(BinaryOpCallSite.class, "test1", + testType); + TEST2 = lookup.findStatic(BinaryOpCallSite.class, "test2", + testType); + FALLBACK = lookup.findVirtual(BinaryOpCallSite.class, + "fallback", MethodType.genericMethodType(2)); + } catch (ReflectiveOperationException e) { + throw new LinkageError(e.getMessage(), e); + } + } + } + + /** + * Garbage class that contains the raw operations used for binary + * operations. All methods must be static returns an Object and takes the + * same type for the two parameter types. + * + * See {@link RT#lookupBinaryOp(String, Class, Class)} for more info. + */ + public static class BinaryOps { + + public static Object add(int v1, int v2) { + return v1 + v2; + } + + public static Object add(double v1, double v2) { + return v1 + v2; + } + + public static Object add(String v1, String v2) { + return v1 + v2; + } + + public static Object mul(int v1, int v2) { + return v1 * v2; + } + + public static Object mul(double v1, double v2) { + return v1 * v2; + } + + public static Object gt(int v1, int v2) { + return v1 > v2; + } + + public static Object gt(double v1, double v2) { + return v1 > v2; + } + + public static Object gt(String v1, String v2) { + return v1.compareTo(v2) > 0; + } + } + + /** + * Select a most specific method among the ones defined in + * {@link RT.BinaryOps}. The algorithm first find the most specific subtype + * between class1 and class2. The order of the types is defined in + * {@link RT#RANK_MAP}: Boolean < Byte < Short < Character < Integer < Long + * < Float < Double < String then the algorithm lookup in + * {@link RT.BinaryOps} to find a method with the name opName taking as + * argument the primitive corresponding to the most specific subtype. If no + * such method exist, the algorithm retry but looking for a method with a + * more specific type (using the same order). The result of the lookup is + * cached in {@link RT#BINARY_CACHE} to avoid to avoid to do a lookup (a + * reflective call) on the same method twice. + */ + static MethodHandle lookupBinaryOp(String opName, Class<?> class1, + Class<?> class2) { + int rank = Math.max(RANK_MAP.get(class1), RANK_MAP.get(class2)); + String mangledName = opName + rank; + MethodHandle mh = BINARY_CACHE.get(mangledName); + if (mh != null) { + return mh; + } + + for (; rank < PRIMITIVE_ARRAY.length;) { + Class<?> primitive = PRIMITIVE_ARRAY[rank]; + try { + mh = MethodHandles.publicLookup().findStatic( + BinaryOps.class, + opName, + MethodType.methodType(Object.class, primitive, + primitive)); + } catch (NoSuchMethodException e) { + rank = rank + 1; + continue; + } catch (IllegalAccessException e) { + throw new LinkageError(e.getMessage(), e); + } + + BINARY_CACHE.put(mangledName, mh); + return mh; + } + throw new LinkageError("unknown operation " + opName + " (" + + class1.getName() + ',' + class2.getName() + ')'); + } + + private static final HashMap<Class<?>, Integer> RANK_MAP; + + private static final Class<?>[] PRIMITIVE_ARRAY; + + private static final HashMap<String, MethodHandle> BINARY_CACHE; + + static { + Class<?>[] primitives = new Class<?>[] { boolean.class, byte.class, + short.class, char.class, int.class, long.class, float.class, + double.class, String.class }; + Class<?>[] wrappers = new Class<?>[] { Boolean.class, Byte.class, + Short.class, Character.class, Integer.class, Long.class, + Float.class, Double.class, String.class }; + HashMap<Class<?>, Integer> rankMap = new HashMap<Class<?>, Integer>(); + for (int i = 0; i < wrappers.length; i++) { + rankMap.put(wrappers[i], i); + } + + RANK_MAP = rankMap; + PRIMITIVE_ARRAY = primitives; + BINARY_CACHE = new HashMap<String, MethodHandle>(); + } +} diff --git a/asm4/examples/compile/etc/execute.properties b/asm4/examples/compile/etc/execute.properties new file mode 100644 index 0000000..43f5d75 --- /dev/null +++ b/asm4/examples/compile/etc/execute.properties @@ -0,0 +1,32 @@ +############################################################################### +#ASM: a very small and fast Java bytecode manipulation framework +#Copyright (c) 2000-2011 INRIA, France Telecom +#All rights reserved. +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions +#are met: +#1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +#2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +#3. Neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +#THE POSSIBILITY OF SUCH DAMAGE. +############################################################################### + +run.classname Compile +run.parameters diff --git a/asm4/examples/compile/src/Compile.java b/asm4/examples/compile/src/Compile.java new file mode 100644 index 0000000..7972867 --- /dev/null +++ b/asm4/examples/compile/src/Compile.java @@ -0,0 +1,293 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +import java.io.FileOutputStream; + +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * @author Eric Bruneton + */ +public class Compile extends ClassLoader { + + public static void main(final String[] args) throws Exception { + // creates the expression tree corresponding to + // exp(i) = i > 3 && 6 > i + Exp exp = new And(new GT(new Var(0), new Cst(3)), new GT(new Cst(6), + new Var(0))); + // compiles this expression into an Expression class + Compile main = new Compile(); + byte[] b = exp.compile("Example"); + FileOutputStream fos = new FileOutputStream("Example.class"); + fos.write(b); + fos.close(); + Class<?> expClass = main.defineClass("Example", b, 0, b.length); + // instantiates this compiled expression class... + Expression iexp = (Expression) expClass.newInstance(); + // ... and uses it to evaluate exp(0) to exp(9) + for (int i = 0; i < 10; ++i) { + boolean val = iexp.eval(i, 0) == 1; + System.out.println(i + " > 3 && " + i + " < 6 = " + val); + } + } +} + +/** + * An abstract expression. + * + * @author Eric Bruneton + */ +abstract class Exp implements Opcodes { + + /* + * Returns the byte code of an Expression class corresponding to this + * expression. + */ + byte[] compile(final String name) { + // class header + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + cw.visit(V1_1, ACC_PUBLIC, name, null, "java/lang/Object", + new String[] { Expression.class.getName() }); + + // default public constructor + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, + null); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + + // eval method + mv = cw.visitMethod(ACC_PUBLIC, "eval", "(II)I", null, null); + compile(mv); + mv.visitInsn(IRETURN); + // max stack and max locals automatically computed + mv.visitMaxs(0, 0); + mv.visitEnd(); + + return cw.toByteArray(); + } + + /* + * Compile this expression. This method must append to the given code writer + * the byte code that evaluates and pushes on the stack the value of this + * expression. + */ + abstract void compile(MethodVisitor mv); +} + +/** + * A constant expression. + */ +class Cst extends Exp { + + int value; + + Cst(final int value) { + this.value = value; + } + + @Override + void compile(final MethodVisitor mv) { + // pushes the constant's value onto the stack + mv.visitLdcInsn(new Integer(value)); + } +} + +/** + * A variable reference expression. + */ +class Var extends Exp { + + int index; + + Var(final int index) { + this.index = index + 1; + } + + @Override + void compile(final MethodVisitor mv) { + // pushes the 'index' local variable onto the stack + mv.visitVarInsn(ILOAD, index); + } +} + +/** + * An abstract binary expression. + */ +abstract class BinaryExp extends Exp { + + Exp e1; + + Exp e2; + + BinaryExp(final Exp e1, final Exp e2) { + this.e1 = e1; + this.e2 = e2; + } +} + +/** + * An addition expression. + */ +class Add extends BinaryExp { + + Add(final Exp e1, final Exp e2) { + super(e1, e2); + } + + @Override + void compile(final MethodVisitor mv) { + // compiles e1, e2, and adds an instruction to add the two values + e1.compile(mv); + e2.compile(mv); + mv.visitInsn(IADD); + } +} + +/** + * A multiplication expression. + */ +class Mul extends BinaryExp { + + Mul(final Exp e1, final Exp e2) { + super(e1, e2); + } + + @Override + void compile(final MethodVisitor mv) { + // compiles e1, e2, and adds an instruction to multiply the two values + e1.compile(mv); + e2.compile(mv); + mv.visitInsn(IMUL); + } +} + +/** + * A "greater than" expression. + */ +class GT extends BinaryExp { + + GT(final Exp e1, final Exp e2) { + super(e1, e2); + } + + @Override + void compile(final MethodVisitor mv) { + // compiles e1, e2, and adds the instructions to compare the two values + e1.compile(mv); + e2.compile(mv); + Label iftrue = new Label(); + Label end = new Label(); + mv.visitJumpInsn(IF_ICMPGT, iftrue); + // case where e1 <= e2 : pushes false and jump to "end" + mv.visitLdcInsn(new Integer(0)); + mv.visitJumpInsn(GOTO, end); + // case where e1 > e2 : pushes true + mv.visitLabel(iftrue); + mv.visitLdcInsn(new Integer(1)); + mv.visitLabel(end); + } +} + +/** + * A logical "and" expression. + */ +class And extends BinaryExp { + + And(final Exp e1, final Exp e2) { + super(e1, e2); + } + + @Override + void compile(final MethodVisitor mv) { + // compiles e1 + e1.compile(mv); + // tests if e1 is false + mv.visitInsn(DUP); + Label end = new Label(); + mv.visitJumpInsn(IFEQ, end); + // case where e1 is true : e1 && e2 is equal to e2 + mv.visitInsn(POP); + e2.compile(mv); + // if e1 is false, e1 && e2 is equal to e1: + // we jump directly to this label, without evaluating e2 + mv.visitLabel(end); + } +} + +/** + * A logical "or" expression. + */ +class Or extends BinaryExp { + + Or(final Exp e1, final Exp e2) { + super(e1, e2); + } + + @Override + void compile(final MethodVisitor mv) { + // compiles e1 + e1.compile(mv); + // tests if e1 is true + mv.visitInsn(DUP); + Label end = new Label(); + mv.visitJumpInsn(IFNE, end); + // case where e1 is false : e1 || e2 is equal to e2 + mv.visitInsn(POP); + e2.compile(mv); + // if e1 is true, e1 || e2 is equal to e1: + // we jump directly to this label, without evaluating e2 + mv.visitLabel(end); + } +} + +/** + * A logical "not" expression. + */ +class Not extends Exp { + + Exp e; + + Not(final Exp e) { + this.e = e; + } + + @Override + void compile(final MethodVisitor mv) { + // computes !e1 by evaluating 1 - e1 + mv.visitLdcInsn(new Integer(1)); + e.compile(mv); + mv.visitInsn(ISUB); + } +} diff --git a/asm4/examples/compile/src/Expression.java b/asm4/examples/compile/src/Expression.java new file mode 100644 index 0000000..83d2eb2 --- /dev/null +++ b/asm4/examples/compile/src/Expression.java @@ -0,0 +1,48 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * An integer or boolean expression of at most two variables. + * + * @author Eric Bruneton + */ +public interface Expression { + + /** + * Evaluates this expression. + * + * @param i + * the value of the first variable. + * @param j + * the value of the second variable. + * @return the value of this expression for the given variable values. + */ + int eval(int i, int j); +} diff --git a/asm4/examples/dependencies/etc/execute.properties b/asm4/examples/dependencies/etc/execute.properties new file mode 100644 index 0000000..345cc81 --- /dev/null +++ b/asm4/examples/dependencies/etc/execute.properties @@ -0,0 +1,32 @@ +############################################################################### +#ASM: a very small and fast Java bytecode manipulation framework +#Copyright (c) 2000-2011 INRIA, France Telecom +#All rights reserved. +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions +#are met: +#1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +#2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +#3. Neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +#THE POSSIBILITY OF SUCH DAMAGE. +############################################################################### + +run.classname org.objectweb.asm.depend.DependencyTracker +run.parameters ../../lib/asm-4.0.jar diff --git a/asm4/examples/dependencies/src/org/objectweb/asm/depend/DependencyTracker.java b/asm4/examples/dependencies/src/org/objectweb/asm/depend/DependencyTracker.java new file mode 100644 index 0000000..e20304c --- /dev/null +++ b/asm4/examples/dependencies/src/org/objectweb/asm/depend/DependencyTracker.java @@ -0,0 +1,201 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.depend; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import javax.imageio.ImageIO; + +import org.objectweb.asm.ClassReader; + +/** + * DependencyTracker + * + * @author Eugene Kuleshov + * + * @see "http://www.onjava.com/pub/a/onjava/2005/08/17/asm3.html" + */ +public class DependencyTracker { + + private static final int CELL_PAD = 1; + + private static final int GRID_SIZE = 10; + + private static final int CELLS_SIZE = 8; + + private static final int LABEL_WIDTH = 200; + + private static final String LABEL_FONT = "Tahoma-9"; + + public static void main(final String[] args) throws IOException { + DependencyVisitor v = new DependencyVisitor(); + + ZipFile f = new ZipFile(args[0]); + + long l1 = System.currentTimeMillis(); + Enumeration<? extends ZipEntry> en = f.entries(); + while (en.hasMoreElements()) { + ZipEntry e = en.nextElement(); + String name = e.getName(); + if (name.endsWith(".class")) { + new ClassReader(f.getInputStream(e)).accept(v, 0); + } + } + long l2 = System.currentTimeMillis(); + + Map<String, Map<String, Integer>> globals = v.getGlobals(); + Set<String> jarPackages = globals.keySet(); + Set<String> classPackages = v.getPackages(); + int size = classPackages.size(); + System.err.println("time: " + (l2 - l1) / 1000f + " " + size); + + String[] jarNames = jarPackages.toArray(new String[jarPackages.size()]); + String[] classNames = classPackages.toArray(new String[classPackages + .size()]); + Arrays.sort(jarNames); + Arrays.sort(classNames); + + buildDiagram(jarNames, classNames, globals); + } + + public static void buildDiagram(final String[] jarNames, + final String[] classNames, + final Map<String, Map<String, Integer>> globals) throws IOException { + // normalize + int max = 0; + for (int i = 0; i < classNames.length; i++) { + Map<String, Integer> map = globals.get(classNames[i]); + if (map == null) { + continue; + } + Integer maxCount = Collections.max(map.values()); + if (maxCount > max) { + max = maxCount; + } + } + + List<Color> colors = new ArrayList<Color>(); + for (int i = LABEL_WIDTH; i >= 0; i--) { + colors.add(new Color(i, i, 255)); + } + for (int i = 255; i >= 128; i--) { + colors.add(new Color(0, 0, i)); + } + int maxcolor = colors.size() - 1; + + int heigh = CELL_PAD + (CELLS_SIZE + CELL_PAD) * classNames.length; + int width = CELL_PAD + (CELLS_SIZE + CELL_PAD) * jarNames.length; + + BufferedImage img = new BufferedImage(width + LABEL_WIDTH, heigh + + LABEL_WIDTH, BufferedImage.TYPE_INT_RGB); + + Graphics2D g = img.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + g.setColor(Color.WHITE); + g.fillRect(0, 0, width + LABEL_WIDTH, heigh + LABEL_WIDTH); + + // draw lines + g.setColor(Color.LIGHT_GRAY); + for (int y = GRID_SIZE; y < classNames.length; y += GRID_SIZE) { + g.drawLine(0, y * (CELLS_SIZE + CELL_PAD), width, y + * (CELLS_SIZE + CELL_PAD)); + } + for (int x = GRID_SIZE; x < jarNames.length; x += GRID_SIZE) { + g.drawLine(x * (CELLS_SIZE + CELL_PAD), 0, x + * (CELLS_SIZE + CELL_PAD), heigh); + } + + // draw diagram + for (int y = 0; y < classNames.length; y++) { + // System.err.println( y+" : "+classNames[ y]); + + for (int x = 0; x < jarNames.length; x++) { + Map<String, Integer> map = globals.get(jarNames[x]); + + Integer count = map == null ? null : map.get(classNames[y]); + if (count != null) { + int b = (int) ((float) count * maxcolor / max); + + g.setColor(colors.get(b)); + g.fillRect(CELL_PAD + x * (CELLS_SIZE + CELL_PAD), CELL_PAD + + y * (CELLS_SIZE + CELL_PAD), CELLS_SIZE, + CELLS_SIZE); + } + } + } + + // draw labels + Font f = Font.decode(LABEL_FONT); + g.setFont(f); + // g.setColor( new Color( 70, 70, 255)); + g.setColor(Color.GRAY); + + for (int y = 0; y < classNames.length; y++) { + AffineTransform trans = g.getTransform(); + g.transform(AffineTransform.getTranslateInstance(CELL_PAD * 2 + + width, CELLS_SIZE + y * (CELLS_SIZE + CELL_PAD))); + g.transform(AffineTransform.getRotateInstance(Math.PI / 12)); + g.drawString(classNames[y], 0, 0); + g.setTransform(trans); + } + + for (int x = 0; x < jarNames.length; x++) { + AffineTransform trans = g.getTransform(); + g.transform(AffineTransform.getTranslateInstance(CELL_PAD * 2 + x + * (CELLS_SIZE + CELL_PAD), heigh + CELL_PAD * 2)); + g.transform(AffineTransform.getRotateInstance(Math.PI / 2.5)); + g.drawString(jarNames[x], 0, 0); + g.setTransform(trans); + } + + FileOutputStream fos = new FileOutputStream("test.png"); + ImageIO.write(img, "png", fos); + fos.flush(); + fos.close(); + } +} diff --git a/asm4/examples/dependencies/src/org/objectweb/asm/depend/DependencyVisitor.java b/asm4/examples/dependencies/src/org/objectweb/asm/depend/DependencyVisitor.java new file mode 100644 index 0000000..bd8d76e --- /dev/null +++ b/asm4/examples/dependencies/src/org/objectweb/asm/depend/DependencyVisitor.java @@ -0,0 +1,356 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.depend; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.signature.SignatureReader; +import org.objectweb.asm.signature.SignatureVisitor; + +/** + * DependencyVisitor + * + * @author Eugene Kuleshov + */ +public class DependencyVisitor extends ClassVisitor { + Set<String> packages = new HashSet<String>(); + + Map<String, Map<String, Integer>> groups = new HashMap<String, Map<String, Integer>>(); + + Map<String, Integer> current; + + public Map<String, Map<String, Integer>> getGlobals() { + return groups; + } + + public Set<String> getPackages() { + return packages; + } + + public DependencyVisitor() { + super(Opcodes.ASM4); + } + + // ClassVisitor + + @Override + public void visit(final int version, final int access, final String name, + final String signature, final String superName, + final String[] interfaces) { + String p = getGroupKey(name); + current = groups.get(p); + if (current == null) { + current = new HashMap<String, Integer>(); + groups.put(p, current); + } + + if (signature == null) { + if (superName != null) { + addInternalName(superName); + } + addInternalNames(interfaces); + } else { + addSignature(signature); + } + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { + addDesc(desc); + return new AnnotationDependencyVisitor(); + } + + @Override + public FieldVisitor visitField(final int access, final String name, + final String desc, final String signature, final Object value) { + if (signature == null) { + addDesc(desc); + } else { + addTypeSignature(signature); + } + if (value instanceof Type) { + addType((Type) value); + } + return new FieldDependencyVisitor(); + } + + @Override + public MethodVisitor visitMethod(final int access, final String name, + final String desc, final String signature, final String[] exceptions) { + if (signature == null) { + addMethodDesc(desc); + } else { + addSignature(signature); + } + addInternalNames(exceptions); + return new MethodDependencyVisitor(); + } + + class AnnotationDependencyVisitor extends AnnotationVisitor { + + public AnnotationDependencyVisitor() { + super(Opcodes.ASM4); + } + + @Override + public void visit(final String name, final Object value) { + if (value instanceof Type) { + addType((Type) value); + } + } + + @Override + public void visitEnum(final String name, final String desc, + final String value) { + addDesc(desc); + } + + @Override + public AnnotationVisitor visitAnnotation(final String name, + final String desc) { + addDesc(desc); + return this; + } + + @Override + public AnnotationVisitor visitArray(final String name) { + return this; + } + } + + class FieldDependencyVisitor extends FieldVisitor { + + public FieldDependencyVisitor() { + super(Opcodes.ASM4); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + addDesc(desc); + return new AnnotationDependencyVisitor(); + } + } + + class MethodDependencyVisitor extends MethodVisitor { + + public MethodDependencyVisitor() { + super(Opcodes.ASM4); + } + + @Override + public AnnotationVisitor visitAnnotationDefault() { + return new AnnotationDependencyVisitor(); + } + + @Override + public AnnotationVisitor visitAnnotation(final String desc, + final boolean visible) { + addDesc(desc); + return new AnnotationDependencyVisitor(); + } + + @Override + public AnnotationVisitor visitParameterAnnotation(final int parameter, + final String desc, final boolean visible) { + addDesc(desc); + return new AnnotationDependencyVisitor(); + } + + @Override + public void visitTypeInsn(final int opcode, final String type) { + addType(Type.getObjectType(type)); + } + + @Override + public void visitFieldInsn(final int opcode, final String owner, + final String name, final String desc) { + addInternalName(owner); + addDesc(desc); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + addInternalName(owner); + addMethodDesc(desc); + } + + @Override + public void visitInvokeDynamicInsn(String name, String desc, + Handle bsm, Object... bsmArgs) { + addMethodDesc(desc); + addConstant(bsm); + for (int i = 0; i < bsmArgs.length; i++) { + addConstant(bsmArgs[i]); + } + } + + @Override + public void visitLdcInsn(final Object cst) { + addConstant(cst); + } + + @Override + public void visitMultiANewArrayInsn(final String desc, final int dims) { + addDesc(desc); + } + + @Override + public void visitLocalVariable(final String name, final String desc, + final String signature, final Label start, final Label end, + final int index) { + addTypeSignature(signature); + } + + @Override + public void visitTryCatchBlock(final Label start, final Label end, + final Label handler, final String type) { + if (type != null) { + addInternalName(type); + } + } + } + + class SignatureDependencyVisitor extends SignatureVisitor { + + String signatureClassName; + + public SignatureDependencyVisitor() { + super(Opcodes.ASM4); + } + + @Override + public void visitClassType(final String name) { + signatureClassName = name; + addInternalName(name); + } + + @Override + public void visitInnerClassType(final String name) { + signatureClassName = signatureClassName + "$" + name; + addInternalName(signatureClassName); + } + } + + // --------------------------------------------- + + private String getGroupKey(String name) { + int n = name.lastIndexOf('/'); + if (n > -1) { + name = name.substring(0, n); + } + packages.add(name); + return name; + } + + private void addName(final String name) { + if (name == null) { + return; + } + String p = getGroupKey(name); + if (current.containsKey(p)) { + current.put(p, current.get(p) + 1); + } else { + current.put(p, 1); + } + } + + void addInternalName(final String name) { + addType(Type.getObjectType(name)); + } + + private void addInternalNames(final String[] names) { + for (int i = 0; names != null && i < names.length; i++) { + addInternalName(names[i]); + } + } + + void addDesc(final String desc) { + addType(Type.getType(desc)); + } + + void addMethodDesc(final String desc) { + addType(Type.getReturnType(desc)); + Type[] types = Type.getArgumentTypes(desc); + for (int i = 0; i < types.length; i++) { + addType(types[i]); + } + } + + void addType(final Type t) { + switch (t.getSort()) { + case Type.ARRAY: + addType(t.getElementType()); + break; + case Type.OBJECT: + addName(t.getInternalName()); + break; + case Type.METHOD: + addMethodDesc(t.getDescriptor()); + break; + } + } + + private void addSignature(final String signature) { + if (signature != null) { + new SignatureReader(signature) + .accept(new SignatureDependencyVisitor()); + } + } + + void addTypeSignature(final String signature) { + if (signature != null) { + new SignatureReader(signature) + .acceptType(new SignatureDependencyVisitor()); + } + } + + void addConstant(final Object cst) { + if (cst instanceof Type) { + addType((Type) cst); + } else if (cst instanceof Handle) { + Handle h = (Handle) cst; + addInternalName(h.getOwner()); + addMethodDesc(h.getDesc()); + } + } +} diff --git a/asm4/examples/helloworld/etc/execute.properties b/asm4/examples/helloworld/etc/execute.properties new file mode 100644 index 0000000..f735b79 --- /dev/null +++ b/asm4/examples/helloworld/etc/execute.properties @@ -0,0 +1,32 @@ +############################################################################### +#ASM: a very small and fast Java bytecode manipulation framework +#Copyright (c) 2000-2011 INRIA, France Telecom +#All rights reserved. +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions +#are met: +#1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +#2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +#3. Neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +#THE POSSIBILITY OF SUCH DAMAGE. +############################################################################### + +run.classname Helloworld +run.parameters diff --git a/asm4/examples/helloworld/src/Helloworld.java b/asm4/examples/helloworld/src/Helloworld.java new file mode 100644 index 0000000..dcc905a --- /dev/null +++ b/asm4/examples/helloworld/src/Helloworld.java @@ -0,0 +1,139 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +import java.io.FileOutputStream; +import java.io.PrintStream; + +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.GeneratorAdapter; +import org.objectweb.asm.commons.Method; + +/** + * @author Eric Bruneton + */ +public class Helloworld extends ClassLoader implements Opcodes { + + public static void main(final String args[]) throws Exception { + + // Generates the bytecode corresponding to the following Java class: + // + // public class Example { + // public static void main (String[] args) { + // System.out.println("Hello world!"); + // } + // } + + // creates a ClassWriter for the Example public class, + // which inherits from Object + ClassWriter cw = new ClassWriter(0); + cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null); + + // creates a MethodWriter for the (implicit) constructor + MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, + null); + // pushes the 'this' variable + mw.visitVarInsn(ALOAD, 0); + // invokes the super class constructor + mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); + mw.visitInsn(RETURN); + // this code uses a maximum of one stack element and one local variable + mw.visitMaxs(1, 1); + mw.visitEnd(); + + // creates a MethodWriter for the 'main' method + mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", + "([Ljava/lang/String;)V", null, null); + // pushes the 'out' field (of type PrintStream) of the System class + mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", + "Ljava/io/PrintStream;"); + // pushes the "Hello World!" String constant + mw.visitLdcInsn("Hello world!"); + // invokes the 'println' method (defined in the PrintStream class) + mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", + "(Ljava/lang/String;)V"); + mw.visitInsn(RETURN); + // this code uses a maximum of two stack elements and two local + // variables + mw.visitMaxs(2, 2); + mw.visitEnd(); + + // gets the bytecode of the Example class, and loads it dynamically + byte[] code = cw.toByteArray(); + + FileOutputStream fos = new FileOutputStream("Example.class"); + fos.write(code); + fos.close(); + + Helloworld loader = new Helloworld(); + Class<?> exampleClass = loader.defineClass("Example", code, 0, + code.length); + + // uses the dynamically generated class to print 'Helloworld' + exampleClass.getMethods()[0].invoke(null, new Object[] { null }); + + // ------------------------------------------------------------------------ + // Same example with a GeneratorAdapter (more convenient but slower) + // ------------------------------------------------------------------------ + + cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null); + + // creates a GeneratorAdapter for the (implicit) constructor + Method m = Method.getMethod("void <init> ()"); + GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, + cw); + mg.loadThis(); + mg.invokeConstructor(Type.getType(Object.class), m); + mg.returnValue(); + mg.endMethod(); + + // creates a GeneratorAdapter for the 'main' method + m = Method.getMethod("void main (String[])"); + mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw); + mg.getStatic(Type.getType(System.class), "out", + Type.getType(PrintStream.class)); + mg.push("Hello world!"); + mg.invokeVirtual(Type.getType(PrintStream.class), + Method.getMethod("void println (String)")); + mg.returnValue(); + mg.endMethod(); + + cw.visitEnd(); + + code = cw.toByteArray(); + loader = new Helloworld(); + exampleClass = loader.defineClass("Example", code, 0, code.length); + + // uses the dynamically generated class to print 'Helloworld' + exampleClass.getMethods()[0].invoke(null, new Object[] { null }); + } +} diff --git a/asm4/examples/jasmin/etc/execute.properties b/asm4/examples/jasmin/etc/execute.properties new file mode 100644 index 0000000..3c53857 --- /dev/null +++ b/asm4/examples/jasmin/etc/execute.properties @@ -0,0 +1,32 @@ +############################################################################### +#ASM: a very small and fast Java bytecode manipulation framework +#Copyright (c) 2000-2011 INRIA, France Telecom +#All rights reserved. +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions +#are met: +#1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +#2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +#3. Neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +#THE POSSIBILITY OF SUCH DAMAGE. +############################################################################### + +run.classname JasminifierClassAdapter +run.parameters java.lang.Object diff --git a/asm4/examples/jasmin/src/JasminifierClassAdapter.java b/asm4/examples/jasmin/src/JasminifierClassAdapter.java new file mode 100644 index 0000000..45d9073 --- /dev/null +++ b/asm4/examples/jasmin/src/JasminifierClassAdapter.java @@ -0,0 +1,900 @@ +/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2011 INRIA, France Telecom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.io.FileInputStream;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.tree.AbstractInsnNode;
+import org.objectweb.asm.tree.AnnotationNode;
+import org.objectweb.asm.tree.ClassNode;
+import org.objectweb.asm.tree.FieldNode;
+import org.objectweb.asm.tree.InnerClassNode;
+import org.objectweb.asm.tree.LabelNode;
+import org.objectweb.asm.tree.LocalVariableNode;
+import org.objectweb.asm.tree.MethodNode;
+import org.objectweb.asm.tree.TryCatchBlockNode;
+import org.objectweb.asm.util.Printer;
+
+/**
+ * A {@link ClassVisitor} that prints a disassembled view of the classes it
+ * visits in Jasmin assembler format. This class visitor can be used alone (see
+ * the {@link #main main} method) to disassemble a class. It can also be used in
+ * the middle of class visitor chain to trace the class that is visited at a
+ * given point in this chain. This may be uselful for debugging purposes.
+ * <p>
+ * The trace printed when visiting the <tt>Hello</tt> class is the following:
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * .bytecode 45.3
+ * .class public Hello
+ * .super java/lang/Object
+ *
+ * .method public <init>()V
+ * aload 0
+ * invokespecial java/lang/Object/<init>()V
+ * return
+ * .limit locals 1
+ * .limit stack 1
+ * .end method
+ *
+ * .method public static main([Ljava/lang/String;)V
+ * getstatic java/lang/System/out Ljava/io/PrintStream;
+ * ldc "hello"
+ * invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
+ * return
+ * .limit locals 2
+ * .limit stack 2
+ * .end method
+ * </pre>
+ *
+ * </blockquote> where <tt>Hello</tt> is defined by:
+ * <p>
+ * <blockquote>
+ *
+ * <pre>
+ * public class Hello {
+ *
+ * public static void main(String[] args) {
+ * System.out.println("hello");
+ * }
+ * }
+ * </pre>
+ *
+ * </blockquote>
+ *
+ * @author Eric Bruneton
+ */
+public class JasminifierClassAdapter extends ClassVisitor {
+
+ /**
+ * The print writer to be used to print the class.
+ */
+ protected PrintWriter pw;
+
+ /**
+ * The label names. This map associate String values to Label keys.
+ */
+ protected final Map<Label, String> labelNames;
+
+ /**
+ * Prints a disassembled view of the given class in Jasmin assembler format
+ * to the standard output.
+ * <p>
+ * Usage: JasminifierClassAdapter [-debug] <fully qualified class name or
+ * class file name >
+ *
+ * @param args
+ * the command line arguments.
+ *
+ * @throws Exception
+ * if the class cannot be found, or if an IO exception occurs.
+ */
+ public static void main(final String[] args) throws Exception {
+ int i = 0;
+ int flags = ClassReader.SKIP_DEBUG;
+
+ boolean ok = true;
+ if (args.length < 1 || args.length > 2) {
+ ok = false;
+ }
+ if (ok && "-debug".equals(args[0])) {
+ i = 1;
+ flags = 0;
+ if (args.length != 2) {
+ ok = false;
+ }
+ }
+ if (!ok) {
+ System.err
+ .println("Prints a disassembled view of the given class.");
+ System.err.println("Usage: JasminifierClassAdapter [-debug] "
+ + "<fully qualified class name or class file name>");
+ return;
+ }
+ ClassReader cr;
+ if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1
+ || args[i].indexOf('/') > -1) {
+ cr = new ClassReader(new FileInputStream(args[i]));
+ } else {
+ cr = new ClassReader(args[i]);
+ }
+ cr.accept(new JasminifierClassAdapter(
+ new PrintWriter(System.out, true), null), flags
+ | ClassReader.EXPAND_FRAMES);
+ }
+
+ /**
+ * Constructs a new {@link JasminifierClassAdapter}.
+ *
+ * @param pw
+ * the print writer to be used to print the class.
+ * @param cv
+ * the {@link ClassVisitor} to which this visitor delegates
+ * calls. May be <tt>null</tt>.
+ */
+ public JasminifierClassAdapter(final PrintWriter pw, final ClassVisitor cv) {
+ super(Opcodes.ASM4, new ClassNode() {
+ @Override
+ public void visitEnd() {
+ if (cv != null) {
+ accept(cv);
+ }
+ }
+ });
+ this.pw = pw;
+ labelNames = new HashMap<Label, String>();
+ }
+
+ @Override
+ public void visitEnd() {
+ ClassNode cn = (ClassNode) cv;
+ pw.print(".bytecode ");
+ pw.print(cn.version & 0xFFFF);
+ pw.print('.');
+ pw.println(cn.version >>> 16);
+ println(".source ", cn.sourceFile);
+ pw.print(".class");
+ pw.print(access(cn.access));
+ pw.print(' ');
+ pw.println(cn.name);
+ if (cn.superName == null) { // TODO Jasmin bug workaround
+ println(".super ", "java/lang/Object");
+ } else {
+ println(".super ", cn.superName);
+ }
+ for (int i = 0; i < cn.interfaces.size(); ++i) {
+ println(".implements ", cn.interfaces.get(i));
+ }
+ if (cn.signature != null)
+ println(".signature ", '"' + cn.signature + '"');
+ if (cn.outerClass != null) {
+ pw.print(".enclosing method ");
+ pw.print(cn.outerClass);
+ if (cn.outerMethod != null) {
+ pw.print('/');
+ pw.print(cn.outerMethod);
+ pw.println(cn.outerMethodDesc);
+ } else {
+ pw.println();
+ }
+ }
+ if ((cn.access & Opcodes.ACC_DEPRECATED) != 0) {
+ pw.println(".deprecated");
+ }
+ printAnnotations(cn.visibleAnnotations, 1);
+ printAnnotations(cn.invisibleAnnotations, 2);
+ println(".debug ", cn.sourceDebug == null ? null
+ : '"' + cn.sourceDebug + '"');
+
+ for (int i = 0; i < cn.innerClasses.size(); ++i) {
+ InnerClassNode in = cn.innerClasses.get(i);
+ pw.print(".inner class");
+ pw.print(access(in.access));
+ if (in.innerName != null) {
+ pw.print(' ');
+ pw.print(in.innerName);
+ }
+ if (in.name != null) {
+ pw.print(" inner ");
+ pw.print(in.name);
+ }
+ if (in.outerName != null) {
+ pw.print(" outer ");
+ pw.print(in.outerName);
+ }
+ pw.println();
+ }
+
+ for (int i = 0; i < cn.fields.size(); ++i) {
+ FieldNode fn = cn.fields.get(i);
+ boolean annotations = false;
+ if (fn.visibleAnnotations != null
+ && fn.visibleAnnotations.size() > 0) {
+ annotations = true;
+ }
+ if (fn.invisibleAnnotations != null
+ && fn.invisibleAnnotations.size() > 0) {
+ annotations = true;
+ }
+ boolean deprecated = (fn.access & Opcodes.ACC_DEPRECATED) != 0;
+ pw.print("\n.field");
+ pw.print(access(fn.access));
+ pw.print(" '");
+ pw.print(fn.name);
+ pw.print("' ");
+ pw.print(fn.desc);
+ if (fn.signature != null && (!deprecated && !annotations)) {
+ pw.print(" signature \"");
+ pw.print(fn.signature);
+ pw.print("\"");
+ }
+ if (fn.value instanceof String) {
+ StringBuffer buf = new StringBuffer();
+ Printer.appendString(buf, (String) fn.value);
+ pw.print(" = ");
+ pw.print(buf.toString());
+ } else if (fn.value != null) {
+ pw.print(" = ");
+ print(fn.value);
+ pw.println();
+ }
+ pw.println();
+ if (fn.signature != null && (deprecated || annotations)) {
+ pw.print(".signature \"");
+ pw.print(fn.signature);
+ pw.println("\"");
+ }
+ if (deprecated) {
+ pw.println(".deprecated");
+ }
+ printAnnotations(fn.visibleAnnotations, 1);
+ printAnnotations(fn.invisibleAnnotations, 2);
+ if (deprecated || annotations) {
+ pw.println(".end field");
+ }
+ }
+
+ for (int i = 0; i < cn.methods.size(); ++i) {
+ MethodNode mn = cn.methods.get(i);
+ pw.print("\n.method");
+ pw.print(access(mn.access));
+ pw.print(' ');
+ pw.print(mn.name);
+ pw.println(mn.desc);
+ if (mn.signature != null) {
+ pw.print(".signature \"");
+ pw.print(mn.signature);
+ pw.println("\"");
+ }
+ if (mn.annotationDefault != null) {
+ pw.println(".annotation default");
+ printAnnotationValue(mn.annotationDefault);
+ pw.println(".end annotation");
+ }
+ printAnnotations(mn.visibleAnnotations, 1);
+ printAnnotations(mn.invisibleAnnotations, 2);
+ if (mn.visibleParameterAnnotations != null) {
+ for (int j = 0; j < mn.visibleParameterAnnotations.length; ++j) {
+ printAnnotations(mn.visibleParameterAnnotations[j], 1);
+ }
+ }
+ if (mn.invisibleParameterAnnotations != null) {
+ for (int j = 0; j < mn.invisibleParameterAnnotations.length; ++j) {
+ printAnnotations(mn.invisibleParameterAnnotations[j], 2);
+ }
+ }
+ for (int j = 0; j < mn.exceptions.size(); ++j) {
+ println(".throws ", mn.exceptions.get(j));
+ }
+ if ((mn.access & Opcodes.ACC_DEPRECATED) != 0) {
+ pw.println(".deprecated");
+ }
+ if (mn.instructions.size() > 0) {
+ labelNames.clear();
+ for (int j = 0; j < mn.tryCatchBlocks.size(); ++j) {
+ TryCatchBlockNode tcb = mn.tryCatchBlocks.get(j);
+ pw.print(".catch ");
+ pw.print(tcb.type);
+ pw.print(" from ");
+ print(tcb.start);
+ pw.print(" to ");
+ print(tcb.end);
+ pw.print(" using ");
+ print(tcb.handler);
+ pw.println();
+ }
+ for (int j = 0; j < mn.instructions.size(); ++j) {
+ AbstractInsnNode in = mn.instructions.get(j);
+ in.accept(new MethodVisitor(Opcodes.ASM4) {
+
+ @Override
+ public void visitFrame(int type, int local,
+ Object[] locals, int stack, Object[] stacks) {
+ if (type != Opcodes.F_FULL && type != Opcodes.F_NEW) {
+ throw new RuntimeException(
+ "Compressed frames unsupported, use EXPAND_FRAMES option");
+ }
+ pw.println(".stack");
+ for (int i = 0; i < local; ++i) {
+ pw.print("locals ");
+ printFrameType(locals[i]);
+ pw.println();
+ }
+ for (int i = 0; i < stack; ++i) {
+ pw.print("stack ");
+ printFrameType(stacks[i]);
+ pw.println();
+ }
+ pw.println(".end stack");
+ }
+
+ @Override
+ public void visitInsn(int opcode) {
+ print(opcode);
+ pw.println();
+ }
+
+ @Override
+ public void visitIntInsn(int opcode, int operand) {
+ print(opcode);
+ if (opcode == Opcodes.NEWARRAY) {
+ switch (operand) {
+ case Opcodes.T_BOOLEAN:
+ pw.println(" boolean");
+ break;
+ case Opcodes.T_CHAR:
+ pw.println(" char");
+ break;
+ case Opcodes.T_FLOAT:
+ pw.println(" float");
+ break;
+ case Opcodes.T_DOUBLE:
+ pw.println(" double");
+ break;
+ case Opcodes.T_BYTE:
+ pw.println(" byte");
+ break;
+ case Opcodes.T_SHORT:
+ pw.println(" short");
+ break;
+ case Opcodes.T_INT:
+ pw.println(" int");
+ break;
+ case Opcodes.T_LONG:
+ default:
+ pw.println(" long");
+ break;
+ }
+ } else {
+ pw.print(' ');
+ pw.println(operand);
+ }
+ }
+
+ @Override
+ public void visitVarInsn(int opcode, int var) {
+ print(opcode);
+ pw.print(' ');
+ pw.println(var);
+ }
+
+ @Override
+ public void visitTypeInsn(int opcode, String type) {
+ print(opcode);
+ pw.print(' ');
+ pw.println(type);
+ }
+
+ @Override
+ public void visitFieldInsn(int opcode, String owner,
+ String name, String desc) {
+ print(opcode);
+ pw.print(' ');
+ pw.print(owner);
+ pw.print('/');
+ pw.print(name);
+ pw.print(' ');
+ pw.println(desc);
+ }
+
+ @Override
+ public void visitMethodInsn(int opcode, String owner,
+ String name, String desc) {
+ print(opcode);
+ pw.print(' ');
+ pw.print(owner);
+ pw.print('/');
+ pw.print(name);
+ pw.print(desc);
+ if (opcode == Opcodes.INVOKEINTERFACE) {
+ pw.print(' ');
+ pw.print((Type.getArgumentsAndReturnSizes(desc) >> 2) - 1);
+ }
+ pw.println();
+ }
+
+ @Override
+ public void visitJumpInsn(int opcode, Label label) {
+ print(opcode);
+ pw.print(' ');
+ print(label);
+ pw.println();
+ }
+
+ @Override
+ public void visitLabel(Label label) {
+ print(label);
+ pw.println(':');
+ }
+
+ @Override
+ public void visitLdcInsn(Object cst) {
+ pw.print("ldc ");
+ if (cst instanceof Type) {
+ pw.print(((Type) cst).getInternalName());
+ } else {
+ print(cst);
+ }
+ pw.println();
+ }
+
+ @Override
+ public void visitIincInsn(int var, int increment) {
+ pw.print("iinc ");
+ pw.print(var);
+ pw.print(' ');
+ pw.println(increment);
+ }
+
+ @Override
+ public void visitTableSwitchInsn(int min, int max,
+ Label dflt, Label... labels) {
+ pw.print("tableswitch ");
+ pw.println(min);
+ for (int i = 0; i < labels.length; ++i) {
+ print(labels[i]);
+ pw.println();
+ }
+ pw.print("default : ");
+ print(dflt);
+ pw.println();
+ }
+
+ @Override
+ public void visitLookupSwitchInsn(Label dflt,
+ int[] keys, Label[] labels) {
+ if (keys.length == 0) {
+ pw.print("goto "); // TODO Jasmin bug
+ // workaround
+ print(dflt);
+ pw.println();
+ return;
+ }
+ pw.println("lookupswitch");
+ for (int i = 0; i < keys.length; ++i) {
+ pw.print(keys[i]);
+ pw.print(" : ");
+ print(labels[i]);
+ pw.println();
+ }
+ pw.print("default : ");
+ print(dflt);
+ pw.println();
+ }
+
+ @Override
+ public void visitMultiANewArrayInsn(String desc,
+ int dims) {
+ pw.print("multianewarray ");
+ pw.print(desc);
+ pw.print(' ');
+ pw.println(dims);
+ }
+
+ @Override
+ public void visitLineNumber(int line, Label start) {
+ pw.print(".line ");
+ pw.println(line);
+ }
+ });
+ }
+ for (int j = 0; j < mn.localVariables.size(); ++j) {
+ LocalVariableNode lv = mn.localVariables.get(j);
+ pw.print(".var ");
+ pw.print(lv.index);
+ pw.print(" is '");
+ pw.print(lv.name);
+ pw.print("' ");
+ pw.print(lv.desc);
+ if (lv.signature != null) {
+ pw.print(" signature \"");
+ pw.print(lv.signature);
+ pw.print("\"");
+ }
+ pw.print(" from ");
+ print(lv.start);
+ pw.print(" to ");
+ print(lv.end);
+ pw.println();
+ }
+ println(".limit locals ", Integer.toString(mn.maxLocals));
+ println(".limit stack ", Integer.toString(mn.maxStack));
+ }
+ pw.println(".end method");
+ }
+ super.visitEnd();
+ }
+
+ protected void println(final String directive, final String arg) {
+ if (arg != null) {
+ pw.print(directive);
+ pw.println(arg);
+ }
+ }
+
+ protected String access(final int access) {
+ StringBuffer b = new StringBuffer();
+ if ((access & Opcodes.ACC_PUBLIC) != 0) {
+ b.append(" public");
+ }
+ if ((access & Opcodes.ACC_PRIVATE) != 0) {
+ b.append(" private");
+ }
+ if ((access & Opcodes.ACC_PROTECTED) != 0) {
+ b.append(" protected");
+ }
+ if ((access & Opcodes.ACC_STATIC) != 0) {
+ b.append(" static");
+ }
+ if ((access & Opcodes.ACC_FINAL) != 0) {
+ b.append(" final");
+ }
+ if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) {
+ b.append(" synchronized");
+ }
+ if ((access & Opcodes.ACC_VOLATILE) != 0) {
+ b.append(" volatile");
+ }
+ if ((access & Opcodes.ACC_TRANSIENT) != 0) {
+ b.append(" transient");
+ }
+ if ((access & Opcodes.ACC_NATIVE) != 0) {
+ b.append(" native");
+ }
+ if ((access & Opcodes.ACC_ABSTRACT) != 0) {
+ b.append(" abstract");
+ }
+ if ((access & Opcodes.ACC_STRICT) != 0) {
+ b.append(" fpstrict");
+ }
+ if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
+ b.append(" synthetic");
+ }
+ if ((access & Opcodes.ACC_INTERFACE) != 0) {
+ b.append(" interface");
+ }
+ if ((access & Opcodes.ACC_ANNOTATION) != 0) {
+ b.append(" annotation");
+ }
+ if ((access & Opcodes.ACC_ENUM) != 0) {
+ b.append(" enum");
+ }
+ return b.toString();
+ }
+
+ protected void print(final int opcode) {
+ pw.print(Printer.OPCODES[opcode].toLowerCase());
+ }
+
+ protected void print(final Object cst) {
+ if (cst instanceof String) {
+ StringBuffer buf = new StringBuffer();
+ Printer.appendString(buf, (String) cst);
+ pw.print(buf.toString());
+ } else if (cst instanceof Float) {
+ Float f = (Float) cst;
+ if (f.isNaN() || f.isInfinite()) {
+ pw.print("0.0"); // TODO Jasmin bug workaround
+ } else {
+ pw.print(f);
+ }
+ } else if (cst instanceof Double) {
+ Double d = (Double) cst;
+ if (d.isNaN() || d.isInfinite()) {
+ pw.print("0.0"); // TODO Jasmin bug workaround
+ } else {
+ pw.print(d);
+ }
+ } else {
+ pw.print(cst);
+ }
+ }
+
+ protected void print(final Label l) {
+ String name = labelNames.get(l);
+ if (name == null) {
+ name = "L" + labelNames.size();
+ labelNames.put(l, name);
+ }
+ pw.print(name);
+ }
+
+ protected void print(final LabelNode l) {
+ print(l.getLabel());
+ }
+
+ protected void printAnnotations(final List<AnnotationNode> annotations,
+ int visible) {
+ if (annotations != null) {
+ for (int j = 0; j < annotations.size(); ++j) {
+ printAnnotation(annotations.get(j), visible, -1);
+ }
+ }
+ }
+
+ protected void printAnnotation(final AnnotationNode n, final int visible,
+ final int param) {
+ pw.print(".annotation ");
+ if (visible > 0) {
+ if (param == -1) {
+ pw.print(visible == 1 ? "visible " : "invisible ");
+ } else {
+ pw.print(visible == 1 ? "visibleparam " : "invisibleparam ");
+ pw.print(param);
+ pw.print(' ');
+ }
+ pw.print(n.desc);
+ }
+ pw.println();
+ if (n.values != null) {
+ for (int i = 0; i < n.values.size(); i += 2) {
+ pw.print(n.values.get(i));
+ pw.print(' ');
+ printAnnotationValue(n.values.get(i + 1));
+ }
+ }
+ pw.println(".end annotation");
+ }
+
+ protected void printAnnotationValue(final Object value) {
+ if (value instanceof String[]) {
+ pw.print("e ");
+ pw.print(((String[]) value)[0]);
+ pw.print(" = ");
+ print(((String[]) value)[1]);
+ pw.println();
+ } else if (value instanceof AnnotationNode) {
+ pw.print("@ ");
+ pw.print(((AnnotationNode) value).desc);
+ pw.print(" = ");
+ printAnnotation((AnnotationNode) value, 0, -1);
+ } else if (value instanceof byte[]) {
+ pw.print("[B = ");
+ byte[] v = (byte[]) value;
+ for (int i = 0; i < v.length; i++) {
+ pw.print(v[i]);
+ pw.print(' ');
+ }
+ pw.println();
+ } else if (value instanceof boolean[]) {
+ pw.print("[Z = ");
+ boolean[] v = (boolean[]) value;
+ for (int i = 0; i < v.length; i++) {
+ pw.print(v[i] ? '1' : '0');
+ pw.print(' ');
+ }
+ pw.println();
+ } else if (value instanceof short[]) {
+ pw.print("[S = ");
+ short[] v = (short[]) value;
+ for (int i = 0; i < v.length; i++) {
+ pw.print(v[i]);
+ pw.print(' ');
+ }
+ pw.println();
+ } else if (value instanceof char[]) {
+ pw.print("[C = ");
+ char[] v = (char[]) value;
+ for (int i = 0; i < v.length; i++) {
+ pw.print(new Integer(v[i]));
+ pw.print(' ');
+ }
+ pw.println();
+ } else if (value instanceof int[]) {
+ pw.print("[I = ");
+ int[] v = (int[]) value;
+ for (int i = 0; i < v.length; i++) {
+ pw.print(v[i]);
+ pw.print(' ');
+ }
+ pw.println();
+ } else if (value instanceof long[]) {
+ pw.print("[J = ");
+ long[] v = (long[]) value;
+ for (int i = 0; i < v.length; i++) {
+ pw.print(v[i]);
+ pw.print(' ');
+ }
+ pw.println();
+ } else if (value instanceof float[]) {
+ pw.print("[F = ");
+ float[] v = (float[]) value;
+ for (int i = 0; i < v.length; i++) {
+ print(new Float(v[i]));
+ pw.print(' ');
+ }
+ pw.println();
+ } else if (value instanceof double[]) {
+ pw.print("[D = ");
+ double[] v = (double[]) value;
+ for (int i = 0; i < v.length; i++) {
+ print(new Double(v[i]));
+ pw.print(' ');
+ }
+ pw.println();
+ } else if (value instanceof List) {
+ List<?> l = (List<?>) value;
+ if (l.size() > 0) {
+ Object o = l.get(0);
+ if (o instanceof String[]) {
+ pw.print("[e ");
+ pw.print(((String[]) o)[0]);
+ pw.print(" = ");
+ } else if (o instanceof AnnotationNode) {
+ pw.print("[& ");
+ pw.print(((AnnotationNode) o).desc);
+ pw.print(" = ");
+ pw.print("[@ = ");
+ } else if (o instanceof String) {
+ pw.print("[s = ");
+ } else if (o instanceof Byte) {
+ pw.print("[B = ");
+ } else if (o instanceof Boolean) {
+ pw.print("[Z = ");
+ } else if (o instanceof Character) {
+ pw.print("[C = ");
+ } else if (o instanceof Short) {
+ pw.print("[S = ");
+ } else if (o instanceof Type) {
+ pw.print("[c = ");
+ } else if (o instanceof Integer) {
+ pw.print("[I = ");
+ } else if (o instanceof Float) {
+ pw.print("[F = ");
+ } else if (o instanceof Long) {
+ pw.print("[J = ");
+ } else if (o instanceof Double) {
+ pw.print("[D = ");
+ }
+ for (int j = 0; j < l.size(); ++j) {
+ printAnnotationArrayValue(l.get(j));
+ pw.print(' ');
+ }
+ } else {
+ pw.print("; empty array annotation value");
+ }
+ pw.println();
+ } else if (value instanceof String) {
+ pw.print("s = ");
+ print(value);
+ pw.println();
+ } else if (value instanceof Byte) {
+ pw.print("B = ");
+ pw.println(((Byte) value).intValue());
+ } else if (value instanceof Boolean) {
+ pw.print("Z = ");
+ pw.println(((Boolean) value).booleanValue() ? 1 : 0);
+ } else if (value instanceof Character) {
+ pw.print("C = ");
+ pw.println(new Integer(((Character) value).charValue()));
+ } else if (value instanceof Short) {
+ pw.print("S = ");
+ pw.println(((Short) value).intValue());
+ } else if (value instanceof Type) {
+ pw.print("c = ");
+ pw.println(((Type) value).getDescriptor());
+ } else if (value instanceof Integer) {
+ pw.print("I = ");
+ print(value);
+ pw.println();
+ } else if (value instanceof Float) {
+ pw.print("F = ");
+ print(value);
+ pw.println();
+ } else if (value instanceof Long) {
+ pw.print("J = ");
+ print(value);
+ pw.println();
+ } else if (value instanceof Double) {
+ pw.print("D = ");
+ print(value);
+ pw.println();
+ } else {
+ throw new RuntimeException();
+ }
+ }
+
+ protected void printAnnotationArrayValue(final Object value) {
+ if (value instanceof String[]) {
+ print(((String[]) value)[1]);
+ } else if (value instanceof AnnotationNode) {
+ printAnnotation((AnnotationNode) value, 0, -1);
+ } else if (value instanceof String) {
+ print(value);
+ } else if (value instanceof Byte) {
+ pw.print(((Byte) value).intValue());
+ } else if (value instanceof Boolean) {
+ pw.print(((Boolean) value).booleanValue() ? 1 : 0);
+ } else if (value instanceof Character) {
+ pw.print(new Integer(((Character) value).charValue()));
+ } else if (value instanceof Short) {
+ pw.print(((Short) value).intValue());
+ } else if (value instanceof Type) {
+ pw.print(((Type) value).getDescriptor());
+ } else {
+ print(value);
+ }
+ }
+
+ protected void printFrameType(final Object type) {
+ if (type == Opcodes.TOP) {
+ pw.print("Top");
+ } else if (type == Opcodes.INTEGER) {
+ pw.print("Integer");
+ } else if (type == Opcodes.FLOAT) {
+ pw.print("Float");
+ } else if (type == Opcodes.LONG) {
+ pw.print("Long");
+ } else if (type == Opcodes.DOUBLE) {
+ pw.print("Double");
+ } else if (type == Opcodes.NULL) {
+ pw.print("Null");
+ } else if (type == Opcodes.UNINITIALIZED_THIS) {
+ pw.print("UninitializedThis");
+ } else if (type instanceof Label) {
+ pw.print("Uninitialized ");
+ print((Label) type);
+ } else {
+ pw.print("Object ");
+ pw.print(type);
+ }
+ }
+}
diff --git a/asm4/examples/jasmin/test/JasminifierClassAdapterTest.java b/asm4/examples/jasmin/test/JasminifierClassAdapterTest.java new file mode 100644 index 0000000..888ec0a --- /dev/null +++ b/asm4/examples/jasmin/test/JasminifierClassAdapterTest.java @@ -0,0 +1,280 @@ +/*** + * ASM tests + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +import jas.jasError; +import jasmin.ClassFile; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.objectweb.asm.Attribute; +import org.objectweb.asm.ByteVector; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.util.TraceClassVisitor; + +class ClassFilter extends ClassVisitor { + + public ClassFilter() { + super(Opcodes.ASM4, null); + } + + public void setNext(final ClassVisitor cv) { + this.cv = cv; + } +} + +class Comment extends Attribute { + + public Comment() { + super("Comment"); + } + + @Override + public boolean isUnknown() { + return false; + } + + @Override + protected Attribute read(final ClassReader cr, final int off, + final int len, final char[] buf, final int codeOff, + final Label[] labels) { + + return new Comment(); + } + + @Override + protected ByteVector write(final ClassWriter cw, final byte[] code, + final int len, final int maxStack, final int maxLocals) { + return new ByteVector(); + } +} + +class CodeComment extends Attribute { + + public CodeComment() { + super("CodeComment"); + } + + @Override + public boolean isUnknown() { + return false; + } + + @Override + public boolean isCodeAttribute() { + return true; + } + + @Override + protected Attribute read(final ClassReader cr, final int off, + final int len, final char[] buf, final int codeOff, + final Label[] labels) { + return new CodeComment(); + } + + @Override + protected ByteVector write(final ClassWriter cw, final byte[] code, + final int len, final int maxStack, final int maxLocals) { + return new ByteVector(); + } + + @Override + protected Label[] getLabels() { + super.getLabels(); + return new Label[] { new Label() }; + } +} + +/** + * JasminifierAdapterTest tests. + * + * @author Eric Bruneton + */ +public class JasminifierClassAdapterTest extends TestCase { + + protected String n; + + protected InputStream is; + + public static TestSuite suite() throws Exception { + return new JasminifierClassAdapterTest().getSuite(); + } + + public JasminifierClassAdapterTest() { + super("test"); + } + + protected void init(final String n, final InputStream is) { + this.n = n; + this.is = is; + } + + protected TestSuite getSuite() throws Exception { + TestSuite suite = new TestSuite(getClass().getName()); + String files = System.getProperty("asm.test") + ","; + String clazz = System.getProperty("asm.test.class"); + String partcount = System.getProperty("parts"); + String partid = System.getProperty("part"); + int parts = partcount == null ? 1 : Integer.parseInt(partcount); + int part = partid == null ? 0 : Integer.parseInt(partid); + int id = 0; + while (files.indexOf(',') != -1) { + String file = files.substring(0, files.indexOf(',')); + files = files.substring(files.indexOf(',') + 1); + File f = new File(file); + if (f.isDirectory()) { + scanDirectory("", f, suite, clazz); + } else { + ZipFile zip = new ZipFile(file); + Enumeration<? extends ZipEntry> entries = zip.entries(); + while (entries.hasMoreElements()) { + ZipEntry e = entries.nextElement(); + String n = e.getName(); + String p = n.replace('/', '.'); + System.out.println(n + " " + clazz); + if (n.endsWith(".class") + && (clazz == null || p.indexOf(clazz) != -1)) { + n = p.substring(0, p.length() - 6); + if (id % parts == part) { + JasminifierClassAdapterTest t; + InputStream is = zip.getInputStream(e); + t = new JasminifierClassAdapterTest(); + t.init(n, is); + suite.addTest(t); + } + ++id; + } + } + } + } + return suite; + } + + private void scanDirectory(final String path, final File f, + final TestSuite suite, final String clazz) throws Exception { + File[] fs = f.listFiles(); + for (int i = 0; i < fs.length; ++i) { + String n = fs[i].getName(); + String qn = path.length() == 0 ? n : path + "." + n; + if (fs[i].isDirectory()) { + scanDirectory(qn, fs[i], suite, clazz); + } else if (qn.endsWith(".class") + && (clazz == null || qn.indexOf(clazz) != -1)) { + qn = qn.substring(0, qn.length() - 6); + InputStream is = new FileInputStream(fs[i]); + JasminifierClassAdapterTest t; + t = new JasminifierClassAdapterTest(); + t.init(qn, is); + suite.addTest(t); + } + } + } + + public void assertEquals(final ClassReader cr1, final ClassReader cr2) + throws Exception { + assertEquals(cr1, cr2, null, null); + } + + public void assertEquals(final ClassReader cr1, final ClassReader cr2, + final ClassFilter filter1, final ClassFilter filter2) + throws Exception { + if (!Arrays.equals(cr1.b, cr2.b)) { + StringWriter sw1 = new StringWriter(); + StringWriter sw2 = new StringWriter(); + ClassVisitor cv1 = new TraceClassVisitor(new PrintWriter(sw1)); + ClassVisitor cv2 = new TraceClassVisitor(new PrintWriter(sw2)); + if (filter1 != null) { + filter1.setNext(cv1); + } + if (filter2 != null) { + filter2.setNext(cv2); + } + cr1.accept(filter1 == null ? cv1 : filter1, 0); + cr2.accept(filter2 == null ? cv2 : filter2, 0); + String s1 = sw1.toString(); + String s2 = sw2.toString(); + assertEquals("different data", s1, s2); + } + } + + @Override + public String getName() { + return super.getName() + ": " + n; + } + + public void test() throws Exception { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + ClassReader cr = new ClassReader(is); + ClassWriter cw = new ClassWriter(0); + ClassVisitor cv = new JasminifierClassAdapter(pw, cw); + cr.accept(cv, new Attribute[] { new Comment(), new CodeComment() }, + ClassReader.EXPAND_FRAMES); + pw.close(); + String jasmin = sw.toString(); + + ClassFile cf = new ClassFile(); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + cf.readJasmin(new StringReader(jasmin), "test", false); + if (cf.errorCount() != 0) { + throw new jasError(); + } + cf.write(bos); + bos.close(); + + assertEquals(cr, new ClassReader(bos.toByteArray()), new ClassFilter() { + + @Override + public void visit(int version, int access, String name, + String signature, String superName, String[] interfaces) { + access |= Opcodes.ACC_SUPER; // Jasmin bug workaround + super.visit(version, access, name, signature, superName, + interfaces); + } + + }, null); + } +} diff --git a/asm4/examples/jasmin/test/build.xml b/asm4/examples/jasmin/test/build.xml new file mode 100644 index 0000000..9ddf2a0 --- /dev/null +++ b/asm4/examples/jasmin/test/build.xml @@ -0,0 +1,74 @@ +<!-- + ! ASM: a very small and fast Java bytecode manipulation framework + ! Copyright (c) 2000-2011 INRIA, France Telecom + ! All rights reserved. + ! + ! Redistribution and use in source and binary forms, with or without + ! modification, are permitted provided that the following conditions + ! are met: + ! 1. Redistributions of source code must retain the above copyright + ! notice, this list of conditions and the following disclaimer. + ! 2. Redistributions in binary form must reproduce the above copyright + ! notice, this list of conditions and the following disclaimer in the + ! documentation and/or other materials provided with the distribution. + ! 3. Neither the name of the copyright holders nor the names of its + ! contributors may be used to endorse or promote products derived from + ! this software without specific prior written permission. + ! + ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + ! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + ! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + ! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + ! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + ! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + ! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + ! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + ! THE POSSIBILITY OF SUCH DAMAGE. +--> + +<project name="jasmin" default="test"> + + <condition property="asm.test" value="${java.home}/lib/rt.jar"> + <not><isset property="asm.test"/></not> + </condition> + + <condition property="asm.test.class" value=""> + <not><isset property="asm.test.class"/></not> + </condition> + + <path id="classpath"> + <fileset dir="${basedir}/../../../lib"> + <include name="*.jar"/> + </fileset> + <pathelement location="${basedir}/jasmin.jar"/> + <pathelement location="${basedir}/../build"/> + </path> + + <target name="compile"> + <javac srcdir="${basedir}" destdir="${basedir}" debug="on"> + <classpath refid="classpath"/> + <include name="*.java"/> + </javac> + </target> + + <target name="test" depends="compile"> + <junit fork="yes" + printsummary="yes" + errorproperty="test.failed" + failureproperty="test.failed"> + <batchtest fork="yes" todir="${basedir}"> + <fileset dir="${basedir}"> + <include name="JasminifierClassAdapterTest.java"/> + <include name="JasminifierClassAdapterUnitTest.java"/> + </fileset> + </batchtest> + <formatter type="xml"/> + <classpath refid="classpath"/> + <jvmarg value="-Dasm.test=${asm.test}"/> + <jvmarg value="-Dasm.test.class=${asm.test.class}"/> + </junit> + </target> + +</project> diff --git a/asm4/examples/jasmin/test/jasmin.jar b/asm4/examples/jasmin/test/jasmin.jar Binary files differnew file mode 100644 index 0000000..e276b1f --- /dev/null +++ b/asm4/examples/jasmin/test/jasmin.jar diff --git a/asm4/examples/jbfc/etc/execute.properties b/asm4/examples/jbfc/etc/execute.properties new file mode 100644 index 0000000..bc81fc9 --- /dev/null +++ b/asm4/examples/jbfc/etc/execute.properties @@ -0,0 +1,32 @@ +###############################################################################
+#ASM: a very small and fast Java bytecode manipulation framework
+#Copyright (c) 2000-2011 INRIA, France Telecom
+#All rights reserved.
+#
+#Redistribution and use in source and binary forms, with or without
+#modification, are permitted provided that the following conditions
+#are met:
+#1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#3. Neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+#THE POSSIBILITY OF SUCH DAMAGE.
+###############################################################################
+
+run.classname org.objectweb.asm.jbfc.BFCompilerTest
+run.parameters
diff --git a/asm4/examples/jbfc/src/jbfc.java b/asm4/examples/jbfc/src/jbfc.java new file mode 100644 index 0000000..7a35504 --- /dev/null +++ b/asm4/examples/jbfc/src/jbfc.java @@ -0,0 +1,86 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; + +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.jbfc.BFCompiler; +import org.objectweb.asm.util.TraceClassVisitor; + +/** + * A naive implementation of compiler for Brain**** language. + * http://www.muppetlabs.com/~breadbox/bf/ * + * + * @author Eugene Kuleshov + */ +public class jbfc { + + public static void main(final String[] args) throws IOException { + if (args.length < 2) { + System.out + .println("Usage: jbfc [-v] <bf program file> <java class name>"); + return; + } + + boolean verbose = false; + String fileName = null; + String className = null; + for (int i = 0; i < args.length; i++) { + if ("-v".equals(args[i])) { + verbose = true; + } else { + fileName = args[i]; + className = args[i + 1]; + break; + } + } + + FileReader r = new FileReader(fileName); + + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + BFCompiler c = new BFCompiler(); + if (verbose) { + c.compile(r, className, fileName, new TraceClassVisitor(cw, + new PrintWriter(System.out))); + } else { + c.compile(r, className, fileName, cw); + } + + r.close(); + + FileOutputStream os = new FileOutputStream(className + ".class"); + os.write(cw.toByteArray()); + os.flush(); + os.close(); + } + +} diff --git a/asm4/examples/jbfc/src/org/objectweb/asm/jbfc/BFCompiler.java b/asm4/examples/jbfc/src/org/objectweb/asm/jbfc/BFCompiler.java new file mode 100644 index 0000000..be7a1f6 --- /dev/null +++ b/asm4/examples/jbfc/src/org/objectweb/asm/jbfc/BFCompiler.java @@ -0,0 +1,206 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.jbfc; + +import java.io.IOException; +import java.io.Reader; +import java.util.Stack; + +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * A naive implementation of compiler for Brain**** language. + * http://www.muppetlabs.com/~breadbox/bf/ * + * + * @author Eugene Kuleshov + */ +public class BFCompiler implements Opcodes { + + private static final int V_IS = 0; + + private static final int V_OS = 1; + + private static final int V_P = 2; + + private static final int V_D = 3; + + public void compile(final Reader r, final String className, + final String sourceName, final ClassVisitor cv) throws IOException { + cv.visit(Opcodes.V1_3, ACC_PUBLIC, className.replace('.', '/'), null, + "java/lang/Object", null); + cv.visitSource(sourceName, null); + + MethodVisitor mv; + { + mv = cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", + "()V"); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + { + // Init local vars for BF environment: + // 0 InputStream + // 1 OutputStream + // 2 Data Pointer + // 3 Data Array (int[ 30000]) + + mv = cv.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", + "([Ljava/lang/String;)V", null, null); + mv.visitCode(); + + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "in", + "Ljava/io/InputStream;"); + mv.visitVarInsn(ASTORE, V_IS); + + mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", + "Ljava/io/PrintStream;"); + mv.visitVarInsn(ASTORE, V_OS); + + mv.visitInsn(ICONST_0); + mv.visitVarInsn(ISTORE, V_P); + + mv.visitIntInsn(SIPUSH, 30000); + mv.visitIntInsn(NEWARRAY, T_INT); + mv.visitVarInsn(ASTORE, V_D); + + Stack<Label> labels = new Stack<Label>(); + + int d = 0; + int p = 0; + + int c; + while ((c = r.read()) != -1) { + switch (c) { + case '>': + d = storeD(mv, d); + p++; + break; + + case '<': + d = storeD(mv, d); + p--; + break; + + case '+': + p = storeP(mv, p); + d++; + break; + + case '-': + p = storeP(mv, p); + d--; + break; + + case '.': + p = storeP(mv, p); + d = storeD(mv, d); + + mv.visitVarInsn(ALOAD, V_OS); + mv.visitVarInsn(ALOAD, V_D); + mv.visitVarInsn(ILOAD, V_P); + mv.visitInsn(IALOAD); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/OutputStream", + "write", "(I)V"); + break; + + case ',': + p = storeP(mv, p); + d = storeD(mv, d); + + mv.visitVarInsn(ALOAD, V_D); + mv.visitVarInsn(ILOAD, V_P); + mv.visitVarInsn(ALOAD, V_IS); + mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/InputStream", + "read", "()I"); + mv.visitInsn(IASTORE); + break; + + case '[': + p = storeP(mv, p); + d = storeD(mv, d); + + Label ls = new Label(); + Label le = new Label(); + labels.push(ls); + labels.push(le); + mv.visitJumpInsn(GOTO, le); + mv.visitLabel(ls); + break; + + case ']': + p = storeP(mv, p); + d = storeD(mv, d); + + mv.visitLabel(labels.pop()); + mv.visitVarInsn(ALOAD, V_D); + mv.visitVarInsn(ILOAD, V_P); + mv.visitInsn(IALOAD); + mv.visitJumpInsn(IFNE, labels.pop()); + break; + } + } + + mv.visitInsn(RETURN); + + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + + } + + private int storeD(final MethodVisitor mv, final int d) { + if (d != 0) { + mv.visitVarInsn(ALOAD, V_D); + mv.visitVarInsn(ILOAD, V_P); + mv.visitInsn(DUP2); + mv.visitInsn(IALOAD); + mv.visitIntInsn(SIPUSH, d); + mv.visitInsn(IADD); + mv.visitInsn(IASTORE); + } + return 0; + } + + private int storeP(final MethodVisitor mv, final int p) { + if (p != 0) { + mv.visitIincInsn(V_P, p); + } + return 0; + } + +} diff --git a/asm4/examples/jbfc/src/org/objectweb/asm/jbfc/BFCompilerTest.java b/asm4/examples/jbfc/src/org/objectweb/asm/jbfc/BFCompilerTest.java new file mode 100644 index 0000000..3fc1ebd --- /dev/null +++ b/asm4/examples/jbfc/src/org/objectweb/asm/jbfc/BFCompilerTest.java @@ -0,0 +1,174 @@ +/*** + * ASM examples: examples showing how ASM can be used + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.objectweb.asm.jbfc; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.io.StringReader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.objectweb.asm.ClassWriter; + +/** + * A naive implementation of compiler for Brain**** language. + * http://www.muppetlabs.com/~breadbox/bf/ * + * + * @author Eugene Kuleshov + */ +public class BFCompilerTest { + + private BFCompiler bc; + + private ClassWriter cw; + + public static void main(String[] args) throws Throwable { + new BFCompilerTest().testCompileHelloWorld(); + new BFCompilerTest().testCompileEcho(); + new BFCompilerTest().testCompileYaPi(); + new BFCompilerTest().testCompileTest1(); + } + + public BFCompilerTest() throws Exception { + bc = new BFCompiler(); + cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + } + + public void testCompileHelloWorld() throws Throwable { + assertEquals( + "Hello World!\n", + execute("Hello", + ">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]" + + "<.#>+++++++++++[<+++++>-]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[" + + "<++++>-]<+.[-]++++++++++.", "")); + } + + public void testCompileEcho() throws Throwable { + assertEquals("AAA", execute("Echo", ",+[-.,+]", "AAA")); + } + + public void testCompileYaPi() throws Throwable { + assertEquals("3.1415926\n", execute("YaPi", + ">+++++[<+++++++++>-]>>>>>>\r\n\r\n+++++ +++ (7 " + + "digits)\r\n\r\n[<<+>++++++++++>-]<<+>>+++<[->>+" + + "<-[>>>]>[[<+>-]>+>>]<<<<<]>[-]>[-]>[<+>-]<[>+<[" + + "-\r\n>>>>>>>+<<<<<<<]>[->+>>>>>>+<<<<<<<]>>>>++" + + ">>-]>[-]<<<[<<<<<<<]<[->>>>>[>>>>>>>]<\r\n<<<<<" + + "<[>>>>[-]>>>>>>>[-<<<<<<<+>>>>>>>]<<<<<<<<[<<++" + + "++++++++>>-]>[<<<<[>+>>+<<<-\r\n]>>>[<<<+>>>-]>" + + "-]<<<<[>>++>+<<<-]>>->[<<<+>>>-]>[-]<<<[->>+<-[" + + ">>>]>[[<+>-]>+>>]<\r\n<<<<]>[-]<<<<<<<<<]>+>>>>" + + ">>->>>>[<<<<<<<<+>>>>>>>>-]<<<<<<<[-]++++++++++" + + "<[->>+<-\r\n[>>>]>[[<+>-]>+>>]<<<<<]>[-]>[>>>>>" + + "+<<<<<-]>[<+>>+<-]>[<+>-]<<<+<+>>[-[-[-[-[-[-\r" + + "\n[-[-[-<->[-<+<->>[<<+>>[-]]]]]]]]]]]]<[+++++[" + + "<<<<++++++++>>>>>++++++++<-]>+<<<<-\r\n>>[>+>-<" + + "<<<<+++++++++>>>-]<<<<[>>>>>>+<<<<<<-]<[>>>>>>>" + + ".<<<<<<<<[+.[-]]>>]>[<]<+\r\n>>>[<.>-]<[-]>>>>>" + + "[-]<[>>[<<<<<<<+>>>>>>>-]<<-]]>>[-]>+<<<<[-]<]+" + + "+++++++++.", "")); + } + + public void testCompileTest1() throws Throwable { + assertEquals("H\n", execute("Test1", + "[]++++++++++[>++++++++++++++++++>+++++++>+<<<-]A;?@![#>>" + + "+<<]>[>++<[-]]>.>.", "")); + } + + public static void assertEquals(String s1, String s2) { + if (!s1.equals(s2)) { + System.out.println("ERROR: expected '" + s1 + "' but got '" + s2 + + "'"); + } + } + + private String execute(final String name, final String code, + final String input) throws Throwable { + bc.compile(new StringReader(code), name, name, cw); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + InputStream is = System.in; + PrintStream os = System.out; + System.setIn(new ByteArrayInputStream(input.getBytes())); + System.setOut(new PrintStream(bos)); + + try { + TestClassLoader cl = new TestClassLoader(getClass() + .getClassLoader(), name, cw.toByteArray()); + Class<?> c = cl.loadClass(name); + Method m = c.getDeclaredMethod("main", + new Class<?>[] { String[].class }); + m.invoke(null, new Object[] { new String[0] }); + + } catch (InvocationTargetException ex) { + throw ex.getCause(); + } finally { + System.setIn(is); + System.setOut(os); + } + + String output = new String(bos.toByteArray(), "ASCII"); + + System.out + .println(code + " WITH INPUT '" + input + "' GIVES " + output); + + return output; + } + + private static final class TestClassLoader extends ClassLoader { + + private final String className; + + private final ClassLoader cl; + + private final byte[] bytecode; + + public TestClassLoader(final ClassLoader cl, final String className, + final byte[] bytecode) { + super(); + this.cl = cl; + this.className = className; + this.bytecode = bytecode; + } + + @Override + public Class<?> loadClass(final String name) + throws ClassNotFoundException { + if (className.equals(name)) { + return super.defineClass(className, bytecode, 0, + bytecode.length); + } + return cl.loadClass(name); + } + + } +} diff --git a/asm4/examples/xml/annotate.xsl b/asm4/examples/xml/annotate.xsl new file mode 100644 index 0000000..82a5bf2 --- /dev/null +++ b/asm4/examples/xml/annotate.xsl @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="ASCII"?> +<!-- + ASM XML Adapter examples. + Copyright (c) 2004-2011, Eugene Kuleshov + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- + XSL transformation for ASM XML document to add annotational comments to the local + variables (name, type and visibility) and labels (line number, try/catch info, + number of incoming calls) +--> + +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<xsl:output method="xml" indent="yes" encoding="ASCII" /> + +<!-- + Annotate opcodes that are working with local variables +--> +<xsl:template match="//ILOAD | //LLOAD | //FLOAD | //DLOAD | //ALOAD | //ISTORE | //LSTORE | //FSTORE | //DSTORE | //ASTORE | //RET"> + <xsl:variable name="n"><xsl:value-of select="@var"/></xsl:variable> + + <xsl:apply-templates select="../LocalVar[@var=$n]" mode="localVar"/> + + <xsl:element name="{name()}"> + <xsl:attribute name="var"><xsl:value-of select="$n"/></xsl:attribute> + </xsl:element> +</xsl:template> + + +<xsl:template match="*" mode="localVar"> + <xsl:comment><xsl:text> </xsl:text><xsl:value-of select="concat( @name, ' ', @desc, ' ', @start, ' - ', @end)"/><xsl:text> </xsl:text></xsl:comment> +</xsl:template> + + +<!-- + Annotate labels +--> +<xsl:template match="//method/code/Label"> + <xsl:variable name="n"><xsl:value-of select="@name"/></xsl:variable> + + <xsl:apply-templates select="../LineNumber[@start=$n]" mode="lineNumber"/> + <xsl:apply-templates select="../TryCatch[@start=$n]" mode="tryStart"/> + <xsl:apply-templates select="../TryCatch[@end=$n]" mode="tryEnd"/> + <xsl:apply-templates select="../TryCatch[@handler=$n]" mode="catch"/> + + <xsl:variable name="c"> + <!-- this is the slowest part --> + <xsl:value-of select="count(../IFEQ[@label=$n] | ../IFNE[@label=$n] | ../IFLT[@label=$n] | ../IFGE[@label=$n] | ../IFGT[@label=$n] | ../IFLE[@label=$n] | ../IF_ICMPEQ[@label=$n] | ../IF_ICMPNE[@label=$n] | ../IF_ICMPLT[@label=$n] | ../IF_ICMPGE[@label=$n] | ../IF_ICMPGT[@label=$n] | ../IF_ICMPLE[@label=$n] | ../IF_ACMPEQ[@label=$n] | ../IF_ACMPNE[@label=$n] | ../GOTO[@label=$n] | ../JSR[@label=$n] | ../IFNULL[@label=$n] | ../IFNONNULL[@label=$n] | ../TABLESWITCHINSN[@dflt=$n] | ../TABLESWITCHINSN/label[@name=$n] | ../LOOKUPSWITCH[@dflt=$n] | ../LOOKUPSWITCH/label[@name=$n])"/> + </xsl:variable> + <xsl:if test="$c>0"> + <xsl:comment><xsl:text> Incoming calls: </xsl:text><xsl:value-of select="$c"/><xsl:text> </xsl:text></xsl:comment> + </xsl:if> + + <label><xsl:apply-templates select="@*"/></label> + +</xsl:template> + + +<xsl:template match="*" mode="lineNumber"> + <xsl:comment><xsl:text> Line: </xsl:text><xsl:value-of select="@line"/><xsl:text> </xsl:text></xsl:comment> +</xsl:template> + +<xsl:template match="*" mode="tryStart"> + <xsl:comment><xsl:text> try start </xsl:text></xsl:comment> +</xsl:template> + +<xsl:template match="*" mode="tryEnd"> + <xsl:comment><xsl:text> try end </xsl:text></xsl:comment> +</xsl:template> + +<xsl:template match="*" mode="catch"> + <xsl:comment> + <xsl:text> catch </xsl:text> + <xsl:if test="string-length(@type)>0"> + <xsl:text>(</xsl:text><xsl:value-of select="@type"/><xsl:text>)</xsl:text> + </xsl:if> + </xsl:comment> +</xsl:template> + + +<!-- copy everything --> +<xsl:template match="@*|*|text()|processing-instruction()"> + <xsl:copy><xsl:apply-templates select="@*|*|text()|processing-instruction()"/></xsl:copy> +</xsl:template> + +</xsl:stylesheet> + diff --git a/asm4/examples/xml/copy.xsl b/asm4/examples/xml/copy.xsl new file mode 100644 index 0000000..dae3de6 --- /dev/null +++ b/asm4/examples/xml/copy.xsl @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="ASCII"?> +<!-- + ASM XML Adapter examples. + Copyright (c) 2004-2011, Eugene Kuleshov + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- + Copy source document into target without changes. +--> + +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<xsl:output method="xml" indent="yes" encoding="ASCII" /> + +<!-- copy everything --> +<xsl:template match="@*|*|text()|processing-instruction()"> + <xsl:copy><xsl:apply-templates select="@*|*|text()|processing-instruction()"/></xsl:copy> +</xsl:template> + +</xsl:stylesheet> + diff --git a/asm4/examples/xml/linenumbers.xsl b/asm4/examples/xml/linenumbers.xsl new file mode 100644 index 0000000..dd63825 --- /dev/null +++ b/asm4/examples/xml/linenumbers.xsl @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="ASCII"?> +<!-- + ASM XML Adapter examples. + Copyright (c) 2004-2011, Eugene Kuleshov + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- + XSL transformation for ASM XML document to add the equivalent of following + Java code for each label that has source line number information. + + System.err.println( "<class>.<method><desc> Line:<source line number>"); +--> + +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<xsl:output method="xml" indent="yes" encoding="ASCII" /> + +<xsl:template match="//method/code/Label"> + <xsl:variable name="n"><xsl:value-of select="@name"/></xsl:variable> + <xsl:variable name="c"><xsl:value-of select="../LineNumber[@start=$n]/@line"/></xsl:variable> + + <label><xsl:apply-templates select="@*"/></label> + + <xsl:if test="string-length($c)>0"> + <xsl:comment> + <xsl:text> Line: </xsl:text><xsl:value-of select="$c"/><xsl:text> </xsl:text> + </xsl:comment> + + <GETSTATIC desc="Ljava/io/PrintStream;" name="err" owner="java/lang/System"/> + <LDC desc="Ljava/lang/String;"> + <xsl:attribute name="cst"> + <xsl:value-of select="concat( /class/@name, '.' ,../../@name, ../../@desc, ' Line:', $c)"/> + </xsl:attribute> + </LDC> + <INVOKEVIRTUAL desc="(Ljava/lang/String;)V" name="println" owner="java/io/PrintStream"/> + </xsl:if> + +</xsl:template> + + +<!-- copy everything --> +<xsl:template match="@*|*|text()|processing-instruction()"> + <xsl:copy><xsl:apply-templates select="@*|*|text()|processing-instruction()"/></xsl:copy> +</xsl:template> + +</xsl:stylesheet> diff --git a/asm4/examples/xml/profile.xsl b/asm4/examples/xml/profile.xsl new file mode 100644 index 0000000..100a268 --- /dev/null +++ b/asm4/examples/xml/profile.xsl @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="ASCII"?> +<!-- + ASM XML Adapter examples. + Copyright (c) 2004-2011, Eugene Kuleshov + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- + XSL transformation for ASM XML document to add the code that will dump + an execution time for each method. +--> + +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<xsl:output method="xml" indent="yes" encoding="ASCII"/> + + +<xsl:template match="//method/code"> + <code> + <!-- add attributes for code element --> + <xsl:apply-templates select="@*"/> + + <!-- store start time into the max variable after method params --> + <INVOKESTATIC desc="()J" name="currentTimeMillis" owner="java/lang/System"/> + <LSTORE> + <xsl:attribute name="var"> + <xsl:value-of select="./Max/@maxLocals"/> + </xsl:attribute> + </LSTORE> + + <!-- process child elements --> + <xsl:apply-templates select="*"/> + + </code> + +</xsl:template> + + +<!-- + Add print statement before return instructions + IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, RETURN, + ATHROW ?? +--> +<xsl:template match="//IRETURN | //LRETURN | //FRETURN | //DRETURN | //ARETURN | //RETURN"> + <GETSTATIC desc="Ljava/io/PrintStream;" name="err" owner="java/lang/System"/> + + <NEW desc="java/lang/StringBuffer"/> + <DUP/> + <INVOKESPECIAL owner="java/lang/StringBuffer" name="<init>" desc="()V"/> + + <INVOKESTATIC desc="()J" name="currentTimeMillis" owner="java/lang/System"/> + <LLOAD> + <xsl:attribute name="var"> + <xsl:value-of select="../Max/@maxLocals"/> + </xsl:attribute> + </LLOAD> + <LSUB/> + <INVOKEVIRTUAL owner="java/lang/StringBuffer" name="append" desc="(J)Ljava/lang/StringBuffer;"/> + + <LDC desc="Ljava/lang/String;"> + <xsl:attribute name="cst"> + <xsl:value-of select="concat( ' : ', ../../../@name, '.', ../../@name, ../../@desc)"/> + </xsl:attribute> + </LDC> + <INVOKEVIRTUAL owner="java/lang/StringBuffer" name="append" desc="(Ljava/lang/String;)Ljava/lang/StringBuffer;"/> + <INVOKEVIRTUAL owner="java/lang/StringBuffer" name="toString" desc="()Ljava/lang/String;"/> + + <INVOKEVIRTUAL desc="(Ljava/lang/String;)V" name="println" owner="java/io/PrintStream"/> + + <xsl:element name="{name()}"/> +</xsl:template> + + +<!-- copy everything --> +<xsl:template match="@*|*|text()|processing-instruction()"> + <xsl:copy><xsl:apply-templates select="@*|*|text()|processing-instruction()"/></xsl:copy> +</xsl:template> + +</xsl:stylesheet> + diff --git a/asm4/examples/xml/readme.txt b/asm4/examples/xml/readme.txt new file mode 100644 index 0000000..b3da367 --- /dev/null +++ b/asm4/examples/xml/readme.txt @@ -0,0 +1,60 @@ +******************************************************************************* +* ASM: a very small and fast Java bytecode manipulation framework +* Copyright (c) 2000-2011 INRIA, France Telecom +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holders nor the names of its +* contributors may be used to endorse or promote products derived from +* this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +* THE POSSIBILITY OF SUCH DAMAGE. +******************************************************************************* + +This directory contains sample XSL transformation templates that +demonstrate features of org.objectweb.asm.xml package. + + +copy.xsl + Copying source document into target without changes. + +strip.xsl + Strips all attribute values from the target XML. + Result document can't be used to generate bytecode. + +annotate.xsl + Adds comments for labels and variable instructions + to the target XML document. + +linenumbers.xsl + Adds code to dump source line numbers for the executing code to System.err + +profile.xsl + Adds code to dump execution time for each method to System.err + + +You can use the following command to transform + +java -jar asm-xml-<version>.jar <in format> <out format> + [-in <input jar>] [-out <output jar>] [-xslt <xslt file>] + + where <in format> and <out format> is one of code, xml or singlexml + when -in or -out is omitted sysin and sysout would be used + diff --git a/asm4/examples/xml/strip.xsl b/asm4/examples/xml/strip.xsl new file mode 100644 index 0000000..b181996 --- /dev/null +++ b/asm4/examples/xml/strip.xsl @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="ASCII"?> +<!-- + ASM XML Adapter examples. + Copyright (c) 2004-2011, Eugene Kuleshov + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + THE POSSIBILITY OF SUCH DAMAGE. +--> + +<!-- + Destructive transformation that removes values from all attributes. + Result bytecode will be invalid. +--> + +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<xsl:output method="xml" encoding="ASCII" indent="yes"/> + +<!-- + Class name must not be removed! +--> +<xsl:template match="//class/@name"> + <xsl:attribute name="name"><xsl:value-of select="."/></xsl:attribute> +</xsl:template> + + +<xsl:template match="@*"> + <xsl:attribute name="{name()}"/> +</xsl:template> + + +<!-- copy everything --> +<xsl:template match="*|text()|processing-instruction()"> + <xsl:copy><xsl:apply-templates select="@*|*|text()|processing-instruction()"/></xsl:copy> +</xsl:template> + +</xsl:stylesheet> |