On 05/24/2016 01:41 PM, Peter Levart wrote:
Hm,
It seems that my example will not help much. It also seems that the
only problem with plain:
static final ClassValue<MetaClass> META_CLASS_CV = new
ClassValue<MetaClass>() {
@Override
protected MetaClass computeValue(Class<?> type) {
return new MetaClass(type);
}
};
...is the fact that MetaClass is a class loaded by non-bootstrap class
loader and that in case this is a Web app class loader, it prevents
undeployment. Can you confirm that a MetaClass instance only
references the 'type' Class<?> it is derived from (it's Methods,
Fields, etc.) and never references objects from any child class
loaders of the type's class loader?
If that is the case, then you could replace MetaClass with a generic
data structure, composed of instances of bootstrap classes (HashMap,
ArrayList, Object[], ...). That way, Groovy runtime class loader will
not be "captured" by a reference from an aClass loaded by bootstrap
class loader.
Is MetaClass a complicated data structure?
...peeking at Groovy sources, very much so. There's a solution though.
Various Meta* classes in Groovy runtime reference at some point the
reflective objects (Class, Method, Constructor, Field) describing the
'type' they are derived from.
Every reference to a Class object from such Meta* object should be
wrapped in something like the following:
public final class ClassReference extends WeakReference<Class<?>>
implements Supplier<Class<?>> {
private static final ConcurrentHashMap<ClassReference,
ClassReference> MAP
= new ConcurrentHashMap<>();
private static final ReferenceQueue<Class<?>> QUEUE
= new ReferenceQueue<>();
public static ClassReference forClass(Class<?> clazz) {
ClassReference oldRef;
while ((oldRef = (ClassReference) QUEUE.poll()) != null) {
MAP.remove(oldRef);
}
ClassReference newRef = new ClassReference(clazz);
oldRef = MAP.putIfAbsent(newRef, newRef);
return oldRef == null ? newRef : oldRef;
}
private final String name;
private final int hash;
private ClassReference(Class<?> clazz) {
super(clazz, QUEUE);
name = clazz.getName();
hash = clazz.hashCode();
}
@Override
public Class<?> get() {
Class<?> clazz = super.get();
if (clazz == null) {
throw new IllegalStateException(
"Class " + name + " has already been unloaded");
}
return clazz;
}
@Override
public int hashCode() {
return hash;
}
@Override
public boolean equals(Object obj) {
Class<?> clazz;
return obj == this ||
(obj instanceof ClassReference &&
(clazz = get()) != null &&
clazz == ((ClassReference) obj).get());
}
}
Every reference to a Method should be wrapped in something like this:
public final class MethodReference implements Supplier<Method> {
private static final ClassValue<Method[]> DECLARED_METHODS_CV =
new ClassValue<Method[]>() {
@Override
protected Method[] computeValue(Class<?> type) {
return type.getDeclaredMethods();
}
};
private final ClassReference declaringClassRef;
private final int index;
public MethodReference(Method method) {
Class<?> declaringClass = method.getDeclaringClass();
declaringClassRef = ClassReference.forClass(declaringClass);
Method[] methods = DECLARED_METHODS_CV.get(declaringClass);
index = Arrays.asList(methods).indexOf(method);
}
@Override
public Method get() {
return DECLARED_METHODS_CV.get(declaringClassRef.get())[index];
}
@Override
public int hashCode() {
return declaringClassRef.hashCode() * 31 + index;
}
@Override
public boolean equals(Object obj) {
return obj == this || (
obj instanceof MethodReference &&
((MethodReference) obj).declaringClassRef ==
this.declaringClassRef &&
((MethodReference) obj).index == this.index
);
}
}
And similar with every reference to a Constructor or Field.
In addition, the MetaClass structure should be isolated from the class
it is derived from with what I presented in the previous message
(ClassValue<WeakReference<MetaClass>> + ArrayList<MetaClass> referenced
from MetaClass static field)
Would that work?
Regards, Peter
_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev