List of usage examples for org.objectweb.asm Type getArgumentsAndReturnSizes
public static int getArgumentsAndReturnSizes(final String methodDescriptor)
From source file:com.google.devtools.build.android.desugar.BytecodeTypeInference.java
License:Open Source License
@Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { if (opcode == Opcodes.INVOKESPECIAL && "<init>".equals(name)) { int argumentSize = (Type.getArgumentsAndReturnSizes(desc) >> 2); InferredType receiverType = getTypeOfOperandFromTop(argumentSize - 1); if (receiverType.isUninitialized()) { InferredType realType = InferredType.createNonUninitializedType('L' + owner + ';'); replaceUninitializedTypeInStack(receiverType, realType); }//from www. java 2 s . c o m } switch (opcode) { case Opcodes.INVOKESPECIAL: case Opcodes.INVOKEVIRTUAL: case Opcodes.INVOKESTATIC: case Opcodes.INVOKEINTERFACE: popDescriptor(desc); if (opcode != Opcodes.INVOKESTATIC) { pop(); // Pop receiver. } pushDescriptor(desc); break; default: throw new RuntimeException(String.format("Unhandled opcode %s, owner=%s, name=%s, desc=%s, itf=%s", opcode, owner, name, desc, itf)); } super.visitMethodInsn(opcode, owner, name, desc, itf); }
From source file:com.google.devtools.build.android.desugar.BytecodeTypeInference.java
License:Open Source License
private final void popDescriptor(String desc) { char c = desc.charAt(0); switch (c) {//from ww w.jav a2s. c o m case '(': int argumentSize = (Type.getArgumentsAndReturnSizes(desc) >> 2) - 1; if (argumentSize > 0) { pop(argumentSize); } break; case 'J': case 'D': pop(2); break; default: pop(1); break; } }
From source file:edu.ubc.mirrors.holograms.HologramMethodGenerator.java
License:Open Source License
@Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { // Various special cases here to adjust for the fact that Object and Throwable // are still in the hierarchy and have some methods with incompatible types. Type stringHologramType = getHologramType(String.class); if (name.equals("toString") && desc.equals(Type.getMethodDescriptor(stringHologramType))) { desc = Type.getMethodDescriptor(Type.getType(String.class)); if (owner.equals(Type.getInternalName(Hologram.class))) { owner = OBJECT_TYPE.getInternalName(); // Handle calling Object.toString() with an invokespecial opcode, // which doesn't work any more since we've changed the superclass. if (opcode == Opcodes.INVOKESPECIAL) { opcode = Opcodes.INVOKESTATIC; owner = objectHologramType.getInternalName(); name = "hologramToString"; desc = Type.getMethodDescriptor(stringType, hologramType); }/*w w w.jav a2 s . c om*/ } super.visitMethodInsn(opcode, owner, name, desc); getClassMirror(this.owner); invokestatic(objectHologramType.getInternalName(), "makeStringHologram", Type.getMethodDescriptor(hologramType, stringType, classMirrorType)); checkcast(stringHologramType); return; } if (name.equals("getClass") && desc.equals(Type.getMethodDescriptor(getHologramType(Class.class)))) { invokeinterface(Type.getInternalName(Hologram.class), "getMirror", Type.getMethodDescriptor(objectMirrorType)); invokeinterface(objectMirrorType.getInternalName(), "getClassMirror", Type.getMethodDescriptor(Type.getType(ClassMirror.class))); invokestatic(objectHologramType.getInternalName(), "make", Type.getMethodDescriptor(hologramType, objectMirrorType)); checkcast(getHologramType(Class.class)); return; } if (owner.equals(Type.getInternalName(Hologram.class))) { if (name.equals("<init>") && this.owner.equals(getHologramType(Throwable.class))) { owner = Type.getInternalName(Throwable.class); } else if (name.equals("<init>") || name.equals("toString")) { owner = objectHologramType.getInternalName(); } else { owner = OBJECT_TYPE.getInternalName(); } } if (name.equals("clone")) { if (desc.equals(Type.getMethodDescriptor(hologramType))) { desc = Type.getMethodDescriptor(OBJECT_TYPE); // Object.clone() on an array type is legal since array types // are treated specially by the JVM, but the mirror interfaces // are not granted the same leeway. Object t = stackType(0); if (t instanceof String) { String internalName = (String) t; Type type = Type.getObjectType(internalName); if (HologramClassGenerator.getOriginalType(type).getSort() == Type.ARRAY) { owner = internalName; } } } if (owner.equals(Type.getType(ObjectArrayMirror.class).getInternalName()) || (owner.startsWith("hologramarray") && !owner.startsWith("hologramarrayimpl"))) { String originalName = getOriginalInternalClassName(owner); owner = getHologramType(Type.getObjectType(originalName), true).getInternalName(); checkcast(Type.getObjectType(owner)); } } // if (owner.equals(getHologramType(Throwable.class).getInternalName())) { // if (name.equals("<init>") && desc.equals(Type.getMethodDescriptor(Type.VOID_TYPE, getHologramType(String.class)))) { // desc = Type.getMethodDescriptor(Type.VOID_TYPE, objectHologramType); // } // } if (owner.equals(hologramThrowableType.getInternalName()) && name.equals("fillInStackTrace") && desc.equals(Type.getMethodDescriptor(hologramThrowableType))) { desc = Type.getMethodDescriptor(throwableType); owner = throwableType.getInternalName(); } if (name.equals("equals") && desc.equals(Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.getType(Hologram.class)))) { desc = Type.getMethodDescriptor(Type.BOOLEAN_TYPE, OBJECT_TYPE); } if (name.equals("<init>") && !owner.equals(Type.getInternalName(Throwable.class))) { int argsSize = Type.getArgumentsAndReturnSizes(desc) >> 2; desc = HologramClassGenerator.addMirrorParam(desc); Object targetType = stackType(argsSize - 1); if (targetType.equals(Opcodes.UNINITIALIZED_THIS)) { // If the target is an uninitialized this (i.e. we're calling super(...) // or this(...)), pass along the extra mirror argument load((methodType.getArgumentsAndReturnSizes() >> 2) - 1, instanceMirrorType); } else if (targetType instanceof Label) { // If the target is just uninitialized (i.e. we're calling <init> after // a new), create the mirror getClassMirror(Type.getObjectType(owner)); invokeinterface(classMirrorType.getInternalName(), "newRawInstance", Type.getMethodDescriptor(instanceMirrorType)); } else { // Shouldn't happen throw new RuntimeException("Calling <init> on already initialized type: " + targetType); } } super.visitMethodInsn(opcode, owner, name, desc); if (owner.equals(Type.getInternalName(Throwable.class)) && name.equals("getStackTraceElement")) { Type steType = Type.getType(StackTraceElement.class); invokestatic(Type.getInternalName(ObjectHologram.class), "cleanStackTraceElement", Type.getMethodDescriptor(steType, steType)); } }
From source file:org.jephyr.easyflow.instrument.ContinuationMethodAdapter.java
License:Open Source License
@Override public void visitEnd() { List<MethodInsnNode> nodes = findNodes(); if (nodes.isEmpty()) { accept(mv);// w ww . j a v a 2s .co m return; } int implVarIndex = maxLocals; maxLocals += 1; Object[] initialLocals = appendValue(ensureSize(frames.get(instructions.getFirst()).locals, implVarIndex), "org/jephyr/continuation/easyflow/ContinuationImpl"); updateFrames(implVarIndex); addMonitorHooks(implVarIndex); LabelNode labelNode = newLabelNode(); instructions.insert(labelNode); if (!isNextFrameNode(labelNode)) { instructions.insert(labelNode, newFrameNode(initialLocals, EMPTY_OBJECTS)); } addInvocationEndedHook(implVarIndex, labelNode); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKESTATIC, "org/jephyr/continuation/easyflow/ContinuationImpl", "currentImpl", "()Lorg/jephyr/continuation/easyflow/ContinuationImpl;", false)); instructions.insertBefore(labelNode, new VarInsnNode(ASTORE, implVarIndex)); instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new JumpInsnNode(IFNULL, labelNode)); instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "isSuspended", "()Z", false)); LabelNode labelNode1 = newLabelNode(); instructions.insertBefore(labelNode, new JumpInsnNode(IFEQ, labelNode1)); LabelNode defaultLabelNode = newLabelNode(); int size = nodes.size(); int length = size - 1; LabelNode[] labelNodes = new LabelNode[length]; for (int i = 0; i < length; i++) { labelNodes[i] = newLabelNode(); } if (length > 0) { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popInt", "()I", false)); instructions.insertBefore(labelNode, new TableSwitchInsnNode(0, length - 1, defaultLabelNode, labelNodes)); } else { instructions.insertBefore(labelNode, new JumpInsnNode(GOTO, defaultLabelNode)); } updateMaxStack(1); Type returnType = Type.getReturnType(desc); for (int i = 0; i < size; i++) { MethodInsnNode node = nodes.get(i); Frame frame = frames.get(node); Object[] locals = frame.locals; Object[] stack = frame.stack; // resume LabelNode labelNode2 = i < length ? labelNodes[i] : defaultLabelNode; instructions.insertBefore(labelNode, labelNode2); instructions.insert(labelNode2, newFrameNode(initialLocals, EMPTY_OBJECTS)); int intCount = length > 0 ? 1 : 0; int floatCount = 0; int longCount = 0; int doubleCount = 0; int objectCount = 0; for (int j = 0, n = locals.length; j < n; j++) { Object value = locals[j]; if (value == INTEGER) { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popInt", "()I", false)); instructions.insertBefore(labelNode, new VarInsnNode(ISTORE, j)); updateMaxStack(1); intCount++; } else if (value == FLOAT) { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popFloat", "()F", false)); instructions.insertBefore(labelNode, new VarInsnNode(FSTORE, j)); updateMaxStack(1); floatCount++; } else if (value == LONG) { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popLong", "()J", false)); instructions.insertBefore(labelNode, new VarInsnNode(LSTORE, j)); updateMaxStack(2); longCount++; } else if (value == DOUBLE) { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popDouble", "()D", false)); instructions.insertBefore(labelNode, new VarInsnNode(DSTORE, j)); updateMaxStack(2); doubleCount++; } else if (value == NULL) { instructions.insertBefore(labelNode, new InsnNode(ACONST_NULL)); instructions.insertBefore(labelNode, new VarInsnNode(ASTORE, j)); updateMaxStack(1); } else if (value instanceof String) { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popObject", "()Ljava/lang/Object;", false)); instructions.insertBefore(labelNode, new TypeInsnNode(CHECKCAST, (String) value)); instructions.insertBefore(labelNode, new VarInsnNode(ASTORE, j)); updateMaxStack(1); objectCount++; } else if (value != TOP) { throw new IllegalStateException(); } } int sizes = Type.getArgumentsAndReturnSizes(node.desc); int argSize = sizes >> 2; boolean invokeStatic = node.getOpcode() == INVOKESTATIC; if (invokeStatic) { argSize -= 1; } int stackSize = 0; for (int j = 0, n = stack.length - argSize; j < n; j++) { Object value = stack[j]; if (value == INTEGER) { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popInt", "()I", false)); stackSize += 1; intCount++; } else if (value == FLOAT) { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popFloat", "()F", false)); stackSize += 1; floatCount++; } else if (value == LONG) { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popLong", "()J", false)); stackSize += 2; longCount++; } else if (value == DOUBLE) { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popDouble", "()D", false)); stackSize += 2; doubleCount++; } else if (value == NULL) { instructions.insertBefore(labelNode, new InsnNode(ACONST_NULL)); stackSize += 1; } else if (value instanceof String) { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popObject", "()Ljava/lang/Object;", false)); instructions.insertBefore(labelNode, new TypeInsnNode(CHECKCAST, (String) value)); stackSize += 1; objectCount++; } else if (value != TOP) { throw new IllegalStateException(); } } updateMaxStack(stackSize); int targetVarIndex; int objVarIndex; int argsVarIndex; if (invokeStatic) { targetVarIndex = -1; objVarIndex = -1; argsVarIndex = -1; for (Type type : Type.getArgumentTypes(node.desc)) { instructions.insertBefore(labelNode, newPushDefaultNode(type)); stackSize += type.getSize(); } } else if (node.owner.equals("java/lang/reflect/Method") && node.name.equals("invoke") && node.desc.equals("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")) { int varIndex = implVarIndex + 1; if (stack[stack.length - 3] == NULL) { targetVarIndex = -1; } else { targetVarIndex = varIndex; varIndex++; } if (stack[stack.length - 2] == NULL) { objVarIndex = -1; } else { objVarIndex = varIndex; varIndex++; } if (stack[stack.length - 1] == NULL) { argsVarIndex = -1; } else { argsVarIndex = varIndex; varIndex++; } if (maxLocals < varIndex) { maxLocals = varIndex; } if (targetVarIndex == -1) { instructions.insertBefore(labelNode, new InsnNode(ACONST_NULL)); } else { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popObject", "()Ljava/lang/Object;", false)); instructions.insertBefore(labelNode, new TypeInsnNode(CHECKCAST, "java/lang/reflect/Method")); instructions.insertBefore(labelNode, new VarInsnNode(ASTORE, targetVarIndex)); instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, targetVarIndex)); objectCount++; } if (objVarIndex == -1) { instructions.insertBefore(labelNode, new InsnNode(ACONST_NULL)); } else { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popObject", "()Ljava/lang/Object;", false)); instructions.insertBefore(labelNode, new TypeInsnNode(CHECKCAST, (String) stack[stack.length - 2])); instructions.insertBefore(labelNode, new VarInsnNode(ASTORE, objVarIndex)); instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, objVarIndex)); objectCount++; } if (targetVarIndex == -1) { instructions.insertBefore(labelNode, new InsnNode(ACONST_NULL)); } else { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, targetVarIndex)); } instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "java/lang/reflect/Method", "getParameterTypes", "()[Ljava/lang/Class;", false)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKESTATIC, "org/jephyr/continuation/easyflow/ContinuationImpl", "getDefaultArguments", "([Ljava/lang/Class;)[Ljava/lang/Object;", false)); stackSize += 3; } else { targetVarIndex = -1; objVarIndex = -1; argsVarIndex = -1; Object value = stack[stack.length - argSize]; if (value == NULL) { instructions.insertBefore(labelNode, new InsnNode(ACONST_NULL)); instructions.insertBefore(labelNode, new VarInsnNode(ASTORE, implVarIndex + 1)); instructions.insertBefore(labelNode, new InsnNode(ACONST_NULL)); } else { instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "popObject", "()Ljava/lang/Object;", false)); instructions.insertBefore(labelNode, new VarInsnNode(ASTORE, implVarIndex + 1)); instructions.insertBefore(labelNode, new VarInsnNode(ALOAD, implVarIndex + 1)); instructions.insertBefore(labelNode, new TypeInsnNode(CHECKCAST, (String) value)); } stackSize += 1; for (Type type : Type.getArgumentTypes(node.desc)) { instructions.insertBefore(labelNode, newPushDefaultNode(type)); stackSize += type.getSize(); } objectCount++; } updateMaxStack(stackSize); LabelNode labelNode3 = newLabelNode(); instructions.insertBefore(labelNode, new JumpInsnNode(GOTO, labelNode3)); // invocation starting if (invokeStatic) { instructions.insertBefore(node, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(node, new JumpInsnNode(IFNULL, labelNode3)); instructions.insertBefore(node, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(node, new LdcInsnNode(Type.getType('L' + node.owner + ';'))); instructions.insertBefore(node, new LdcInsnNode(node.name)); instructions.insertBefore(node, new LdcInsnNode(node.desc)); instructions.insertBefore(node, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "staticInvocationStarting", "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)V", false)); instructions.insertBefore(node, labelNode3); instructions.insert(labelNode3, newFrameNode(appendValue(ensureSize(locals, implVarIndex), "org/jephyr/continuation/easyflow/ContinuationImpl"), stack)); } else if (node.owner.equals("java/lang/reflect/Method") && node.name.equals("invoke") && node.desc.equals("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")) { instructions.insertBefore(node, new VarInsnNode(ALOAD, implVarIndex)); LabelNode labelNode4 = newLabelNode(); instructions.insertBefore(node, new JumpInsnNode(IFNULL, labelNode4)); instructions.insertBefore(node, argsVarIndex == -1 ? new InsnNode(POP) : new VarInsnNode(ASTORE, argsVarIndex)); instructions.insertBefore(node, objVarIndex == -1 ? new InsnNode(POP) : new VarInsnNode(ASTORE, objVarIndex)); instructions.insertBefore(node, targetVarIndex == -1 ? new InsnNode(POP) : new VarInsnNode(ASTORE, targetVarIndex)); instructions.insertBefore(node, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(node, targetVarIndex == -1 ? new InsnNode(ACONST_NULL) : new VarInsnNode(ALOAD, targetVarIndex)); instructions.insertBefore(node, objVarIndex == -1 ? new InsnNode(ACONST_NULL) : new VarInsnNode(ALOAD, objVarIndex)); instructions.insertBefore(node, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "reflectiveInvocationStarting", "(Ljava/lang/reflect/Method;Ljava/lang/Object;)V", false)); instructions.insertBefore(node, targetVarIndex == -1 ? new InsnNode(ACONST_NULL) : new VarInsnNode(ALOAD, targetVarIndex)); instructions.insertBefore(node, objVarIndex == -1 ? new InsnNode(ACONST_NULL) : new VarInsnNode(ALOAD, objVarIndex)); instructions.insertBefore(node, argsVarIndex == -1 ? new InsnNode(ACONST_NULL) : new VarInsnNode(ALOAD, argsVarIndex)); instructions.insertBefore(node, new JumpInsnNode(GOTO, labelNode3)); instructions.insertBefore(node, labelNode4); instructions.insert(labelNode4, newFrameNode(appendValue(ensureSize(locals, implVarIndex), "org/jephyr/continuation/easyflow/ContinuationImpl"), stack)); if (targetVarIndex != -1) { instructions.insertBefore(node, new InsnNode(ACONST_NULL)); instructions.insertBefore(node, new VarInsnNode(ASTORE, targetVarIndex)); } if (objVarIndex != -1) { instructions.insertBefore(node, new InsnNode(ACONST_NULL)); instructions.insertBefore(node, new VarInsnNode(ASTORE, objVarIndex)); } instructions.insertBefore(node, labelNode3); Object[] locals1 = appendValue(ensureSize(locals, implVarIndex), "org/jephyr/continuation/easyflow/ContinuationImpl"); if (targetVarIndex != -1) { locals1 = appendValue(locals1, "java/lang/reflect/Method"); } if (objVarIndex != -1) { locals1 = appendValue(locals1, "java/lang/Object"); } instructions.insert(labelNode3, newFrameNode(locals1, stack)); } else { instructions.insertBefore(node, new VarInsnNode(ALOAD, implVarIndex)); LabelNode labelNode4 = newLabelNode(); instructions.insertBefore(node, new JumpInsnNode(IFNULL, labelNode4)); targetVarIndex = implVarIndex + 1; int varIndex = targetVarIndex + 1; for (int j = stack.length - 1, k = stack.length - argSize + 1; j >= k; j--) { Object value = stack[j]; if (value == INTEGER) { instructions.insertBefore(node, new VarInsnNode(ISTORE, varIndex)); varIndex += 1; } else if (value == FLOAT) { instructions.insertBefore(node, new VarInsnNode(FSTORE, varIndex)); varIndex += 1; } else if (value == DOUBLE) { instructions.insertBefore(node, new VarInsnNode(DSTORE, varIndex)); varIndex += 2; } else if (value == LONG) { instructions.insertBefore(node, new VarInsnNode(LSTORE, varIndex)); varIndex += 2; } else if (value == NULL) { instructions.insertBefore(node, new InsnNode(POP)); } else if (value instanceof String) { instructions.insertBefore(node, new VarInsnNode(ASTORE, varIndex)); varIndex += 1; } } if (maxLocals < varIndex) { maxLocals = varIndex; } instructions.insertBefore(node, new VarInsnNode(ASTORE, targetVarIndex)); instructions.insertBefore(node, new VarInsnNode(ALOAD, targetVarIndex)); for (int j = stack.length - argSize + 1, n = stack.length; j < n; j++) { Object value = stack[j]; if (value == INTEGER) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(ILOAD, varIndex)); } else if (value == FLOAT) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(FLOAD, varIndex)); } else if (value == DOUBLE) { varIndex -= 2; instructions.insertBefore(node, new VarInsnNode(DLOAD, varIndex)); } else if (value == LONG) { varIndex -= 2; instructions.insertBefore(node, new VarInsnNode(LLOAD, varIndex)); } else if (value == NULL) { instructions.insertBefore(node, new InsnNode(ACONST_NULL)); } else if (value instanceof String) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(ALOAD, varIndex)); } } instructions.insertBefore(node, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(node, new VarInsnNode(ALOAD, targetVarIndex)); instructions.insertBefore(node, new LdcInsnNode(node.name)); instructions.insertBefore(node, new LdcInsnNode(node.desc)); instructions.insertBefore(node, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "invocationStarting", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V", false)); instructions.insertBefore(node, new JumpInsnNode(GOTO, labelNode3)); instructions.insertBefore(node, labelNode4); instructions.insert(labelNode4, newFrameNode(appendValue(ensureSize(locals, implVarIndex), "org/jephyr/continuation/easyflow/ContinuationImpl"), stack)); instructions.insertBefore(node, new InsnNode(ACONST_NULL)); instructions.insertBefore(node, new VarInsnNode(ASTORE, targetVarIndex)); instructions.insertBefore(node, labelNode3); instructions.insert(labelNode3, newFrameNode( appendValues(ensureSize(locals, implVarIndex), "org/jephyr/continuation/easyflow/ContinuationImpl", "java/lang/Object"), stack)); } updateMaxStack(stack.length + 4); // suspend Frame frame1 = findNextFrame(frames, node); Object[] stack1 = frame1.stack; int stackSize1 = stack1.length; LabelNode labelNode4 = newLabelNode(); instructions.insert(node, labelNode4); if (!isNextFrameNode(labelNode4)) { instructions.insert(labelNode4, newFrameNode(appendValue(ensureSize(frame1.locals, implVarIndex), "org/jephyr/continuation/easyflow/ContinuationImpl"), stack1)); } instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new JumpInsnNode(IFNULL, labelNode4)); instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "isSuspending", "()Z", false)); instructions.insertBefore(labelNode4, new JumpInsnNode(IFEQ, labelNode4)); int returnSize = sizes & 0x03; if (returnSize == 1) { instructions.insertBefore(labelNode4, new InsnNode(POP)); stackSize1 -= 1; } else if (returnSize == 2) { instructions.insertBefore(labelNode4, new InsnNode(POP2)); stackSize1 -= 2; } if (intCount > 0) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, newPushNode(intCount)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "ensureIntStackSize", "(I)V", false)); updateMaxStack(stackSize1 + 1); } if (floatCount > 0) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, newPushNode(floatCount)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "ensureFloatStackSize", "(I)V", false)); updateMaxStack(stackSize1 + 1); } if (longCount > 0) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, newPushNode(longCount)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "ensureLongStackSize", "(I)V", false)); updateMaxStack(stackSize1 + 1); } if (doubleCount > 0) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, newPushNode(doubleCount)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "ensureDoubleStackSize", "(I)V", false)); updateMaxStack(stackSize1 + 1); } if (objectCount > 0) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, newPushNode(objectCount)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "ensureObjectStackSize", "(I)V", false)); updateMaxStack(stackSize1 + 1); } if (!invokeStatic) { if (node.owner.equals("java/lang/reflect/Method") && node.name.equals("invoke") && node.desc.equals("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")) { if (objVarIndex != -1) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, objVarIndex)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushObject", "(Ljava/lang/Object;)V", false)); updateMaxStack(stackSize1 + 2); } if (targetVarIndex != -1) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, targetVarIndex)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushObject", "(Ljava/lang/Object;)V", false)); updateMaxStack(stackSize1 + 2); } } else if (stack[stack.length - argSize] != NULL) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, targetVarIndex)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushObject", "(Ljava/lang/Object;)V", false)); updateMaxStack(stackSize1 + 2); } } for (int j = stack.length - argSize - 1; j >= 0; j--) { Object value = stack[j]; if (value == INTEGER) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new InsnNode(SWAP)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushInt", "(I)V", false)); updateMaxStack(stackSize1 + 1); stackSize1 -= 1; } else if (value == FLOAT) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new InsnNode(SWAP)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushFloat", "(F)V", false)); updateMaxStack(stackSize1 + 1); stackSize1 -= 1; } else if (value == LONG) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new InsnNode(DUP_X2)); instructions.insertBefore(labelNode4, new InsnNode(POP)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushLong", "(J)V", false)); updateMaxStack(stackSize1 + 2); stackSize1 -= 2; } else if (value == DOUBLE) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new InsnNode(DUP_X2)); instructions.insertBefore(labelNode4, new InsnNode(POP)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushDouble", "(D)V", false)); updateMaxStack(stackSize1 + 2); stackSize1 -= 2; } else if (value == NULL) { instructions.insertBefore(labelNode4, new InsnNode(POP)); stackSize1 -= 1; } else if (value instanceof String) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new InsnNode(SWAP)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushObject", "(Ljava/lang/Object;)V", false)); updateMaxStack(stackSize1 + 1); stackSize1 -= 1; } } for (int j = locals.length - 1; j >= 0; j--) { Object value = locals[j]; if (value == INTEGER) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new VarInsnNode(ILOAD, j)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushInt", "(I)V", false)); updateMaxStack(stackSize1 + 2); } else if (value == FLOAT) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new VarInsnNode(FLOAD, j)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushFloat", "(F)V", false)); updateMaxStack(stackSize1 + 2); } else if (value == LONG) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new VarInsnNode(LLOAD, j)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushLong", "(J)V", false)); updateMaxStack(stackSize1 + 3); } else if (value == DOUBLE) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new VarInsnNode(DLOAD, j)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushDouble", "(D)V", false)); updateMaxStack(stackSize1 + 3); } else if (value instanceof String) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, j)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushObject", "(Ljava/lang/Object;)V", false)); updateMaxStack(stackSize1 + 2); } } if (length > 0) { instructions.insertBefore(labelNode4, new VarInsnNode(ALOAD, implVarIndex)); instructions.insertBefore(labelNode4, newPushNode(i)); instructions.insertBefore(labelNode4, new MethodInsnNode(INVOKEVIRTUAL, "org/jephyr/continuation/easyflow/ContinuationImpl", "pushInt", "(I)V", false)); updateMaxStack(stackSize1 + 2); } int returnSize1 = returnType.getSize(); if (returnSize1 > 0) { instructions.insertBefore(labelNode4, newPushDefaultNode(returnType)); updateMaxStack(stackSize1 + returnSize1); } instructions.insertBefore(labelNode4, new InsnNode(returnType.getOpcode(IRETURN))); } instructions.insertBefore(labelNode, labelNode1); instructions.insert(labelNode1, newFrameNode(initialLocals, EMPTY_OBJECTS)); addInvocationStartedHook(implVarIndex, labelNode); accept(mv); }
From source file:org.jephyr.easyflow.instrument.NewRelocatorMethodAdapter.java
License:Open Source License
private static int getInvokeDelta(String desc) { int sizes = Type.getArgumentsAndReturnSizes(desc); return (sizes & 0x03) - (sizes >> 2); }
From source file:org.jephyr.easyflow.instrument.NewRelocatorMethodAdapter.java
License:Open Source License
private int handleInvokeSpecial(MethodInsnNode node, int stackSize) { int stackSize1 = stackSize; int sizes = Type.getArgumentsAndReturnSizes(node.desc); int argSize = sizes >> 2; if (node.name.charAt(0) == '<') { Frame frame = frames.get(node); Object[] locals = frame.locals; Object[] stack = frame.stack; AbstractInsnNode newNode = (AbstractInsnNode) stack[stack.length - argSize]; boolean noLocalNews = true; for (Object value : locals) { if (value == newNode) { noLocalNews = false;/*from w w w .jav a 2s . c o m*/ break; } } int stackNewCount = 0; for (Object value : stack) { if (value == newNode) { stackNewCount++; } } if (noLocalNews && stackNewCount == 2 && stack[stack.length - argSize - 1] == newNode) { if (argSize == 1) { instructions.insertBefore(node, new TypeInsnNode(NEW, node.owner)); instructions.insertBefore(node, new InsnNode(DUP)); stackSize1 += 2; updateMaxStack(stackSize1); } else if (argSize == 2 || argSize >= 4 && isLong(stack[stack.length - argSize + 2])) { int varIndex = locals.length; for (int i = stack.length - 1, k = stack.length - argSize + 2; i >= k; i--) { Object value = stack[i]; if (value == INTEGER) { instructions.insertBefore(node, new VarInsnNode(ISTORE, varIndex)); stackSize1 -= 1; varIndex += 1; } else if (value == FLOAT) { instructions.insertBefore(node, new VarInsnNode(FSTORE, varIndex)); stackSize1 -= 1; varIndex += 1; } else if (value == DOUBLE) { instructions.insertBefore(node, new VarInsnNode(DSTORE, varIndex)); stackSize1 -= 2; varIndex += 2; } else if (value == LONG) { instructions.insertBefore(node, new VarInsnNode(LSTORE, varIndex)); stackSize1 -= 2; varIndex += 2; } else if (value == NULL) { instructions.insertBefore(node, new InsnNode(POP)); stackSize1 -= 1; } else if (value instanceof String) { instructions.insertBefore(node, new VarInsnNode(ASTORE, varIndex)); stackSize1 -= 1; varIndex += 1; } } if (maxLocals < varIndex) { maxLocals = varIndex; } instructions.insertBefore(node, new TypeInsnNode(NEW, node.owner)); instructions.insertBefore(node, new InsnNode(DUP)); instructions.insertBefore(node, new InsnNode(DUP2_X1)); instructions.insertBefore(node, new InsnNode(POP2)); stackSize1 += 2; updateMaxStack(stackSize1 + 2); for (int i = stack.length - argSize + 2, n = stack.length; i < n; i++) { Object value = stack[i]; if (value == INTEGER) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(ILOAD, varIndex)); stackSize1 += 1; } else if (value == FLOAT) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(FLOAD, varIndex)); stackSize1 += 1; } else if (value == DOUBLE) { varIndex -= 2; instructions.insertBefore(node, new VarInsnNode(DLOAD, varIndex)); stackSize1 += 2; } else if (value == LONG) { varIndex -= 2; instructions.insertBefore(node, new VarInsnNode(LLOAD, varIndex)); stackSize1 += 2; } else if (value == NULL) { instructions.insertBefore(node, new InsnNode(ACONST_NULL)); stackSize1 += 1; } else if (value instanceof String) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(ALOAD, varIndex)); stackSize1 += 1; } } updateMaxStack(stackSize1); } else { int varIndex = locals.length; for (int i = stack.length - 1, k = stack.length - argSize + 3; i >= k; i--) { Object value = stack[i]; if (value == INTEGER) { instructions.insertBefore(node, new VarInsnNode(ISTORE, varIndex)); stackSize1 -= 1; varIndex += 1; } else if (value == FLOAT) { instructions.insertBefore(node, new VarInsnNode(FSTORE, varIndex)); stackSize1 -= 1; varIndex += 1; } else if (value == DOUBLE) { instructions.insertBefore(node, new VarInsnNode(DSTORE, varIndex)); stackSize1 -= 2; varIndex += 2; } else if (value == LONG) { instructions.insertBefore(node, new VarInsnNode(LSTORE, varIndex)); stackSize1 -= 2; varIndex += 2; } else if (value == NULL) { instructions.insertBefore(node, new InsnNode(POP)); stackSize1 -= 1; } else if (value instanceof String) { instructions.insertBefore(node, new VarInsnNode(ASTORE, varIndex)); stackSize1 -= 1; varIndex += 1; } } if (maxLocals < varIndex) { maxLocals = varIndex; } instructions.insertBefore(node, new TypeInsnNode(NEW, node.owner)); instructions.insertBefore(node, new InsnNode(DUP)); instructions.insertBefore(node, new InsnNode(DUP2_X2)); instructions.insertBefore(node, new InsnNode(POP2)); stackSize1 += 2; updateMaxStack(stackSize1 + 2); for (int i = stack.length - argSize + 3, n = stack.length; i < n; i++) { Object value = stack[i]; if (value == INTEGER) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(ILOAD, varIndex)); stackSize1 += 1; } else if (value == FLOAT) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(FLOAD, varIndex)); stackSize1 += 1; } else if (value == DOUBLE) { varIndex -= 2; instructions.insertBefore(node, new VarInsnNode(DLOAD, varIndex)); stackSize1 += 2; } else if (value == LONG) { varIndex -= 2; instructions.insertBefore(node, new VarInsnNode(LLOAD, varIndex)); stackSize1 += 2; } else if (value == NULL) { instructions.insertBefore(node, new InsnNode(ACONST_NULL)); stackSize1 += 1; } else if (value instanceof String) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(ALOAD, varIndex)); stackSize1 += 1; } } updateMaxStack(stackSize1); } } else { int k = 0; for (Object value : stack) { if (value == newNode) { break; } k++; } int newVarIndex = locals.length; int varIndex = newVarIndex + 1; for (int i = stack.length - 1; i >= k; i--) { Object value = stack[i]; if (value == INTEGER) { instructions.insertBefore(node, new VarInsnNode(ISTORE, varIndex)); stackSize1 -= 1; varIndex += 1; } else if (value == FLOAT) { instructions.insertBefore(node, new VarInsnNode(FSTORE, varIndex)); stackSize1 -= 1; varIndex += 1; } else if (value == DOUBLE) { instructions.insertBefore(node, new VarInsnNode(DSTORE, varIndex)); stackSize1 -= 2; varIndex += 2; } else if (value == LONG) { instructions.insertBefore(node, new VarInsnNode(LSTORE, varIndex)); stackSize1 -= 2; varIndex += 2; } else if (value == NULL) { instructions.insertBefore(node, new InsnNode(POP)); stackSize1 -= 1; } else if (value instanceof String) { instructions.insertBefore(node, new VarInsnNode(ASTORE, varIndex)); stackSize1 -= 1; varIndex += 1; } } if (maxLocals < varIndex) { maxLocals = varIndex; } instructions.insertBefore(node, new TypeInsnNode(NEW, node.owner)); instructions.insertBefore(node, new VarInsnNode(ASTORE, newVarIndex)); for (int i = 0; i < newVarIndex; i++) { if (locals[i] == newNode) { instructions.insertBefore(node, new VarInsnNode(ALOAD, newVarIndex)); instructions.insertBefore(node, new VarInsnNode(ASTORE, i)); } } updateMaxStack(stackSize1 + 1); for (int i = k, n = stack.length; i < n; i++) { Object value = stack[i]; if (value == INTEGER) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(ILOAD, varIndex)); stackSize1 += 1; } else if (value == FLOAT) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(FLOAD, varIndex)); stackSize1 += 1; } else if (value == DOUBLE) { varIndex -= 2; instructions.insertBefore(node, new VarInsnNode(DLOAD, varIndex)); stackSize1 += 2; } else if (value == LONG) { varIndex -= 2; instructions.insertBefore(node, new VarInsnNode(LLOAD, varIndex)); stackSize1 += 2; } else if (value == NULL) { instructions.insertBefore(node, new InsnNode(ACONST_NULL)); stackSize1 += 1; } else if (value instanceof String) { varIndex -= 1; instructions.insertBefore(node, new VarInsnNode(ALOAD, varIndex)); stackSize1 += 1; } else if (value == newNode) { instructions.insertBefore(node, new VarInsnNode(ALOAD, newVarIndex)); stackSize1 += 1; } } updateMaxStack(stackSize1); } } stackSize1 += (sizes & 0x03) - argSize; updateMaxStack(stackSize1); return stackSize1; }
From source file:pl.clareo.coroutines.core.ClassTransformer.java
License:Apache License
private static String getCoroutineName(MethodNode method) { // little name mangling, let's feel like we were writing C++ compiler // :-)//w ww . j a v a 2 s. c o m StringBuilder sb = new StringBuilder(method.name); int descHash = abs(Type.getArgumentsAndReturnSizes(method.desc)); sb.append(descHash); Type[] argsTypes = Type.getArgumentTypes(method.desc); for (Type t : argsTypes) { if (t.getSort() == Type.OBJECT) { String argClassname = t.getClassName(); sb.append('_').append(abs(argClassname.hashCode())); } else { sb.append('_').append(t.getSort()); } } return sb.toString(); }
From source file:pl.clareo.coroutines.core.ClassTransformer.java
License:Apache License
@SuppressWarnings("unchecked") void transform() { for (MethodNode coroutine : coroutines) { if (log.isLoggable(Level.FINEST)) { log.finest("Generating method for coroutine " + coroutine.name + coroutine.desc); }//from ww w. j a va 2 s . com String coroutineName = getCoroutineName(coroutine); MethodTransformer methodTransformer = new MethodTransformer(coroutine, thisType); MethodNode coroutineImpl = methodTransformer.transform(coroutineName, generateDebugCode); thisNode.methods.add(coroutineImpl); /* * generate co iterators and method stubs */ log.finest("Generating CoIterator implementation and method stubs"); String baseCoIteratorName; Map<String, Object> annotation = getCoroutineAnnotationValues(coroutine); if (getBoolean(annotation, "threadLocal")) { baseCoIteratorName = Type.getInternalName(ThreadLocalCoIterator.class); } else { baseCoIteratorName = Type.getInternalName(SingleThreadedCoIterator.class); } String coIteratorClassName = "pl/clareo/coroutines/core/CoIterator" + num; ClassNode coIteratorClass = new ClassNode(); coIteratorClass.version = Opcodes.V1_6; coIteratorClass.access = Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_SUPER; coIteratorClass.name = coIteratorClassName; coIteratorClass.superName = baseCoIteratorName; if (generateDebugCode) { /* * If debugging code is emitted create field keeping JDK logger */ FieldNode loggerField = new FieldNode(Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC, "logger", "Ljava/util/logging/Logger;", null, null); coIteratorClass.fields.add(loggerField); MethodNode clinit = new MethodNode(); clinit.access = Opcodes.ACC_STATIC; clinit.name = "<clinit>"; clinit.desc = "()V"; clinit.exceptions = Collections.EMPTY_LIST; String loggerName = thisType.getClassName(); InsnList clinitCode = clinit.instructions; clinitCode.add(new LdcInsnNode(loggerName)); clinitCode.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/util/logging/Logger", "getLogger", "(Ljava/lang/String;)Ljava/util/logging/Logger;")); clinitCode.add(new FieldInsnNode(Opcodes.PUTSTATIC, coIteratorClassName, "logger", "Ljava/util/logging/Logger;")); clinitCode.add(new InsnNode(Opcodes.RETURN)); clinit.maxStack = 1; clinit.maxLocals = 0; coIteratorClass.methods.add(clinit); } /* * Generate constructor */ MethodNode init = new MethodNode(); init.access = Opcodes.ACC_PUBLIC; init.name = "<init>"; init.desc = CO_ITERATOR_CONSTRUCTOR_DESCRIPTOR; init.exceptions = Collections.EMPTY_LIST; InsnList initCode = init.instructions; initCode.add(new VarInsnNode(Opcodes.ALOAD, 0)); initCode.add(new VarInsnNode(Opcodes.ALOAD, 1)); initCode.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, baseCoIteratorName, "<init>", CO_ITERATOR_CONSTRUCTOR_DESCRIPTOR)); initCode.add(new InsnNode(Opcodes.RETURN)); init.maxStack = 2; init.maxLocals = 2; coIteratorClass.methods.add(init); /* * Generate overriden call to coroutine */ MethodNode call = new MethodNode(); call.access = Opcodes.ACC_PROTECTED; call.name = "call"; call.desc = CALL_METHOD_DESCRIPTOR; call.exceptions = Collections.EMPTY_LIST; InsnList callCode = call.instructions; /* * if debug needed generate call details */ if (generateDebugCode) { String coroutineId = "Coroutine " + coroutine.name; callCode.add(loggingInstructions(coIteratorClassName, "logger", Level.FINER, coroutineId + " call. Caller sent: ", 2)); callCode.add(new FrameNode(Opcodes.F_SAME, 0, EMPTY_LOCALS, 0, EMPTY_STACK)); callCode.add(loggingInstructions(coIteratorClassName, "logger", Level.FINEST, coroutineId + " state ", 1)); callCode.add(new FrameNode(Opcodes.F_SAME, 0, EMPTY_LOCALS, 0, EMPTY_STACK)); } /* * push call arguments: this (if not static), frame, input, output */ boolean isStatic = (coroutine.access & Opcodes.ACC_STATIC) != 0; if (!isStatic) { callCode.add(new VarInsnNode(Opcodes.ALOAD, 1)); callCode.add( new MethodInsnNode(Opcodes.INVOKEVIRTUAL, FRAME_NAME, "getThis", "()Ljava/lang/Object;")); callCode.add(new TypeInsnNode(Opcodes.CHECKCAST, thisType.getInternalName())); } callCode.add(new VarInsnNode(Opcodes.ALOAD, 1)); callCode.add(new InsnNode(Opcodes.ACONST_NULL)); callCode.add(new VarInsnNode(Opcodes.ALOAD, 2)); callCode.add(new MethodInsnNode(isStatic ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, thisType.getInternalName(), coroutineName, COROUTINE_METHOD_DESCRIPTOR)); // stack: * if (!generateDebugCode) { callCode.add(new InsnNode(Opcodes.ARETURN)); } else { // save result display suspension point (two more locals // needed) callCode.add(new VarInsnNode(Opcodes.ASTORE, 3)); callCode.add(new VarInsnNode(Opcodes.ALOAD, 1)); callCode.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, FRAME_NAME, "getLineOfCode", "()I")); callCode.add(box_int(Type.INT)); callCode.add(new VarInsnNode(Opcodes.ASTORE, 4)); callCode.add(loggingInstructions(coIteratorClassName, "logger", Level.FINER, "Coroutine suspended at line ", 4, ". Yielded:", 3)); callCode.add(new FrameNode(Opcodes.F_APPEND, 2, new Object[] { "java/lang/Object", "java/lang/Integer" }, 0, EMPTY_STACK)); callCode.add(new VarInsnNode(Opcodes.ALOAD, 3)); callCode.add(new InsnNode(Opcodes.ARETURN)); } coIteratorClass.methods.add(call); // if debugging code is emitted it needs space for two // additional locals and 5 stack operand if (generateDebugCode) { call.maxStack = 5; call.maxLocals = 5; } else { if (isStatic) { call.maxStack = 3; } else { call.maxStack = 4; } call.maxLocals = 3; } /* * CoIterator created - define it in the runtime and verify if * needed */ if (log.isLoggable(Level.FINEST)) { log.finest("Generated class " + coIteratorClassName); } ClassWriter cw = new ClassWriter(0); coIteratorClass.accept(cw); byte[] classBytes = cw.toByteArray(); try { CoroutineInstrumentator.dumpClass(coIteratorClassName, classBytes); } catch (IOException e) { throw new CoroutineGenerationException("Unable to write class " + coIteratorClassName, e); } /* * start generating method - new method is named as the method in * user code, it: returns instance of appropriate CoIterator (see * above), saves arguments of call */ if (log.isLoggable(Level.FINEST)) { log.finest("Instrumenting method " + coroutine.name); } InsnList code = coroutine.instructions; code.clear(); /* * create new Frame */ boolean isDebugFramePossible = generateDebugCode && coroutine.localVariables != null; if (isDebugFramePossible) { code.add(createDebugFrame(coroutine)); } else { code.add(createFrame(coroutine)); } /* * save frame in the first, and locals array in the second local * variable */ int argsSize = Type.getArgumentsAndReturnSizes(coroutine.desc) >> 2; if (isStatic) { argsSize -= 1; } code.add(new VarInsnNode(Opcodes.ASTORE, argsSize)); code.add(new VarInsnNode(Opcodes.ALOAD, argsSize)); code.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, FRAME_NAME, "getLocals", "()[Ljava/lang/Object;")); int localsArrayIndex = argsSize + 1; code.add(new VarInsnNode(Opcodes.ASTORE, localsArrayIndex)); /* * save all call arguments (along with this if this method is not * static) into locals array */ Type[] argsTypes = Type.getArgumentTypes(coroutine.desc); if (!isStatic) { code.add(saveloc(localsArrayIndex, 0, 0, JAVA_LANG_OBJECT)); code.add(savelocs(localsArrayIndex, 1, 1, argsTypes)); } else { code.add(savelocs(localsArrayIndex, 0, 0, argsTypes)); } /* * create CoIterator instance with saved frame, make initial call to * next if needed and return to caller */ code.add(new TypeInsnNode(Opcodes.NEW, coIteratorClassName)); code.add(new InsnNode(Opcodes.DUP)); code.add(new VarInsnNode(Opcodes.ALOAD, argsSize)); code.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, coIteratorClassName, "<init>", CO_ITERATOR_CONSTRUCTOR_DESCRIPTOR)); if (!getBoolean(annotation, "generator", true)) { code.add(new InsnNode(Opcodes.DUP)); code.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, coIteratorClassName, "next", "()Ljava/lang/Object;")); code.add(new InsnNode(Opcodes.POP)); } code.add(new InsnNode(Opcodes.ARETURN)); /* * end method generation; maxs can be statically determined 3 * operands on stack (call to frame setLocals and CoIterator * constructor) + 1 if any argument is long or double (debug frame * needs 7 operands for variable names creation); locals = argsSize * + 1 reference to frame + 1 array of locals */ if (isDebugFramePossible) { coroutine.maxStack = 7; } else { boolean isCategory2ArgumentPresent = false; for (Type argType : argsTypes) { int sort = argType.getSort(); if (sort == Type.LONG || sort == Type.DOUBLE) { isCategory2ArgumentPresent = true; break; } } coroutine.maxStack = isCategory2ArgumentPresent ? 4 : 3; } coroutine.maxLocals = localsArrayIndex + 1; coroutine.localVariables.clear(); coroutine.tryCatchBlocks.clear(); num++; } }