Fix SpEL compilation of static method/property/field operations

Before this change the compilation of a method reference or property/field
access was not properly cleaning up the stack if compilation meant
calling a static method or accessing a static field. In these cases there
is no need for a target object on the stack and it should be removed if
present. For a simple expression it is harmless since the end result of
the expression is the thing on the top of the stack, but for nested
expressions if the inner expression suffered this issue, the outer
expression can find itself operating on the wrong element.

The particular issue covered the case of a static field access but this
fix (and associated tests) cover static method, property and field access.

Issue: SPR-13781
This commit is contained in:
Andy Clement
2015-12-11 15:50:02 -08:00
parent 9d944fbe7f
commit a28fc760ba
4 changed files with 139 additions and 9 deletions

View File

@@ -124,14 +124,8 @@ public class CompoundExpression extends SpelNodeImpl {
@Override
public void generateCode(MethodVisitor mv, CodeFlow cf) {
// TODO could optimize T(SomeType).staticMethod - no need to generate the T() part
for (int i = 0; i < this.children.length;i++) {
SpelNodeImpl child = this.children[i];
if (child instanceof TypeReference && (i + 1) < this.children.length &&
this.children[i + 1] instanceof MethodReference) {
continue;
}
child.generateCode(mv, cf);
this.children[i].generateCode(mv, cf);
}
cf.pushDescriptor(this.exitTypeDescriptor);
}

View File

@@ -292,8 +292,16 @@ public class MethodReference extends SpelNodeImpl {
boolean isStaticMethod = Modifier.isStatic(method.getModifiers());
String descriptor = cf.lastDescriptor();
if (descriptor == null && !isStaticMethod) {
cf.loadTarget(mv);
if (descriptor == null) {
if (!isStaticMethod) {
// Nothing on the stack but something is needed
cf.loadTarget(mv);
}
} else {
if (isStaticMethod) {
// Something on the stack when nothing is needed
mv.visitInsn(POP);
}
}
if (CodeFlow.isPrimitive(descriptor)) {

View File

@@ -685,6 +685,12 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (descriptor == null || !memberDeclaringClassSlashedDescriptor.equals(descriptor.substring(1))) {
mv.visitTypeInsn(CHECKCAST, memberDeclaringClassSlashedDescriptor);
}
} else {
if (descriptor != null) {
// A static field/method call will not consume what is on the stack,
// it needs to be popped off.
mv.visitInsn(POP);
}
}
if (this.member instanceof Field) {
mv.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, memberDeclaringClassSlashedDescriptor,