Use byte code generation if Javassist is available.

This commit is contained in:
Trustin Lee 2013-02-08 21:45:14 +09:00
parent a3b46ec9d7
commit 54d44c6ac1
5 changed files with 131 additions and 7 deletions

View File

@ -0,0 +1,71 @@
/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you 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 io.netty.util.internal;
import io.netty.logging.InternalLogger;
import io.netty.logging.InternalLoggerFactory;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.Modifier;
import java.lang.reflect.Method;
final class JavassistTypeParameterMatcherGenerator {
private static final InternalLogger logger =
InternalLoggerFactory.getInstance(JavassistTypeParameterMatcherGenerator.class);
private static final ClassPool classPool = new ClassPool(true);
static TypeParameterMatcher generate(Class<?> type) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
}
return generate(type, classLoader);
}
static TypeParameterMatcher generate(Class<?> type, ClassLoader classLoader) {
final String className = "io.netty.util.internal.__matchers__." + type.getName() + "Matcher";
try {
try {
return (TypeParameterMatcher) Class.forName(className, true, classLoader).newInstance();
} catch (Exception e) {
// Not defined in the specified class loader.
}
CtClass c = classPool.getAndRename(NoOpTypeParameterMatcher.class.getName(), className);
c.setModifiers(c.getModifiers() | Modifier.FINAL);
c.getDeclaredMethod("match").setBody("{ return $1 instanceof " + type.getName() + "; }");
byte[] byteCode = c.toBytecode();
c.detach();
Method method = ClassLoader.class.getDeclaredMethod(
"defineClass", String.class, byte[].class, int.class, int.class);
method.setAccessible(true);
Class<?> generated = (Class<?>) method.invoke(classLoader, className, byteCode, 0, byteCode.length);
logger.debug("Generated: {}", generated.getName());
return (TypeParameterMatcher) generated.newInstance();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private JavassistTypeParameterMatcherGenerator() { }
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you 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 io.netty.util.internal;
public final class NoOpTypeParameterMatcher extends TypeParameterMatcher {
@Override
public boolean match(Object msg) {
return true;
}
}

View File

@ -48,6 +48,8 @@ public final class PlatformDependent {
private static final boolean CAN_FREE_DIRECT_BUFFER = canFreeDirectBuffer0();
private static final boolean IS_UNALIGNED = isUnaligned0();
private static final boolean HAS_JAVASSIST = hasJavassist0();
/**
* Returns {@code true} if and only if the current platform is Android
*/
@ -106,6 +108,13 @@ public final class PlatformDependent {
return IS_UNALIGNED;
}
/**
* Returns {@code true} if and only if Javassist is available.
*/
public static boolean hasJavassist() {
return HAS_JAVASSIST;
}
public static long directBufferAddress(ByteBuffer buffer) {
return PlatformDependent0.directBufferAddress(buffer);
}
@ -275,6 +284,15 @@ public final class PlatformDependent {
return PlatformDependent0.isUnaligned();
}
private static boolean hasJavassist0() {
try {
JavassistTypeParameterMatcherGenerator.generate(Object.class, PlatformDependent.class.getClassLoader());
return true;
} catch (Throwable t) {
return false;
}
}
private PlatformDependent() {
// only static method supported
}

View File

@ -23,12 +23,7 @@ import java.util.Map;
public abstract class TypeParameterMatcher {
private static final TypeParameterMatcher NOOP = new TypeParameterMatcher() {
@Override
public boolean match(Object msg) {
return true;
}
};
private static final TypeParameterMatcher NOOP = new NoOpTypeParameterMatcher();
private static final ThreadLocal<Map<Class<?>, TypeParameterMatcher>> typeMap =
new ThreadLocal<Map<Class<?>, TypeParameterMatcher>>() {
@ -58,6 +53,13 @@ public abstract class TypeParameterMatcher {
Class<?> messageType = (Class<?>) types[typeParamIndex];
if (messageType == Object.class) {
matcher = NOOP;
} else if (PlatformDependent.hasJavassist()) {
try {
matcher = JavassistTypeParameterMatcherGenerator.generate(messageType);
} catch (Exception e) {
// Will not usually happen, but just in case.
matcher = new ReflectiveMatcher(messageType);
}
} else {
matcher = new ReflectiveMatcher(messageType);
}
@ -87,5 +89,5 @@ public abstract class TypeParameterMatcher {
}
}
TypeParameterMatcher() { }
protected TypeParameterMatcher() { }
}

View File

@ -191,6 +191,15 @@
</dependencyManagement>
<dependencies>
<!-- Byte code generator - completely optional -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.17.1-GA</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- Testing frameworks and related dependencies -->
<dependency>
<groupId>junit</groupId>