Reduce SpEL compilation restrictions on mathematical expressions

Prior to this change the SpEL compiler would not compile mathematical
expressions where the operands were of differing types (e.g. int
and double). This required the expression writer to do the conversion
in the expression text. For example:

T(Integer).valueOf(someInt).doubleValue()/35d

With this commit the restriction is lifted and it is more like Java
so that you can simply do someInt/35d. The mathematical operators
affected are divide/plus/minus/multiply and modulus. This change
involved removing some guards so that the exitTypeDescriptor (the
trigger for whether compilation is allowed) is set more frequently
and enhancing bytecode generation to perform more sophisticated
conversion/coercion automatically.

Issue: SPR-12789
This commit is contained in:
Andy Clement
2015-03-06 10:26:53 -08:00
parent 7fbc951691
commit b7ef04767a
8 changed files with 1263 additions and 110 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -63,6 +63,98 @@ public class SpelCompilationPerformanceTests extends AbstractExpressionTests {
}
}
public static class NumberHolder {
public int payload = 36;
}
/**
* This test verifies the new support for compiling mathematical expressions with
* different operand types.
*/
@Test
public void compilingMathematicalExpressionsWithDifferentOperandTypes() throws Exception {
NumberHolder nh = new NumberHolder();
expression = parser.parseExpression("(T(Integer).valueOf(payload).doubleValue())/18D");
Object o = expression.getValue(nh);
assertEquals(2d,o);
System.out.println("Performance check for SpEL expression: '(T(Integer).valueOf(payload).doubleValue())/18D'");
long stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
compile(expression);
System.out.println("Now compiled:");
o = expression.getValue(nh);
assertEquals(2d, o);
stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
expression = parser.parseExpression("payload/18D");
o = expression.getValue(nh);
assertEquals(2d,o);
System.out.println("Performance check for SpEL expression: 'payload/18D'");
stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
compile(expression);
System.out.println("Now compiled:");
o = expression.getValue(nh);
assertEquals(2d, o);
stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
stime = System.currentTimeMillis();
for (int i=0;i<1000000;i++) {
o = expression.getValue(nh);
}
System.out.println("One million iterations: "+(System.currentTimeMillis()-stime)+"ms");
}
@Test
public void inlineLists() throws Exception {
expression = parser.parseExpression("{'abcde','ijklm'}[0].substring({1,3,4}[0],{1,3,4}[1])");