summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-09-24 23:06:30 +0000
committerPaul Phillips <paulp@improving.org>2009-09-24 23:06:30 +0000
commitd17b40768ccb498e36464dd800ed5b602a7de372 (patch)
treeab923a2709e91831cae4f41012c752bd6597d0d4 /src/compiler/scala/tools/nsc
parent67a8cdb404b54439abdce81790fdff147e073103 (diff)
downloadscala-d17b40768ccb498e36464dd800ed5b602a7de372.tar.gz
scala-d17b40768ccb498e36464dd800ed5b602a7de372.tar.bz2
scala-d17b40768ccb498e36464dd800ed5b602a7de372.zip
This patch represents breaking out bits of code...
This patch represents breaking out bits of code generation related to equality so that I can log what they're doing and easily alter them; to that end there is some code generation refactoring and a couple minor XML issues that came up.
Diffstat (limited to 'src/compiler/scala/tools/nsc')
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala13
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala326
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala2
6 files changed, 184 insertions, 162 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index 027c25cd0c..4a5afb7baf 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -819,7 +819,7 @@ trait ScalacSettings {
val Ystatistics = BooleanSetting ("-Ystatistics", "Print compiler statistics")
val stop = PhasesSetting ("-Ystop", "Stop after phase")
val logEquality = BooleanSetting ("-Ylog-equality", "Log all noteworthy equality tests (hardcoded to /tmp/scala-equality-log.txt)") .
- withPostSetHook(() => scala.runtime.BoxesRunTime.setEqEqLogging(true))
+ withPostSetHook(() => scala.runtime.Equality.logEverything = true)
val refinementMethodDispatch =
ChoiceSetting ("-Ystruct-dispatch", "Selects dispatch method for structural refinement method calls",
List("no-cache", "mono-cache", "poly-cache", "invoke-dynamic"), "poly-cache") .
diff --git a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
index d205ab1098..290d90b3e9 100644
--- a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
+++ b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
@@ -508,6 +508,8 @@ abstract class ScalaPrimitives {
case _ => false
}
+ def isUniversalEqualityOp(code: Int): Boolean = (code == EQ) || (code == NE)
+ def isReferenceEqualityOp(code: Int): Boolean = (code == ID) || (code == NI)
def isArithmeticOp(code: Int): Boolean = code match {
case POS | NEG | NOT => true; // unary
diff --git a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
index 27c71e60a3..def5f1060d 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/BasicBlocks.scala
@@ -340,6 +340,19 @@ trait BasicBlocks {
instrs foreach (i => emit(i, i.pos))
}
+ /** The semantics of this are a little odd but it's designed to work
+ * seamlessly with the existing code. It emits each supplied instruction,
+ * then closes the block. The odd part is that if the instruction has
+ * pos == NoPosition, it calls the 1-arg emit, but otherwise it calls
+ * the 2-arg emit. This way I could retain existing behavior exactly by
+ * calling setPos on any instruction using the two arg version which
+ * I wanted to include in a call to emitOnly.
+ */
+ def emitOnly(instrs: Instruction*) {
+ instrs foreach (i => if (i.pos == NoPosition) emit(i) else emit(i, i.pos))
+ this.close
+ }
+
/** Close the block */
def close {
assert(instructionList.length > 0, "Empty block.")
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 5919351614..da067ae1d9 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -12,7 +12,7 @@ package icode
import scala.collection.mutable.{Map, HashMap, ListBuffer, Buffer, HashSet}
import scala.tools.nsc.symtab._
import scala.tools.nsc.util.Position
-
+import PartialFunction._
/** This class ...
*
@@ -25,6 +25,14 @@ abstract class GenICode extends SubComponent {
import global._
import icodes._
import icodes.opcodes._
+ import definitions.{
+ ArrayClass, ObjectClass, ThrowableClass,
+ Object_equals
+ }
+ import scalaPrimitives.{
+ isArrayOp, isComparisonOp, isLogicalOp,
+ isUniversalEqualityOp, isReferenceEqualityOp
+ }
val phaseName = "icode"
@@ -40,11 +48,11 @@ abstract class GenICode extends SubComponent {
val STRING = REFERENCE(definitions.StringClass)
// this depends on the backend! should be changed.
- val ANY_REF_CLASS = REFERENCE(definitions.ObjectClass)
+ val ANY_REF_CLASS = REFERENCE(ObjectClass)
val SCALA_ALL = REFERENCE(definitions.NothingClass)
val SCALA_ALLREF = REFERENCE(definitions.NullClass)
- val THROWABLE = REFERENCE(definitions.ThrowableClass)
+ val THROWABLE = REFERENCE(ThrowableClass)
val BoxesRunTime_equals =
if (!forMSIL)
@@ -526,9 +534,9 @@ abstract class GenICode extends SubComponent {
genLoad(duplicateFinalizer, ctx1, UNIT);
})
- case Ident(nme.WILDCARD) => (definitions.ThrowableClass, kind, {
+ case Ident(nme.WILDCARD) => (ThrowableClass, kind, {
ctx: Context =>
- ctx.bb.emit(DROP(REFERENCE(definitions.ThrowableClass)))
+ ctx.bb.emit(DROP(REFERENCE(ThrowableClass)))
val ctx1 = genLoad(body, ctx, kind)
if (guardResult) {
ctx1.bb.emit(STORE_LOCAL(tmp))
@@ -755,10 +763,9 @@ abstract class GenICode extends SubComponent {
} else if (code == scalaPrimitives.CONCAT) {
ctx1 = genStringConcat(tree, ctx1)
generatedType = STRING
- } else if (scalaPrimitives.isArrayOp(code)) {
+ } else if (isArrayOp(code)) {
ctx1 = genArrayOp(tree, ctx1, code)
- } else if (scalaPrimitives.isLogicalOp(code) ||
- scalaPrimitives.isComparisonOp(code)) {
+ } else if (isLogicalOp(code) || isComparisonOp(code)) {
val trueCtx = ctx1.newBlock
val falseCtx = ctx1.newBlock
@@ -773,7 +780,7 @@ abstract class GenICode extends SubComponent {
generatedType = BOOL
ctx1 = afterCtx
} else if (code == scalaPrimitives.SYNCHRONIZED) {
- val monitor = ctx.makeLocal(tree.pos, definitions.ObjectClass.tpe, "monitor")
+ val monitor = ctx.makeLocal(tree.pos, ObjectClass.tpe, "monitor")
ctx1 = genLoadQualifier(fun, ctx1)
ctx1.bb.emit(DUP(ANY_REF_CLASS))
ctx1.bb.emit(STORE_LOCAL(monitor))
@@ -829,7 +836,7 @@ abstract class GenICode extends SubComponent {
val hostClass = fun match {
case Select(qualifier, _)
- if (qualifier.tpe.typeSymbol != definitions.ArrayClass) =>
+ if (qualifier.tpe.typeSymbol != ArrayClass) =>
qualifier.tpe.typeSymbol
case _ => sym.owner
}
@@ -864,8 +871,8 @@ abstract class GenICode extends SubComponent {
generatedType = REFERENCE(tree.symbol)
} else {
ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
- if (tree.symbol == definitions.ArrayClass)
- generatedType = REFERENCE(definitions.ObjectClass)
+ if (tree.symbol == ArrayClass)
+ generatedType = REFERENCE(ObjectClass)
else
generatedType = REFERENCE(ctx.clazz.symbol)
}
@@ -1272,6 +1279,12 @@ abstract class GenICode extends SubComponent {
List(tree)
}
+ /** Some useful equality helpers.
+ */
+ def isNull(t: Tree) = cond(t) { case Literal(Constant(null)) => true }
+
+ /* If l or r is constant null, returns the other ; otherwise null */
+ def ifOneIsNull(l: Tree, r: Tree) = if (isNull(l)) r else if (isNull(r)) l else null
/**
* Traverse the tree and store label stubs in the context. This is
@@ -1313,23 +1326,8 @@ abstract class GenICode extends SubComponent {
elseCtx: Context): Unit =
{
def genComparisonOp(l: Tree, r: Tree, code: Int) {
- // special-case reference (in)equality test for null
- if (code == scalaPrimitives.ID || code == scalaPrimitives.NI) {
- val expr: Tree = (l, r) match {
- case (Literal(Constant(null)), expr) => expr
- case (expr, Literal(Constant(null))) => expr
- case _ => null
- }
- if (expr ne null) {
- val ctx1 = genLoad(expr, ctx, ANY_REF_CLASS)
- if (code == scalaPrimitives.ID)
- ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS))
- else
- ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, ANY_REF_CLASS))
- ctx1.bb.close
- return
- }
- }
+ if (settings.logEquality.value && isUniversalEqualityOp(code))
+ logEqEq(tree, l, r, code)
val op: TestOp = code match {
case scalaPrimitives.LT => LT
@@ -1342,100 +1340,74 @@ abstract class GenICode extends SubComponent {
case _ => abort("Unknown comparison primitive: " + code)
}
- val kind = getMaxType(l.tpe :: r.tpe :: Nil)
- var ctx1 = genLoad(l, ctx, kind);
- ctx1 = genLoad(r, ctx1, kind);
- ctx1.bb.emit(CJUMP(thenCtx.bb, elseCtx.bb, op, kind), r.pos)
- ctx1.bb.close
- }
-
- /** Log equality tests to file if they are playing with typefire */
- def logEqEq(l: Tree, r: Tree, op: String) {
- def mayBeNumericComparison: Boolean = {
- def isPossiblyBoxed(sym: Symbol): Boolean = {
- import definitions._
-
- // good enough for now
- (sym == ObjectClass) ||
- (sym isNonBottomSubClass BoxedNumberClass) ||
- (sym isNonBottomSubClass BoxedCharacterClass)
- }
-
- val lsym = l.tpe.typeSymbol
- val rsym = r.tpe.typeSymbol
-
- (lsym != rsym) && (isPossiblyBoxed(lsym) && isPossiblyBoxed(rsym))
+ // special-case reference (in)equality test for null (null eq x, x eq null)
+ lazy val nonNullSide = ifOneIsNull(l, r)
+ if (isReferenceEqualityOp(code) && nonNullSide != null) {
+ val ctx1 = genLoad(nonNullSide, ctx, ANY_REF_CLASS)
+ ctx1.bb.emitOnly(
+ CZJUMP(thenCtx.bb, elseCtx.bb, op, ANY_REF_CLASS)
+ )
+ }
+ else {
+ val kind = getMaxType(l.tpe :: r.tpe :: Nil)
+ var ctx1 = genLoad(l, ctx, kind)
+ ctx1 = genLoad(r, ctx1, kind)
+
+ ctx1.bb.emitOnly(
+ CJUMP(thenCtx.bb, elseCtx.bb, op, kind) setPos r.pos
+ )
}
-
- val tkl = toTypeKind(l.tpe)
- val tkr = toTypeKind(r.tpe)
- lazy val whereAreWe = tree.pos.source + ":" + tree.pos.line
- def logit(preface: String) =
- runtime.BoxesRunTime.log("[%s] %s %s %s (%s)".format(preface, l.tpe, op, r.tpe, whereAreWe))
-
- if (tkl.isNumericType && tkr.isNumericType && tkl != tkr)
- logit(" KNOWN ")
- else if (mayBeNumericComparison)
- logit("UNKNOWN")
}
if (settings.debug.value)
log("Entering genCond with tree: " + tree);
+ // the default emission
+ def default = {
+ val ctx1 = genLoad(tree, ctx, BOOL)
+ ctx1.bb.emitOnly(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL) setPos tree.pos)
+ }
+
tree match {
- case Apply(fun, args)
- if isPrimitive(fun.symbol) =>
- val code = scalaPrimitives.getPrimitive(fun.symbol)
+ // The comparison symbol is in ScalaPrimitives's "primitives" map
+ case Apply(fun, args) if isPrimitive(fun.symbol) =>
+ import scalaPrimitives.{ ZNOT, ZAND, ZOR, EQ, getPrimitive }
- if (code == scalaPrimitives.ZNOT) {
- val Select(leftArg, _) = fun
- genCond(leftArg, ctx, elseCtx, thenCtx)
- }
- else if ((code == scalaPrimitives.EQ || code == scalaPrimitives.NE)) {
- val Select(leftArg, _) = fun;
- if (settings.logEquality.value)
- logEqEq(leftArg, args.head, (if (code == scalaPrimitives.EQ) "==" else "!="))
-
- if (toTypeKind(leftArg.tpe).isReferenceType) {
- if (code == scalaPrimitives.EQ)
- genEqEqPrimitive(leftArg, args.head, ctx, thenCtx, elseCtx)
- else
- genEqEqPrimitive(leftArg, args.head, ctx, elseCtx, thenCtx)
- }
- else
- genComparisonOp(leftArg, args.head, code);
- }
- else if (scalaPrimitives.isComparisonOp(code)) {
- val Select(leftArg, _) = fun
- genComparisonOp(leftArg, args.head, code)
- }
- else {
- code match {
- case scalaPrimitives.ZAND =>
- val Select(leftArg, _) = fun
+ // lhs and rhs of test
+ lazy val Select(lhs, _) = fun
+ lazy val rhs = args.head
- val ctxInterm = ctx.newBlock
- genCond(leftArg, ctx, ctxInterm, elseCtx)
- genCond(args.head, ctxInterm, thenCtx, elseCtx)
+ def genZandOrZor(and: Boolean) = {
+ val ctxInterm = ctx.newBlock
- case scalaPrimitives.ZOR =>
- val Select(leftArg, _) = fun
+ if (and) genCond(lhs, ctx, ctxInterm, elseCtx)
+ else genCond(lhs, ctx, thenCtx, ctxInterm)
- val ctxInterm = ctx.newBlock
- genCond(leftArg, ctx, thenCtx, ctxInterm)
- genCond(args.head, ctxInterm, thenCtx, elseCtx)
+ genCond(rhs, ctxInterm, thenCtx, elseCtx)
+ }
+ def genRefEq(isEq: Boolean) = {
+ val f = genEqEqPrimitive(lhs, rhs, ctx) _
+ if (isEq) f(thenCtx, elseCtx)
+ else f(elseCtx, thenCtx)
+ }
- case _ =>
- var ctx1 = genLoad(tree, ctx, BOOL)
- ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL), tree.pos)
- ctx1.bb.close
+ getPrimitive(fun.symbol) match {
+ case ZNOT => genCond(lhs, ctx, elseCtx, thenCtx)
+ case ZAND => genZandOrZor(and = true)
+ case ZOR => genZandOrZor(and = false)
+ case code =>
+ // x == y where LHS is reference type
+ if (isUniversalEqualityOp(code) && toTypeKind(lhs.tpe).isReferenceType) {
+ if (code == EQ) genRefEq(isEq = true)
+ else genRefEq(isEq = false)
}
- }
+ else if (isComparisonOp(code))
+ genComparisonOp(lhs, rhs, code)
+ else
+ default
+ }
- case _ =>
- var ctx1 = genLoad(tree, ctx, BOOL)
- ctx1.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL), tree.pos)
- ctx1.bb.close
+ case _ => default
}
}
@@ -1449,9 +1421,7 @@ abstract class GenICode extends SubComponent {
* @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 =
- {
+ def genEqEqPrimitive(l: Tree, r: Tree, ctx: Context)(thenCtx: Context, elseCtx: Context): Unit = {
def eqEqTempName: Name = "eqEqTemp$"
@@ -1479,8 +1449,8 @@ abstract class GenICode extends SubComponent {
val lsym = l.tpe.typeSymbol
val rsym = r.tpe.typeSymbol
- (lsym == definitions.ObjectClass) ||
- (rsym == definitions.ObjectClass) ||
+ (lsym == ObjectClass) ||
+ (rsym == ObjectClass) ||
(lsym != rsym) && (isBoxed(lsym) || isBoxed(rsym))
}
@@ -1488,57 +1458,58 @@ abstract class GenICode extends SubComponent {
val ctx1 = genLoad(l, ctx, ANY_REF_CLASS)
val ctx2 = genLoad(r, ctx1, ANY_REF_CLASS)
- ctx2.bb.emit(CALL_METHOD(BoxesRunTime_equals, Static(false)))
- ctx2.bb.emit(CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL))
- ctx2.bb.close
-
+ ctx2.bb.emitOnly(
+ CALL_METHOD(BoxesRunTime_equals, Static(false)),
+ CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)
+ )
}
else {
- (l, r) match {
+ if (isNull(l))
// null == expr -> expr eq null
- case (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 (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)
+ genLoad(r, ctx, ANY_REF_CLASS).bb emitOnly CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)
+ else {
+ val eqEqTempLocal = getTempLocal
+ var ctx1 = genLoad(l, ctx, ANY_REF_CLASS)
+
+ // dicey refactor section
+ lazy val nonNullCtx = ctx1.newBlock
+
+ if (isNull(r)) {
+ // expr == null -> if (l eq null) true else l.equals(null)
+ ctx1.bb.emitOnly(
+ DUP(ANY_REF_CLASS),
+ STORE_LOCAL(eqEqTempLocal) setPos l.pos,
+ CZJUMP(thenCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS)
+ )
+ nonNullCtx.bb.emitOnly(
+ LOAD_LOCAL(eqEqTempLocal) setPos l.pos,
+ CONSTANT(Constant(null)) setPos r.pos,
+ CALL_METHOD(Object_equals, Dynamic),
+ CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)
+ )
+ }
+ else {
+ // l == r -> if (l eq null) r eq null else l.equals(r)
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
+ ctx1.bb.emitOnly(
+ STORE_LOCAL(eqEqTempLocal) setPos l.pos,
+ DUP(ANY_REF_CLASS),
+ CZJUMP(nullCtx.bb, nonNullCtx.bb, EQ, ANY_REF_CLASS)
+ )
+ nullCtx.bb.emitOnly(
+ DROP(ANY_REF_CLASS) setPos l.pos, // type of AnyRef
+ LOAD_LOCAL(eqEqTempLocal),
+ CZJUMP(thenCtx.bb, elseCtx.bb, EQ, ANY_REF_CLASS)
+ )
+ nonNullCtx.bb.emitOnly(
+ LOAD_LOCAL(eqEqTempLocal) setPos l.pos,
+ CALL_METHOD(Object_equals, Dynamic),
+ CZJUMP(thenCtx.bb, elseCtx.bb, NE, BOOL)
+ )
+ }
}
}
}
@@ -1984,7 +1955,7 @@ abstract class GenICode extends SubComponent {
*
* <code> ctx.Try( ctx => {
* ctx.bb.emit(...) // protected block
- * }, (definitions.ThrowableClass,
+ * }, (ThrowableClass,
* ctx => {
* ctx.bb.emit(...); // exception handler
* }), (AnotherExceptionClass,
@@ -2002,7 +1973,7 @@ abstract class GenICode extends SubComponent {
val exh = outerCtx.newHandler(NoSymbol, toTypeKind(finalizer.tpe)) // finalizer covers exception handlers
this.addActiveHandler(exh) // .. and body aswell
val ctx = finalizerCtx.enterHandler(exh)
- val exception = ctx.makeLocal(finalizer.pos, definitions.ThrowableClass.tpe, "exc")
+ val exception = ctx.makeLocal(finalizer.pos, ThrowableClass.tpe, "exc")
if (settings.Xdce.value) ctx.bb.emit(LOAD_EXCEPTION())
ctx.bb.emit(STORE_LOCAL(exception));
val ctx1 = genLoad(finalizer, ctx, UNIT);
@@ -2189,4 +2160,39 @@ abstract class GenICode extends SubComponent {
override def varsInScope: Buffer[Local] = new ListBuffer
}
+ /** Log equality tests to file if they are playing with typefire */
+ def logEqEq(tree: Tree, l: Tree, r: Tree, code: Int) {
+ import definitions._
+ val op = if (code == scalaPrimitives.EQ) "==" else if (code == scalaPrimitives.NE) "!=" else "??"
+
+ def mayBeNumericComparison: Boolean = {
+ def isPossiblyBoxed(sym: Symbol): Boolean = {
+ import definitions._
+ // classes as which a boxed primitive may statically appear
+ val possibleBoxes = List(BoxedNumberClass, BoxedCharacterClass, SerializableClass, ComparableClass)
+
+ (sym == ObjectClass) || (possibleBoxes exists (sym isNonBottomSubClass _))
+ }
+
+ val lsym = l.tpe.typeSymbol
+ val rsym = r.tpe.typeSymbol
+
+ def isSameBox = {
+ def isFinalBox(s: Symbol) = (s isNonBottomSubClass BoxedNumberClass) && s.isFinal
+ isFinalBox(lsym) && isFinalBox(rsym) && lsym == rsym
+ }
+ isPossiblyBoxed(lsym) && isPossiblyBoxed(rsym) && !isSameBox
+ }
+
+ val tkl = toTypeKind(l.tpe)
+ val tkr = toTypeKind(r.tpe)
+ lazy val whereAreWe = tree.pos.source + ":" + tree.pos.line
+ def logit(preface: String) =
+ runtime.Equality.log("[%s] %s %s %s (%s)".format(preface, l.tpe, op, r.tpe, whereAreWe))
+
+ if (tkl.isNumericType && tkr.isNumericType && tkl != tkr)
+ logit(" KNOWN ")
+ else if (mayBeNumericComparison)
+ logit("UNKNOWN")
+ }
}
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 5c7d8229e3..404ffbafc1 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -127,6 +127,7 @@ trait Definitions {
lazy val TypeConstraintClass = getClass("scala.TypeConstraint")
lazy val SingletonClass = newClass(ScalaPackageClass, nme.Singleton, anyparam) setFlag (ABSTRACT | TRAIT | FINAL)
lazy val SerializableClass = getClass(sn.Serializable)
+ lazy val ComparableClass = getClass("java.lang.Comparable")
lazy val RepeatedParamClass = newCovariantPolyClass(
ScalaPackageClass,
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index 25330bd641..904983a80f 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -811,7 +811,7 @@ abstract class ClassfileParser {
}
def parseAnnotArg: Option[ClassfileAnnotArg] = {
- val tag = in.nextByte
+ val tag = in.nextByte.toChar
val index = in.nextChar
tag match {
case STRING_TAG =>