diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java index d17330eea8f..757041429a4 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java @@ -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); diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java index b50ec7b8040..c9d24212bbc 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java @@ -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()); } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/BasicAPITests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/BasicAPITests.java index b7479b505fe..338e3f00113 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/BasicAPITests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/BasicAPITests.java @@ -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;"); + } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefOperationTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefOperationTests.java index 1b548efa3b8..9f171a96889 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefOperationTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefOperationTests.java @@ -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")); diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/EqualsTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/EqualsTests.java index 59f9aadc6aa..cc308c70ded 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/EqualsTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/EqualsTests.java @@ -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;"));