Skip to content

Commit

Permalink
Merge pull request #974 from google/moe_writing_branch_from_7f1714ba3…
Browse files Browse the repository at this point in the history
…d3681bed29d8238468533e63c07ba9f

Moe writing branch from 7f1714b
  • Loading branch information
sameb committed Jan 6, 2016
2 parents 059807b + 5698a14 commit 2e620fa
Show file tree
Hide file tree
Showing 17 changed files with 613 additions and 188 deletions.
4 changes: 2 additions & 2 deletions build.xml
Expand Up @@ -289,10 +289,10 @@
<replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/asm-5.0.3.jar"/>]]></replacetoken>
</replace>
<replace file="build/no_aop/common.xml" value="">
<replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.1.jar"/>]]></replacetoken>
<replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.2.jar"/>]]></replacetoken>
</replace>
<replace file="build/no_aop/common.xml" value="">
<replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.1.jar"><include name="LICENSE"/><include name="NOTICE"/></zipfileset>]]></replacetoken>
<replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.2.jar"><include name="LICENSE"/><include name="NOTICE"/></zipfileset>]]></replacetoken>
</replace>
<replace file="build/no_aop/common.xml" value='Bundle-Name" value="$${ant.project.name} (no_aop)'>
<replacetoken><![CDATA[Bundle-Name" value="${ant.project.name}]]></replacetoken>
Expand Down
2 changes: 1 addition & 1 deletion common.xml
Expand Up @@ -144,7 +144,7 @@
classpath="${common.basedir}/lib/build/jarjar-1.1.jar"/>
<jarjar jarfile="${build.dir}/${ant.project.name}-with-deps.jar">
<fileset dir="${build.dir}/classes"/>
<zipfileset src="${common.basedir}/lib/build/cglib-3.1.jar"/>
<zipfileset src="${common.basedir}/lib/build/cglib-3.2.jar"/>
<zipfileset src="${common.basedir}/lib/build/asm-5.0.3.jar"/>
<rule pattern="net.sf.cglib.*" result="com.google.inject.internal.cglib.$@1"/>
<rule pattern="net.sf.cglib.**.*" result="com.google.inject.internal.cglib.@1.$@2"/>
Expand Down
102 changes: 95 additions & 7 deletions core/src/com/google/inject/internal/BytecodeGen.java
Expand Up @@ -29,6 +29,7 @@
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
Expand All @@ -48,8 +49,8 @@
* <p>For each generated class, there's multiple class loaders involved:
* <ul>
* <li><strong>The related class's class loader.</strong> Every generated class services exactly
* one user-supplied class. This class loader must be used to access members with private and
* package visibility.
* one user-supplied class. This class loader must be used to access members with protected
* and package visibility.
* <li><strong>Guice's class loader.</strong>
* <li><strong>Our bridge class loader.</strong> This is a child of the user's class loader. It
* selectively delegates to either the user's class loader (for user classes) or the Guice
Expand Down Expand Up @@ -191,19 +192,106 @@ private static ClassLoader getClassLoader(Class<?> type, ClassLoader delegate) {
}

/*if[AOP]*/
// use fully-qualified names so imports don't need preprocessor statements
public static net.sf.cglib.reflect.FastClass newFastClass(Class<?> type, Visibility visibility) {
// use fully-qualified names so imports don't need preprocessor statements
/**
* Returns a FastClass proxy for invoking the given member or {@code null} if access rules
* disallow it.
*
* @see #newFastClassForMember(Class, Member) for a full description
*/
public static net.sf.cglib.reflect.FastClass newFastClassForMember(Member member) {
return newFastClassForMember(member.getDeclaringClass(), member);
}

/**
* Returns a FastClass proxy for invoking the given member or {@code null} if access rules
* disallow it.
*
* <p>FastClass works by generating a type in the same package as the target {@code type}. This
* may or may not work depending on the access level of the class/member. It breaks down into the
* following cases depending on accessibility:
* <ul>
* <li>Public: This always works since we can generate the type into the
* {@link BridgeClassLoader} which ensures there are no versioning issues.
* <li>Package private and Protected: This works as long as:
* <ul>
* <li>We can generate into the same classloader as the type. This is not possible for JDK
* types which use the 'bootstrap' loader.
* <li>The classloader of the type has the same version of {@code FastClass} as we do. This
* may be violated when running in OSGI bundles.
* </ul>
* <li>Private: This never works.
* </ul>
*
* If we are unable to generate the type, then we return null and callers should work around by
* using normal java reflection.
*/
public static net.sf.cglib.reflect.FastClass newFastClassForMember(Class<?> type, Member member) {
if (!new net.sf.cglib.core.VisibilityPredicate(type, false).evaluate(member)) {
// the member cannot be indexed by fast class. Bail out.
return null;
}

boolean publiclyCallable = isPubliclyCallable(member);
if (!publiclyCallable && !hasSameVersionOfCglib(type.getClassLoader())) {
// The type is in a classloader with a different version of cglib and is not publicly visible
// (so we can't use the bridge classloader to work around). Bail out.
return null;
}
net.sf.cglib.reflect.FastClass.Generator generator
= new net.sf.cglib.reflect.FastClass.Generator();
generator.setType(type);
if (visibility == Visibility.PUBLIC) {
if (publiclyCallable) {
// Use the bridge classloader if we can
generator.setClassLoader(getClassLoader(type));
}
generator.setType(type);
generator.setNamingPolicy(FASTCLASS_NAMING_POLICY);
logger.fine("Loading " + type + " FastClass with " + generator.getClassLoader());
if (logger.isLoggable(Level.FINE)) {
logger.fine("Loading " + type + " FastClass with " + generator.getClassLoader());
}
return generator.create();
}

/**
* Returns true if the types classloader has the same version of cglib that BytecodeGen has. This
* only returns false in strange OSGI situations, but it prevents us from using FastClass for non
* public members.
*/
private static boolean hasSameVersionOfCglib(ClassLoader classLoader) {
Class<?> fc = net.sf.cglib.reflect.FastClass.class;
try {
return classLoader.loadClass(fc.getName()) == fc;
} catch (ClassNotFoundException e) {
return false;
}
}

/**
* Returns true if the member can be called by a fast class generated in a different classloader.
*/
private static boolean isPubliclyCallable(Member member) {
if (!Modifier.isPublic(member.getModifiers())) {
return false;
}
Class<?>[] parameterTypes;
if (member instanceof Constructor) {
parameterTypes = ((Constructor) member).getParameterTypes();
} else {
Method method = (Method) member;
if (!Modifier.isPublic(method.getReturnType().getModifiers())) {
return false;
}
parameterTypes = method.getParameterTypes();
}

for (Class<?> type : parameterTypes) {
if (!Modifier.isPublic(type.getModifiers())) {
return false;
}
}
return true;
}

public static net.sf.cglib.proxy.Enhancer newEnhancer(Class<?> type, Visibility visibility) {
net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer();
enhancer.setSuperclass(type);
Expand Down
Expand Up @@ -16,8 +16,8 @@

package com.google.inject.internal;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.inject.internal.BytecodeGen.Visibility;
import com.google.inject.spi.InjectionPoint;

import java.lang.reflect.Constructor;
Expand All @@ -42,66 +42,111 @@ final class DefaultConstructionProxyFactory<T> implements ConstructionProxyFacto
this.injectionPoint = injectionPoint;
}

@Override
public ConstructionProxy<T> create() {
@SuppressWarnings("unchecked") // the injection point is for a constructor of T
final Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember();

// Use FastConstructor if the constructor is public.
if (Modifier.isPublic(constructor.getModifiers())) {
Class<T> classToConstruct = constructor.getDeclaringClass();
/*if[AOP]*/
try {
final net.sf.cglib.reflect.FastConstructor fastConstructor
= BytecodeGen.newFastClass(classToConstruct, Visibility.forMember(constructor))
.getConstructor(constructor);

return new ConstructionProxy<T>() {
@SuppressWarnings("unchecked")
public T newInstance(Object... arguments) throws InvocationTargetException {
return (T) fastConstructor.newInstance(arguments);
}
public InjectionPoint getInjectionPoint() {
return injectionPoint;
}
public Constructor<T> getConstructor() {
return constructor;
}
public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
getMethodInterceptors() {
return ImmutableMap.of();
}
};
} catch (net.sf.cglib.core.CodeGenerationException e) {/* fall-through */}
/*end[AOP]*/
if (!Modifier.isPublic(classToConstruct.getModifiers())) {
constructor.setAccessible(true);
/*if[AOP]*/
try {
net.sf.cglib.reflect.FastClass fc =
BytecodeGen.newFastClassForMember(constructor);
if (fc != null) {
int index = fc.getIndex(constructor.getParameterTypes());
// We could just fall back to reflection in this case but I believe this should actually
// be impossible.
Preconditions.checkArgument(index >= 0,
"Could not find constructor %s in fast class",
constructor);
return new FastClassProxy<T>(injectionPoint, constructor, fc, index);
}
} else {
constructor.setAccessible(true);
} catch (net.sf.cglib.core.CodeGenerationException e) {/* fall-through */}
/*end[AOP]*/

return new ReflectiveProxy<T>(injectionPoint, constructor);
}

/*if[AOP]*/
/** A {@link ConstructionProxy} that uses FastClass to invoke the constructor. */
private static final class FastClassProxy<T> implements ConstructionProxy<T> {
final InjectionPoint injectionPoint;
final Constructor<T> constructor;
final net.sf.cglib.reflect.FastClass fc;
final int index;

private FastClassProxy(InjectionPoint injectionPoint, Constructor<T> constructor,
net.sf.cglib.reflect.FastClass fc, int index) {
this.injectionPoint = injectionPoint;
this.constructor = constructor;
this.fc = fc;
this.index = index;
}

return new ConstructionProxy<T>() {
public T newInstance(Object... arguments) throws InvocationTargetException {
try {
return constructor.newInstance(arguments);
} catch (InstantiationException e) {
throw new AssertionError(e); // shouldn't happen, we know this is a concrete type
} catch (IllegalAccessException e) {
throw new AssertionError(e); // a security manager is blocking us, we're hosed
}
}
public InjectionPoint getInjectionPoint() {
return injectionPoint;
}
public Constructor<T> getConstructor() {
return constructor;
@Override
@SuppressWarnings("unchecked")
public T newInstance(Object... arguments) throws InvocationTargetException {
// Use this method instead of FastConstructor to save a stack frame
return (T) fc.newInstance(index, arguments);
}

@Override
public InjectionPoint getInjectionPoint() {
return injectionPoint;
}

@Override
public Constructor<T> getConstructor() {
return constructor;
}

@Override
public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
getMethodInterceptors() {
return ImmutableMap.of();
}
}
/*end[AOP]*/

private static final class ReflectiveProxy<T> implements ConstructionProxy<T> {
final Constructor<T> constructor;
final InjectionPoint injectionPoint;

ReflectiveProxy(InjectionPoint injectionPoint, Constructor<T> constructor) {
if (!Modifier.isPublic(constructor.getDeclaringClass().getModifiers())
|| !Modifier.isPublic(constructor.getModifiers())) {
constructor.setAccessible(true);
}
/*if[AOP]*/
public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
getMethodInterceptors() {
return ImmutableMap.of();
this.injectionPoint = injectionPoint;
this.constructor = constructor;
}

@Override
public T newInstance(Object... arguments) throws InvocationTargetException {
try {
return constructor.newInstance(arguments);
} catch (InstantiationException e) {
throw new AssertionError(e); // shouldn't happen, we know this is a concrete type
} catch (IllegalAccessException e) {
throw new AssertionError(e); // a security manager is blocking us, we're hosed
}
/*end[AOP]*/
};
}

@Override
public InjectionPoint getInjectionPoint() {
return injectionPoint;
}

@Override
public Constructor<T> getConstructor() {
return constructor;
}

/*if[AOP]*/
@Override
public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
getMethodInterceptors() {
return ImmutableMap.of();
}
/*end[AOP]*/
}
}

0 comments on commit 2e620fa

Please sign in to comment.