Fix boxing.

This commit is contained in:
Jack Conradson 2016-05-20 10:38:06 -07:00
parent c0eb813e10
commit 2b793c1e06
5 changed files with 72 additions and 11 deletions

View File

@ -33,6 +33,12 @@ import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import static org.elasticsearch.painless.WriterConstants.BOOLEAN_OBJECT;
import static org.elasticsearch.painless.WriterConstants.BOOLEAN_VALUE_OF;
import static org.elasticsearch.painless.WriterConstants.BYTE_OBJECT;
import static org.elasticsearch.painless.WriterConstants.BYTE_VALUE_OF;
import static org.elasticsearch.painless.WriterConstants.CHARACTER_OBJECT;
import static org.elasticsearch.painless.WriterConstants.CHARACTER_VALUE_OF;
import static org.elasticsearch.painless.WriterConstants.CHAR_TO_STRING;
import static org.elasticsearch.painless.WriterConstants.DEF_ADD_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_AND_CALL;
@ -61,9 +67,19 @@ import static org.elasticsearch.painless.WriterConstants.DEF_TO_SHORT_IMPLICIT;
import static org.elasticsearch.painless.WriterConstants.DEF_UTIL_TYPE;
import static org.elasticsearch.painless.WriterConstants.DEF_USH_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_XOR_CALL;
import static org.elasticsearch.painless.WriterConstants.DOUBLE_OBJECT;
import static org.elasticsearch.painless.WriterConstants.DOUBLE_VALUE_OF;
import static org.elasticsearch.painless.WriterConstants.FLOAT_OBJECT;
import static org.elasticsearch.painless.WriterConstants.FLOAT_VALUE_OF;
import static org.elasticsearch.painless.WriterConstants.INDY_STRING_CONCAT_BOOTSTRAP_HANDLE;
import static org.elasticsearch.painless.WriterConstants.INTEGER_OBJECT;
import static org.elasticsearch.painless.WriterConstants.INTEGER_VALUE_OF;
import static org.elasticsearch.painless.WriterConstants.LONG_OBJECT;
import static org.elasticsearch.painless.WriterConstants.LONG_VALUE_OF;
import static org.elasticsearch.painless.WriterConstants.MAX_INDY_STRING_CONCAT_ARGS;
import static org.elasticsearch.painless.WriterConstants.PAINLESS_ERROR_TYPE;
import static org.elasticsearch.painless.WriterConstants.SHORT_OBJECT;
import static org.elasticsearch.painless.WriterConstants.SHORT_VALUE_OF;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_APPEND_BOOLEAN;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_APPEND_CHAR;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_APPEND_DOUBLE;
@ -184,6 +200,22 @@ public final class MethodWriter extends GeneratorAdapter {
}
}
@Override
public void box(final org.objectweb.asm.Type type) {
switch (type.getSort()) {
case org.objectweb.asm.Type.BOOLEAN: invokeStatic(BOOLEAN_OBJECT , BOOLEAN_VALUE_OF); break;
case org.objectweb.asm.Type.BYTE: invokeStatic(BYTE_OBJECT , BYTE_VALUE_OF); break;
case org.objectweb.asm.Type.SHORT: invokeStatic(SHORT_OBJECT , SHORT_VALUE_OF); break;
case org.objectweb.asm.Type.CHAR: invokeStatic(CHARACTER_OBJECT, CHARACTER_VALUE_OF); break;
case org.objectweb.asm.Type.INT: invokeStatic(INTEGER_OBJECT , INTEGER_VALUE_OF); break;
case org.objectweb.asm.Type.LONG: invokeStatic(LONG_OBJECT , LONG_VALUE_OF); break;
case org.objectweb.asm.Type.FLOAT: invokeStatic(FLOAT_OBJECT , FLOAT_VALUE_OF); break;
case org.objectweb.asm.Type.DOUBLE: invokeStatic(DOUBLE_OBJECT , DOUBLE_VALUE_OF); break;
default:
throw new IllegalArgumentException("Illegal tree structure.");
}
}
public void writeBranch(final Label tru, final Label fals) {
if (tru != null) {
visitJumpInsn(Opcodes.IFNE, tru);

View File

@ -138,6 +138,25 @@ public final class WriterConstants {
public final static Method CHECKEQUALS =
getAsmMethod(boolean.class, "checkEquals", Object.class, Object.class);
public final static Type BOOLEAN_OBJECT = Type.getType(Boolean.class);
public final static Type BYTE_OBJECT = Type.getType(Byte.class);
public final static Type SHORT_OBJECT = Type.getType(Short.class);
public final static Type CHARACTER_OBJECT = Type.getType(Character.class);
public final static Type INTEGER_OBJECT = Type.getType(Integer.class);
public final static Type LONG_OBJECT = Type.getType(Long.class);
public final static Type FLOAT_OBJECT = Type.getType(Float.class);
public final static Type DOUBLE_OBJECT = Type.getType(Double.class);
/** box methods to replace the GeneratorAdapter's slow way of boxing */
public final static Method BOOLEAN_VALUE_OF = getAsmMethod(Boolean.class , "valueOf", boolean.class);
public final static Method BYTE_VALUE_OF = getAsmMethod(Byte.class , "valueOf", byte.class);
public final static Method SHORT_VALUE_OF = getAsmMethod(Short.class , "valueOf", short.class);
public final static Method CHARACTER_VALUE_OF = getAsmMethod(Character.class, "valueOf", char.class);
public final static Method INTEGER_VALUE_OF = getAsmMethod(Integer.class , "valueOf", int.class);
public final static Method LONG_VALUE_OF = getAsmMethod(Long.class , "valueOf", long.class);
public final static Method FLOAT_VALUE_OF = getAsmMethod(Float.class , "valueOf", float.class);
public final static Method DOUBLE_VALUE_OF = getAsmMethod(Double.class , "valueOf", double.class);
private static Method getAsmMethod(final Class<?> rtype, final String name, final Class<?>... ptypes) {
return new Method(name, MethodType.methodType(rtype, ptypes).toMethodDescriptorString());
}

View File

@ -45,39 +45,49 @@ public class BasicAPITests extends ScriptTestCase {
assertEquals(3, exec("Map x = new HashMap(); x.put(2, 2); x.put(3, 3); x.put(-2, -2); Iterator y = x.values().iterator(); " +
"int total = 0; while (y.hasNext()) total += (int)y.next(); return total;"));
}
/** Test loads and stores with a map */
public void testMapLoadStore() {
assertEquals(5, exec("def x = new HashMap(); x.abc = 5; return x.abc;"));
assertEquals(5, exec("def x = new HashMap(); x['abc'] = 5; return x['abc'];"));
}
/** Test loads and stores with a list */
public void testListLoadStore() {
assertEquals(5, exec("def x = new ArrayList(); x.add(3); x.0 = 5; return x.0;"));
assertEquals(5, exec("def x = new ArrayList(); x.add(3); x[0] = 5; return x[0];"));
}
/** Test shortcut for getters with isXXXX */
public void testListEmpty() {
assertEquals(true, exec("def x = new ArrayList(); return x.empty;"));
assertEquals(true, exec("def x = new HashMap(); return x.empty;"));
}
/** Test list method invocation */
public void testListGet() {
assertEquals(5, exec("def x = new ArrayList(); x.add(5); return x.get(0);"));
assertEquals(5, exec("def x = new ArrayList(); x.add(5); def index = 0; return x.get(index);"));
}
public void testListAsArray() {
assertEquals(1, exec("def x = new ArrayList(); x.add(5); return x.length"));
assertEquals(5, exec("def x = new ArrayList(); x.add(5); return x[0]"));
assertEquals(1, exec("List x = new ArrayList(); x.add('Hallo'); return x.length"));
}
public void testDefAssignments() {
assertEquals(2, exec("int x; def y = 2.0; x = (int)y;"));
}
public void testInternalBoxing() {
assertBytecodeExists("def x = true", "INVOKESTATIC java/lang/Boolean.valueOf (Z)Ljava/lang/Boolean;");
assertBytecodeExists("def x = (byte)1", "INVOKESTATIC java/lang/Byte.valueOf (B)Ljava/lang/Byte;");
assertBytecodeExists("def x = (short)1", "INVOKESTATIC java/lang/Short.valueOf (S)Ljava/lang/Short;");
assertBytecodeExists("def x = (char)1", "INVOKESTATIC java/lang/Character.valueOf (C)Ljava/lang/Character;");
assertBytecodeExists("def x = 1", "INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;");
assertBytecodeExists("def x = 1L", "INVOKESTATIC java/lang/Long.valueOf (J)Ljava/lang/Long;");
assertBytecodeExists("def x = 1F", "INVOKESTATIC java/lang/Float.valueOf (F)Ljava/lang/Float;");
assertBytecodeExists("def x = 1D", "INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;");
}
}

View File

@ -799,7 +799,7 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(false, exec("def x = (byte)7; def y = (int)7; return x === y"));
assertEquals(false, exec("def x = (short)6; def y = (int)6; return x === y"));
assertEquals(false, exec("def x = (char)5; def y = (int)5; return x === y"));
assertEquals(false, exec("def x = (int)4; def y = (int)4; return x === y"));
assertEquals(true, exec("def x = (int)4; def y = (int)4; return x === y"));
assertEquals(false, exec("def x = (long)5; def y = (int)3; return x === y"));
assertEquals(false, exec("def x = (float)6; def y = (int)2; return x === y"));
assertEquals(false, exec("def x = (double)7; def y = (int)1; return x === y"));
@ -837,7 +837,7 @@ public class DefOperationTests extends ScriptTestCase {
assertEquals(true, exec("def x = (byte)7; def y = (int)7; return x !== y"));
assertEquals(true, exec("def x = (short)6; def y = (int)6; return x !== y"));
assertEquals(true, exec("def x = (char)5; def y = (int)5; return x !== y"));
assertEquals(true, exec("def x = (int)4; def y = (int)4; return x !== y"));
assertEquals(false, exec("def x = (int)4; def y = (int)4; return x !== y"));
assertEquals(true, exec("def x = (long)5; def y = (int)3; return x !== y"));
assertEquals(true, exec("def x = (float)6; def y = (int)2; return x !== y"));
assertEquals(true, exec("def x = (double)7; def y = (int)1; return x !== y"));

View File

@ -118,7 +118,7 @@ public class EqualsTests extends ScriptTestCase {
public void testBranchEquals() {
assertEquals(0, exec("def a = (char)'a'; def b = (char)'b'; if (a == b) return 1; else return 0;"));
assertEquals(1, exec("def a = (char)'a'; def b = (char)'a'; if (a == b) return 1; else return 0;"));
assertEquals(0, exec("def a = 1; def b = 1; if (a === b) return 1; else return 0;"));
assertEquals(1, exec("def a = 1; def b = 1; if (a === b) return 1; else return 0;"));
assertEquals(0, exec("def a = (char)'a'; def b = (char)'a'; if (a === b) return 1; else return 0;"));
assertEquals(1, exec("def a = (char)'a'; Object b = a; if (a === b) return 1; else return 0;"));
assertEquals(1, exec("def a = 1; Number b = a; Number c = a; if (c === b) return 1; else return 0;"));
@ -128,7 +128,7 @@ public class EqualsTests extends ScriptTestCase {
public void testBranchNotEquals() {
assertEquals(1, exec("def a = (char)'a'; def b = (char)'b'; if (a != b) return 1; else return 0;"));
assertEquals(0, exec("def a = (char)'a'; def b = (char)'a'; if (a != b) return 1; else return 0;"));
assertEquals(1, exec("def a = 1; def b = 1; if (a !== b) return 1; else return 0;"));
assertEquals(0, exec("def a = 1; def b = 1; if (a !== b) return 1; else return 0;"));
assertEquals(1, exec("def a = (char)'a'; def b = (char)'a'; if (a !== b) return 1; else return 0;"));
assertEquals(0, exec("def a = (char)'a'; Object b = a; if (a !== b) return 1; else return 0;"));
assertEquals(0, exec("def a = 1; Number b = a; Number c = a; if (c !== b) return 1; else return 0;"));