001/* 002 * BridJ - Dynamic and blazing-fast native interop for Java. 003 * http://bridj.googlecode.com/ 004 * 005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/) 006 * All rights reserved. 007 * 008 * Redistribution and use in source and binary forms, with or without 009 * modification, are permitted provided that the following conditions are met: 010 * 011 * * Redistributions of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * * Redistributions in binary form must reproduce the above copyright 014 * notice, this list of conditions and the following disclaimer in the 015 * documentation and/or other materials provided with the distribution. 016 * * Neither the name of Olivier Chafik nor the 017 * names of its contributors may be used to endorse or promote products 018 * derived from this software without specific prior written permission. 019 * 020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY 021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 030 */ 031package org.bridj.util; 032 033import java.io.IOException; 034import java.lang.reflect.Modifier; 035import java.lang.reflect.ParameterizedType; 036import org.bridj.Pointer; 037import org.objectweb.asm.*; 038import static org.objectweb.asm.Opcodes.*; 039 040/** 041 * Utilities for <a href="http://asm.ow2.org/">ASM</a>. 042 * 043 * @author ochafik 044 */ 045public class ASMUtils { 046 047 public static String typeDesc(java.lang.reflect.Type t) { 048 if (t instanceof Class) { 049 Class c = (Class) t; 050 if (c == Pointer.class) { 051 return "Pointer"; 052 } 053 if (c.isPrimitive()) { 054 String s = c.getSimpleName(); 055 return Character.toUpperCase(s.charAt(0)) + s.substring(1); 056 } else if (c.isArray()) { 057 return typeDesc(c.getComponentType()) + "Array"; 058 } 059 return c.getName().replace('.', '_'); 060 } else { 061 ParameterizedType p = (ParameterizedType) t; 062 StringBuilder b = new StringBuilder(typeDesc(p.getRawType())); 063 for (java.lang.reflect.Type pp : p.getActualTypeArguments()) { 064 b.append("_").append(typeDesc(pp)); 065 } 066 return b.toString(); 067 } 068 } 069 070 public static void addSuperCall(ClassVisitor cv, String superClassInternalName) { 071 MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 072 mv.visitCode(); 073 mv.visitVarInsn(ALOAD, 0); 074 mv.visitMethodInsn(INVOKESPECIAL, superClassInternalName, "<init>", "()V"); 075 mv.visitInsn(RETURN); 076 mv.visitMaxs(1, 1); 077 mv.visitEnd(); 078 } 079 080 public static <T> Class<? extends T> createSubclassWithSynchronizedNativeMethodsAndNoStaticFields(Class<T> original, ClassDefiner classDefiner) throws IOException { 081 String suffix = "$SynchronizedNative"; 082 final String originalInternalName = JNIUtils.getNativeName(original); 083 final String synchronizedName = original.getName() + suffix; 084 final String synchronizedInternalName = originalInternalName + suffix; 085 086 ClassWriter classWriter = new ClassWriter(0); 087 //TraceClassVisitor traceVisitor = new TraceClassVisitor(classWriter, new PrintWriter(System.out)); 088 ClassVisitor cv = new ClassVisitor(ASM4, classWriter) { 089 @Override 090 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { 091 super.visit(version, access, synchronizedInternalName, null, originalInternalName, new String[0]); 092 addSuperCall(cv, originalInternalName); 093 } 094 095 @Override 096 public void visitInnerClass(String name, String outerName, String innerName, int access) { 097 // Do nothing. 098 } 099 100 @Override 101 public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { 102 return null; 103 } 104 105 @Override 106 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { 107 if (!Modifier.isNative(access)) { 108 return null; 109 } 110 111 return super.visitMethod(access | Modifier.SYNCHRONIZED, name, desc, signature, exceptions); 112 } 113 }; 114 115 ClassReader classReader = new ClassReader(original.getName()); 116 classReader.accept(cv, 0); 117 return (Class<? extends T>) classDefiner.defineClass(synchronizedName, classWriter.toByteArray()); 118 } 119}