forked from openrs2/openrs2
parent
862d4a3504
commit
d2bd8c69f4
@ -1,207 +0,0 @@ |
|||||||
package dev.openrs2.asm.classpath; |
|
||||||
|
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList; |
|
||||||
import com.google.common.collect.ImmutableSet; |
|
||||||
import dev.openrs2.asm.MemberDesc; |
|
||||||
import dev.openrs2.asm.MemberRef; |
|
||||||
import dev.openrs2.util.collect.DisjointSet; |
|
||||||
import dev.openrs2.util.collect.ForestDisjointSet; |
|
||||||
import org.objectweb.asm.commons.Remapper; |
|
||||||
import org.objectweb.asm.tree.ClassNode; |
|
||||||
|
|
||||||
public final class ClassPath { |
|
||||||
private final ClassLoader runtime; |
|
||||||
private final ImmutableList<Library> dependencies, libraries; |
|
||||||
private final Map<String, ClassMetadata> cache = new HashMap<>(); |
|
||||||
|
|
||||||
public ClassPath(ClassLoader runtime, ImmutableList<Library> dependencies, ImmutableList<Library> libraries) { |
|
||||||
this.runtime = runtime; |
|
||||||
this.dependencies = dependencies; |
|
||||||
this.libraries = libraries; |
|
||||||
} |
|
||||||
|
|
||||||
public ImmutableList<Library> getLibraries() { |
|
||||||
return libraries; |
|
||||||
} |
|
||||||
|
|
||||||
public ImmutableList<ClassMetadata> getLibraryClasses() { |
|
||||||
var classes = ImmutableList.<ClassMetadata>builder(); |
|
||||||
|
|
||||||
for (var library : libraries) { |
|
||||||
for (var clazz : library) { |
|
||||||
classes.add(get(clazz.name)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return classes.build(); |
|
||||||
} |
|
||||||
|
|
||||||
public ClassMetadata get(String name) { |
|
||||||
var metadata = cache.get(name); |
|
||||||
if (metadata != null) { |
|
||||||
return metadata; |
|
||||||
} |
|
||||||
|
|
||||||
for (var library : libraries) { |
|
||||||
var clazz = library.get(name); |
|
||||||
if (clazz != null) { |
|
||||||
metadata = new AsmClassMetadata(this, clazz, false); |
|
||||||
cache.put(name, metadata); |
|
||||||
return metadata; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
for (var library : dependencies) { |
|
||||||
var clazz = library.get(name); |
|
||||||
if (clazz != null) { |
|
||||||
metadata = new AsmClassMetadata(this, clazz, true); |
|
||||||
cache.put(name, metadata); |
|
||||||
return metadata; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
var reflectionName = name.replace('/', '.'); |
|
||||||
|
|
||||||
Class<?> clazz; |
|
||||||
try { |
|
||||||
clazz = runtime.loadClass(reflectionName); |
|
||||||
} catch (ClassNotFoundException ex) { |
|
||||||
throw new IllegalArgumentException("Unknown class " + name); |
|
||||||
} |
|
||||||
|
|
||||||
metadata = new ReflectionClassMetadata(this, clazz); |
|
||||||
cache.put(name, metadata); |
|
||||||
return metadata; |
|
||||||
} |
|
||||||
|
|
||||||
public ClassNode getNode(String name) { |
|
||||||
for (var library : libraries) { |
|
||||||
var clazz = library.get(name); |
|
||||||
if (clazz != null) { |
|
||||||
return clazz; |
|
||||||
} |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
public void remap(Remapper remapper) { |
|
||||||
for (var library : libraries) { |
|
||||||
library.remap(remapper); |
|
||||||
} |
|
||||||
|
|
||||||
cache.clear(); |
|
||||||
} |
|
||||||
|
|
||||||
public DisjointSet<MemberRef> createInheritedFieldSets() { |
|
||||||
var disjointSet = new ForestDisjointSet<MemberRef>(); |
|
||||||
var ancestorCache = new HashMap<ClassMetadata, ImmutableSet<MemberDesc>>(); |
|
||||||
|
|
||||||
for (var library : libraries) { |
|
||||||
for (var clazz : library) { |
|
||||||
populateInheritedFieldSets(ancestorCache, disjointSet, get(clazz.name)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return disjointSet; |
|
||||||
} |
|
||||||
|
|
||||||
private ImmutableSet<MemberDesc> populateInheritedFieldSets(Map<ClassMetadata, ImmutableSet<MemberDesc>> ancestorCache, DisjointSet<MemberRef> disjointSet, ClassMetadata clazz) { |
|
||||||
var ancestors = ancestorCache.get(clazz); |
|
||||||
if (ancestors != null) { |
|
||||||
return ancestors; |
|
||||||
} |
|
||||||
var ancestorsBuilder = ImmutableSet.<MemberDesc>builder(); |
|
||||||
|
|
||||||
var superClass = clazz.getSuperClass(); |
|
||||||
if (superClass != null) { |
|
||||||
var fields = populateInheritedFieldSets(ancestorCache, disjointSet, superClass); |
|
||||||
|
|
||||||
for (var field : fields) { |
|
||||||
var partition1 = disjointSet.add(new MemberRef(clazz.getName(), field)); |
|
||||||
var partition2 = disjointSet.add(new MemberRef(superClass.getName(), field)); |
|
||||||
disjointSet.union(partition1, partition2); |
|
||||||
} |
|
||||||
|
|
||||||
ancestorsBuilder.addAll(fields); |
|
||||||
} |
|
||||||
|
|
||||||
for (var superInterface : clazz.getSuperInterfaces()) { |
|
||||||
var fields = populateInheritedFieldSets(ancestorCache, disjointSet, superInterface); |
|
||||||
|
|
||||||
for (var field : fields) { |
|
||||||
var partition1 = disjointSet.add(new MemberRef(clazz.getName(), field)); |
|
||||||
var partition2 = disjointSet.add(new MemberRef(superInterface.getName(), field)); |
|
||||||
disjointSet.union(partition1, partition2); |
|
||||||
} |
|
||||||
|
|
||||||
ancestorsBuilder.addAll(fields); |
|
||||||
} |
|
||||||
|
|
||||||
for (var field : clazz.getFields()) { |
|
||||||
disjointSet.add(new MemberRef(clazz.getName(), field)); |
|
||||||
ancestorsBuilder.add(field); |
|
||||||
} |
|
||||||
|
|
||||||
ancestors = ancestorsBuilder.build(); |
|
||||||
ancestorCache.put(clazz, ancestors); |
|
||||||
return ancestors; |
|
||||||
} |
|
||||||
|
|
||||||
public DisjointSet<MemberRef> createInheritedMethodSets() { |
|
||||||
var disjointSet = new ForestDisjointSet<MemberRef>(); |
|
||||||
var ancestorCache = new HashMap<ClassMetadata, ImmutableSet<MemberDesc>>(); |
|
||||||
|
|
||||||
for (var library : libraries) { |
|
||||||
for (var clazz : library) { |
|
||||||
populateInheritedMethodSets(ancestorCache, disjointSet, get(clazz.name)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return disjointSet; |
|
||||||
} |
|
||||||
|
|
||||||
private ImmutableSet<MemberDesc> populateInheritedMethodSets(Map<ClassMetadata, ImmutableSet<MemberDesc>> ancestorCache, DisjointSet<MemberRef> disjointSet, ClassMetadata clazz) { |
|
||||||
var ancestors = ancestorCache.get(clazz); |
|
||||||
if (ancestors != null) { |
|
||||||
return ancestors; |
|
||||||
} |
|
||||||
var ancestorsBuilder = ImmutableSet.<MemberDesc>builder(); |
|
||||||
|
|
||||||
var superClass = clazz.getSuperClass(); |
|
||||||
if (superClass != null) { |
|
||||||
var methods = populateInheritedMethodSets(ancestorCache, disjointSet, superClass); |
|
||||||
|
|
||||||
for (var method : methods) { |
|
||||||
var partition1 = disjointSet.add(new MemberRef(clazz.getName(), method)); |
|
||||||
var partition2 = disjointSet.add(new MemberRef(superClass.getName(), method)); |
|
||||||
disjointSet.union(partition1, partition2); |
|
||||||
} |
|
||||||
|
|
||||||
ancestorsBuilder.addAll(methods); |
|
||||||
} |
|
||||||
|
|
||||||
for (var superInterface : clazz.getSuperInterfaces()) { |
|
||||||
var methods = populateInheritedMethodSets(ancestorCache, disjointSet, superInterface); |
|
||||||
|
|
||||||
for (var method : methods) { |
|
||||||
var partition1 = disjointSet.add(new MemberRef(clazz.getName(), method)); |
|
||||||
var partition2 = disjointSet.add(new MemberRef(superInterface.getName(), method)); |
|
||||||
disjointSet.union(partition1, partition2); |
|
||||||
} |
|
||||||
|
|
||||||
ancestorsBuilder.addAll(methods); |
|
||||||
} |
|
||||||
|
|
||||||
for (var method : clazz.getMethods()) { |
|
||||||
disjointSet.add(new MemberRef(clazz.getName(), method)); |
|
||||||
ancestorsBuilder.add(method); |
|
||||||
} |
|
||||||
|
|
||||||
ancestors = ancestorsBuilder.build(); |
|
||||||
ancestorCache.put(clazz, ancestors); |
|
||||||
return ancestors; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,194 @@ |
|||||||
|
package dev.openrs2.asm.classpath |
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList |
||||||
|
import dev.openrs2.asm.MemberDesc |
||||||
|
import dev.openrs2.asm.MemberRef |
||||||
|
import dev.openrs2.util.collect.DisjointSet |
||||||
|
import dev.openrs2.util.collect.ForestDisjointSet |
||||||
|
import org.objectweb.asm.commons.Remapper |
||||||
|
import org.objectweb.asm.tree.ClassNode |
||||||
|
|
||||||
|
class ClassPath( |
||||||
|
private val runtime: ClassLoader, |
||||||
|
private val dependencies: ImmutableList<Library>, |
||||||
|
val libraries: List<Library> |
||||||
|
) { |
||||||
|
private val cache = mutableMapOf<String, ClassMetadata>() |
||||||
|
|
||||||
|
val libraryClasses: List<ClassMetadata> |
||||||
|
get() { |
||||||
|
val classes = mutableListOf<ClassMetadata>() |
||||||
|
for (library in libraries) { |
||||||
|
for (clazz in library) { |
||||||
|
classes.add(get(clazz.name)) |
||||||
|
} |
||||||
|
} |
||||||
|
return classes |
||||||
|
} |
||||||
|
|
||||||
|
operator fun get(name: String): ClassMetadata { |
||||||
|
var metadata = cache[name] |
||||||
|
if (metadata != null) { |
||||||
|
return metadata |
||||||
|
} |
||||||
|
|
||||||
|
for (library in libraries) { |
||||||
|
val clazz = library[name] |
||||||
|
if (clazz != null) { |
||||||
|
metadata = AsmClassMetadata(this, clazz, false) |
||||||
|
cache[name] = metadata |
||||||
|
return metadata |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (library in dependencies) { |
||||||
|
val clazz = library[name] |
||||||
|
if (clazz != null) { |
||||||
|
metadata = AsmClassMetadata(this, clazz, true) |
||||||
|
cache[name] = metadata |
||||||
|
return metadata |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val reflectionName = name.replace('/', '.') |
||||||
|
|
||||||
|
val clazz = try { |
||||||
|
runtime.loadClass(reflectionName) |
||||||
|
} catch (ex: ClassNotFoundException) { |
||||||
|
throw IllegalArgumentException("Unknown class $name") |
||||||
|
} |
||||||
|
|
||||||
|
metadata = ReflectionClassMetadata(this, clazz) |
||||||
|
cache[name] = metadata |
||||||
|
return metadata |
||||||
|
} |
||||||
|
|
||||||
|
fun getNode(name: String): ClassNode? { |
||||||
|
for (library in libraries) { |
||||||
|
val clazz = library[name] |
||||||
|
if (clazz != null) { |
||||||
|
return clazz |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return null |
||||||
|
} |
||||||
|
|
||||||
|
fun remap(remapper: Remapper) { |
||||||
|
for (library in libraries) { |
||||||
|
library.remap(remapper) |
||||||
|
} |
||||||
|
|
||||||
|
cache.clear() |
||||||
|
} |
||||||
|
|
||||||
|
fun createInheritedFieldSets(): DisjointSet<MemberRef> { |
||||||
|
val disjointSet = ForestDisjointSet<MemberRef>() |
||||||
|
val ancestorCache = mutableMapOf<ClassMetadata, Set<MemberDesc>>() |
||||||
|
|
||||||
|
for (library in libraries) { |
||||||
|
for (clazz in library) { |
||||||
|
populateInheritedFieldSets(ancestorCache, disjointSet, get(clazz.name)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return disjointSet |
||||||
|
} |
||||||
|
|
||||||
|
private fun populateInheritedFieldSets( |
||||||
|
ancestorCache: MutableMap<ClassMetadata, Set<MemberDesc>>, |
||||||
|
disjointSet: DisjointSet<MemberRef>, |
||||||
|
clazz: ClassMetadata |
||||||
|
): Set<MemberDesc> { |
||||||
|
val ancestors = ancestorCache[clazz] |
||||||
|
if (ancestors != null) { |
||||||
|
return ancestors |
||||||
|
} |
||||||
|
|
||||||
|
val ancestorsBuilder = mutableSetOf<MemberDesc>() |
||||||
|
|
||||||
|
val superClass = clazz.superClass |
||||||
|
if (superClass != null) { |
||||||
|
val fields = populateInheritedFieldSets(ancestorCache, disjointSet, superClass) |
||||||
|
for (field in fields) { |
||||||
|
val partition1 = disjointSet.add(MemberRef(clazz.name, field)) |
||||||
|
val partition2 = disjointSet.add(MemberRef(superClass.name, field)) |
||||||
|
disjointSet.union(partition1, partition2) |
||||||
|
} |
||||||
|
ancestorsBuilder.addAll(fields) |
||||||
|
} |
||||||
|
|
||||||
|
for (superInterface in clazz.superInterfaces) { |
||||||
|
val fields = populateInheritedFieldSets(ancestorCache, disjointSet, superInterface) |
||||||
|
for (field in fields) { |
||||||
|
val partition1 = disjointSet.add(MemberRef(clazz.name, field)) |
||||||
|
val partition2 = disjointSet.add(MemberRef(superInterface.name, field)) |
||||||
|
disjointSet.union(partition1, partition2) |
||||||
|
} |
||||||
|
ancestorsBuilder.addAll(fields) |
||||||
|
} |
||||||
|
|
||||||
|
for (field in clazz.fields) { |
||||||
|
disjointSet.add(MemberRef(clazz.name, field)) |
||||||
|
ancestorsBuilder.add(field) |
||||||
|
} |
||||||
|
|
||||||
|
ancestorCache[clazz] = ancestorsBuilder |
||||||
|
return ancestorsBuilder |
||||||
|
} |
||||||
|
|
||||||
|
fun createInheritedMethodSets(): DisjointSet<MemberRef> { |
||||||
|
val disjointSet = ForestDisjointSet<MemberRef>() |
||||||
|
val ancestorCache = mutableMapOf<ClassMetadata, Set<MemberDesc>>() |
||||||
|
|
||||||
|
for (library in libraries) { |
||||||
|
for (clazz in library) { |
||||||
|
populateInheritedMethodSets(ancestorCache, disjointSet, get(clazz.name)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return disjointSet |
||||||
|
} |
||||||
|
|
||||||
|
private fun populateInheritedMethodSets( |
||||||
|
ancestorCache: MutableMap<ClassMetadata, Set<MemberDesc>>, |
||||||
|
disjointSet: DisjointSet<MemberRef>, |
||||||
|
clazz: ClassMetadata |
||||||
|
): Set<MemberDesc> { |
||||||
|
val ancestors = ancestorCache[clazz] |
||||||
|
if (ancestors != null) { |
||||||
|
return ancestors |
||||||
|
} |
||||||
|
|
||||||
|
val ancestorsBuilder = mutableSetOf<MemberDesc>() |
||||||
|
|
||||||
|
val superClass = clazz.superClass |
||||||
|
if (superClass != null) { |
||||||
|
val methods = populateInheritedMethodSets(ancestorCache, disjointSet, superClass) |
||||||
|
for (method in methods) { |
||||||
|
val partition1 = disjointSet.add(MemberRef(clazz.name, method)) |
||||||
|
val partition2 = disjointSet.add(MemberRef(superClass.name, method)) |
||||||
|
disjointSet.union(partition1, partition2) |
||||||
|
} |
||||||
|
ancestorsBuilder.addAll(methods) |
||||||
|
} |
||||||
|
|
||||||
|
for (superInterface in clazz.superInterfaces) { |
||||||
|
val methods = populateInheritedMethodSets(ancestorCache, disjointSet, superInterface) |
||||||
|
for (method in methods) { |
||||||
|
val partition1 = disjointSet.add(MemberRef(clazz.name, method)) |
||||||
|
val partition2 = disjointSet.add(MemberRef(superInterface.name, method)) |
||||||
|
disjointSet.union(partition1, partition2) |
||||||
|
} |
||||||
|
ancestorsBuilder.addAll(methods) |
||||||
|
} |
||||||
|
|
||||||
|
for (method in clazz.methods) { |
||||||
|
disjointSet.add(MemberRef(clazz.name, method)) |
||||||
|
ancestorsBuilder.add(method) |
||||||
|
} |
||||||
|
|
||||||
|
ancestorCache[clazz] = ancestorsBuilder |
||||||
|
return ancestorsBuilder |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue