/* * Copyright 2010-2012 VMware and contributors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springsource.loaded; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * This is similar to SystemClassReflectionRewriter but this version just summarizes what it finds, rather than making * any changes. Using the results of this we can determine whether it needs proper rewriting by the * SystemClassReflectionRewriter (which would be done by adding this class to the list of those in the SLPP that should * be processed like that). * * @author Andy Clement * @since 0.7.3 */ public class SystemClassReflectionInvestigator { public static int investigate(String slashedClassName, byte[] bytes, boolean print) { ClassReader fileReader = new ClassReader(bytes); RewriteClassAdaptor classAdaptor = new RewriteClassAdaptor(print); fileReader.accept(classAdaptor, ClassReader.SKIP_FRAMES); return classAdaptor.hitCount; } static class RewriteClassAdaptor extends ClassVisitor implements Constants { int hitCount = 0; private ClassWriter cw; int bits = 0x0000; private boolean print; private String classname; private static boolean isInterceptable(String owner, String methodName) { return MethodInvokerRewriter.RewriteClassAdaptor.intercepted.contains(owner + "." + methodName); } public RewriteClassAdaptor(boolean print) { // TODO should it also compute frames? super(ASM5, new ClassWriter(ClassWriter.COMPUTE_MAXS)); this.print = print; cw = (ClassWriter) cv; } public byte[] getBytes() { byte[] bytes = cw.toByteArray(); return bytes; } public int getBits() { return bits; } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { super.visit(version, access, name, signature, superName, interfaces); this.classname = name; } @Override public MethodVisitor visitMethod(int flags, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(flags, name, descriptor, signature, exceptions); return new RewritingMethodAdapter(mv); } class RewritingMethodAdapter extends MethodVisitor implements Opcodes, Constants { public RewritingMethodAdapter(MethodVisitor mv) { super(ASM5, mv); } private boolean interceptReflection(String owner, String name, String desc) { if (isInterceptable(owner, name)) { hitCount++; if (print) { System.out.println("SystemClassReflectionInvestigator: " + classname + " uses " + owner + "." + name + desc); } } return false; } int unitializedObjectsCount = 0; @Override public void visitTypeInsn(final int opcode, final String type) { if (opcode == NEW) { unitializedObjectsCount++; } super.visitTypeInsn(opcode, type); } @Override public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf) { if (!GlobalConfiguration.interceptReflection || rewriteReflectiveCall(opcode, owner, name, desc)) { return; } if (opcode == INVOKESPECIAL) { unitializedObjectsCount--; } super.visitMethodInsn(opcode, owner, name, desc, itf); } /** * Determine if a method call is a reflective call and an attempt should be made to rewrite it. * * @return true if the call was rewritten */ private boolean rewriteReflectiveCall(int opcode, String owner, String name, String desc) { if (owner.length() > 10 && owner.charAt(8) == 'g' && (owner.startsWith("java/lang/reflect/") || owner.equals("java/lang/Class"))) { boolean rewritten = interceptReflection(owner, name, desc); if (rewritten) { return true; } } return false; } } } }