@@ -202,14 +202,14 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
202
202
val hasElse = ! elsep.isEmpty
203
203
val postIf = if (hasElse) new asm.Label else failure
204
204
205
- genCond(condp, success, failure)
205
+ genCond(condp, success, failure, targetIfNoJump = success)
206
+ markProgramPoint(success)
206
207
207
208
val thenKind = tpeTK(thenp)
208
209
val elseKind = if (! hasElse) UNIT else tpeTK(elsep)
209
210
def hasUnitBranch = (thenKind == UNIT || elseKind == UNIT )
210
211
val resKind = if (hasUnitBranch) UNIT else tpeTK(tree)
211
212
212
- markProgramPoint(success)
213
213
genLoad(thenp, resKind)
214
214
if (hasElse) { bc goTo postIf }
215
215
markProgramPoint(failure)
@@ -234,14 +234,14 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
234
234
else if (isArrayOp(code)) genArrayOp(tree, code, expectedType)
235
235
else if (isLogicalOp(code) || isComparisonOp(code)) {
236
236
val success, failure, after = new asm.Label
237
- genCond(tree, success, failure)
237
+ genCond(tree, success, failure, targetIfNoJump = success )
238
238
// success block
239
- markProgramPoint(success)
240
- bc boolconst true
241
- bc goTo after
239
+ markProgramPoint(success)
240
+ bc boolconst true
241
+ bc goTo after
242
242
// failure block
243
- markProgramPoint(failure)
244
- bc boolconst false
243
+ markProgramPoint(failure)
244
+ bc boolconst false
245
245
// after
246
246
markProgramPoint(after)
247
247
@@ -1108,53 +1108,58 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
1108
1108
}
1109
1109
1110
1110
/* Emit code to compare the two top-most stack values using the 'op' operator. */
1111
- private def genCJUMP (success : asm.Label , failure : asm.Label , op : TestOp , tk : BType ) {
1112
- if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
1113
- bc.emitIF_ICMP(op, success)
1114
- } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
1115
- bc.emitIF_ACMP(op, success)
1116
- } else {
1117
- (tk : @ unchecked) match {
1118
- case LONG => emit(asm.Opcodes .LCMP )
1119
- case FLOAT =>
1120
- if (op == TestOp .LT || op == TestOp .LE ) emit(asm.Opcodes .FCMPG )
1121
- else emit(asm.Opcodes .FCMPL )
1122
- case DOUBLE =>
1123
- if (op == TestOp .LT || op == TestOp .LE ) emit(asm.Opcodes .DCMPG )
1124
- else emit(asm.Opcodes .DCMPL )
1111
+ private def genCJUMP (success : asm.Label , failure : asm.Label , op : TestOp , tk : BType , targetIfNoJump : asm.Label ) {
1112
+ if (targetIfNoJump == success) genCJUMP(failure, success, op.negate, tk, targetIfNoJump)
1113
+ else {
1114
+ if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
1115
+ bc.emitIF_ICMP(op, success)
1116
+ } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
1117
+ bc.emitIF_ACMP(op, success)
1118
+ } else {
1119
+ (tk : @ unchecked) match {
1120
+ case LONG => emit(asm.Opcodes .LCMP )
1121
+ case FLOAT =>
1122
+ if (op == TestOp .LT || op == TestOp .LE ) emit(asm.Opcodes .FCMPG )
1123
+ else emit(asm.Opcodes .FCMPL )
1124
+ case DOUBLE =>
1125
+ if (op == TestOp .LT || op == TestOp .LE ) emit(asm.Opcodes .DCMPG )
1126
+ else emit(asm.Opcodes .DCMPL )
1127
+ }
1128
+ bc.emitIF(op, success)
1125
1129
}
1126
- bc.emitIF(op, success)
1130
+ if (targetIfNoJump != failure) bc goTo failure
1127
1131
}
1128
- bc goTo failure
1129
1132
}
1130
1133
1131
1134
/* Emits code to compare (and consume) stack-top and zero using the 'op' operator */
1132
- private def genCZJUMP (success : asm.Label , failure : asm.Label , op : TestOp , tk : BType ) {
1133
- if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
1134
- bc.emitIF(op, success)
1135
- } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
1136
- // @unchecked because references aren't compared with GT, GE, LT, LE.
1137
- (op : @ unchecked) match {
1138
- case TestOp .EQ => bc emitIFNULL success
1139
- case TestOp .NE => bc emitIFNONNULL success
1140
- }
1141
- } else {
1142
- (tk : @ unchecked) match {
1143
- case LONG =>
1144
- emit(asm.Opcodes .LCONST_0 )
1145
- emit(asm.Opcodes .LCMP )
1146
- case FLOAT =>
1147
- emit(asm.Opcodes .FCONST_0 )
1148
- if (op == TestOp .LT || op == TestOp .LE ) emit(asm.Opcodes .FCMPG )
1149
- else emit(asm.Opcodes .FCMPL )
1150
- case DOUBLE =>
1151
- emit(asm.Opcodes .DCONST_0 )
1152
- if (op == TestOp .LT || op == TestOp .LE ) emit(asm.Opcodes .DCMPG )
1153
- else emit(asm.Opcodes .DCMPL )
1135
+ private def genCZJUMP (success : asm.Label , failure : asm.Label , op : TestOp , tk : BType , targetIfNoJump : asm.Label ) {
1136
+ if (targetIfNoJump == success) genCZJUMP(failure, success, op.negate, tk, targetIfNoJump)
1137
+ else {
1138
+ if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
1139
+ bc.emitIF(op, success)
1140
+ } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
1141
+ op match { // references are only compared with EQ and NE
1142
+ case TestOp .EQ => bc emitIFNULL success
1143
+ case TestOp .NE => bc emitIFNONNULL success
1144
+ }
1145
+ } else {
1146
+ (tk : @ unchecked) match {
1147
+ case LONG =>
1148
+ emit(asm.Opcodes .LCONST_0 )
1149
+ emit(asm.Opcodes .LCMP )
1150
+ case FLOAT =>
1151
+ emit(asm.Opcodes .FCONST_0 )
1152
+ if (op == TestOp .LT || op == TestOp .LE ) emit(asm.Opcodes .FCMPG )
1153
+ else emit(asm.Opcodes .FCMPL )
1154
+ case DOUBLE =>
1155
+ emit(asm.Opcodes .DCONST_0 )
1156
+ if (op == TestOp .LT || op == TestOp .LE ) emit(asm.Opcodes .DCMPG )
1157
+ else emit(asm.Opcodes .DCMPL )
1158
+ }
1159
+ bc.emitIF(op, success)
1154
1160
}
1155
- bc.emitIF(op, success)
1161
+ if (targetIfNoJump != failure) bc goTo failure
1156
1162
}
1157
- bc goTo failure
1158
1163
}
1159
1164
1160
1165
def testOpForPrimitive (primitiveCode : Int ) = (primitiveCode : @ switch) match {
@@ -1179,29 +1184,26 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
1179
1184
* Generate code for conditional expressions.
1180
1185
* The jump targets success/failure of the test are `then-target` and `else-target` resp.
1181
1186
*/
1182
- private def genCond (tree : Tree , success : asm.Label , failure : asm.Label ) {
1187
+ private def genCond (tree : Tree , success : asm.Label , failure : asm.Label , targetIfNoJump : asm. Label ) {
1183
1188
1184
1189
def genComparisonOp (l : Tree , r : Tree , code : Int ) {
1185
- val op : TestOp = testOpForPrimitive(code)
1186
- // special-case reference (in)equality test for null (null eq x, x eq null)
1187
- var nonNullSide : Tree = null
1188
- if (scalaPrimitives.isReferenceEqualityOp(code) &&
1189
- { nonNullSide = ifOneIsNull(l, r); nonNullSide != null }
1190
- ) {
1190
+ val op = testOpForPrimitive(code)
1191
+ val nonNullSide = if (scalaPrimitives.isReferenceEqualityOp(code)) ifOneIsNull(l, r) else null
1192
+ if (nonNullSide != null ) {
1193
+ // special-case reference (in)equality test for null (null eq x, x eq null)
1191
1194
genLoad(nonNullSide, ObjectRef )
1192
- genCZJUMP(success, failure, op, ObjectRef )
1193
- }
1194
- else {
1195
+ genCZJUMP(success, failure, op, ObjectRef , targetIfNoJump)
1196
+ } else {
1195
1197
val tk = tpeTK(l).maxType(tpeTK(r))
1196
1198
genLoad(l, tk)
1197
1199
genLoad(r, tk)
1198
- genCJUMP(success, failure, op, tk)
1200
+ genCJUMP(success, failure, op, tk, targetIfNoJump )
1199
1201
}
1200
1202
}
1201
1203
1202
- def default () = {
1204
+ def loadAndTestBoolean () = {
1203
1205
genLoad(tree, BOOL )
1204
- genCZJUMP(success, failure, TestOp .NE , BOOL )
1206
+ genCZJUMP(success, failure, TestOp .NE , BOOL , targetIfNoJump )
1205
1207
}
1206
1208
1207
1209
lineNumber(tree)
@@ -1212,37 +1214,35 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
1212
1214
1213
1215
// lhs and rhs of test
1214
1216
lazy val Select (lhs, _) = fun
1215
- val rhs = if (args.isEmpty) EmptyTree else args.head; // args.isEmpty only for ZNOT
1217
+ val rhs = if (args.isEmpty) EmptyTree else args.head // args.isEmpty only for ZNOT
1216
1218
1217
- def genZandOrZor (and : Boolean ) { // TODO WRONG
1219
+ def genZandOrZor (and : Boolean ) {
1218
1220
// reaching "keepGoing" indicates the rhs should be evaluated too (ie not short-circuited).
1219
1221
val keepGoing = new asm.Label
1220
1222
1221
- if (and) genCond(lhs, keepGoing, failure)
1222
- else genCond(lhs, success, keepGoing)
1223
+ if (and) genCond(lhs, keepGoing, failure, targetIfNoJump = keepGoing )
1224
+ else genCond(lhs, success, keepGoing, targetIfNoJump = keepGoing )
1223
1225
1224
1226
markProgramPoint(keepGoing)
1225
- genCond(rhs, success, failure)
1227
+ genCond(rhs, success, failure, targetIfNoJump )
1226
1228
}
1227
1229
1228
1230
getPrimitive(fun.symbol) match {
1229
- case ZNOT => genCond(lhs, failure, success)
1231
+ case ZNOT => genCond(lhs, failure, success, targetIfNoJump )
1230
1232
case ZAND => genZandOrZor(and = true )
1231
1233
case ZOR => genZandOrZor(and = false )
1232
1234
case code =>
1233
- // TODO !!!!!!!!!! isReferenceType, in the sense of TypeKind? (ie non-array, non-boxed, non-nothing, may be null)
1234
1235
if (scalaPrimitives.isUniversalEqualityOp(code) && tpeTK(lhs).isClass) {
1235
- // `lhs` has reference type
1236
- if (code == EQ ) genEqEqPrimitive(lhs, rhs, success, failure, tree.pos)
1237
- else genEqEqPrimitive(lhs, rhs, failure, success, tree.pos)
1238
- }
1239
- else if (scalaPrimitives.isComparisonOp(code))
1236
+ // rewrite `==` to null tests and `equals`. not needed for arrays (`equals` is reference equality).
1237
+ if (code == EQ ) genEqEqPrimitive(lhs, rhs, success, failure, targetIfNoJump, tree.pos)
1238
+ else genEqEqPrimitive(lhs, rhs, failure, success, targetIfNoJump, tree.pos)
1239
+ } else if (scalaPrimitives.isComparisonOp(code)) {
1240
1240
genComparisonOp(lhs, rhs, code)
1241
- else
1242
- default
1241
+ } else
1242
+ loadAndTestBoolean()
1243
1243
}
1244
1244
1245
- case _ => default
1245
+ case _ => loadAndTestBoolean()
1246
1246
}
1247
1247
1248
1248
} // end of genCond()
@@ -1254,7 +1254,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
1254
1254
* @param l left-hand-side of the '=='
1255
1255
* @param r right-hand-side of the '=='
1256
1256
*/
1257
- def genEqEqPrimitive (l : Tree , r : Tree , success : asm.Label , failure : asm.Label , pos : Position ) {
1257
+ def genEqEqPrimitive (l : Tree , r : Tree , success : asm.Label , failure : asm.Label , targetIfNoJump : asm. Label , pos : Position ) {
1258
1258
1259
1259
/* True if the equality comparison is between values that require the use of the rich equality
1260
1260
* comparator (scala.runtime.Comparator.equals). This is the case when either side of the
@@ -1264,7 +1264,6 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
1264
1264
*/
1265
1265
val mustUseAnyComparator : Boolean = {
1266
1266
val areSameFinals = l.tpe.isFinalType && r.tpe.isFinalType && (l.tpe =:= r.tpe)
1267
-
1268
1267
! areSameFinals && platform.isMaybeBoxed(l.tpe.typeSymbol) && platform.isMaybeBoxed(r.tpe.typeSymbol)
1269
1268
}
1270
1269
@@ -1279,23 +1278,22 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
1279
1278
genLoad(l, ObjectRef )
1280
1279
genLoad(r, ObjectRef )
1281
1280
genCallMethod(equalsMethod, InvokeStyle .Static , pos)
1282
- genCZJUMP(success, failure, TestOp .NE , BOOL )
1283
- }
1284
- else {
1281
+ genCZJUMP(success, failure, TestOp .NE , BOOL , targetIfNoJump)
1282
+ } else {
1285
1283
if (isNull(l)) {
1286
1284
// null == expr -> expr eq null
1287
1285
genLoad(r, ObjectRef )
1288
- genCZJUMP(success, failure, TestOp .EQ , ObjectRef )
1286
+ genCZJUMP(success, failure, TestOp .EQ , ObjectRef , targetIfNoJump )
1289
1287
} else if (isNull(r)) {
1290
1288
// expr == null -> expr eq null
1291
1289
genLoad(l, ObjectRef )
1292
- genCZJUMP(success, failure, TestOp .EQ , ObjectRef )
1290
+ genCZJUMP(success, failure, TestOp .EQ , ObjectRef , targetIfNoJump )
1293
1291
} else if (isNonNullExpr(l)) {
1294
1292
// SI-7852 Avoid null check if L is statically non-null.
1295
1293
genLoad(l, ObjectRef )
1296
1294
genLoad(r, ObjectRef )
1297
1295
genCallMethod(Object_equals , InvokeStyle .Virtual , pos)
1298
- genCZJUMP(success, failure, TestOp .NE , BOOL )
1296
+ genCZJUMP(success, failure, TestOp .NE , BOOL , targetIfNoJump )
1299
1297
} else {
1300
1298
// l == r -> if (l eq null) r eq null else l.equals(r)
1301
1299
val eqEqTempLocal = locals.makeLocal(ObjectRef , nme.EQEQ_LOCAL_VAR .toString)
@@ -1306,17 +1304,17 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
1306
1304
genLoad(r, ObjectRef )
1307
1305
locals.store(eqEqTempLocal)
1308
1306
bc dup ObjectRef
1309
- genCZJUMP(lNull, lNonNull, TestOp .EQ , ObjectRef )
1307
+ genCZJUMP(lNull, lNonNull, TestOp .EQ , ObjectRef , targetIfNoJump = lNull )
1310
1308
1311
1309
markProgramPoint(lNull)
1312
1310
bc drop ObjectRef
1313
1311
locals.load(eqEqTempLocal)
1314
- genCZJUMP(success, failure, TestOp .EQ , ObjectRef )
1312
+ genCZJUMP(success, failure, TestOp .EQ , ObjectRef , targetIfNoJump = lNonNull )
1315
1313
1316
1314
markProgramPoint(lNonNull)
1317
1315
locals.load(eqEqTempLocal)
1318
1316
genCallMethod(Object_equals , InvokeStyle .Virtual , pos)
1319
- genCZJUMP(success, failure, TestOp .NE , BOOL )
1317
+ genCZJUMP(success, failure, TestOp .NE , BOOL , targetIfNoJump )
1320
1318
}
1321
1319
}
1322
1320
}
0 commit comments