@@ -205,14 +205,14 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
205
205
val hasElse = ! elsep.isEmpty
206
206
val postIf = if (hasElse) new asm.Label else failure
207
207
208
- genCond(condp, success, failure)
208
+ genCond(condp, success, failure, targetIfNoJump = success)
209
+ markProgramPoint(success)
209
210
210
211
val thenKind = tpeTK(thenp)
211
212
val elseKind = if (! hasElse) UNIT else tpeTK(elsep)
212
213
def hasUnitBranch = (thenKind == UNIT || elseKind == UNIT ) && expectedType == UNIT
213
214
val resKind = if (hasUnitBranch) UNIT else tpeTK(tree)
214
215
215
- markProgramPoint(success)
216
216
genLoad(thenp, resKind)
217
217
if (hasElse) { bc goTo postIf }
218
218
markProgramPoint(failure)
@@ -238,14 +238,14 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
238
238
else if (isArrayOp(code)) genArrayOp(tree, code, expectedType)
239
239
else if (isLogicalOp(code) || isComparisonOp(code)) {
240
240
val success, failure, after = new asm.Label
241
- genCond(tree, success, failure)
241
+ genCond(tree, success, failure, targetIfNoJump = success )
242
242
// success block
243
- markProgramPoint(success)
244
- bc boolconst true
245
- bc goTo after
243
+ markProgramPoint(success)
244
+ bc boolconst true
245
+ bc goTo after
246
246
// failure block
247
- markProgramPoint(failure)
248
- bc boolconst false
247
+ markProgramPoint(failure)
248
+ bc boolconst false
249
249
// after
250
250
markProgramPoint(after)
251
251
@@ -1167,57 +1167,60 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1167
1167
}
1168
1168
1169
1169
/* Emit code to compare the two top-most stack values using the 'op' operator. */
1170
- private def genCJUMP (success : asm.Label , failure : asm.Label , op : TestOp , tk : BType ): Unit = {
1171
- if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
1172
- bc.emitIF_ICMP(op, success)
1173
- } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
1174
- bc.emitIF_ACMP(op, success)
1175
- } else {
1176
- import Primitives ._
1177
- (tk : @ unchecked) match {
1178
- case LONG => emit(asm.Opcodes .LCMP )
1179
- case FLOAT =>
1180
- if (op == LT || op == LE ) emit(asm.Opcodes .FCMPG )
1181
- else emit(asm.Opcodes .FCMPL )
1182
- case DOUBLE =>
1183
- if (op == LT || op == LE ) emit(asm.Opcodes .DCMPG )
1184
- else emit(asm.Opcodes .DCMPL )
1170
+ private def genCJUMP (success : asm.Label , failure : asm.Label , op : TestOp , tk : BType , targetIfNoJump : asm.Label ): Unit = {
1171
+ if (targetIfNoJump == success) genCJUMP(failure, success, op.negate(), tk, targetIfNoJump)
1172
+ else {
1173
+ if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
1174
+ bc.emitIF_ICMP(op, success)
1175
+ } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
1176
+ bc.emitIF_ACMP(op, success)
1177
+ } else {
1178
+ import Primitives ._
1179
+ (tk : @ unchecked) match {
1180
+ case LONG => emit(asm.Opcodes .LCMP )
1181
+ case FLOAT =>
1182
+ if (op == LT || op == LE ) emit(asm.Opcodes .FCMPG )
1183
+ else emit(asm.Opcodes .FCMPL )
1184
+ case DOUBLE =>
1185
+ if (op == LT || op == LE ) emit(asm.Opcodes .DCMPG )
1186
+ else emit(asm.Opcodes .DCMPL )
1187
+ }
1188
+ bc.emitIF(op, success)
1185
1189
}
1186
- bc.emitIF(op, success)
1190
+ if (targetIfNoJump != failure) bc goTo failure
1187
1191
}
1188
- bc goTo failure
1189
1192
}
1190
1193
1191
1194
/* Emits code to compare (and consume) stack-top and zero using the 'op' operator */
1192
- private def genCZJUMP (success : asm.Label , failure : asm.Label , op : TestOp , tk : BType ): Unit = {
1195
+ private def genCZJUMP (success : asm.Label , failure : asm.Label , op : TestOp , tk : BType , targetIfNoJump : asm. Label ): Unit = {
1193
1196
import Primitives ._
1194
-
1195
- if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
1196
- bc.emitIF(op, success)
1197
- } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
1198
- // @unchecked because references aren't compared with GT, GE, LT, LE.
1199
-
1200
- (op : @ unchecked) match {
1201
- case EQ => bc emitIFNULL success
1202
- case NE => bc emitIFNONNULL success
1203
- }
1204
- } else {
1205
- (tk : @ unchecked) match {
1206
- case LONG =>
1207
- emit(asm.Opcodes .LCONST_0 )
1208
- emit(asm.Opcodes .LCMP )
1209
- case FLOAT =>
1210
- emit(asm.Opcodes .FCONST_0 )
1211
- if (op == LT || op == LE ) emit(asm.Opcodes .FCMPG )
1212
- else emit(asm.Opcodes .FCMPL )
1213
- case DOUBLE =>
1214
- emit(asm.Opcodes .DCONST_0 )
1215
- if (op == LT || op == LE ) emit(asm.Opcodes .DCMPG )
1216
- else emit(asm.Opcodes .DCMPL )
1197
+ if (targetIfNoJump == success) genCZJUMP(failure, success, op.negate(), tk, targetIfNoJump)
1198
+ else {
1199
+ if (tk.isIntSizedType) { // BOOL, BYTE, CHAR, SHORT, or INT
1200
+ bc.emitIF(op, success)
1201
+ } else if (tk.isRef) { // REFERENCE(_) | ARRAY(_)
1202
+ op match { // references are only compared with EQ and NE
1203
+ case EQ => bc emitIFNULL success
1204
+ case NE => bc emitIFNONNULL success
1205
+ }
1206
+ } else {
1207
+ (tk : @ unchecked) match {
1208
+ case LONG =>
1209
+ emit(asm.Opcodes .LCONST_0 )
1210
+ emit(asm.Opcodes .LCMP )
1211
+ case FLOAT =>
1212
+ emit(asm.Opcodes .FCONST_0 )
1213
+ if (op == LT || op == LE ) emit(asm.Opcodes .FCMPG )
1214
+ else emit(asm.Opcodes .FCMPL )
1215
+ case DOUBLE =>
1216
+ emit(asm.Opcodes .DCONST_0 )
1217
+ if (op == LT || op == LE ) emit(asm.Opcodes .DCMPG )
1218
+ else emit(asm.Opcodes .DCMPL )
1219
+ }
1220
+ bc.emitIF(op, success)
1217
1221
}
1218
- bc.emitIF(op, success)
1222
+ if (targetIfNoJump != failure) bc goTo failure
1219
1223
}
1220
- bc goTo failure
1221
1224
}
1222
1225
1223
1226
val testOpForPrimitive : Array [TestOp ] = {
@@ -1232,29 +1235,26 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1232
1235
* Generate code for conditional expressions.
1233
1236
* The jump targets success/failure of the test are `then-target` and `else-target` resp.
1234
1237
*/
1235
- private def genCond (tree : Tree , success : asm.Label , failure : asm.Label ): Unit = {
1238
+ private def genCond (tree : Tree , success : asm.Label , failure : asm.Label , targetIfNoJump : asm. Label ): Unit = {
1236
1239
1237
1240
def genComparisonOp (l : Tree , r : Tree , code : Int ): Unit = {
1238
- val op : TestOp = testOpForPrimitive(code - ScalaPrimitivesOps .ID )
1239
- // special-case reference (in)equality test for null (null eq x, x eq null)
1240
- var nonNullSide : Tree = null
1241
- if (ScalaPrimitivesOps .isReferenceEqualityOp(code) &&
1242
- { nonNullSide = ifOneIsNull(l, r); nonNullSide != null }
1243
- ) {
1241
+ val op = testOpForPrimitive(code)
1242
+ val nonNullSide = if (ScalaPrimitivesOps .isReferenceEqualityOp(code)) ifOneIsNull(l, r) else null
1243
+ if (nonNullSide != null ) {
1244
+ // special-case reference (in)equality test for null (null eq x, x eq null)
1244
1245
genLoad(nonNullSide, ObjectReference )
1245
- genCZJUMP(success, failure, op, ObjectReference )
1246
- }
1247
- else {
1246
+ genCZJUMP(success, failure, op, ObjectReference , targetIfNoJump)
1247
+ } else {
1248
1248
val tk = tpeTK(l).maxType(tpeTK(r))
1249
1249
genLoad(l, tk)
1250
1250
genLoad(r, tk)
1251
- genCJUMP(success, failure, op, tk)
1251
+ genCJUMP(success, failure, op, tk, targetIfNoJump )
1252
1252
}
1253
1253
}
1254
1254
1255
- def default () = {
1255
+ def loadAndTestBoolean () = {
1256
1256
genLoad(tree, BOOL )
1257
- genCZJUMP(success, failure, Primitives .NE , BOOL )
1257
+ genCZJUMP(success, failure, Primitives .NE , BOOL , targetIfNoJump )
1258
1258
}
1259
1259
1260
1260
lineNumber(tree)
@@ -1265,38 +1265,35 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1265
1265
1266
1266
// lhs and rhs of test
1267
1267
lazy val Select (lhs, _) = fun
1268
- val rhs = if (args.isEmpty) EmptyTree else args.head; // args.isEmpty only for ZNOT
1268
+ val rhs = if (args.isEmpty) EmptyTree else args.head // args.isEmpty only for ZNOT
1269
1269
1270
- def genZandOrZor (and : Boolean ): Unit = { // TODO WRONG
1270
+ def genZandOrZor (and : Boolean ): Unit = {
1271
1271
// reaching "keepGoing" indicates the rhs should be evaluated too (ie not short-circuited).
1272
1272
val keepGoing = new asm.Label
1273
1273
1274
- if (and) genCond(lhs, keepGoing, failure)
1275
- else genCond(lhs, success, keepGoing)
1274
+ if (and) genCond(lhs, keepGoing, failure, targetIfNoJump = keepGoing )
1275
+ else genCond(lhs, success, keepGoing, targetIfNoJump = keepGoing )
1276
1276
1277
1277
markProgramPoint(keepGoing)
1278
- genCond(rhs, success, failure)
1278
+ genCond(rhs, success, failure, targetIfNoJump )
1279
1279
}
1280
1280
1281
-
1282
1281
primitives.getPrimitive(tree, lhs.tpe) match {
1283
- case ZNOT => genCond(lhs, failure, success)
1282
+ case ZNOT => genCond(lhs, failure, success, targetIfNoJump )
1284
1283
case ZAND => genZandOrZor(and = true )
1285
1284
case ZOR => genZandOrZor(and = false )
1286
1285
case code =>
1287
- // TODO !!!!!!!!!! isReferenceType, in the sense of TypeKind? (ie non-array, non-boxed, non-nothing, may be null)
1288
1286
if (ScalaPrimitivesOps .isUniversalEqualityOp(code) && tpeTK(lhs).isClass) {
1289
- // `lhs` has reference type
1290
- if (code == EQ ) genEqEqPrimitive(lhs, rhs, success, failure)
1291
- else genEqEqPrimitive(lhs, rhs, failure, success)
1292
- }
1293
- else if (ScalaPrimitivesOps .isComparisonOp(code))
1287
+ // rewrite `==` to null tests and `equals`. not needed for arrays (`equals` is reference equality).
1288
+ if (code == EQ ) genEqEqPrimitive(lhs, rhs, success, failure, targetIfNoJump)
1289
+ else genEqEqPrimitive(lhs, rhs, failure, success, targetIfNoJump)
1290
+ } else if (ScalaPrimitivesOps .isComparisonOp(code)) {
1294
1291
genComparisonOp(lhs, rhs, code)
1295
- else
1296
- default ()
1292
+ } else
1293
+ loadAndTestBoolean ()
1297
1294
}
1298
1295
1299
- case _ => default ()
1296
+ case _ => loadAndTestBoolean ()
1300
1297
}
1301
1298
1302
1299
} // end of genCond()
@@ -1308,7 +1305,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1308
1305
* @param l left-hand-side of the '=='
1309
1306
* @param r right-hand-side of the '=='
1310
1307
*/
1311
- def genEqEqPrimitive (l : Tree , r : Tree , success : asm.Label , failure : asm.Label ): Unit = {
1308
+ def genEqEqPrimitive (l : Tree , r : Tree , success : asm.Label , failure : asm.Label , targetIfNoJump : asm. Label ): Unit = {
1312
1309
1313
1310
/* True if the equality comparison is between values that require the use of the rich equality
1314
1311
* comparator (scala.runtime.Comparator.equals). This is the case when either side of the
@@ -1330,26 +1327,27 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1330
1327
else externalEqualsNumObject
1331
1328
} else externalEquals
1332
1329
}
1330
+
1333
1331
genLoad(l, ObjectReference )
1334
1332
genLoad(r, ObjectReference )
1335
1333
genCallMethod(equalsMethod, InvokeStyle .Static )
1336
- genCZJUMP(success, failure, Primitives .NE , BOOL )
1334
+ genCZJUMP(success, failure, Primitives .NE , BOOL , targetIfNoJump )
1337
1335
}
1338
1336
else {
1339
1337
if (isNull(l)) {
1340
1338
// null == expr -> expr eq null
1341
1339
genLoad(r, ObjectReference )
1342
- genCZJUMP(success, failure, Primitives .EQ , ObjectReference )
1340
+ genCZJUMP(success, failure, Primitives .EQ , ObjectReference , targetIfNoJump )
1343
1341
} else if (isNull(r)) {
1344
1342
// expr == null -> expr eq null
1345
1343
genLoad(l, ObjectReference )
1346
- genCZJUMP(success, failure, Primitives .EQ , ObjectReference )
1344
+ genCZJUMP(success, failure, Primitives .EQ , ObjectReference , targetIfNoJump )
1347
1345
} else if (isNonNullExpr(l)) {
1348
1346
// SI-7852 Avoid null check if L is statically non-null.
1349
1347
genLoad(l, ObjectReference )
1350
1348
genLoad(r, ObjectReference )
1351
1349
genCallMethod(Object_equals , InvokeStyle .Virtual )
1352
- genCZJUMP(success, failure, Primitives .NE , BOOL )
1350
+ genCZJUMP(success, failure, Primitives .NE , BOOL , targetIfNoJump )
1353
1351
} else {
1354
1352
// l == r -> if (l eq null) r eq null else l.equals(r)
1355
1353
val eqEqTempLocal = locals.makeLocal(ObjectReference , nme_EQEQ_LOCAL_VAR.mangledString, Object_Type , r.pos)
@@ -1360,17 +1358,17 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
1360
1358
genLoad(r, ObjectReference )
1361
1359
locals.store(eqEqTempLocal)
1362
1360
bc dup ObjectReference
1363
- genCZJUMP(lNull, lNonNull, Primitives .EQ , ObjectReference )
1361
+ genCZJUMP(lNull, lNonNull, Primitives .EQ , ObjectReference , targetIfNoJump = lNull )
1364
1362
1365
1363
markProgramPoint(lNull)
1366
1364
bc drop ObjectReference
1367
1365
locals.load(eqEqTempLocal)
1368
- genCZJUMP(success, failure, Primitives .EQ , ObjectReference )
1366
+ genCZJUMP(success, failure, Primitives .EQ , ObjectReference , targetIfNoJump = lNonNull )
1369
1367
1370
1368
markProgramPoint(lNonNull)
1371
1369
locals.load(eqEqTempLocal)
1372
1370
genCallMethod(Object_equals , InvokeStyle .Virtual )
1373
- genCZJUMP(success, failure, Primitives .NE , BOOL )
1371
+ genCZJUMP(success, failure, Primitives .NE , BOOL , targetIfNoJump )
1374
1372
}
1375
1373
}
1376
1374
}
0 commit comments