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