Search in sources :

Example 1 with JumpInsnNode

use of org.objectweb.asm.tree.JumpInsnNode 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;
}
Also used : LabelNode(org.objectweb.asm.tree.LabelNode) FrameNode(org.objectweb.asm.tree.FrameNode) FieldNode(org.objectweb.asm.tree.FieldNode) FieldInsnNode(org.objectweb.asm.tree.FieldInsnNode) TypeInsnNode(org.objectweb.asm.tree.TypeInsnNode) FieldInsnNode(org.objectweb.asm.tree.FieldInsnNode) MethodInsnNode(org.objectweb.asm.tree.MethodInsnNode) TypeInsnNode(org.objectweb.asm.tree.TypeInsnNode) JumpInsnNode(org.objectweb.asm.tree.JumpInsnNode) VarInsnNode(org.objectweb.asm.tree.VarInsnNode) InsnNode(org.objectweb.asm.tree.InsnNode) Type(org.objectweb.asm.Type) MethodNode(org.objectweb.asm.tree.MethodNode) AnnotationNode(org.objectweb.asm.tree.AnnotationNode) MethodInsnNode(org.objectweb.asm.tree.MethodInsnNode) Event(net.minecraftforge.fml.common.eventhandler.Event) JumpInsnNode(org.objectweb.asm.tree.JumpInsnNode) VarInsnNode(org.objectweb.asm.tree.VarInsnNode)

Example 2 with JumpInsnNode

use of org.objectweb.asm.tree.JumpInsnNode in project jphp by jphp-compiler.

the class IfElseCompiler method writeBody.

private void writeBody(IfStmtToken token) {
    LabelNode end = new LabelNode();
    LabelNode elseL = new LabelNode();
    expr.writePopBoolean();
    add(new JumpInsnNode(IFEQ, token.getElseBody() != null ? elseL : end));
    expr.stackPop();
    if (token.getBody() != null) {
        expr.write(token.getBody());
    }
    if (token.getElseBody() != null) {
        add(new JumpInsnNode(GOTO, end));
        add(elseL);
        expr.write(token.getElseBody());
    }
    add(end);
    add(new LineNumberNode(token.getMeta().getEndLine(), end));
}
Also used : LabelNode(org.objectweb.asm.tree.LabelNode) JumpInsnNode(org.objectweb.asm.tree.JumpInsnNode) LineNumberNode(org.objectweb.asm.tree.LineNumberNode)

Example 3 with JumpInsnNode

use of org.objectweb.asm.tree.JumpInsnNode in project jphp by jphp-compiler.

the class DoCompiler method write.

@Override
public void write(DoStmtToken token) {
    expr.writeDefineVariables(token.getLocal());
    LabelNode start = expr.writeLabel(node, token.getMeta().getStartLine());
    LabelNode end = new LabelNode();
    method.pushJump(end, start);
    expr.write(token.getBody());
    method.popJump();
    expr.writeConditional(token.getCondition(), end);
    add(new JumpInsnNode(GOTO, start));
    add(end);
    add(new LineNumberNode(token.getMeta().getEndLine(), end));
    expr.writeUndefineVariables(token.getLocal());
}
Also used : LabelNode(org.objectweb.asm.tree.LabelNode) JumpInsnNode(org.objectweb.asm.tree.JumpInsnNode) LineNumberNode(org.objectweb.asm.tree.LineNumberNode)

Example 4 with JumpInsnNode

use of org.objectweb.asm.tree.JumpInsnNode in project jphp by jphp-compiler.

the class ReturnCompiler method write.

@Override
public void write(ReturnStmtToken token) {
    boolean isGeneratorReturn = false;
    if (token.getValue() != null && method.getGeneratorEntity() != null) {
        isGeneratorReturn = true;
        expr.writeVarLoad(LocalVariable.THIS);
        expr.writePushEnv();
        expr.writePushTraceInfo(token);
    /*env.error(
                    token.toTraceInfo(compiler.getContext()),
                    ErrorType.E_ERROR,
                    "Generators cannot return values using \"return\""
            );*/
    }
    Memory result = token.isEmpty() ? Memory.UNDEFINED : Memory.NULL;
    boolean isImmutable = method.getEntity().isImmutable();
    if (token.getValue() != null) {
        result = expr.writeExpression(token.getValue(), true, true);
        if (methodStatement.getReturnHintType() == HintType.VOID) {
            String suffix = result != null && result.isNull() ? " (did you mean \"return;\" instead of \"return null;\"?)" : "";
            env.error(token.toTraceInfo(compiler.getContext()), ErrorType.E_ERROR, "A void function must not return a value" + suffix);
        }
    }
    if (result != null) {
        if (methodStatement.getReturnHintType() == HintType.VOID) {
            if (methodStatement.isReturnOptional()) {
                env.error(token.toTraceInfo(compiler.getContext()), ErrorType.E_ERROR, "Void type cannot be nullable");
            }
        }
        if (isImmutable) {
            Memory r = method.getEntity().getResult();
            if (r == null || r.isUndefined()) {
                method.getEntity().setResult(result);
            }
        }
        expr.writePushMemory(result);
    } else {
        method.getEntity().setImmutable(false);
    }
    if (expr.stackEmpty(false)) {
        expr.writePushNull();
    } else {
        expr.writePopBoxing(false);
    }
    if (method.getEntity().isReturnReference()) {
        expr.writePushDup();
        expr.writePushEnv();
        expr.writePushTraceInfo(token);
        expr.writeSysStaticCall(InvokeHelper.class, "checkReturnReference", void.class, Memory.class, Environment.class, TraceInfo.class);
    } else {
        expr.writePopImmutable();
    }
    if (isGeneratorReturn) {
        expr.writeSysDynamicCall(Generator.class, "setReturn", Memory.class, Environment.class, TraceInfo.class, Memory.class);
    }
    if (!method.getTryStack().empty()) {
        LocalVariable variable = method.getLocalVariable("~result~");
        if (variable == null) {
            variable = method.addLocalVariable("~result~", null, Memory.class);
        }
        expr.writeVarStore(variable, false, false);
        add(new JumpInsnNode(GOTO, method.getTryStack().peek().getReturnLabel()));
    } else {
        add(new InsnNode(ARETURN));
        // removeStackFrame();
        expr.stackPop();
    }
}
Also used : JumpInsnNode(org.objectweb.asm.tree.JumpInsnNode) InsnNode(org.objectweb.asm.tree.InsnNode) Memory(php.runtime.Memory) LocalVariable(org.develnext.jphp.core.compiler.jvm.misc.LocalVariable) JumpInsnNode(org.objectweb.asm.tree.JumpInsnNode)

Example 5 with JumpInsnNode

use of org.objectweb.asm.tree.JumpInsnNode in project jphp by jphp-compiler.

the class SwitchCompiler method write.

@Override
public void write(SwitchStmtToken token) {
    expr.writeDefineVariables(token.getLocal());
    LabelNode l = new LabelNode();
    LabelNode end = new LabelNode();
    add(l);
    LocalVariable switchValue = method.addLocalVariable("~switch~" + method.nextStatementIndex(Memory.class), l, Memory.class);
    switchValue.setEndLabel(end);
    LabelNode[][] jumps = new LabelNode[token.getCases().size() + 1][2];
    int i = 0;
    for (CaseStmtToken one : token.getCases()) {
        // checkLabel, bodyLabel
        jumps[i] = new LabelNode[] { new LabelNode(), new LabelNode() };
        if (i == jumps.length - 1)
            jumps[i] = new LabelNode[] { end, end };
        i++;
    }
    jumps[jumps.length - 1] = new LabelNode[] { end, end };
    method.pushJump(end, end);
    expr.writeExpression(token.getValue(), true, false);
    expr.writePopBoxing();
    expr.writeVarStore(switchValue, false, false);
    i = 0;
    for (CaseStmtToken one : token.getCases()) {
        // conditional
        add(jumps[i][0]);
        if (one.getConditional() != null) {
            expr.writeVarLoad(switchValue);
            expr.writeExpression(one.getConditional(), true, false);
            expr.writeSysDynamicCall(Memory.class, "equal", Boolean.TYPE, expr.stackPeek().type.toClass());
            add(new JumpInsnNode(IFEQ, jumps[i + 1][0]));
            expr.stackPop();
        }
        // if is done...
        add(new JumpInsnNode(GOTO, jumps[i][1]));
        i++;
    }
    i = 0;
    for (CaseStmtToken one : token.getCases()) {
        add(jumps[i][1]);
        expr.writeDefineVariables(one.getLocals());
        expr.write(BodyStmtToken.class, one.getBody());
        i++;
        expr.writeUndefineVariables(one.getLocals());
    }
    method.popJump();
    add(end);
    add(new LineNumberNode(token.getMeta().getEndLine(), end));
    method.prevStatementIndex(Memory.class);
    expr.writeUndefineVariables(token.getLocal());
}
Also used : LabelNode(org.objectweb.asm.tree.LabelNode) CaseStmtToken(org.develnext.jphp.core.tokenizer.token.stmt.CaseStmtToken) LocalVariable(org.develnext.jphp.core.compiler.jvm.misc.LocalVariable) JumpInsnNode(org.objectweb.asm.tree.JumpInsnNode) LineNumberNode(org.objectweb.asm.tree.LineNumberNode)

Aggregations

JumpInsnNode (org.objectweb.asm.tree.JumpInsnNode)49 LabelNode (org.objectweb.asm.tree.LabelNode)36 MethodInsnNode (org.objectweb.asm.tree.MethodInsnNode)28 AbstractInsnNode (org.objectweb.asm.tree.AbstractInsnNode)26 InsnNode (org.objectweb.asm.tree.InsnNode)25 VarInsnNode (org.objectweb.asm.tree.VarInsnNode)24 InsnList (org.objectweb.asm.tree.InsnList)22 FieldInsnNode (org.objectweb.asm.tree.FieldInsnNode)19 LdcInsnNode (org.objectweb.asm.tree.LdcInsnNode)18 MethodNode (org.objectweb.asm.tree.MethodNode)18 TypeInsnNode (org.objectweb.asm.tree.TypeInsnNode)15 ClassNode (org.objectweb.asm.tree.ClassNode)14 ClassReader (org.objectweb.asm.ClassReader)12 Label (org.objectweb.asm.Label)11 Type (org.objectweb.asm.Type)9 LocalVariable (org.develnext.jphp.core.compiler.jvm.misc.LocalVariable)6 LineNumberNode (org.objectweb.asm.tree.LineNumberNode)4 LinkedList (java.util.LinkedList)3 Mutation (org.evosuite.coverage.mutation.Mutation)3 FieldNode (org.objectweb.asm.tree.FieldNode)3