use of org.objectweb.asm.tree.AnnotationNode in project LogisticsPipes by RS485.
the class LogisticsPipesClassInjector method transform.
@Override
@SuppressWarnings("unchecked")
public byte[] transform(String name, String transformedName, byte[] bytes) {
if (bytes != null) {
if (name.startsWith("logisticspipes.")) {
final ClassReader reader = new ClassReader(bytes);
final ClassNode node = new ClassNode();
reader.accept(node, 0);
if (node.visibleAnnotations != null) {
for (AnnotationNode a : node.visibleAnnotations) {
if (a.desc.equals("Llogisticspipes/asm/ModVersionedClass;")) {
if (a.values.size() == 8 && a.values.get(0).equals("modId") && a.values.get(2).equals("version") && a.values.get(4).equals("classData") && a.values.get(6).equals("classDataDev")) {
String modId = a.values.get(1).toString();
String version = a.values.get(3).toString();
String classData = a.values.get(5).toString();
String classDataDev = a.values.get(7).toString();
if (ModStatusHelper.isModLoaded(modId) && !ModStatusHelper.isModVersionEqualsOrHigher(modId, version)) {
if (isObfEnv == null) {
try {
isObfEnv = (Class.forName("net.minecraft.world.World").getDeclaredField("chunkProvider") == null);
} catch (Throwable e) {
isObfEnv = true;
}
}
bytes = transform(name, transformedName, DatatypeConverter.parseBase64Binary(isObfEnv ? classData : classDataDev));
}
} else {
throw new UnsupportedOperationException("Can't parse the annotations correctly");
}
}
}
}
}
return bytes;
}
try {
if (name.startsWith("logisticspipes.proxy.opencomputers.asm.BaseWrapperClass$") && name.endsWith("$OpenComputersWrapper")) {
String correctName = name.substring(56, name.length() - 21);
Class<?> clazz = Launch.classLoader.findClass(correctName);
bytes = ClassCreator.getWrappedClassAsBytes(CCObjectWrapper.getWrapperInformation(clazz), clazz.getName());
Set<String> set = new TreeSet<>();
set.add(name);
Launch.classLoader.clearNegativeEntries(set);
Map<String, byte[]> map = (Map<String, byte[]>) fResourceCache.get(Launch.classLoader);
map.put(name, bytes);
return bytes;
}
} catch (Exception e) {
if (LPConstants.DEBUG) {
// For better Debugging
e.printStackTrace();
return bytes;
}
throw new RuntimeException(e);
}
return bytes;
}
use of org.objectweb.asm.tree.AnnotationNode in project MinecraftForge by MinecraftForge.
the class EventSubscriptionTransformer method buildEvents.
private boolean buildEvents(ClassNode classNode) throws Exception {
// Yes, this recursively loads classes until we get this base class. THIS IS NOT A ISSUE. Coremods should handle re-entry just fine.
// If they do not this a COREMOD issue NOT a Forge/LaunchWrapper issue.
Class<?> parent = this.getClass().getClassLoader().loadClass(classNode.superName.replace('/', '.'));
if (!Event.class.isAssignableFrom(parent)) {
return false;
}
//Class<?> listenerListClazz = Class.forName("net.minecraftforge.fml.common.eventhandler.ListenerList", false, getClass().getClassLoader());
Type tList = Type.getType("Lnet/minecraftforge/fml/common/eventhandler/ListenerList;");
boolean edited = false;
boolean hasSetup = false;
boolean hasGetListenerList = false;
boolean hasDefaultCtr = false;
boolean hasCancelable = false;
boolean hasResult = false;
String voidDesc = Type.getMethodDescriptor(VOID_TYPE);
String boolDesc = Type.getMethodDescriptor(BOOLEAN_TYPE);
String listDesc = tList.getDescriptor();
String listDescM = Type.getMethodDescriptor(tList);
for (MethodNode method : classNode.methods) {
if (method.name.equals("setup") && method.desc.equals(voidDesc) && (method.access & ACC_PROTECTED) == ACC_PROTECTED)
hasSetup = true;
if ((method.access & ACC_PUBLIC) == ACC_PUBLIC) {
if (method.name.equals("getListenerList") && method.desc.equals(listDescM))
hasGetListenerList = true;
if (method.name.equals("isCancelable") && method.desc.equals(boolDesc))
hasCancelable = true;
if (method.name.equals("hasResult") && method.desc.equals(boolDesc))
hasResult = true;
}
if (method.name.equals("<init>") && method.desc.equals(voidDesc))
hasDefaultCtr = true;
}
if (classNode.visibleAnnotations != null) {
for (AnnotationNode node : classNode.visibleAnnotations) {
if (!hasResult && node.desc.equals("Lnet/minecraftforge/fml/common/eventhandler/Event$HasResult;")) {
/* Add:
* public boolean hasResult()
* {
* return true;
* }
*/
MethodNode method = new MethodNode(ACC_PUBLIC, "hasResult", boolDesc, null, null);
method.instructions.add(new InsnNode(ICONST_1));
method.instructions.add(new InsnNode(IRETURN));
classNode.methods.add(method);
edited = true;
} else if (!hasCancelable && node.desc.equals("Lnet/minecraftforge/fml/common/eventhandler/Cancelable;")) {
/* Add:
* public boolean isCancelable()
* {
* return true;
* }
*/
MethodNode method = new MethodNode(ACC_PUBLIC, "isCancelable", boolDesc, null, null);
method.instructions.add(new InsnNode(ICONST_1));
method.instructions.add(new InsnNode(IRETURN));
classNode.methods.add(method);
edited = true;
}
}
}
if (hasSetup) {
if (!hasGetListenerList)
throw new RuntimeException("Event class defines setup() but does not define getListenerList! " + classNode.name);
else
return edited;
}
Type tSuper = Type.getType(classNode.superName);
//Add private static ListenerList LISTENER_LIST
classNode.fields.add(new FieldNode(ACC_PRIVATE | ACC_STATIC, "LISTENER_LIST", listDesc, null, null));
/*Add:
* public <init>()
* {
* super();
* }
*/
if (!hasDefaultCtr) {
MethodNode method = new MethodNode(ACC_PUBLIC, "<init>", voidDesc, null, null);
method.instructions.add(new VarInsnNode(ALOAD, 0));
method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "<init>", voidDesc, false));
method.instructions.add(new InsnNode(RETURN));
classNode.methods.add(method);
}
/*Add:
* protected void setup()
* {
* super.setup();
* if (LISTENER_LIST != NULL)
* {
* return;
* }
* LISTENER_LIST = new ListenerList(super.getListenerList());
* }
*/
MethodNode method = new MethodNode(ACC_PROTECTED, "setup", voidDesc, null, null);
method.instructions.add(new VarInsnNode(ALOAD, 0));
method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "setup", voidDesc, false));
method.instructions.add(new FieldInsnNode(GETSTATIC, classNode.name, "LISTENER_LIST", listDesc));
LabelNode initListener = new LabelNode();
method.instructions.add(new JumpInsnNode(IFNULL, initListener));
method.instructions.add(new InsnNode(RETURN));
method.instructions.add(initListener);
method.instructions.add(new FrameNode(F_SAME, 0, null, 0, null));
method.instructions.add(new TypeInsnNode(NEW, tList.getInternalName()));
method.instructions.add(new InsnNode(DUP));
method.instructions.add(new VarInsnNode(ALOAD, 0));
method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "getListenerList", listDescM, false));
method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tList.getInternalName(), "<init>", getMethodDescriptor(VOID_TYPE, tList), false));
method.instructions.add(new FieldInsnNode(PUTSTATIC, classNode.name, "LISTENER_LIST", listDesc));
method.instructions.add(new InsnNode(RETURN));
classNode.methods.add(method);
/*Add:
* public ListenerList getListenerList()
* {
* return this.LISTENER_LIST;
* }
*/
method = new MethodNode(ACC_PUBLIC, "getListenerList", listDescM, null, null);
method.instructions.add(new FieldInsnNode(GETSTATIC, classNode.name, "LISTENER_LIST", listDesc));
method.instructions.add(new InsnNode(ARETURN));
classNode.methods.add(method);
return true;
}
use of org.objectweb.asm.tree.AnnotationNode in project MinecraftForge by MinecraftForge.
the class SideTransformer method remove.
private boolean remove(List<AnnotationNode> anns, String side) {
if (anns == null) {
return false;
}
for (AnnotationNode ann : anns) {
if (ann.desc.equals(Type.getDescriptor(SideOnly.class))) {
if (ann.values != null) {
for (int x = 0; x < ann.values.size() - 1; x += 2) {
Object key = ann.values.get(x);
Object value = ann.values.get(x + 1);
if (key instanceof String && key.equals("value")) {
if (value instanceof String[]) {
if (!((String[]) value)[1].equals(side)) {
return true;
}
}
}
}
}
}
}
return false;
}
use of org.objectweb.asm.tree.AnnotationNode in project quasar by puniverse.
the class InstrumentMethod method accept.
public void accept(MethodVisitor mv, boolean hasAnnotation) {
db.log(LogLevel.INFO, "Instrumenting method %s:%s#%s%s", sourceName, className, mn.name, mn.desc);
if (mn.name.charAt(0) == '<')
throw new UnableToInstrumentException("special method", className, mn.name, mn.desc);
collectCallsites();
final boolean skipInstrumentation = canInstrumentationBeSkipped(suspCallsBcis);
emitInstrumentedAnn(db, mv, mn, sourceName, className, skipInstrumentation, startSourceLine, endSourceLine, suspCallsSourceLines, suspCallsNames, null);
if (skipInstrumentation) {
db.log(LogLevel.INFO, "[OPTIMIZE] Skipping instrumentation for method %s:%s#%s%s", sourceName, className, mn.name, mn.desc);
// Dump
mn.accept(mv);
return;
}
// Else instrument
// Must be called first, sets flags & state used below
collectCodeBlocks();
//noinspection ConstantConditions
final boolean handleProxyInvocations = HANDLE_PROXY_INVOCATIONS && callsSuspendableSupers;
mv.visitCode();
Label lMethodStart = new Label();
Label lMethodStart2 = new Label();
Label lMethodEnd = new Label();
Label lCatchSEE = new Label();
Label lCatchUTE = new Label();
Label lCatchAll = new Label();
Label[] lMethodCalls = new Label[numCodeBlocks - 1];
Label[][] refInvokeTryCatch;
for (int i = 1; i < numCodeBlocks; i++) lMethodCalls[i - 1] = new Label();
mv.visitInsn(Opcodes.ACONST_NULL);
mv.visitVarInsn(Opcodes.ASTORE, lvarInvocationReturnValue);
// if (verifyInstrumentation) {
// mv.visitInsn(Opcodes.ICONST_0);
// mv.visitVarInsn(Opcodes.ISTORE, lvarSuspendableCalled);
// }
mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchSEE, SUSPEND_EXECUTION_NAME);
mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchSEE, RUNTIME_SUSPEND_EXECUTION_NAME);
if (handleProxyInvocations)
mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchUTE, UNDECLARED_THROWABLE_NAME);
// Prepare visitTryCatchBlocks for InvocationTargetException.
// With reflective invocations, the SuspendExecution exception will be wrapped in InvocationTargetException. We need to catch it and unwrap it.
// Note that the InvocationTargetException will be regenrated on every park, adding further overhead on top of the reflective call.
// This must be done here, before all other visitTryCatchBlock, because the exception's handler
// will be matched according to the order of in which visitTryCatchBlock has been called. Earlier calls take precedence.
refInvokeTryCatch = new Label[numCodeBlocks - 1][];
for (int i = 1; i < numCodeBlocks; i++) {
final FrameInfo fi = codeBlocks[i];
final AbstractInsnNode in = mn.instructions.get(fi.endInstruction);
if (mn.instructions.get(fi.endInstruction) instanceof MethodInsnNode) {
MethodInsnNode min = (MethodInsnNode) in;
if (isReflectInvocation(min.owner, min.name)) {
Label[] ls = new Label[3];
for (int k = 0; k < 3; k++) ls[k] = new Label();
refInvokeTryCatch[i - 1] = ls;
mv.visitTryCatchBlock(ls[0], ls[1], ls[2], "java/lang/reflect/InvocationTargetException");
}
}
}
// Output try-catch blocks
for (final Object o : mn.tryCatchBlocks) {
final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
if (// we allow catch of SuspendExecution only in methods annotated with @Suspendable and in lambda-generated ones.
SUSPEND_EXECUTION_NAME.equals(tcb.type) && !hasAnnotation && !mn.name.startsWith(Classes.LAMBDA_METHOD_PREFIX))
throw new UnableToInstrumentException("catch for SuspendExecution", className, mn.name, mn.desc);
if (// we allow catch of SuspendExecution in method annotated with @Suspendable.
handleProxyInvocations && UNDECLARED_THROWABLE_NAME.equals(tcb.type))
throw new UnableToInstrumentException("catch for UndeclaredThrowableException", className, mn.name, mn.desc);
// if (INTERRUPTED_EXCEPTION_NAME.equals(tcb.type))
// throw new UnableToInstrumentException("catch for " + InterruptedException.class.getSimpleName(), className, mn.name, mn.desc);
tcb.accept(mv);
}
// Output parameter annotations
if (mn.visibleParameterAnnotations != null)
dumpParameterAnnotations(mv, mn.visibleParameterAnnotations, true);
if (mn.invisibleParameterAnnotations != null)
dumpParameterAnnotations(mv, mn.invisibleParameterAnnotations, false);
// Output method annotations
if (mn.visibleAnnotations != null) {
for (Object o : mn.visibleAnnotations) {
AnnotationNode an = (AnnotationNode) o;
an.accept(mv.visitAnnotation(an.desc, true));
}
}
mv.visitTryCatchBlock(lMethodStart, lMethodEnd, lCatchAll, null);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, STACK_NAME, "getStack", "()L" + STACK_NAME + ";", false);
mv.visitInsn(Opcodes.DUP);
mv.visitVarInsn(Opcodes.ASTORE, lvarStack);
// println(mv, "STACK: ", lvarStack);
// dumpStack(mv);
// DUAL
mv.visitJumpInsn(Opcodes.IFNULL, lMethodStart);
mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
// we'll assume we have been resumed
emitStoreResumed(mv, true);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "nextMethodEntry", "()I", false);
mv.visitTableSwitchInsn(1, numCodeBlocks - 1, lMethodStart2, lMethodCalls);
mv.visitLabel(lMethodStart2);
// the following code handles the case of an instrumented method called not as part of a suspendable code path
// isFirstInStack will return false in that case.
mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "isFirstInStackOrPushed", "()Z", false);
// if true
mv.visitJumpInsn(Opcodes.IFNE, lMethodStart);
// This will reset the fiber stack local if isFirstStack returns false.
mv.visitInsn(Opcodes.ACONST_NULL);
mv.visitVarInsn(Opcodes.ASTORE, lvarStack);
mv.visitLabel(lMethodStart);
// no, we have not been resumed
emitStoreResumed(mv, false);
dumpCodeBlock(mv, 0, 0);
// Blocks leading to suspendable calls
for (int i = 1; i < numCodeBlocks; i++) {
final FrameInfo fi = codeBlocks[i];
// Emit instrumented call
final AbstractInsnNode min = mn.instructions.get(fi.endInstruction);
final String owner = getMethodOwner(min), name = getMethodName(min), desc = getMethodDesc(min);
if (isYieldMethod(owner, name)) {
// special case - call to yield
if (min.getOpcode() != Opcodes.INVOKESTATIC)
throw new UnableToInstrumentException("invalid call to suspending method.", className, mn.name, mn.desc);
final int numYieldArgs = TypeAnalyzer.getNumArguments(desc);
final boolean yieldReturnsValue = (Type.getReturnType(desc) != Type.VOID_TYPE);
// we preserve the arguments for the call to yield on the operand stack
emitStoreState(mv, i, fi, numYieldArgs);
// we have not been resumed
emitStoreResumed(mv, false);
// emitSuspendableCalled(mv);
// we call the yield method
min.accept(mv);
if (yieldReturnsValue)
// we ignore the returned value...
mv.visitInsn(Opcodes.POP);
// we resume AFTER the call
mv.visitLabel(lMethodCalls[i - 1]);
final Label afterPostRestore = new Label();
mv.visitVarInsn(Opcodes.ILOAD, lvarResumed);
mv.visitJumpInsn(Opcodes.IFEQ, afterPostRestore);
emitPostRestore(mv);
mv.visitLabel(afterPostRestore);
emitRestoreState(mv, i, fi, numYieldArgs);
if (yieldReturnsValue)
// ... and replace the returned value with the value of resumed
mv.visitVarInsn(Opcodes.ILOAD, lvarResumed);
dumpCodeBlock(mv, i, 1);
} else {
final Label lbl = new Label();
// DUAL
mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
mv.visitJumpInsn(Opcodes.IFNULL, lbl);
// normal case - call to a suspendable method - resume before the call
emitStoreState(mv, i, fi, 0);
// we have not been resumed
emitStoreResumed(mv, false);
// emitPreemptionPoint(mv, PREEMPTION_CALL);
mv.visitLabel(lMethodCalls[i - 1]);
emitRestoreState(mv, i, fi, 0);
// DUAL
mv.visitLabel(lbl);
if (isReflectInvocation(owner, name)) {
// We catch the InvocationTargetException and unwrap it if it wraps a SuspendExecution exception.
Label[] ls = refInvokeTryCatch[i - 1];
final Label startTry = ls[0];
final Label endTry = ls[1];
final Label startCatch = ls[2];
final Label endCatch = new Label();
final Label notSuspendExecution = new Label();
// mv.visitTryCatchBlock(startTry, endTry, startCatch, "java/lang/reflect/InvocationTargetException");
// try {
mv.visitLabel(startTry);
// method.invoke()
min.accept(mv);
// save return value
mv.visitVarInsn(Opcodes.ASTORE, lvarInvocationReturnValue);
// }
mv.visitLabel(endTry);
mv.visitJumpInsn(Opcodes.GOTO, endCatch);
// catch(InvocationTargetException ex) {
mv.visitLabel(startCatch);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;", false);
mv.visitTypeInsn(Opcodes.INSTANCEOF, SUSPEND_EXECUTION_NAME);
mv.visitJumpInsn(Opcodes.IFEQ, notSuspendExecution);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;", false);
mv.visitLabel(notSuspendExecution);
mv.visitInsn(Opcodes.ATHROW);
mv.visitLabel(endCatch);
// restore return value
mv.visitVarInsn(Opcodes.ALOAD, lvarInvocationReturnValue);
dumpCodeBlock(mv, i, 1);
} else {
// emitSuspendableCalled(mv);
dumpCodeBlock(mv, i, 0);
}
}
}
// Emit catchall's catch section
mv.visitLabel(lMethodEnd);
if (handleProxyInvocations) {
mv.visitLabel(lCatchUTE);
mv.visitInsn(Opcodes.DUP);
// println(mv, "CTCH: ");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;", false);
// println(mv, "CAUSE: ");
mv.visitTypeInsn(Opcodes.INSTANCEOF, SUSPEND_EXECUTION_NAME);
mv.visitJumpInsn(Opcodes.IFEQ, lCatchAll);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Throwable", "getCause", "()Ljava/lang/Throwable;", false);
mv.visitJumpInsn(Opcodes.GOTO, lCatchSEE);
}
mv.visitLabel(lCatchAll);
emitPopMethod(mv);
mv.visitLabel(lCatchSEE);
// println(mv, "THROW: ");
// rethrow shared between catchAll and catchSSE
mv.visitInsn(Opcodes.ATHROW);
if (mn.localVariables != null) {
for (Object o : mn.localVariables) ((LocalVariableNode) o).accept(mv);
}
// Needed by ASM analysis
mv.visitMaxs(mn.maxStack + ADD_OPERANDS, mn.maxLocals + NUM_LOCALS + additionalLocals);
mv.visitEnd();
}
use of org.objectweb.asm.tree.AnnotationNode in project quasar by puniverse.
the class InstrumentMethod method dumpParameterAnnotations.
private static void dumpParameterAnnotations(MethodVisitor mv, List[] parameterAnnotations, boolean visible) {
for (int i = 0; i < parameterAnnotations.length; i++) {
if (parameterAnnotations[i] != null) {
for (Object o : parameterAnnotations[i]) {
AnnotationNode an = (AnnotationNode) o;
an.accept(mv.visitParameterAnnotation(i, an.desc, visible));
}
}
}
}
Aggregations