diff options
author | mihaylov <mihaylov@epfl.ch> | 2006-11-15 11:18:36 +0000 |
---|---|---|
committer | mihaylov <mihaylov@epfl.ch> | 2006-11-15 11:18:36 +0000 |
commit | d26dfbdf59f03da6adc2eb87754ba56f142dc06e (patch) | |
tree | 8b54854565e66432317cf3ee6bb8a2c2cdceb11a | |
parent | 41b2863d8dd4159058563a32ec4e9295623c9b8e (diff) | |
download | scala-d26dfbdf59f03da6adc2eb87754ba56f142dc06e.tar.gz scala-d26dfbdf59f03da6adc2eb87754ba56f142dc06e.tar.bz2 scala-d26dfbdf59f03da6adc2eb87754ba56f142dc06e.zip |
Implemented proper behaviour for sth == null an...
Implemented proper behaviour for sth == null and null == sth
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/GenICode.scala | 96 |
1 files changed, 56 insertions, 40 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 6269b012e6..abb417d230 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1340,62 +1340,78 @@ abstract class GenICode extends SubComponent { } } - def eqEqTemp: Name = "eqEqTemp$" - /** * Generate the "==" code for object references. It is equivalent of - * if (l eq null) then r eq null else l.equals(r); + * if (l eq null) r eq null else l.equals(r); * * @param l left-hand side of the '==' * @param r right-hand side of the '==' * @param ctx current context - * @param thenCtx ... - * @param elseCtx ... + * @param thenCtx target context if the comparison yields true + * @param elseCtx target context if the comparison yields false */ def genEqEqPrimitive(l: Tree, r: Tree, ctx: Context, thenCtx: Context, elseCtx: Context): Unit = { - // special-case 'null == sth' to 'sth eq null' - l match { - case Literal(Constant(null)) => - val ctx1 = genLoad(r, ctx, ANY_REF_CLASS) - ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)) - ctx1.bb.close - return - case _ => () - } - var eqEqTempVar: Symbol = null - var eqEqTempLocal: Local = null + def eqEqTempName: Name = "eqEqTemp$" - ctx.method.lookupLocal(eqEqTemp) match { - case Some(local) => - eqEqTempVar = local.sym; eqEqTempLocal = local + def getTempLocal: Local = ctx.method.lookupLocal(eqEqTempName) match { + case Some(local) => local case None => - eqEqTempVar = ctx.method.symbol.newVariable(l.pos, eqEqTemp).setFlag(Flags.SYNTHETIC) + val eqEqTempVar = + ctx.method.symbol.newVariable(l.pos, eqEqTempName).setFlag(Flags.SYNTHETIC) eqEqTempVar.setInfo(definitions.AnyRefClass.typeConstructor) - eqEqTempLocal = new Local(eqEqTempVar, REFERENCE(definitions.AnyRefClass), false) - ctx.method.addLocal(eqEqTempLocal) + val local = new Local(eqEqTempVar, REFERENCE(definitions.AnyRefClass), false) + ctx.method.addLocal(local) + local } - var ctx1 = genLoad(l, ctx, ANY_REF_CLASS) - ctx1 = genLoad(r, ctx1, ANY_REF_CLASS) - val tmpNullCtx = ctx1.newBlock - val tmpNonNullCtx = ctx1.newBlock - ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos) - ctx1.bb.emit(DUP(ANY_REF_CLASS)) - ctx1.bb.emit(CZJUMP(tmpNullCtx.bb, tmpNonNullCtx.bb, EQ, ANY_REF_CLASS)) - ctx1.bb.close - - tmpNullCtx.bb.emit(DROP(ANY_REF_CLASS), l.pos) // type of AnyRef - tmpNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal)) - tmpNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)) - tmpNullCtx.bb.close - - tmpNonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos) - tmpNonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic)) - tmpNonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) - tmpNonNullCtx.bb.close + Pair(l, r) match { + // null == expr -> expr eq null + case Pair(Literal(Constant(null)), expr) => + val ctx1 = genLoad(expr, ctx, ANY_REF_CLASS) + ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)) + ctx1.bb.close + + // expr == null -> if(expr eq null) true else expr.equals(null) + case Pair(expr, Literal(Constant(null))) => + val eqEqTempLocal = getTempLocal + var ctx1 = genLoad(expr, ctx, ANY_REF_CLASS) + ctx1.bb.emit(DUP(ANY_REF_CLASS)) + ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos) + val nonNullCtx = ctx1.newBlock + ctx1.bb.emit(CZJUMP(thenCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS)) + ctx1.bb.close + + nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos) + nonNullCtx.bb.emit(CONSTANT(Constant(null)), r.pos) + nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic)) + nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) + nonNullCtx.bb.close + + // l == r -> if (l eq null) r eq null else l.equals(r) + case _ => + val eqEqTempLocal = getTempLocal + var ctx1 = genLoad(l, ctx, ANY_REF_CLASS) + ctx1 = genLoad(r, ctx1, ANY_REF_CLASS) + val nullCtx = ctx1.newBlock + val nonNullCtx = ctx1.newBlock + ctx1.bb.emit(STORE_LOCAL(eqEqTempLocal), l.pos) + ctx1.bb.emit(DUP(ANY_REF_CLASS)) + ctx1.bb.emit(CZJUMP(nullCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS)) + ctx1.bb.close + + nullCtx.bb.emit(DROP(ANY_REF_CLASS), l.pos) // type of AnyRef + nullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal)) + nullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)) + nullCtx.bb.close + + nonNullCtx.bb.emit(LOAD_LOCAL(eqEqTempLocal), l.pos) + nonNullCtx.bb.emit(CALL_METHOD(definitions.Object_equals, Dynamic)) + nonNullCtx.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)) + nonNullCtx.bb.close + } } /** |