Fixed issue 9, hand calculated MAXS. Thanks serverperformance!

This commit is contained in:
Nathan Sweet 2012-06-15 22:49:12 +00:00
parent 03e957db94
commit 14bbe83269

View File

@ -104,7 +104,7 @@ public abstract class FieldAccess {
String accessClassNameInternal = accessClassName.replace('.', '/'); String accessClassNameInternal = accessClassName.replace('.', '/');
String classNameInternal = className.replace('.', '/'); String classNameInternal = className.replace('.', '/');
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassWriter cw = new ClassWriter(0);
cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/FieldAccess", cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/FieldAccess",
null); null);
@ -147,16 +147,18 @@ public abstract class FieldAccess {
mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "com/esotericsoftware/reflectasm/FieldAccess", "<init>", "()V"); mv.visitMethodInsn(INVOKESPECIAL, "com/esotericsoftware/reflectasm/FieldAccess", "<init>", "()V");
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
mv.visitMaxs(0, 0); mv.visitMaxs(1, 1);
mv.visitEnd(); mv.visitEnd();
} }
static private void insertSetObject (ClassWriter cw, String classNameInternal, ArrayList<Field> fields) { static private void insertSetObject (ClassWriter cw, String classNameInternal, ArrayList<Field> fields) {
int maxStack = 6;
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "set", "(Ljava/lang/Object;ILjava/lang/Object;)V", null, null); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "set", "(Ljava/lang/Object;ILjava/lang/Object;)V", null, null);
mv.visitCode(); mv.visitCode();
mv.visitVarInsn(ILOAD, 2); mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) { if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()]; Label[] labels = new Label[fields.size()];
for (int i = 0, n = labels.length; i < n; i++) for (int i = 0, n = labels.length; i < n; i++)
labels[i] = new Label(); labels[i] = new Label();
@ -222,16 +224,18 @@ public abstract class FieldAccess {
mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitFrame(F_SAME, 0, null, 0, null);
} }
mv = insertThrowExceptionForFieldNotFound(mv); mv = insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(0, 0); mv.visitMaxs(maxStack, 4);
mv.visitEnd(); mv.visitEnd();
} }
static private void insertGetObject (ClassWriter cw, String classNameInternal, ArrayList<Field> fields) { static private void insertGetObject (ClassWriter cw, String classNameInternal, ArrayList<Field> fields) {
int maxStack = 6;
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;I)Ljava/lang/Object;", null, null); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;I)Ljava/lang/Object;", null, null);
mv.visitCode(); mv.visitCode();
mv.visitVarInsn(ILOAD, 2); mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) { if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()]; Label[] labels = new Label[fields.size()];
for (int i = 0, n = labels.length; i < n; i++) for (int i = 0, n = labels.length; i < n; i++)
labels[i] = new Label(); labels[i] = new Label();
@ -282,49 +286,60 @@ public abstract class FieldAccess {
mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitFrame(F_SAME, 0, null, 0, null);
} }
insertThrowExceptionForFieldNotFound(mv); insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(0, 0); mv.visitMaxs(maxStack, 3);
mv.visitEnd(); mv.visitEnd();
} }
static private void insertGetString (ClassWriter cw, String classNameInternal, ArrayList<Field> fields) { static private void insertGetString (ClassWriter cw, String classNameInternal, ArrayList<Field> fields) {
int maxStack = 6;
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getString", "(Ljava/lang/Object;I)Ljava/lang/String;", null, null); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getString", "(Ljava/lang/Object;I)Ljava/lang/String;", null, null);
mv.visitCode(); mv.visitCode();
mv.visitVarInsn(ILOAD, 2); mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) { if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()]; Label[] labels = new Label[fields.size()];
for (int i = 0, n = labels.length; i < n; i++) Label labelForInvalidTypes = new Label();
labels[i] = new Label(); boolean hasAnyBadTypeLabel = false;
for (int i = 0, n = labels.length; i < n; i++) {
if (fields.get(i).getType().equals(String.class))
labels[i] = new Label();
else {
labels[i] = labelForInvalidTypes;
hasAnyBadTypeLabel = true;
}
}
Label defaultLabel = new Label(); Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels); mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
ArrayList<Label> labelsForOtherTypes = new ArrayList<Label>();
for (int i = 0, n = labels.length; i < n; i++) { for (int i = 0, n = labels.length; i < n; i++) {
Field field = fields.get(i); if (!labels[i].equals(labelForInvalidTypes)) {
if (field.getType().equals(String.class)) {
mv.visitLabel(labels[i]); mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal); mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitFieldInsn(GETFIELD, classNameInternal, field.getName(), "Ljava/lang/String;"); mv.visitFieldInsn(GETFIELD, classNameInternal, fields.get(i).getName(), "Ljava/lang/String;");
mv.visitInsn(ARETURN); mv.visitInsn(ARETURN);
} else }
labelsForOtherTypes.add(labels[i]);
} }
// Rest of fields: different type // Rest of fields: different type
for (int i = 0, n = labelsForOtherTypes.size(); i < n; i++) if (hasAnyBadTypeLabel) {
mv.visitLabel(labelsForOtherTypes.get(i)); mv.visitLabel(labelForInvalidTypes);
insertThrowExceptionForFieldType(mv, "String"); mv.visitFrame(F_SAME, 0, null, 0, null);
insertThrowExceptionForFieldType(mv, "String");
}
// Default: field not found // Default: field not found
mv.visitLabel(defaultLabel); mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitFrame(F_SAME, 0, null, 0, null);
} }
insertThrowExceptionForFieldNotFound(mv); insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(0, 0); mv.visitMaxs(maxStack, 3);
mv.visitEnd(); mv.visitEnd();
} }
static private void insertSetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields, Type primitiveType) { static private void insertSetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields, Type primitiveType) {
int maxStack = 6;
int maxLocals = 4; // See correction below for LLOAD and DLOAD
final String setterMethodName; final String setterMethodName;
final String typeNameInternal = primitiveType.getDescriptor(); final String typeNameInternal = primitiveType.getDescriptor();
final int loadValueInstruction; final int loadValueInstruction;
@ -356,10 +371,12 @@ public abstract class FieldAccess {
case Type.LONG: case Type.LONG:
setterMethodName = "setLong"; setterMethodName = "setLong";
loadValueInstruction = LLOAD; loadValueInstruction = LLOAD;
maxLocals++; // (LLOAD and DLOAD actually load two slots)
break; break;
case Type.DOUBLE: case Type.DOUBLE:
setterMethodName = "setDouble"; setterMethodName = "setDouble";
loadValueInstruction = DLOAD; loadValueInstruction = DLOAD; // (LLOAD and DLOAD actually load two slots)
maxLocals++;
break; break;
default: default:
setterMethodName = "set"; setterMethodName = "set";
@ -372,41 +389,49 @@ public abstract class FieldAccess {
mv.visitVarInsn(ILOAD, 2); mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) { if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()]; Label[] labels = new Label[fields.size()];
for (int i = 0, n = labels.length; i < n; i++) Label labelForInvalidTypes = new Label();
labels[i] = new Label(); boolean hasAnyBadTypeLabel = false;
for (int i = 0, n = labels.length; i < n; i++) {
if (Type.getType(fields.get(i).getType()).equals(primitiveType))
labels[i] = new Label();
else {
labels[i] = labelForInvalidTypes;
hasAnyBadTypeLabel = true;
}
}
Label defaultLabel = new Label(); Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels); mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
ArrayList<Label> labelsForOtherTypes = new ArrayList<Label>();
for (int i = 0, n = labels.length; i < n; i++) { for (int i = 0, n = labels.length; i < n; i++) {
Field field = fields.get(i); if (!labels[i].equals(labelForInvalidTypes)) {
if (Type.getType(field.getType()).equals(primitiveType)) {
mv.visitLabel(labels[i]); mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal); mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitVarInsn(loadValueInstruction, 3); mv.visitVarInsn(loadValueInstruction, 3);
mv.visitFieldInsn(PUTFIELD, classNameInternal, field.getName(), typeNameInternal); mv.visitFieldInsn(PUTFIELD, classNameInternal, fields.get(i).getName(), typeNameInternal);
mv.visitInsn(RETURN); mv.visitInsn(RETURN);
} else }
labelsForOtherTypes.add(labels[i]);
} }
// Rest of fields: different type // Rest of fields: different type
for (int i = 0, n = labelsForOtherTypes.size(); i < n; i++) if (hasAnyBadTypeLabel) {
mv.visitLabel(labelsForOtherTypes.get(i)); mv.visitLabel(labelForInvalidTypes);
insertThrowExceptionForFieldType(mv, primitiveType.getClassName()); mv.visitFrame(F_SAME, 0, null, 0, null);
insertThrowExceptionForFieldType(mv, primitiveType.getClassName());
}
// Default: field not found // Default: field not found
mv.visitLabel(defaultLabel); mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitFrame(F_SAME, 0, null, 0, null);
} }
mv = insertThrowExceptionForFieldNotFound(mv); mv = insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(0, 0); mv.visitMaxs(maxStack, maxLocals);
mv.visitEnd(); mv.visitEnd();
} }
static private void insertGetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields, Type primitiveType) { static private void insertGetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields, Type primitiveType) {
int maxStack = 6;
final String getterMethodName; final String getterMethodName;
final String typeNameInternal = primitiveType.getDescriptor(); final String typeNameInternal = primitiveType.getDescriptor();
final int returnValueInstruction; final int returnValueInstruction;
@ -453,35 +478,44 @@ public abstract class FieldAccess {
mv.visitVarInsn(ILOAD, 2); mv.visitVarInsn(ILOAD, 2);
if (!fields.isEmpty()) { if (!fields.isEmpty()) {
maxStack--;
Label[] labels = new Label[fields.size()]; Label[] labels = new Label[fields.size()];
for (int i = 0, n = labels.length; i < n; i++) Label labelForInvalidTypes = new Label();
labels[i] = new Label(); boolean hasAnyBadTypeLabel = false;
for (int i = 0, n = labels.length; i < n; i++) {
if (Type.getType(fields.get(i).getType()).equals(primitiveType))
labels[i] = new Label();
else {
labels[i] = labelForInvalidTypes;
hasAnyBadTypeLabel = true;
}
}
Label defaultLabel = new Label(); Label defaultLabel = new Label();
mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels); mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
ArrayList<Label> labelsForOtherTypes = new ArrayList<Label>();
for (int i = 0, n = labels.length; i < n; i++) { for (int i = 0, n = labels.length; i < n; i++) {
Field field = fields.get(i); Field field = fields.get(i);
if (Type.getType(field.getType()).equals(primitiveType)) { if (!labels[i].equals(labelForInvalidTypes)) {
mv.visitLabel(labels[i]); mv.visitLabel(labels[i]);
mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitFrame(F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, classNameInternal); mv.visitTypeInsn(CHECKCAST, classNameInternal);
mv.visitFieldInsn(GETFIELD, classNameInternal, field.getName(), typeNameInternal); mv.visitFieldInsn(GETFIELD, classNameInternal, field.getName(), typeNameInternal);
mv.visitInsn(returnValueInstruction); mv.visitInsn(returnValueInstruction);
} else }
labelsForOtherTypes.add(labels[i]);
} }
// Rest of fields: different type // Rest of fields: different type
for (int i = 0, n = labelsForOtherTypes.size(); i < n; i++) if (hasAnyBadTypeLabel) {
mv.visitLabel(labelsForOtherTypes.get(i)); mv.visitLabel(labelForInvalidTypes);
insertThrowExceptionForFieldType(mv, primitiveType.getClassName()); mv.visitFrame(F_SAME, 0, null, 0, null);
insertThrowExceptionForFieldType(mv, primitiveType.getClassName());
}
// Default: field not found // Default: field not found
mv.visitLabel(defaultLabel); mv.visitLabel(defaultLabel);
mv.visitFrame(F_SAME, 0, null, 0, null); mv.visitFrame(F_SAME, 0, null, 0, null);
} }
mv = insertThrowExceptionForFieldNotFound(mv); mv = insertThrowExceptionForFieldNotFound(mv);
mv.visitMaxs(0, 0); mv.visitMaxs(maxStack, 3);
mv.visitEnd(); mv.visitEnd();
} }
@ -514,4 +548,5 @@ public abstract class FieldAccess {
mv.visitInsn(ATHROW); mv.visitInsn(ATHROW);
return mv; return mv;
} }
} }