Move hash computation into its own method
This commit is contained in:
parent
bbe5709070
commit
2a29aee37b
|
|
@ -82,6 +82,44 @@ public class ModernFixCachingClassTransformer extends ClassTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ArrayList<byte[]> computeHash(String className, boolean isEmpty, String reason) {
|
||||||
|
final String internalName = className.replace('.', '/');
|
||||||
|
final Type classDesc = Type.getObjectType(internalName);
|
||||||
|
ArrayList<ILaunchPluginService> pluginList = new ArrayList<>();
|
||||||
|
for(ILaunchPluginService plugin : plugins.values()) {
|
||||||
|
if(!plugin.handlesClass(classDesc, isEmpty, reason).isEmpty()) {
|
||||||
|
pluginList.add(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final boolean needsTransforming = transformStore.needsTransforming(internalName);
|
||||||
|
if (!needsTransforming && pluginList.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
/* Now compute the hash list for the required transformers */
|
||||||
|
ArrayList<byte[]> hashList = new ArrayList<>();
|
||||||
|
pluginList.sort((service1, service2) -> Comparator.<String>naturalOrder().compare(service1.name(), service2.name()));
|
||||||
|
for(ILaunchPluginService service : pluginList) {
|
||||||
|
byte[] hash = obtainHash(service, className);
|
||||||
|
if(hash == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
hashList.add(hash);
|
||||||
|
}
|
||||||
|
if(needsTransforming) {
|
||||||
|
List<ITransformer<?>> transformers = this.transformersByClass.get(internalName);
|
||||||
|
if(transformers != null) {
|
||||||
|
for(ITransformer<?> transformer : transformers) {
|
||||||
|
byte[] hash = obtainHash(transformer, className);
|
||||||
|
if(hash == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
hashList.add(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hashList;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the hashed list of transformers and use a cached version of the class if possible. This code needs
|
* Check the hashed list of transformers and use a cached version of the class if possible. This code needs
|
||||||
* to be very fast as the entire point is to spend very little time doing transformation work that was done before.
|
* to be very fast as the entire point is to spend very little time doing transformation work that was done before.
|
||||||
|
|
@ -93,76 +131,45 @@ public class ModernFixCachingClassTransformer extends ClassTransformer {
|
||||||
@Override
|
@Override
|
||||||
public byte[] transform(byte[] inputClass, String className, String reason) {
|
public byte[] transform(byte[] inputClass, String className, String reason) {
|
||||||
/* We only want to cache actual transformations */
|
/* We only want to cache actual transformations */
|
||||||
if(!ITransformerActivity.CLASSLOADING_REASON.equals(reason)) {
|
if(ITransformerActivity.CLASSLOADING_REASON.equals(reason)) {
|
||||||
return super.transform(inputClass, className, reason);
|
ArrayList<byte[]> hashList = computeHash(className, inputClass.length == 0, reason);
|
||||||
}
|
if(hashList != null) {
|
||||||
final String internalName = className.replace('.', '/');
|
/* Check if the cache contains a transformed class matching these hashes */
|
||||||
final Type classDesc = Type.getObjectType(internalName);
|
/* TODO maybe sanitize the class name? */
|
||||||
ArrayList<ILaunchPluginService> pluginList = new ArrayList<>();
|
File cacheLocation = new File(CLASS_CACHE_FOLDER, className.replace('.', '/'));
|
||||||
for(ILaunchPluginService plugin : plugins.values()) {
|
boolean hashesMatch = true;
|
||||||
if(!plugin.handlesClass(classDesc, inputClass.length == 0, reason).isEmpty()) {
|
try(ObjectInputStream stream = new ObjectInputStream(new FileInputStream(cacheLocation))) {
|
||||||
pluginList.add(plugin);
|
ArrayList<byte[]> savedHash = (ArrayList<byte[]>)stream.readObject();
|
||||||
}
|
for(int i = 0; i < savedHash.size(); i++) {
|
||||||
}
|
if(!Arrays.equals(savedHash.get(i), hashList.get(i))) {
|
||||||
final boolean needsTransforming = transformStore.needsTransforming(internalName);
|
hashesMatch = false;
|
||||||
if (!needsTransforming && pluginList.isEmpty()) {
|
break;
|
||||||
return inputClass;
|
}
|
||||||
}
|
|
||||||
/* Now compute the hash list for the required transformers */
|
|
||||||
ArrayList<byte[]> hashList = new ArrayList<>();
|
|
||||||
pluginList.sort((service1, service2) -> Comparator.<String>naturalOrder().compare(service1.name(), service2.name()));
|
|
||||||
for(ILaunchPluginService service : pluginList) {
|
|
||||||
byte[] hash = obtainHash(service, className);
|
|
||||||
if(hash == null) {
|
|
||||||
return super.transform(inputClass, className, reason);
|
|
||||||
}
|
|
||||||
hashList.add(hash);
|
|
||||||
}
|
|
||||||
if(needsTransforming) {
|
|
||||||
List<ITransformer<?>> transformers = this.transformersByClass.get(internalName);
|
|
||||||
if(transformers != null) {
|
|
||||||
for(ITransformer<?> transformer : transformers) {
|
|
||||||
byte[] hash = obtainHash(transformer, className);
|
|
||||||
if(hash == null) {
|
|
||||||
return super.transform(inputClass, className, reason);
|
|
||||||
}
|
}
|
||||||
hashList.add(hash);
|
if(hashesMatch)
|
||||||
}
|
inputClass = (byte[])stream.readObject();
|
||||||
}
|
} catch(IOException | ClassNotFoundException | ClassCastException e) {
|
||||||
}
|
if(!(e instanceof FileNotFoundException))
|
||||||
/* Check if the cache contains a transformed class matching these hashes */
|
e.printStackTrace();
|
||||||
/* TODO maybe sanitize the class name? */
|
|
||||||
File cacheLocation = new File(CLASS_CACHE_FOLDER, className.replace('.', '/'));
|
|
||||||
boolean hashesMatch = true;
|
|
||||||
try(ObjectInputStream stream = new ObjectInputStream(new FileInputStream(cacheLocation))) {
|
|
||||||
ArrayList<byte[]> savedHash = (ArrayList<byte[]>)stream.readObject();
|
|
||||||
for(int i = 0; i < savedHash.size(); i++) {
|
|
||||||
if(!Arrays.equals(savedHash.get(i), hashList.get(i))) {
|
|
||||||
hashesMatch = false;
|
hashesMatch = false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if(!hashesMatch) {
|
||||||
|
inputClass = super.transform(inputClass, className, reason);
|
||||||
|
final byte[] classToSave = inputClass;
|
||||||
|
classSaverPool.submit(() -> {
|
||||||
|
cacheLocation.getParentFile().mkdirs();
|
||||||
|
try(ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(cacheLocation))) {
|
||||||
|
stream.writeObject(hashList);
|
||||||
|
stream.writeObject(classToSave);
|
||||||
|
} catch(IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return inputClass;
|
||||||
}
|
}
|
||||||
if(hashesMatch)
|
|
||||||
inputClass = (byte[])stream.readObject();
|
|
||||||
} catch(IOException | ClassNotFoundException | ClassCastException e) {
|
|
||||||
if(!(e instanceof FileNotFoundException))
|
|
||||||
e.printStackTrace();
|
|
||||||
hashesMatch = false;
|
|
||||||
}
|
}
|
||||||
if(!hashesMatch) {
|
return super.transform(inputClass, className, reason);
|
||||||
inputClass = super.transform(inputClass, className, reason);
|
|
||||||
final byte[] classToSave = inputClass;
|
|
||||||
classSaverPool.submit(() -> {
|
|
||||||
cacheLocation.getParentFile().mkdirs();
|
|
||||||
try(ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(cacheLocation))) {
|
|
||||||
stream.writeObject(hashList);
|
|
||||||
stream.writeObject(classToSave);
|
|
||||||
} catch(IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return inputClass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final byte[] FORGE_HASH = LoadingModList.get().getModFileById("forge").getMods().get(0).getVersion().toString().getBytes(StandardCharsets.UTF_8);
|
private final byte[] FORGE_HASH = LoadingModList.get().getModFileById("forge").getMods().get(0).getVersion().toString().getBytes(StandardCharsets.UTF_8);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user