/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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.elasticsearch.painless;
public class DefOptimizationTests extends ScriptTestCase {
public void testIntBraceArrayOptiLoad() {
final String script = "int x = 0; def y = new int[1]; y[0] = 5; x = y[0]; return x;";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayLoad(Ljava/lang/Object;I)I");
assertEquals(5, exec(script));
}
public void testIntBraceArrayOptiStore() {
final String script = "int x = 1; def y = new int[1]; y[0] = x; return y[0];";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayStore(Ljava/lang/Object;II)");
assertEquals(1, exec(script));
}
public void testIntBraceListOptiLoad() {
final String script = "int x = 0; def y = new ArrayList(); y.add(5); x = y[0]; return x;";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayLoad(Ljava/lang/Object;I)I");
assertEquals(5, exec(script));
}
public void testIntBraceListOptiStore() {
final String script = "int x = 1; def y = new ArrayList(); y.add(0); y[0] = x; return y[0];";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayStore(Ljava/lang/Object;II)");
assertEquals(1, exec(script));
}
public void testIntBraceMapOptiLoad() {
final String script = "int x = 0; def y = new HashMap(); y.put(0, 5); x = y[0];";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayLoad(Ljava/lang/Object;I)I");
assertEquals(5, exec(script));
}
public void testIntBraceMapOptiStore() {
final String script = "int x = 1; def y = new HashMap(); y.put(0, 1); y[0] = x;";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayStore(Ljava/lang/Object;II)");
assertEquals(1, exec(script));
}
public void testIntFieldListOptiLoad() {
final String script = "int x = 0; def y = new ArrayList(); y.add(5); x = y.0;";
assertBytecodeExists(script, "INVOKEDYNAMIC 0(Ljava/lang/Object;)I");
assertEquals(5, exec(script));
}
public void testIntFieldListOptiStore() {
final String script = "int x = 1; def y = new ArrayList(); y.add(0); y.0 = x;";
assertBytecodeExists(script, "INVOKEDYNAMIC 0(Ljava/lang/Object;I)");
assertEquals(1, exec(script));
}
public void testIntFieldMapOptiLoad() {
final String script = "int x = 0; def y = new HashMap(); y.put('0', 5); x = y.0; return x;";
assertBytecodeExists(script, "INVOKEDYNAMIC 0(Ljava/lang/Object;)I");
assertEquals(5, exec(script));
}
public void testIntFieldMapOptiStore() {
final String script = "int x = 1; def y = new HashMap(); y.put('0', 1); y.0 = x; return y.0;";
assertBytecodeExists(script, "INVOKEDYNAMIC 0(Ljava/lang/Object;I)");
assertEquals(1, exec(script));
}
public void testIntCall0Opti() {
final String script = "int x; def y = new HashMap(); y['int'] = 1; x = y.get('int'); return x;";
assertBytecodeExists(script, "INVOKEDYNAMIC get(Ljava/lang/Object;Ljava/lang/String;)I");
assertEquals(1, exec(script));
}
public void testIntCall1Opti() {
final String script = "int x; def y = new HashMap(); y['int'] = 1; x = y.get('int');";
assertBytecodeExists(script, "INVOKEDYNAMIC get(Ljava/lang/Object;Ljava/lang/String;)I");
assertEquals(1, exec(script));
}
public void testDoubleBraceArrayOptiLoad() {
final String script = "double x = 0; def y = new double[1]; y[0] = 5.0; x = y[0]; return x;";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayLoad(Ljava/lang/Object;I)D");
assertEquals(5.0, exec(script));
}
public void testDoubleBraceArrayOptiStore() {
final String script = "double x = 1; def y = new double[1]; y[0] = x; return y[0];";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayStore(Ljava/lang/Object;ID)");
assertEquals(1.0, exec(script));
}
public void testDoubleBraceListOptiLoad() {
final String script = "double x = 0.0; def y = new ArrayList(); y.add(5.0); x = y[0]; return x;";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayLoad(Ljava/lang/Object;I)D");
assertEquals(5.0, exec(script));
}
public void testDoubleBraceListOptiStore() {
final String script = "double x = 1.0; def y = new ArrayList(); y.add(0.0); y[0] = x; return y[0];";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayStore(Ljava/lang/Object;ID)");
assertEquals(1.0, exec(script));
}
public void testDoubleBraceMapOptiLoad() {
final String script = "double x = 0.0; def y = new HashMap(); y.put(0, 5.0); x = y[0];";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayLoad(Ljava/lang/Object;I)D");
assertEquals(5.0, exec(script));
}
public void testDoubleBraceMapOptiStore() {
final String script = "double x = 1.0; def y = new HashMap(); y.put(0, 2.0); y[0] = x;";
assertBytecodeExists(script, "INVOKEDYNAMIC arrayStore(Ljava/lang/Object;ID)");
assertEquals(1.0, exec(script));
}
public void testDoubleFieldListOptiLoad() {
final String script = "double x = 0; def y = new ArrayList(); y.add(5.0); x = y.0;";
assertBytecodeExists(script, "INVOKEDYNAMIC 0(Ljava/lang/Object;)D");
assertEquals(5.0, exec(script));
}
public void testDoubleFieldListOptiStore() {
final String script = "double x = 1.0; def y = new ArrayList(); y.add(0); y.0 = x;";
assertBytecodeExists(script, "INVOKEDYNAMIC 0(Ljava/lang/Object;D)");
assertEquals(1.0, exec(script));
}
public void testDoubleFieldMapOptiLoad() {
final String script = "double x = 0; def y = new HashMap(); y.put('0', 5.0); x = y.0; return x;";
assertBytecodeExists(script, "INVOKEDYNAMIC 0(Ljava/lang/Object;)D");
assertEquals(5.0, exec(script));
}
public void testDoubleFieldMapOptiStore() {
final String script = "double x = 1.0; def y = new HashMap(); y.put('0', 1.0); y.0 = x; return y.0;";
assertBytecodeExists(script, "INVOKEDYNAMIC 0(Ljava/lang/Object;D)");
assertEquals(1.0, exec(script));
}
public void testDoubleCall0Opti() {
final String script = "double x; def y = new HashMap(); y['double'] = 1.0; x = y.get('double'); return x;";
assertBytecodeExists(script, "INVOKEDYNAMIC get(Ljava/lang/Object;Ljava/lang/String;)D");
assertEquals(1.0, exec(script));
}
public void testDoubleCall1Opti() {
final String script = "double x; def y = new HashMap(); y['double'] = 1.0; x = y.get('double');";
assertBytecodeExists(script, "INVOKEDYNAMIC get(Ljava/lang/Object;Ljava/lang/String;)D");
assertEquals(1.0, exec(script));
}
public void testIllegalCast() {
final String script = "int x;\ndef y = new HashMap();\ny['double'] = 1.0;\nx = y.get('double');\n";
assertBytecodeExists(script, "INVOKEDYNAMIC get(Ljava/lang/Object;Ljava/lang/String;)I");
final Exception exception = expectScriptThrows(ClassCastException.class, () -> {
exec(script);
});
assertTrue(exception.getMessage().contains("Cannot cast java.lang.Double to java.lang.Integer"));
}
public void testMulOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x * y",
"INVOKEDYNAMIC mul(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testMulOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x * y",
"INVOKEDYNAMIC mul(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testMulOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x * y",
"INVOKEDYNAMIC mul(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testDivOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x / y",
"INVOKEDYNAMIC div(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testDivOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x / y",
"INVOKEDYNAMIC div(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testDivOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x / y",
"INVOKEDYNAMIC div(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testRemOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x % y",
"INVOKEDYNAMIC rem(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testRemOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x % y",
"INVOKEDYNAMIC rem(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testRemOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x % y",
"INVOKEDYNAMIC rem(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testAddOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x + y",
"INVOKEDYNAMIC add(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testAddOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x + y",
"INVOKEDYNAMIC add(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testAddOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x + y",
"INVOKEDYNAMIC add(Ljava/lang/Object;Ljava/lang/Object;)D");
}
// horrible, sorry
public void testAddOptNullGuards() {
// needs null guard
assertBytecodeHasPattern("def x = 1; def y = 2; return x + y",
"(?s).*INVOKEDYNAMIC add.*arguments:\\s+" + "\\d+"
+ ",\\s+" + DefBootstrap.BINARY_OPERATOR
+ ",\\s+" + DefBootstrap.OPERATOR_ALLOWS_NULL + ".*");
// still needs null guard, NPE is the wrong thing!
assertBytecodeHasPattern("def x = 1; def y = 2; double z = x + y",
"(?s).*INVOKEDYNAMIC add.*arguments:\\s+" + "\\d+"
+ ",\\s+" + DefBootstrap.BINARY_OPERATOR
+ ",\\s+" + DefBootstrap.OPERATOR_ALLOWS_NULL + ".*");
// a primitive argument is present: no null guard needed
assertBytecodeHasPattern("def x = 1; int y = 2; return x + y",
"(?s).*INVOKEDYNAMIC add.*arguments:\\s+" + "\\d+"
+ ",\\s+" + DefBootstrap.BINARY_OPERATOR
+ ",\\s+" + 0 + ".*");
assertBytecodeHasPattern("int x = 1; def y = 2; return x + y",
"(?s).*INVOKEDYNAMIC add.*arguments:\\s+" + "\\d+"
+ ",\\s+" + DefBootstrap.BINARY_OPERATOR
+ ",\\s+" + 0 + ".*");
}
public void testSubOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x - y",
"INVOKEDYNAMIC sub(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testSubOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x - y",
"INVOKEDYNAMIC sub(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testSubOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x - y",
"INVOKEDYNAMIC sub(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testLshOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x << y",
"INVOKEDYNAMIC lsh(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testLshOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x << y",
"INVOKEDYNAMIC lsh(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testLshOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x << y",
"INVOKEDYNAMIC lsh(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testRshOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x >> y",
"INVOKEDYNAMIC rsh(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testRshOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x >> y",
"INVOKEDYNAMIC rsh(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testRshOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x >> y",
"INVOKEDYNAMIC rsh(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testUshOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x >>> y",
"INVOKEDYNAMIC ush(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testUshOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x >>> y",
"INVOKEDYNAMIC ush(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testUshOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x >>> y",
"INVOKEDYNAMIC ush(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testAndOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x & y",
"INVOKEDYNAMIC and(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testAndOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x & y",
"INVOKEDYNAMIC and(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testAndOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x & y",
"INVOKEDYNAMIC and(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testOrOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x | y",
"INVOKEDYNAMIC or(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testOrOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x | y",
"INVOKEDYNAMIC or(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testOrOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x | y",
"INVOKEDYNAMIC or(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testXorOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x ^ y",
"INVOKEDYNAMIC xor(ILjava/lang/Object;)Ljava/lang/Object;");
}
public void testXorOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x ^ y",
"INVOKEDYNAMIC xor(Ljava/lang/Object;I)Ljava/lang/Object;");
}
public void testXorOptRet() {
assertBytecodeExists("def x = 1; def y = 2; double d = x ^ y",
"INVOKEDYNAMIC xor(Ljava/lang/Object;Ljava/lang/Object;)D");
}
public void testBooleanXorOptLHS() {
assertBytecodeExists("boolean x = true; def y = true; return x ^ y",
"INVOKEDYNAMIC xor(ZLjava/lang/Object;)Ljava/lang/Object;");
}
public void testBooleanXorOptRHS() {
assertBytecodeExists("def x = true; boolean y = true; return x ^ y",
"INVOKEDYNAMIC xor(Ljava/lang/Object;Z)Ljava/lang/Object;");
}
public void testBooleanXorOptRet() {
assertBytecodeExists("def x = true; def y = true; boolean v = x ^ y",
"INVOKEDYNAMIC xor(Ljava/lang/Object;Ljava/lang/Object;)Z");
}
public void testLtOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x < y",
"INVOKEDYNAMIC lt(ILjava/lang/Object;)Z");
}
public void testLtOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x < y",
"INVOKEDYNAMIC lt(Ljava/lang/Object;I)Z");
}
public void testLteOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x <= y",
"INVOKEDYNAMIC lte(ILjava/lang/Object;)Z");
}
public void testLteOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x <= y",
"INVOKEDYNAMIC lte(Ljava/lang/Object;I)Z");
}
public void testEqOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x == y",
"INVOKEDYNAMIC eq(ILjava/lang/Object;)Z");
}
public void testEqOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x == y",
"INVOKEDYNAMIC eq(Ljava/lang/Object;I)Z");
}
public void testNeqOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x != y",
"INVOKEDYNAMIC eq(ILjava/lang/Object;)Z");
}
public void testNeqOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x != y",
"INVOKEDYNAMIC eq(Ljava/lang/Object;I)Z");
}
public void testGteOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x >= y",
"INVOKEDYNAMIC gte(ILjava/lang/Object;)Z");
}
public void testGteOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x >= y",
"INVOKEDYNAMIC gte(Ljava/lang/Object;I)Z");
}
public void testGtOptLHS() {
assertBytecodeExists("int x = 1; def y = 2; return x > y",
"INVOKEDYNAMIC gt(ILjava/lang/Object;)Z");
}
public void testGtOptRHS() {
assertBytecodeExists("def x = 1; int y = 2; return x > y",
"INVOKEDYNAMIC gt(Ljava/lang/Object;I)Z");
}
public void testUnaryMinusOptRet() {
assertBytecodeExists("def x = 1; double y = -x; return y",
"INVOKEDYNAMIC neg(Ljava/lang/Object;)D");
}
public void testUnaryNotOptRet() {
assertBytecodeExists("def x = 1; double y = ~x; return y",
"INVOKEDYNAMIC not(Ljava/lang/Object;)D");
}
public void testUnaryPlusOptRet() {
assertBytecodeExists("def x = 1; double y = +x; return y",
"INVOKEDYNAMIC plus(Ljava/lang/Object;)D");
}
public void testLambdaReturnType() {
assertBytecodeExists("List l = new ArrayList(); l.removeIf(x -> x < 10)",
"synthetic lambda$0(Ljava/lang/Object;)Z");
}
public void testLambdaArguments() {
assertBytecodeExists("List l = new ArrayList(); l.stream().mapToDouble(Double::valueOf).map(x -> x + 1)",
"synthetic lambda$0(D)D");
}
}