1
1
/*
2
- * Copyright 2002-2014 the original author or authors.
2
+ * Copyright 2002-2016 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
16
16
17
17
package org .springframework .expression .spel .ast ;
18
18
19
- import org .springframework .asm .Label ;
20
19
import org .springframework .asm .MethodVisitor ;
20
+ import org .springframework .expression .EvaluationContext ;
21
21
import org .springframework .expression .EvaluationException ;
22
22
import org .springframework .expression .spel .CodeFlow ;
23
23
import org .springframework .expression .spel .ExpressionState ;
@@ -43,105 +43,52 @@ public BooleanTypedValue getValueInternal(ExpressionState state) throws Evaluati
43
43
Object right = getRightOperand ().getValueInternal (state ).getValue ();
44
44
this .leftActualDescriptor = CodeFlow .toDescriptorFromObject (left );
45
45
this .rightActualDescriptor = CodeFlow .toDescriptorFromObject (right );
46
- return BooleanTypedValue .forValue (equalityCheck (state , left , right ));
46
+ return BooleanTypedValue .forValue (
47
+ equalityCheck (state .getEvaluationContext (), left , right ));
47
48
}
48
-
49
+
49
50
// This check is different to the one in the other numeric operators (OpLt/etc)
50
51
// because it allows for simple object comparison
51
52
@ Override
52
53
public boolean isCompilable () {
53
54
SpelNodeImpl left = getLeftOperand ();
54
- SpelNodeImpl right = getRightOperand ();
55
+ SpelNodeImpl right = getRightOperand ();
55
56
if (!left .isCompilable () || !right .isCompilable ()) {
56
57
return false ;
57
58
}
58
59
59
60
String leftDesc = left .exitTypeDescriptor ;
60
61
String rightDesc = right .exitTypeDescriptor ;
61
- DescriptorComparison dc = DescriptorComparison .checkNumericCompatibility (
62
- leftDesc , rightDesc , this .leftActualDescriptor , this .rightActualDescriptor );
62
+ DescriptorComparison dc = DescriptorComparison .checkNumericCompatibility (leftDesc ,
63
+ rightDesc , this .leftActualDescriptor , this .rightActualDescriptor );
63
64
return (!dc .areNumbers || dc .areCompatible );
64
65
}
65
-
66
-
66
+
67
67
@ Override
68
68
public void generateCode (MethodVisitor mv , CodeFlow cf ) {
69
+ cf .loadEvaluationContext (mv );
69
70
String leftDesc = getLeftOperand ().exitTypeDescriptor ;
70
71
String rightDesc = getRightOperand ().exitTypeDescriptor ;
71
- Label elseTarget = new Label ();
72
- Label endOfIf = new Label ();
73
72
boolean leftPrim = CodeFlow .isPrimitive (leftDesc );
74
73
boolean rightPrim = CodeFlow .isPrimitive (rightDesc );
75
74
76
- DescriptorComparison dc = DescriptorComparison .checkNumericCompatibility (
77
- leftDesc , rightDesc , this .leftActualDescriptor , this .rightActualDescriptor );
78
-
79
- if (dc .areNumbers && dc .areCompatible ) {
80
- char targetType = dc .compatibleType ;
81
- getLeftOperand ().generateCode (mv , cf );
82
- if (!leftPrim ) {
83
- CodeFlow .insertUnboxInsns (mv , targetType , leftDesc );
84
- }
85
- cf .enterCompilationScope ();
86
- getRightOperand ().generateCode (mv , cf );
87
- cf .exitCompilationScope ();
88
- if (!rightPrim ) {
89
- CodeFlow .insertUnboxInsns (mv , targetType , rightDesc );
90
- }
91
- // assert: SpelCompiler.boxingCompatible(leftDesc, rightDesc)
92
- if (targetType == 'D' ) {
93
- mv .visitInsn (DCMPL );
94
- mv .visitJumpInsn (IFNE , elseTarget );
95
- }
96
- else if (targetType == 'F' ) {
97
- mv .visitInsn (FCMPL );
98
- mv .visitJumpInsn (IFNE , elseTarget );
99
- }
100
- else if (targetType == 'J' ) {
101
- mv .visitInsn (LCMP );
102
- mv .visitJumpInsn (IFNE , elseTarget );
103
- }
104
- else if (targetType == 'I' || targetType == 'Z' ) {
105
- mv .visitJumpInsn (IF_ICMPNE , elseTarget );
106
- }
107
- else {
108
- throw new IllegalStateException ("Unexpected descriptor " + leftDesc );
109
- }
75
+ cf .enterCompilationScope ();
76
+ getLeftOperand ().generateCode (mv , cf );
77
+ cf .exitCompilationScope ();
78
+ if (leftPrim ) {
79
+ CodeFlow .insertBoxIfNecessary (mv , leftDesc .charAt (0 ));
110
80
}
111
- else {
112
- getLeftOperand ().generateCode (mv , cf );
113
- if (leftPrim ) {
114
- CodeFlow .insertBoxIfNecessary (mv , leftDesc .charAt (0 ));
115
- }
116
- getRightOperand ().generateCode (mv , cf );
117
- if (rightPrim ) {
118
- CodeFlow .insertBoxIfNecessary (mv , rightDesc .charAt (0 ));
119
- }
120
- Label leftNotNull = new Label ();
121
- mv .visitInsn (DUP_X1 ); // dup right on the top of the stack
122
- mv .visitJumpInsn (IFNONNULL , leftNotNull );
123
- // Right is null!
124
- mv .visitInsn (SWAP );
125
- mv .visitInsn (POP ); // remove it
126
- Label rightNotNull = new Label ();
127
- mv .visitJumpInsn (IFNONNULL , rightNotNull );
128
- // Left is null too
129
- mv .visitInsn (ICONST_1 );
130
- mv .visitJumpInsn (GOTO , endOfIf );
131
- mv .visitLabel (rightNotNull );
132
- mv .visitInsn (ICONST_0 );
133
- mv .visitJumpInsn (GOTO , endOfIf );
134
- mv .visitLabel (leftNotNull );
135
- mv .visitMethodInsn (INVOKEVIRTUAL , "java/lang/Object" , "equals" , "(Ljava/lang/Object;)Z" , false );
136
- mv .visitLabel (endOfIf );
137
- cf .pushDescriptor ("Z" );
138
- return ;
81
+ cf .enterCompilationScope ();
82
+ getRightOperand ().generateCode (mv , cf );
83
+ cf .exitCompilationScope ();
84
+ if (rightPrim ) {
85
+ CodeFlow .insertBoxIfNecessary (mv , rightDesc .charAt (0 ));
139
86
}
140
- mv . visitInsn ( ICONST_1 );
141
- mv . visitJumpInsn ( GOTO , endOfIf );
142
- mv . visitLabel ( elseTarget );
143
- mv .visitInsn ( ICONST_0 );
144
- mv . visitLabel ( endOfIf );
87
+
88
+ String operatorClassName = Operator . class . getName (). replace ( '.' , '/' );
89
+ String evaluationContextClassName = EvaluationContext . class . getName (). replace ( '.' , '/' );
90
+ mv .visitMethodInsn ( INVOKESTATIC , operatorClassName , "equalityCheck" ,
91
+ "(L" + evaluationContextClassName + ";Ljava/lang/Object;Ljava/lang/Object;)Z" , false );
145
92
cf .pushDescriptor ("Z" );
146
93
}
147
94
0 commit comments