/*
* Copyright 2009-2010 MBTE Sweden AB.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mbte.groovypp.compiler.bytecode;
import org.codehaus.groovy.ast.*;
import org.codehaus.groovy.ast.expr.MethodCallExpression;
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
import static org.codehaus.groovy.ast.ClassHelper.*;
import org.codehaus.groovy.classgen.BytecodeExpression;
import org.codehaus.groovy.classgen.BytecodeHelper;
import org.codehaus.groovy.classgen.ClassGeneratorException;
import org.codehaus.groovy.reflection.ReflectionCache;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
import org.codehaus.groovy.syntax.Types;
import org.mbte.groovypp.compiler.CompilerTransformer;
import org.mbte.groovypp.compiler.PresentationUtil;
import org.mbte.groovypp.compiler.TypeUtil;
import org.mbte.groovypp.compiler.Register;
import org.mbte.groovypp.runtime.DefaultGroovyPPMethods;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.math.BigDecimal;
import java.math.BigInteger;
public abstract class BytecodeExpr extends BytecodeExpression implements Opcodes {
public final void visit(MethodVisitor mv) {
compile(mv);
}
public BytecodeExpr(ASTNode parent, ClassNode type) {
setSourcePosition(parent);
setType(type);
}
protected abstract void compile(MethodVisitor mv);
public BytecodeExpr createPrefixOp(ASTNode exp, int type, CompilerTransformer compiler) {
ClassNode vtype = getType();
if (TypeUtil.isNumericalType(vtype)) {
return new BytecodeExpr(exp, vtype) {
protected void compile(MethodVisitor mv) {
BytecodeExpr.this.visit(mv);
}
};
}
if (ClassHelper.isPrimitiveType(vtype))
vtype = TypeUtil.wrapSafely(vtype);
String methodName = type == Types.PLUS_PLUS ? "next" : "previous";
final MethodNode methodNode = compiler.findMethod(vtype, methodName, ClassNode.EMPTY_ARRAY, false);
if (methodNode == null) {
compiler.addError("Cannot find method " + methodName + "() for type " + PresentationUtil.getText(vtype), exp);
return null;
}
final BytecodeExpr nextCall = (BytecodeExpr) compiler.transform(new MethodCallExpression(
new BytecodeExpr(exp, vtype) {
protected void compile(MethodVisitor mv) {
}
},
methodName,
new ArgumentListExpression()
));
return new BytecodeExpr(exp, vtype) {
protected void compile(MethodVisitor mv) {
BytecodeExpr.this.visit(mv);
mv.visitInsn(DUP);
nextCall.visit(mv);
pop(nextCall.getType(), mv);
}
};
}
public BytecodeExpr createPostfixOp(ASTNode exp, int type, CompilerTransformer compiler) {
ClassNode vtype = getType();
if (TypeUtil.isNumericalType(vtype)) {
return new BytecodeExpr(exp, vtype) {
protected void compile(MethodVisitor mv) {
BytecodeExpr.this.visit(mv);
}
};
}
if (ClassHelper.isPrimitiveType(vtype))
vtype = TypeUtil.wrapSafely(vtype);
String methodName = type == Types.PLUS_PLUS ? "next" : "previous";
final MethodNode methodNode = compiler.findMethod(vtype, methodName, ClassNode.EMPTY_ARRAY, false);
if (methodNode == null) {
compiler.addError("Cannot find method " + methodName + " for type " + PresentationUtil.getText(vtype), exp);
return null;
}
final BytecodeExpr nextCall = (BytecodeExpr) compiler.transform(new MethodCallExpression(
new BytecodeExpr(exp, vtype) {
protected void compile(MethodVisitor mv) {
}
},
methodName,
new ArgumentListExpression()
));
return new BytecodeExpr(exp, vtype) {
protected void compile(MethodVisitor mv) {
BytecodeExpr.this.visit(mv);
mv.visitInsn(DUP);
nextCall.visit(mv);
pop(nextCall.getType(), mv);
}
};
}
/**
* box the primitive value on the stack
*
* @param type
* @param mv
*/
public void quickBoxIfNecessary(ClassNode type, MethodVisitor mv) {
String descr = getTypeDescription(type);
if (type == boolean_TYPE) {
boxBoolean(mv);
} else if (isPrimitiveType(type) && type != VOID_TYPE) {
ClassNode wrapper = TypeUtil.wrapSafely(type);
String internName = getClassInternalName(wrapper);
mv.visitTypeInsn(Opcodes.NEW, internName);
mv.visitInsn(Opcodes.DUP);
if (type == double_TYPE || type == long_TYPE) {
mv.visitInsn(Opcodes.DUP2_X2);
mv.visitInsn(Opcodes.POP2);
} else {
mv.visitInsn(Opcodes.DUP2_X1);
mv.visitInsn(Opcodes.POP2);
}
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, internName, "<init>", "(" + descr + ")V");
}
}
public static void box(ClassNode type, MethodVisitor mv) {
if (type.isPrimaryClassNode()) return;
Class type1 = type.getTypeClass();
if (ReflectionCache.getCachedClass(type1).isPrimitive && type1 != void.class) {
String returnString = "(" + getTypeDescription(type) + ")" + getTypeDescription(TypeUtil.wrapSafely(type));
mv.visitMethodInsn(Opcodes.INVOKESTATIC, getClassInternalName(DefaultGroovyPPMethods.class.getName()), "box", returnString);
}
}
/**
* Generates the bytecode to unbox the current value on the stack
*/
public static void unbox(Class type, MethodVisitor mv) {
if (type.isPrimitive() && type != Void.TYPE) {
String returnString = "(Ljava/lang/Object;)" + getTypeDescription(type);
mv.visitMethodInsn(
Opcodes.INVOKESTATIC,
getClassInternalName(DefaultTypeTransformation.class.getName()),
type.getName() + "Unbox",
returnString);
}
}
public static void unbox(ClassNode type, MethodVisitor mv) {
if (type.isPrimaryClassNode()) return;
unbox(type.getTypeClass(), mv);
}
public static String getClassInternalName(ClassNode t) {
if (t.isPrimaryClassNode()) {
return getClassInternalName(t.getName());
}
return getClassInternalName(t.getTypeClass());
}
public static String getClassInternalName(Class t) {
return org.objectweb.asm.Type.getInternalName(t);
}
/**
* @return the ASM internal name of the type
*/
public static String getClassInternalName(String name) {
return name.replace('.', '/');
}
/**
* @return the ASM method type descriptor
*/
public static String getMethodDescriptor(ClassNode returnType, Parameter[] parameters) {
StringBuffer buffer = new StringBuffer("(");
for (int i = 0; i < parameters.length; i++) {
buffer.append(getTypeDescription(parameters[i].getType()));
}
buffer.append(")");
buffer.append(getTypeDescription(returnType));
return buffer.toString();
}
/**
* @return the ASM method type descriptor
*/
public static String getMethodDescriptor(Class returnType, Class[] paramTypes) {
// lets avoid class loading
StringBuffer buffer = new StringBuffer("(");
for (int i = 0; i < paramTypes.length; i++) {
buffer.append(getTypeDescription(paramTypes[i]));
}
buffer.append(")");
buffer.append(getTypeDescription(returnType));
return buffer.toString();
}
public static String getTypeDescription(Class c) {
return org.objectweb.asm.Type.getDescriptor(c);
}
/**
* array types are special:
* eg.: String[]: classname: [Ljava.lang.String;
* Object: classname: java.lang.Object
* int[] : classname: [I
* unlike getTypeDescription '.' is not replaced by '/'.
* it seems that makes problems for
* the class loading if '.' is replaced by '/'
*
* @return the ASM type description for class loading
*/
public static String getClassLoadingTypeDescription(ClassNode c) {
StringBuffer buf = new StringBuffer();
boolean array = false;
while (true) {
if (c.isArray()) {
buf.append('[');
c = c.getComponentType();
array = true;
} else {
if (isPrimitiveType(c)) {
buf.append(getTypeDescription(c));
} else {
if (array) buf.append('L');
buf.append(c.getName());
if (array) buf.append(';');
}
return buf.toString();
}
}
}
/**
* array types are special:
* eg.: String[]: classname: [Ljava/lang/String;
* int[]: [I
*
* @return the ASM type description
*/
public static String getTypeDescription(ClassNode c) {
return getTypeDescription(c, true);
}
/**
* array types are special:
* eg.: String[]: classname: [Ljava/lang/String;
* int[]: [I
*
* @return the ASM type description
*/
private static String getTypeDescription(ClassNode c, boolean end) {
StringBuffer buf = new StringBuffer();
ClassNode d = c;
while (true) {
if (isPrimitiveType(d)) {
char car;
if (d == int_TYPE) {
car = 'I';
} else if (d == VOID_TYPE) {
car = 'V';
} else if (d == boolean_TYPE) {
car = 'Z';
} else if (d == byte_TYPE) {
car = 'B';
} else if (d == char_TYPE) {
car = 'C';
} else if (d == short_TYPE) {
car = 'S';
} else if (d == double_TYPE) {
car = 'D';
} else if (d == float_TYPE) {
car = 'F';
} else /* long */ {
car = 'J';
}
buf.append(car);
return buf.toString();
} else if (d.isArray()) {
buf.append('[');
d = d.getComponentType();
} else {
buf.append('L');
String name = d.getName();
int len = name.length();
for (int i = 0; i < len; ++i) {
char car = name.charAt(i);
buf.append(car == '.' ? '/' : car);
}
if (end) buf.append(';');
return buf.toString();
}
}
}
/**
* @return an array of ASM internal names of the type
*/
public static String[] getClassInternalNames(ClassNode[] names) {
int size = names.length;
String[] answer = new String[size];
for (int i = 0; i < size; i++) {
answer[i] = getClassInternalName(names[i]);
}
return answer;
}
protected void pushConstant(boolean value, MethodVisitor mv) {
if (value) {
mv.visitInsn(Opcodes.ICONST_1);
} else {
mv.visitInsn(Opcodes.ICONST_0);
}
}
public void pushConstant(int value, MethodVisitor mv) {
switch (value) {
case 0:
mv.visitInsn(Opcodes.ICONST_0);
break;
case 1:
mv.visitInsn(Opcodes.ICONST_1);
break;
case 2:
mv.visitInsn(Opcodes.ICONST_2);
break;
case 3:
mv.visitInsn(Opcodes.ICONST_3);
break;
case 4:
mv.visitInsn(Opcodes.ICONST_4);
break;
case 5:
mv.visitInsn(Opcodes.ICONST_5);
break;
default:
if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, value);
} else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, value);
} else {
mv.visitLdcInsn(Integer.valueOf(value));
}
}
}
public static void load(ClassNode type, int idx, MethodVisitor mv) {
if (type == double_TYPE) {
mv.visitVarInsn(Opcodes.DLOAD, idx);
} else if (type == float_TYPE) {
mv.visitVarInsn(Opcodes.FLOAD, idx);
} else if (type == long_TYPE) {
mv.visitVarInsn(Opcodes.LLOAD, idx);
} else if (
type == boolean_TYPE
|| type == char_TYPE
|| type == byte_TYPE
|| type == int_TYPE
|| type == short_TYPE) {
mv.visitVarInsn(Opcodes.ILOAD, idx);
} else {
mv.visitVarInsn(Opcodes.ALOAD, idx);
}
}
public static void load(Register v, MethodVisitor mv) {
load(v.getType(), v.getIndex(), mv);
}
public static void store(ClassNode type, int idx, MethodVisitor mv) {
if (type == double_TYPE) {
mv.visitVarInsn(Opcodes.DSTORE, idx);
} else if (type == float_TYPE) {
mv.visitVarInsn(Opcodes.FSTORE, idx);
} else if (type == long_TYPE) {
mv.visitVarInsn(Opcodes.LSTORE, idx);
} else if (
type == boolean_TYPE
|| type == char_TYPE
|| type == byte_TYPE
|| type == int_TYPE
|| type == short_TYPE) {
mv.visitVarInsn(Opcodes.ISTORE, idx);
} else {
mv.visitVarInsn(Opcodes.ASTORE, idx);
}
}
/**
* load the constant on the operand stack. primitives auto-boxed.
*/
void loadConstant(Object value, MethodVisitor mv) {
if (value == null) {
mv.visitInsn(Opcodes.ACONST_NULL);
} else if (value instanceof String) {
mv.visitLdcInsn(value);
} else if (value instanceof Character) {
String className = "java/lang/Character";
mv.visitTypeInsn(Opcodes.NEW, className);
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn(value);
String methodType = "(C)V";
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, className, "<init>", methodType);
} else if (value instanceof Number) {
/** todo it would be more efficient to generate class constants */
Number n = (Number) value;
String className = BytecodeHelper.getClassInternalName(value.getClass().getName());
mv.visitTypeInsn(Opcodes.NEW, className);
mv.visitInsn(Opcodes.DUP);
String methodType;
if (n instanceof Integer) {
//pushConstant(n.intValue());
mv.visitLdcInsn(n);
methodType = "(I)V";
} else if (n instanceof Double) {
mv.visitLdcInsn(n);
methodType = "(D)V";
} else if (n instanceof Float) {
mv.visitLdcInsn(n);
methodType = "(F)V";
} else if (n instanceof Long) {
mv.visitLdcInsn(n);
methodType = "(J)V";
} else if (n instanceof BigDecimal) {
mv.visitLdcInsn(n.toString());
methodType = "(Ljava/lang/String;)V";
} else if (n instanceof BigInteger) {
mv.visitLdcInsn(n.toString());
methodType = "(Ljava/lang/String;)V";
} else if (n instanceof Short) {
mv.visitLdcInsn(n);
methodType = "(S)V";
} else if (n instanceof Byte) {
mv.visitLdcInsn(n);
methodType = "(B)V";
} else {
throw new ClassGeneratorException(
"Cannot generate bytecode for constant: " + value
+ " of type: " + value.getClass().getName()
+ ". Numeric constant type not supported.");
}
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, className, "<init>", methodType);
} else if (value instanceof Boolean) {
Boolean bool = (Boolean) value;
String text = (bool.booleanValue()) ? "TRUE" : "FALSE";
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", text, "Ljava/lang/Boolean;");
} else if (value instanceof Class) {
Class vc = (Class) value;
if (vc.getName().equals("java.lang.Void")) {
// load nothing here for void
} else {
throw new ClassGeneratorException(
"Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
}
} else {
throw new ClassGeneratorException(
"Cannot generate bytecode for constant: " + value + " of type: " + value.getClass().getName());
}
}
/**
* load the value of the variable on the operand stack. unbox it if it's a reference
*
* @param variable
* @param mv
*/
public static void loadVar(Register variable, MethodVisitor mv) {
load(variable, mv);
box(variable.getType(), mv);
}
public void putField(FieldNode fld, MethodVisitor mv) {
putField(fld, getClassInternalName(fld.getOwner()), mv);
}
public void putField(FieldNode fld, String ownerName, MethodVisitor mv) {
mv.visitFieldInsn(Opcodes.PUTFIELD, ownerName, fld.getName(), getTypeDescription(fld.getType()));
}
public void swapObjectWith(ClassNode type, MethodVisitor mv) {
if (type == long_TYPE || type == double_TYPE) {
mv.visitInsn(Opcodes.DUP_X2);
mv.visitInsn(Opcodes.POP);
} else {
mv.visitInsn(Opcodes.SWAP);
}
}
public void swapWithObject(ClassNode type, MethodVisitor mv) {
if (type == long_TYPE || type == double_TYPE) {
mv.visitInsn(Opcodes.DUP2_X1);
mv.visitInsn(Opcodes.POP2);
} else {
mv.visitInsn(Opcodes.SWAP);
}
}
public static ClassNode boxOnPrimitive(ClassNode type) {
if (!type.isArray()) return TypeUtil.wrapSafely(type);
return boxOnPrimitive(type.getComponentType()).makeArray();
}
/**
* convert boolean to Boolean
* @param mv
*/
public void boxBoolean(MethodVisitor mv) {
Label l0 = new Label();
mv.visitJumpInsn(Opcodes.IFEQ, l0);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
Label l1 = new Label();
mv.visitJumpInsn(Opcodes.GOTO, l1);
mv.visitLabel(l0);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
mv.visitLabel(l1);
}
/**
* negate a boolean on stack. true->false, false->true
* @param mv
*/
public void negateBoolean(MethodVisitor mv) {
// code to negate the primitive boolean
Label endLabel = new Label();
Label falseLabel = new Label();
mv.visitJumpInsn(Opcodes.IFNE, falseLabel);
mv.visitInsn(Opcodes.ICONST_1);
mv.visitJumpInsn(Opcodes.GOTO, endLabel);
mv.visitLabel(falseLabel);
mv.visitInsn(Opcodes.ICONST_0);
mv.visitLabel(endLabel);
}
/**
* load a message on the stack and remove it right away. Good for put a mark in the generated bytecode for debugging purpose.
*
* @param msg
* @param mv
*/
public void mark(String msg, MethodVisitor mv) {
mv.visitLdcInsn(msg);
mv.visitInsn(Opcodes.POP);
}
/**
* returns a name that Class.forName() can take. Notablely for arrays:
* [I, [Ljava.lang.String; etc
* Regular object type: java.lang.String
*
* @param name
*/
public static String formatNameForClassLoading(String name) {
if (name == null) {
return "java.lang.Object;";
}
if (name.equals("int")
|| name.equals("long")
|| name.equals("short")
|| name.equals("float")
|| name.equals("double")
|| name.equals("byte")
|| name.equals("char")
|| name.equals("boolean")
|| name.equals("void")
) {
return name;
}
if (name.startsWith("[")) {
return name.replace('/', '.');
}
if (name.startsWith("L")) {
name = name.substring(1);
if (name.endsWith(";")) {
name = name.substring(0, name.length() - 1);
}
return name.replace('/', '.');
}
String prefix = "";
if (name.endsWith("[]")) { // todo need process multi
prefix = "[";
name = name.substring(0, name.length() - 2);
if (name.equals("int")) {
return prefix + "I";
} else if (name.equals("long")) {
return prefix + "J";
} else if (name.equals("short")) {
return prefix + "S";
} else if (name.equals("float")) {
return prefix + "F";
} else if (name.equals("double")) {
return prefix + "D";
} else if (name.equals("byte")) {
return prefix + "B";
} else if (name.equals("char")) {
return prefix + "C";
} else if (name.equals("boolean")) {
return prefix + "Z";
} else {
return prefix + "L" + name.replace('/', '.') + ";";
}
}
return name.replace('/', '.');
}
public static void dup(ClassNode type, MethodVisitor mv) {
if (type == double_TYPE || type == long_TYPE)
mv.visitInsn(Opcodes.DUP2);
else
mv.visitInsn(Opcodes.DUP);
}
public static void dup_x1(ClassNode type, MethodVisitor mv) {
if (type == double_TYPE || type == long_TYPE)
mv.visitInsn(Opcodes.DUP2_X1);
else
mv.visitInsn(Opcodes.DUP_X1);
}
public static void dup_x2(ClassNode type, MethodVisitor mv) {
if (type == double_TYPE || type == long_TYPE)
mv.visitInsn(Opcodes.DUP2_X2);
else
mv.visitInsn(Opcodes.DUP_X2);
}
public static void pop(ClassNode type, MethodVisitor mv) {
if (type == double_TYPE || type == long_TYPE)
mv.visitInsn(Opcodes.POP2);
else
mv.visitInsn(Opcodes.POP);
}
public static void doReturn(MethodVisitor mv, ClassNode returnType) {
if (returnType == double_TYPE) {
mv.visitInsn(Opcodes.DRETURN);
} else if (returnType == float_TYPE) {
mv.visitInsn(Opcodes.FRETURN);
} else if (returnType == long_TYPE) {
mv.visitInsn(Opcodes.LRETURN);
} else if (
returnType == boolean_TYPE
|| returnType == char_TYPE
|| returnType == byte_TYPE
|| returnType == int_TYPE
|| returnType == short_TYPE) {
//byte,short,boolean,int are all IRETURN
mv.visitInsn(Opcodes.IRETURN);
} else if (returnType == VOID_TYPE) {
mv.visitInsn(Opcodes.RETURN);
} else {
mv.visitInsn(Opcodes.ARETURN);
}
}
public void doReturn(ClassNode returnType, MethodVisitor mv) {
doReturn(mv, returnType);
}
private static boolean hasGenerics(Parameter[] param) {
if (param.length == 0) return false;
for (int i = 0; i < param.length; i++) {
ClassNode type = param[i].getType();
if (type.getGenericsTypes() != null) return true;
}
return false;
}
public static String getGenericsMethodSignature(MethodNode node) {
GenericsType[] generics = node.getGenericsTypes();
Parameter[] param = node.getParameters();
ClassNode returnType = node.getReturnType();
if (generics == null && !hasGenerics(param) && returnType.getGenericsTypes() == null) return null;
StringBuffer ret = new StringBuffer(100);
getGenericsTypeSpec(ret, generics);
GenericsType[] paramTypes = new GenericsType[param.length];
for (int i = 0; i < param.length; i++) {
ClassNode pType = param[i].getType();
if (pType.getGenericsTypes() == null || !pType.isGenericsPlaceHolder()) {
paramTypes[i] = new GenericsType(pType);
} else {
paramTypes[i] = pType.getGenericsTypes()[0];
}
}
addSubTypes(ret, paramTypes, "(", ")");
if (returnType.isGenericsPlaceHolder()) {
addSubTypes(ret, returnType.getGenericsTypes(), "", "");
} else {
writeGenericsBounds(ret, new GenericsType(returnType), false);
}
return ret.toString();
}
private static boolean usesGenericsInClassSignature(ClassNode node) {
if (!node.isUsingGenerics()) return false;
if (node.getGenericsTypes() != null) return true;
ClassNode sclass = node.getUnresolvedSuperClass(false);
if (sclass.isUsingGenerics()) return true;
ClassNode[] interfaces = node.getInterfaces();
if (interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].isUsingGenerics()) return true;
}
}
return false;
}
public static String getGenericsSignature(ClassNode node) {
if (!usesGenericsInClassSignature(node)) return null;
GenericsType[] genericsTypes = node.getGenericsTypes();
StringBuffer ret = new StringBuffer(100);
getGenericsTypeSpec(ret, genericsTypes);
GenericsType extendsPart = new GenericsType(node.getUnresolvedSuperClass(false));
writeGenericsBounds(ret, extendsPart, true);
ClassNode[] interfaces = node.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
GenericsType interfacePart = new GenericsType(interfaces[i]);
writeGenericsBounds(ret, interfacePart, false);
}
return ret.toString();
}
private static void getGenericsTypeSpec(StringBuffer ret, GenericsType[] genericsTypes) {
if (genericsTypes == null) return;
ret.append('<');
for (int i = 0; i < genericsTypes.length; i++) {
String name = genericsTypes[i].getName();
ret.append(name);
ret.append(':');
writeGenericsBounds(ret, genericsTypes[i], true);
}
ret.append('>');
}
public static String getGenericsBounds(ClassNode type) {
GenericsType[] genericsTypes = type.getGenericsTypes();
if (genericsTypes == null) return null;
StringBuffer ret = new StringBuffer(100);
if (type.isGenericsPlaceHolder()) {
addSubTypes(ret, type.getGenericsTypes(), "", "");
} else {
GenericsType gt = new GenericsType(type);
writeGenericsBounds(ret, gt, false);
}
return ret.toString();
}
private static void writeGenericsBoundType(StringBuffer ret, ClassNode printType, boolean writeInterfaceMarker) {
if (writeInterfaceMarker && printType.isInterface()) ret.append(":");
ret.append(getTypeDescription(printType, false));
addSubTypes(ret, printType.getGenericsTypes(), "<", ">");
if (!isPrimitiveType(printType)) ret.append(";");
}
private static void writeGenericsBounds(StringBuffer ret, GenericsType type, boolean writeInterfaceMarker) {
if (type.getUpperBounds() != null) {
ClassNode[] bounds = type.getUpperBounds();
for (int i = 0; i < bounds.length; i++) {
writeGenericsBoundType(ret, bounds[i], writeInterfaceMarker);
}
} else if (type.getLowerBound() != null) {
writeGenericsBoundType(ret, type.getLowerBound(), writeInterfaceMarker);
} else {
writeGenericsBoundType(ret, type.getType(), writeInterfaceMarker);
}
}
private static void addSubTypes(StringBuffer ret, GenericsType[] types, String start, String end) {
if (types == null) return;
ret.append(start);
for (int i = 0; i < types.length; i++) {
String name = types[i].getName();
if (types[i].isPlaceholder()) {
ret.append('T');
ret.append(name);
ret.append(';');
} else if (types[i].isWildcard()) {
if (types[i].getUpperBounds() != null) {
ret.append('+');
writeGenericsBounds(ret, types[i], false);
} else if (types[i].getLowerBound() != null) {
ret.append('-');
writeGenericsBounds(ret, types[i], false);
} else {
ret.append('*');
}
} else {
writeGenericsBounds(ret, types[i], false);
}
}
ret.append(end);
}
public static boolean isIntegralType(ClassNode expr) {
return expr.equals(Integer_TYPE) || expr.equals(Byte_TYPE) || expr.equals(Short_TYPE);
}
public static void cast(ClassNode expr, ClassNode type, MethodVisitor mv) {
if (isPrimitiveType(expr) || isPrimitiveType(type)) {
throw new RuntimeException("Cannot convert " + expr.getName() + " to " + type.getName());
}
expr = expr.redirect();
type = type.redirect();
if (TypeUtil.isDirectlyAssignableFrom(type, expr)) {
return;
}
if (expr.isArray()) {
castArray (expr, type, mv);
} else if (isIntegralType(expr)) {
castIntegral(expr, type, mv);
} else if (expr == Character_TYPE) {
unbox(getUnwrapper(expr), mv);
box (int_TYPE, mv);
castIntegral(Integer_TYPE, type, mv);
} else if (expr == Boolean_TYPE) {
unbox(getUnwrapper(expr), mv);
box (int_TYPE, mv);
castIntegral(Integer_TYPE, type, mv);
} else if (expr == Long_TYPE) {
castLong(expr, type, mv);
} else if (expr == Double_TYPE) {
castDouble(expr, type, mv);
} else if (expr == Float_TYPE) {
castFloat(expr, type, mv);
} else if (expr == BigDecimal_TYPE) {
castBigDecimal(expr, type, mv);
} else if (expr == BigInteger_TYPE) {
castBigInteger(expr, type, mv);
} else if (expr == STRING_TYPE) {
castString(expr, type, mv);
} else if (expr.equals(TypeUtil.Number_TYPE)) {
castNumber(expr, type, mv);
} else if (expr.implementsInterface(TypeUtil.COLLECTION_TYPE) && type.isArray()) {
castArrayToCollection(expr, type, mv);
} else {
if (TypeUtil.isNumericalType(type) && !type.equals(TypeUtil.Number_TYPE)) {
if(TypeUtil.isBigDecimal(type) || TypeUtil.isBigInteger(type)) {
checkCast(type, mv);
} else {
Label nullLabel = new Label(), doneLabel = new Label();
mv.visitInsn(DUP);
mv.visitJumpInsn(IFNULL, nullLabel);
unbox(getUnwrapper(type), mv);
box(getUnwrapper(type), mv);
mv.visitJumpInsn(GOTO, doneLabel);
mv.visitLabel(nullLabel);
checkCast(type, mv);
mv.visitLabel(doneLabel);
}
} else {
if (expr != TypeUtil.NULL_TYPE) {
if (type.equals(STRING_TYPE)) {
Label nullLabel = new Label(), doneLabel = new Label();
mv.visitInsn(DUP);
mv.visitJumpInsn(IFNULL, nullLabel);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
mv.visitJumpInsn(GOTO, doneLabel);
mv.visitLabel(nullLabel);
checkCast(type, mv);
mv.visitLabel(doneLabel);
} else {
checkCast(type, mv);
}
}
}
}
}
private static void castArray(ClassNode expr, ClassNode type, MethodVisitor mv) {
mv.visitLdcInsn(BytecodeHelper.getClassLoadingTypeDescription(type));
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/ScriptBytecodeAdapter", "asType", "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
checkCast(type, mv);
}
private static void castNumber(ClassNode expr, ClassNode type, MethodVisitor mv) {
if (type == Integer_TYPE) {
unbox(int_TYPE, mv);
box(int_TYPE, mv);
} else if (type == Boolean_TYPE) {
unbox(int_TYPE, mv);
box(boolean_TYPE, mv);
} else if (type == Byte_TYPE) {
unbox(int_TYPE, mv);
box(byte_TYPE, mv);
} else if (type == Short_TYPE) {
unbox(int_TYPE, mv);
box(short_TYPE, mv);
} else if (type == Character_TYPE) {
unbox(int_TYPE, mv);
box(char_TYPE, mv);
} else if (type == Long_TYPE) {
unbox(long_TYPE, mv);
box(long_TYPE, mv);
} else if (type == Float_TYPE) {
unbox(float_TYPE, mv);
box(float_TYPE, mv);
} else if (type == Double_TYPE) {
unbox(double_TYPE, mv);
box(double_TYPE, mv);
} else if (type == BigDecimal_TYPE) {
mv.visitMethodInsn(INVOKESTATIC, "org/mbte/groovypp/runtime/DefaultGroovyPPMethods", "asBigDecimal", "(Ljava/lang/Number;)Ljava/math/BigDecimal;");
} else if (type == BigInteger_TYPE) {
if (expr.equals(Character_TYPE)) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
box(int_TYPE, mv);
}
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
mv.visitTypeInsn(NEW, "java/math/BigInteger");
mv.visitInsn(DUP_X1);
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKESPECIAL, "java/math/BigInteger", "<init>", "(Ljava/lang/String;)V");
} else {
checkCast(type, mv);
}
}
private static void castArrayToCollection(ClassNode expr, ClassNode type, MethodVisitor mv) {
if (type.isArray()) {
if (!ClassHelper.isPrimitiveType(type.getComponentType())) {
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Collection", "size", "()I");
mv.visitTypeInsn(ANEWARRAY, BytecodeHelper.getClassInternalName(type.getComponentType()));
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Collection", "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;");
checkCast(type, mv);
return;
} else {
mv.visitLdcInsn(BytecodeHelper.getClassLoadingTypeDescription(type));
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation", "asArray", "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
checkCast(type, mv);
return;
}
}
throw new IllegalStateException("Impossible cast");
}
public static void checkCast(ClassNode type, MethodVisitor mv) {
mv.visitTypeInsn(CHECKCAST, type.isArray() ? BytecodeHelper.getTypeDescription(type): BytecodeHelper.getClassInternalName(type));
}
private static void castString(ClassNode expr, ClassNode type, MethodVisitor mv) {
if (TypeUtil.isNumericalType(type)) {
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation", "castToNumber", "(Ljava/lang/Object;)Ljava/lang/Number;");
checkCast(Integer_TYPE, mv);
castIntegral(Integer_TYPE, type, mv);
} else if (type == Boolean_TYPE) {
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "asBoolean", "(Ljava/lang/CharSequence;)Z");
box(boolean_TYPE, mv);
} else if (type == boolean_TYPE) {
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "asBoolean", "(Ljava/lang/CharSequence;)Z");
} else
throw new IllegalStateException("Impossible cast");
}
private static void castIntegral(ClassNode expr, ClassNode type, MethodVisitor mv) {
if (type == Integer_TYPE) {
unbox(getUnwrapper(expr), mv);
box(int_TYPE, mv);
} else if (type == Boolean_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(ICONST_1);
mv.visitInsn(IAND);
box(boolean_TYPE, mv);
} else if (type == Byte_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(I2B);
box(byte_TYPE, mv);
} else if (type == Short_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(I2S);
box(short_TYPE, mv);
} else if (type == Character_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(I2C);
box(char_TYPE, mv);
} else if (type == Long_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(I2L);
box(long_TYPE, mv);
} else if (type == Float_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(I2F);
box(float_TYPE, mv);
} else if (type == Double_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(I2D);
box(double_TYPE, mv);
} else if (type == BigDecimal_TYPE) {
mv.visitMethodInsn(INVOKESTATIC, "org/mbte/groovypp/runtime/DefaultGroovyPPMethods", "asBigDecimal", "(Ljava/lang/Number;)Ljava/math/BigDecimal;");
} else if (type == BigInteger_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
mv.visitTypeInsn(NEW, "java/math/BigInteger");
mv.visitInsn(DUP_X1);
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKESPECIAL, "java/math/BigInteger", "<init>", "(Ljava/lang/String;)V");
} else {
checkCast(type, mv);
}
}
private static void castLong(ClassNode expr, ClassNode type, MethodVisitor mv) {
if (type == Integer_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(L2I);
box(int_TYPE, mv);
} else if (type == Boolean_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(L2I);
mv.visitInsn(ICONST_1);
mv.visitInsn(IAND);
box(boolean_TYPE, mv);
} else if (type == Byte_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(L2I);
mv.visitInsn(I2B);
box(byte_TYPE, mv);
} else if (type == Short_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(L2I);
mv.visitInsn(I2S);
box(short_TYPE, mv);
} else if (type == Character_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(L2I);
mv.visitInsn(I2C);
box(char_TYPE, mv);
} else if (type == Long_TYPE) {
} else if (type == Float_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(L2F);
box(float_TYPE, mv);
} else if (type == Double_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(L2D);
box(double_TYPE, mv);
} else if (type == BigDecimal_TYPE) {
mv.visitMethodInsn(INVOKESTATIC, "org/mbte/groovypp/runtime/DefaultGroovyPPMethods", "asBigDecimal", "(Ljava/lang/Number;)Ljava/math/BigDecimal;");
} else if (type == BigInteger_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
mv.visitTypeInsn(NEW, "java/math/BigInteger");
mv.visitInsn(DUP_X1);
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKESPECIAL, "java/math/BigInteger", "<init>", "(Ljava/lang/String;)V");
} else {
checkCast(type, mv);
}
}
private static void castDouble(ClassNode expr, ClassNode type, MethodVisitor mv) {
if (type == Integer_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(D2I);
box(int_TYPE, mv);
} else if (type == Boolean_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(D2I);
mv.visitInsn(ICONST_1);
mv.visitInsn(IAND);
box(boolean_TYPE, mv);
} else if (type == Byte_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(D2I);
mv.visitInsn(I2B);
box(byte_TYPE, mv);
} else if (type == Short_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(D2I);
mv.visitInsn(I2S);
box(short_TYPE, mv);
} else if (type == Character_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(D2I);
mv.visitInsn(I2C);
box(char_TYPE, mv);
} else if (type == Long_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(D2L);
box(long_TYPE, mv);
} else if (type == Float_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(D2F);
box(float_TYPE, mv);
} else if (type == Double_TYPE) {
} else if (type == BigDecimal_TYPE) {
mv.visitMethodInsn(INVOKESTATIC, "org/mbte/groovypp/runtime/DefaultGroovyPPMethods", "asBigDecimal", "(Ljava/lang/Number;)Ljava/math/BigDecimal;");
} else if (type == BigInteger_TYPE) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J");
box(long_TYPE, mv);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
mv.visitTypeInsn(NEW, "java/math/BigInteger");
mv.visitInsn(DUP_X1);
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKESPECIAL, "java/math/BigInteger", "<init>", "(Ljava/lang/String;)V");
} else {
checkCast(type, mv);
}
}
private static void castFloat(ClassNode expr, ClassNode type, MethodVisitor mv) {
if (type == Integer_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(F2I);
box(int_TYPE, mv);
} else if (type == Boolean_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(F2I);
mv.visitInsn(ICONST_1);
mv.visitInsn(IAND);
box(boolean_TYPE, mv);
} else if (type == Byte_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(F2I);
mv.visitInsn(I2B);
box(byte_TYPE, mv);
} else if (type == Short_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(F2I);
mv.visitInsn(I2S);
box(short_TYPE, mv);
} else if (type == Character_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(F2I);
mv.visitInsn(I2C);
box(char_TYPE, mv);
} else if (type == Long_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(F2L);
box(long_TYPE, mv);
} else if (type == Float_TYPE) {
} else if (type == Double_TYPE) {
unbox(getUnwrapper(expr), mv);
mv.visitInsn(F2D);
box(double_TYPE, mv);
} else if (type == BigDecimal_TYPE) {
mv.visitMethodInsn(INVOKESTATIC, "org/mbte/groovypp/runtime/DefaultGroovyPPMethods", "asBigDecimal", "(Ljava/lang/Number;)Ljava/math/BigDecimal;");
} else if (type == BigInteger_TYPE) {
mv.visitTypeInsn(CHECKCAST, "java/lang/Number");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J");
box(long_TYPE, mv);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;");
mv.visitTypeInsn(NEW, "java/math/BigInteger");
mv.visitInsn(DUP_X1);
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKESPECIAL, "java/math/BigInteger", "<init>", "(Ljava/lang/String;)V");
} else {
checkCast(type, mv);
}
}
private static void castBigDecimal(ClassNode expr, ClassNode type, MethodVisitor mv) {
if (type == Integer_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
box(int_TYPE, mv);
} else if (type == Boolean_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
mv.visitInsn(ICONST_1);
mv.visitInsn(IAND);
box(boolean_TYPE, mv);
} else if (type == Byte_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
mv.visitInsn(I2B);
box(byte_TYPE, mv);
} else if (type == Short_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
mv.visitInsn(I2S);
box(short_TYPE, mv);
} else if (type == Character_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
mv.visitInsn(I2C);
box(char_TYPE, mv);
} else if (type == Long_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J");
box(long_TYPE, mv);
} else if (type == Float_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "floatValue", "()F");
box(float_TYPE, mv);
} else if (type == Double_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "doubleValue", "()D");
box(double_TYPE, mv);
} else if (type == BigDecimal_TYPE) {
} else if (type == BigInteger_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/math/BigDecimal", "toBigInteger", "()Ljava/math/BigInteger;");
} else {
checkCast(type, mv);
}
}
private static void castBigInteger(ClassNode expr, ClassNode type, MethodVisitor mv) {
if (type == Integer_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
box(int_TYPE, mv);
} else if (type == Boolean_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
mv.visitInsn(ICONST_1);
mv.visitInsn(IAND);
box(boolean_TYPE, mv);
} else if (type == Byte_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
mv.visitInsn(I2B);
box(byte_TYPE, mv);
} else if (type == Short_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
mv.visitInsn(I2S);
box(short_TYPE, mv);
} else if (type == Character_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I");
mv.visitInsn(I2C);
box(char_TYPE, mv);
} else if (type == Long_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "longValue", "()J");
box(long_TYPE, mv);
} else if (type == Float_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "floatValue", "()F");
box(float_TYPE, mv);
} else if (type == Double_TYPE) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "doubleValue", "()D");
box(double_TYPE, mv);
} else if (type == BigDecimal_TYPE) {
mv.visitMethodInsn(INVOKESTATIC, "org/mbte/groovypp/runtime/DefaultGroovyPPMethods", "asBigDecimal", "(Ljava/lang/Number;)Ljava/math/BigDecimal;");
} else if (type == BigInteger_TYPE) {
} else {
checkCast(type, mv);
}
}
protected void incOrDecPrimitive(ClassNode primType, final int op, MethodVisitor mv) {
boolean add = op == Types.PLUS_PLUS;
if (primType == BigDecimal_TYPE || primType == BigInteger_TYPE) {
if (add)
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "next", "(Ljava/lang/Number;)Ljava/lang/Number;");
else
mv.visitMethodInsn(INVOKESTATIC, "org/codehaus/groovy/runtime/DefaultGroovyMethods", "previous", "(Ljava/lang/Number;)Ljava/lang/Number;");
checkCast(primType, mv);
} else if (primType == double_TYPE) {
mv.visitInsn(DCONST_1);
mv.visitInsn(add ? DADD : DSUB);
} else if (primType == long_TYPE) {
mv.visitInsn(LCONST_1);
mv.visitInsn(add ? LADD : LSUB);
} else if (primType == float_TYPE) {
mv.visitInsn(FCONST_1);
mv.visitInsn(add ? FADD : FSUB);
} else {
mv.visitInsn(ICONST_1);
mv.visitInsn(add ? IADD : ISUB);
}
}
protected void toInt(ClassNode type, MethodVisitor mv) {
if (isPrimitiveType(type)) {
if (type == double_TYPE) {
mv.visitInsn(D2I);
} else if (type == long_TYPE) {
mv.visitInsn(L2I);
} else if (type == float_TYPE) {
mv.visitInsn(F2I);
}
} else {
unbox(int_TYPE, mv);
}
}
protected void loadArray(ClassNode type, MethodVisitor mv) {
if (type == byte_TYPE) {
mv.visitInsn(BALOAD);
} else if (type == char_TYPE) {
mv.visitInsn(CALOAD);
} else if (type == short_TYPE) {
mv.visitInsn(SALOAD);
} else if (type == int_TYPE) {
mv.visitInsn(IALOAD);
} else if (type == long_TYPE) {
mv.visitInsn(LALOAD);
} else if (type == float_TYPE) {
mv.visitInsn(FALOAD);
} else if (type == double_TYPE) {
mv.visitInsn(DALOAD);
} else {
mv.visitInsn(AALOAD);
}
}
protected void storeArray(ClassNode type, MethodVisitor mv) {
if (type == byte_TYPE) {
mv.visitInsn(BASTORE);
} else if (type == char_TYPE) {
mv.visitInsn(CASTORE);
} else if (type == short_TYPE) {
mv.visitInsn(SASTORE);
} else if (type == int_TYPE) {
mv.visitInsn(IASTORE);
} else if (type == long_TYPE) {
mv.visitInsn(LASTORE);
} else if (type == float_TYPE) {
mv.visitInsn(FASTORE);
} else if (type == double_TYPE) {
mv.visitInsn(DASTORE);
} else {
mv.visitInsn(AASTORE);
}
}
public boolean isThis() {
return false;
}
}