1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.expression.spel.ast;
18
19 import org.springframework.asm.Label;
20 import org.springframework.asm.MethodVisitor;
21 import org.springframework.expression.EvaluationException;
22 import org.springframework.expression.spel.CodeFlow;
23 import org.springframework.expression.spel.ExpressionState;
24 import org.springframework.expression.spel.support.BooleanTypedValue;
25
26
27
28
29
30
31
32 public class OpEQ extends Operator {
33
34 public OpEQ(int pos, SpelNodeImpl... operands) {
35 super("==", pos, operands);
36 this.exitTypeDescriptor = "Z";
37 }
38
39
40 @Override
41 public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
42 Object left = getLeftOperand().getValueInternal(state).getValue();
43 Object right = getRightOperand().getValueInternal(state).getValue();
44 this.leftActualDescriptor = CodeFlow.toDescriptorFromObject(left);
45 this.rightActualDescriptor = CodeFlow.toDescriptorFromObject(right);
46 return BooleanTypedValue.forValue(equalityCheck(state, left, right));
47 }
48
49
50
51 @Override
52 public boolean isCompilable() {
53 SpelNodeImpl left = getLeftOperand();
54 SpelNodeImpl right= getRightOperand();
55 if (!left.isCompilable() || !right.isCompilable()) {
56 return false;
57 }
58
59 String leftDesc = left.exitTypeDescriptor;
60 String rightDesc = right.exitTypeDescriptor;
61 DescriptorComparison dc = DescriptorComparison.checkNumericCompatibility(leftDesc, rightDesc,
62 this.leftActualDescriptor, this.rightActualDescriptor);
63 return (!dc.areNumbers || dc.areCompatible);
64 }
65
66
67 @Override
68 public void generateCode(MethodVisitor mv, CodeFlow cf) {
69 String leftDesc = getLeftOperand().exitTypeDescriptor;
70 String rightDesc = getRightOperand().exitTypeDescriptor;
71 Label elseTarget = new Label();
72 Label endOfIf = new Label();
73 boolean leftPrim = CodeFlow.isPrimitive(leftDesc);
74 boolean rightPrim = CodeFlow.isPrimitive(rightDesc);
75
76 DescriptorComparison dc = DescriptorComparison.checkNumericCompatibility(leftDesc, rightDesc,
77 this.leftActualDescriptor, this.rightActualDescriptor);
78
79 if (dc.areNumbers && dc.areCompatible) {
80 char targetType = dc.compatibleType;
81
82 getLeftOperand().generateCode(mv, cf);
83 if (!leftPrim) {
84 CodeFlow.insertUnboxInsns(mv, targetType, leftDesc);
85 }
86
87 cf.enterCompilationScope();
88 getRightOperand().generateCode(mv, cf);
89 cf.exitCompilationScope();
90 if (!rightPrim) {
91 CodeFlow.insertUnboxInsns(mv, targetType, rightDesc);
92 }
93
94 if (targetType=='D') {
95 mv.visitInsn(DCMPL);
96 mv.visitJumpInsn(IFNE, elseTarget);
97 }
98 else if (targetType=='F') {
99 mv.visitInsn(FCMPL);
100 mv.visitJumpInsn(IFNE, elseTarget);
101 }
102 else if (targetType=='J') {
103 mv.visitInsn(LCMP);
104 mv.visitJumpInsn(IFNE, elseTarget);
105 }
106 else if (targetType=='I' || targetType=='Z') {
107 mv.visitJumpInsn(IF_ICMPNE, elseTarget);
108 }
109 else {
110 throw new IllegalStateException("Unexpected descriptor "+leftDesc);
111 }
112 }
113 else {
114 getLeftOperand().generateCode(mv, cf);
115 if (leftPrim) {
116 CodeFlow.insertBoxIfNecessary(mv, leftDesc.charAt(0));
117 }
118 getRightOperand().generateCode(mv, cf);
119 if (rightPrim) {
120 CodeFlow.insertBoxIfNecessary(mv, rightDesc.charAt(0));
121 }
122 Label leftNotNull = new Label();
123 mv.visitInsn(DUP_X1);
124 mv.visitJumpInsn(IFNONNULL,leftNotNull);
125
126 mv.visitInsn(SWAP);
127 mv.visitInsn(POP);
128 Label rightNotNull = new Label();
129 mv.visitJumpInsn(IFNONNULL, rightNotNull);
130
131 mv.visitInsn(ICONST_1);
132 mv.visitJumpInsn(GOTO, endOfIf);
133 mv.visitLabel(rightNotNull);
134 mv.visitInsn(ICONST_0);
135 mv.visitJumpInsn(GOTO,endOfIf);
136 mv.visitLabel(leftNotNull);
137 mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false);
138 mv.visitLabel(endOfIf);
139 cf.pushDescriptor("Z");
140 return;
141 }
142 mv.visitInsn(ICONST_1);
143 mv.visitJumpInsn(GOTO,endOfIf);
144 mv.visitLabel(elseTarget);
145 mv.visitInsn(ICONST_0);
146 mv.visitLabel(endOfIf);
147 cf.pushDescriptor("Z");
148 }
149
150 }