1 package org.robolectric.internal.bytecode; 2 3 import static org.objectweb.asm.Type.ARRAY; 4 import static org.objectweb.asm.Type.OBJECT; 5 6 import java.lang.reflect.Modifier; 7 import org.objectweb.asm.Opcodes; 8 import org.objectweb.asm.Type; 9 import org.objectweb.asm.commons.GeneratorAdapter; 10 import org.objectweb.asm.tree.MethodNode; 11 import org.robolectric.internal.bytecode.ClassInstrumentor.TryCatch; 12 13 /** 14 * GeneratorAdapter implementation specific to generate code for Robolectric purposes 15 */ 16 public class RobolectricGeneratorAdapter extends GeneratorAdapter { 17 final boolean isStatic; 18 private final String desc; 19 RobolectricGeneratorAdapter(MethodNode methodNode)20 public RobolectricGeneratorAdapter(MethodNode methodNode) { 21 super(Opcodes.ASM4, methodNode, methodNode.access, methodNode.name, methodNode.desc); 22 this.isStatic = Modifier.isStatic(methodNode.access); 23 this.desc = methodNode.desc; 24 } 25 loadThisOrNull()26 public void loadThisOrNull() { 27 if (isStatic) { 28 loadNull(); 29 } else { 30 loadThis(); 31 } 32 } 33 isStatic()34 public boolean isStatic() { 35 return isStatic; 36 } 37 loadNull()38 public void loadNull() { 39 visitInsn(Opcodes.ACONST_NULL); 40 } 41 42 @Override getReturnType()43 public Type getReturnType() { 44 return Type.getReturnType(desc); 45 } 46 47 /** 48 * Forces a return of a default value, depending on the method's return type 49 * 50 * @param type The method's return type 51 */ pushDefaultReturnValueToStack(Type type)52 public void pushDefaultReturnValueToStack(Type type) { 53 if (type.equals(Type.BOOLEAN_TYPE)) { 54 push(false); 55 } else if (type.equals(Type.INT_TYPE) || type.equals(Type.SHORT_TYPE) || type.equals(Type.BYTE_TYPE) || type.equals(Type.CHAR_TYPE)) { 56 push(0); 57 } else if (type.equals(Type.LONG_TYPE)) { 58 push(0L); 59 } else if (type.equals(Type.FLOAT_TYPE)) { 60 push(0f); 61 } else if (type.equals(Type.DOUBLE_TYPE)) { 62 push(0d); 63 } else if (type.getSort() == ARRAY || type.getSort() == OBJECT) { 64 loadNull(); 65 } 66 } 67 invokeMethod(String internalClassName, MethodNode method)68 public void invokeMethod(String internalClassName, MethodNode method) { 69 invokeMethod(internalClassName, method.name, method.desc); 70 } 71 invokeMethod(String internalClassName, String methodName, String methodDesc)72 void invokeMethod(String internalClassName, String methodName, String methodDesc) { 73 if (isStatic()) { 74 loadArgs(); // this, [args] 75 visitMethodInsn(Opcodes.INVOKESTATIC, internalClassName, methodName, methodDesc, false); 76 } else { 77 loadThisOrNull(); // this 78 loadArgs(); // this, [args] 79 visitMethodInsn(Opcodes.INVOKESPECIAL, internalClassName, methodName, methodDesc, false); 80 } 81 } 82 tryStart(Type exceptionType)83 public TryCatch tryStart(Type exceptionType) { 84 return new TryCatch(this, exceptionType); 85 } 86 } 87