summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2009-11-16 21:30:36 +0000
committerPaul Phillips <paulp@improving.org>2009-11-16 21:30:36 +0000
commit773b7a287b7db8793b971e2aa920d5c56c7b4b51 (patch)
tree05ee38485e1d527815d7d00967965bf0bd678d9f
parent0da0208af4e3824e9ccc5fe8fe641ee541737fcc (diff)
downloadscala-773b7a287b7db8793b971e2aa920d5c56c7b4b51.tar.gz
scala-773b7a287b7db8793b971e2aa920d5c56c7b4b51.tar.bz2
scala-773b7a287b7db8793b971e2aa920d5c56c7b4b51.zip
Some organization & duplication removal in GenI...
Some organization & duplication removal in GenICode stemming from optimizer appeasement.
-rw-r--r--src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala12
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala738
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala73
3 files changed, 377 insertions, 446 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
index 290d90b3e9..88e867e487 100644
--- a/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
+++ b/src/compiler/scala/tools/nsc/backend/ScalaPrimitives.scala
@@ -469,6 +469,18 @@ abstract class ScalaPrimitives {
def isCoercion(code: Int): Boolean = (code >= B2B) && (code <= D2D)
+ final val typeOfArrayOp: Map[Int, TypeKind] = Map(
+ (List(ZARRAY_LENGTH, ZARRAY_GET, ZARRAY_SET) map (_ -> BOOL)) ++
+ (List(BARRAY_LENGTH, BARRAY_GET, BARRAY_SET) map (_ -> BYTE)) ++
+ (List(SARRAY_LENGTH, SARRAY_GET, SARRAY_SET) map (_ -> SHORT)) ++
+ (List(CARRAY_LENGTH, CARRAY_GET, CARRAY_SET) map (_ -> CHAR)) ++
+ (List(IARRAY_LENGTH, IARRAY_GET, IARRAY_SET) map (_ -> INT)) ++
+ (List(LARRAY_LENGTH, LARRAY_GET, LARRAY_SET) map (_ -> LONG)) ++
+ (List(FARRAY_LENGTH, FARRAY_GET, FARRAY_SET) map (_ -> FLOAT)) ++
+ (List(DARRAY_LENGTH, DARRAY_GET, DARRAY_SET) map (_ -> DOUBLE)) ++
+ (List(OARRAY_LENGTH, OARRAY_GET, OARRAY_SET) map (_ -> REFERENCE(AnyRefClass))) : _*
+ )
+
/** Check whether the given operation code is an array operation. */
def isArrayOp(code: Int): Boolean =
isArrayNew(code) | isArrayLength(code) | isArrayGet(code) | isArraySet(code)
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 4628d58a98..4d6757dd80 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -12,6 +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 scala.annotation.switch
import PartialFunction._
/** This class ...
@@ -27,7 +28,7 @@ abstract class GenICode extends SubComponent {
import icodes.opcodes._
import definitions.{
ArrayClass, ObjectClass, ThrowableClass,
- Object_equals
+ Object_equals, Object_isInstanceOf, Object_asInstanceOf
}
import scalaPrimitives.{
isArrayOp, isComparisonOp, isLogicalOp,
@@ -38,6 +39,9 @@ abstract class GenICode extends SubComponent {
override def newPhase(prev: Phase) = new ICodePhase(prev)
+ private def debugLog(msg: => String): Unit =
+ if (settings.debug.value) log(msg)
+
class ICodePhase(prev: Phase) extends StdPhase(prev) {
override def description = "Generate ICode from the AST"
@@ -150,14 +154,8 @@ abstract class GenICode extends SubComponent {
abort("Illegal tree in gen: " + tree)
}
- private def genStat(trees: List[Tree], ctx: Context): Context = {
- var currentCtx = ctx
-
- for (t <- trees)
- currentCtx = genStat(t, currentCtx)
-
- currentCtx
- }
+ private def genStat(trees: List[Tree], ctx: Context): Context =
+ trees.foldLeft(ctx)((currentCtx, t) => genStat(t, currentCtx))
/**
* Generate code for the given tree. The trees should contain statements
@@ -169,30 +167,282 @@ abstract class GenICode extends SubComponent {
* @return a new context. This is necessary for control flow instructions
* which may change the current basic block.
*/
- private def genStat(tree: Tree, ctx: Context): Context = {
+ private def genStat(tree: Tree, ctx: Context): Context = tree match {
+ case Assign(lhs @ Select(_, _), rhs) =>
+ val isStatic = lhs.symbol.isStaticMember
+ var ctx1 = if (isStatic) ctx else genLoadQualifier(lhs, ctx)
- tree match {
- case Assign(lhs @ Select(_, _), rhs) =>
- if (lhs.symbol.isStaticMember) {
- val ctx1 = genLoad(rhs, ctx, toTypeKind(lhs.symbol.info))
- ctx1.bb.emit(STORE_FIELD(lhs.symbol, true), tree.pos)
- ctx1
- } else {
- var ctx1 = genLoadQualifier(lhs, ctx)
- ctx1 = genLoad(rhs, ctx1, toTypeKind(lhs.symbol.info))
- ctx1.bb.emit(STORE_FIELD(lhs.symbol, false), tree.pos)
- ctx1
+ ctx1 = genLoad(rhs, ctx1, toTypeKind(lhs.symbol.info))
+ ctx1.bb.emit(STORE_FIELD(lhs.symbol, isStatic), tree.pos)
+ ctx1
+
+ case Assign(lhs, rhs) =>
+ val ctx1 = genLoad(rhs, ctx, toTypeKind(lhs.symbol.info))
+ val Some(l) = ctx.method.lookupLocal(lhs.symbol)
+ ctx1.bb.emit(STORE_LOCAL(l), tree.pos)
+ ctx1
+
+ case _ =>
+ genLoad(tree, ctx, UNIT)
+ }
+ /**
+ * Generate code for primitive arithmetic operations.
+ * Returns (Context, Generated Type)
+ */
+ private def genArithmeticOp(tree: Tree, ctx: Context, code: Int): (Context, TypeKind) = {
+ val Apply(fun @ Select(larg, _), args) = tree
+ var ctx1 = ctx
+ var resKind = toTypeKind(larg.tpe)
+
+ if (settings.debug.value) {
+ assert(args.length <= 1,
+ "Too many arguments for primitive function: " + fun.symbol)
+ assert(resKind.isNumericType | resKind == BOOL,
+ resKind.toString() + " is not a numeric or boolean type " +
+ "[operation: " + fun.symbol + "]")
+ }
+
+ args match {
+ // unary operation
+ case Nil =>
+ ctx1 = genLoad(larg, ctx1, resKind)
+ code match {
+ case scalaPrimitives.POS =>
+ () // nothing
+ case scalaPrimitives.NEG =>
+ ctx1.bb.emit(CALL_PRIMITIVE(Negation(resKind)), larg.pos)
+ case scalaPrimitives.NOT =>
+ ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(NOT, resKind)), larg.pos)
+ case _ =>
+ abort("Unknown unary operation: " + fun.symbol.fullNameString +
+ " code: " + code)
}
- case Assign(lhs, rhs) =>
- val ctx1 = genLoad(rhs, ctx, toTypeKind(lhs.symbol.info))
- val Some(l) = ctx.method.lookupLocal(lhs.symbol)
- ctx1.bb.emit(STORE_LOCAL(l), tree.pos)
- ctx1
+ // binary operation
+ case rarg :: Nil =>
+ resKind = getMaxType(larg.tpe :: rarg.tpe :: Nil);
+ if (scalaPrimitives.isShiftOp(code) || scalaPrimitives.isBitwiseOp(code))
+ assert(resKind.isIntType | resKind == BOOL,
+ resKind.toString() + " incompatible with arithmetic modulo operation: " + ctx1);
+
+ ctx1 = genLoad(larg, ctx1, resKind)
+ ctx1 = genLoad(rarg,
+ ctx1, // check .NET size of shift arguments!
+ if (scalaPrimitives.isShiftOp(code)) INT else resKind)
+
+ val primitiveOp = code match {
+ case scalaPrimitives.ADD => Arithmetic(ADD, resKind)
+ case scalaPrimitives.SUB => Arithmetic(SUB, resKind)
+ case scalaPrimitives.MUL => Arithmetic(MUL, resKind)
+ case scalaPrimitives.DIV => Arithmetic(DIV, resKind)
+ case scalaPrimitives.MOD => Arithmetic(REM, resKind)
+ case scalaPrimitives.OR => Logical(OR, resKind)
+ case scalaPrimitives.XOR => Logical(XOR, resKind)
+ case scalaPrimitives.AND => Logical(AND, resKind)
+ case scalaPrimitives.LSL => Shift(LSL, resKind)
+ case scalaPrimitives.LSR => Shift(LSR, resKind)
+ case scalaPrimitives.ASR => Shift(ASR, resKind)
+ case _ => abort("Unknown primitive: " + fun.symbol + "[" + code + "]")
+ }
+ ctx1.bb.emit(CALL_PRIMITIVE(primitiveOp), tree.pos)
case _ =>
- genLoad(tree, ctx, UNIT)
+ abort("Too many arguments for primitive function: " + tree)
+ }
+ (ctx1, resKind)
+ }
+
+ /** Generate primitive array operations.
+ *
+ * @param tree ...
+ * @param ctx ...
+ * @param code ...
+ * @return ...
+ */
+ private def genArrayOp(tree: Tree, ctx: Context, code: Int, expectedType: TypeKind): (Context, TypeKind) = {
+ import scalaPrimitives._
+ val Apply(Select(arrayObj, _), args) = tree
+ val k = toTypeKind(arrayObj.tpe)
+ val ARRAY(elem) = k
+ var ctx1 = genLoad(arrayObj, ctx, k)
+ val elementType = (typeOfArrayOp get code) getOrElse abort("Unknown operation on arrays: " + tree + " code: " + code)
+
+ var generatedType = expectedType
+
+ if (scalaPrimitives.isArrayGet(code)) {
+ // load argument on stack
+ if (settings.debug.value)
+ assert(args.length == 1,
+ "Too many arguments for array get operation: " + tree);
+ ctx1 = genLoad(args.head, ctx1, INT)
+ generatedType = elem
+ ctx1.bb.emit(LOAD_ARRAY_ITEM(elementType), tree.pos)
+ }
+ else if (scalaPrimitives.isArraySet(code)) {
+ if (settings.debug.value)
+ assert(args.length == 2,
+ "Too many arguments for array set operation: " + tree);
+ ctx1 = genLoad(args.head, ctx1, INT)
+ ctx1 = genLoad(args.tail.head, ctx1, toTypeKind(args.tail.head.tpe))
+ // the following line should really be here, but because of bugs in erasure
+ // we pretend we generate whatever type is expected from us.
+ //generatedType = UNIT
+
+ ctx1.bb.emit(STORE_ARRAY_ITEM(elementType), tree.pos)
+ }
+ else {
+ generatedType = INT
+ ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(elementType)), tree.pos)
+ }
+
+ (ctx1, generatedType)
+ }
+ private def genSynchronized(tree: Apply, ctx: Context, expectedType: TypeKind): (Context, TypeKind) = {
+ val Apply(fun, args) = tree
+ val monitor = ctx.makeLocal(tree.pos, ObjectClass.tpe, "monitor")
+ var ctx1 = genLoadQualifier(fun, ctx)
+ ctx1.bb.emit(Seq(
+ DUP(ANY_REF_CLASS),
+ STORE_LOCAL(monitor),
+ MONITOR_ENTER() setPos tree.pos
+ ))
+ ctx1.enterSynchronized(monitor)
+ debugLog("synchronized block start")
+
+ ctx1 = ctx1.Try(
+ bodyCtx => {
+ val ctx2 = genLoad(args.head, bodyCtx, expectedType /* toTypeKind(tree.tpe.resultType) */)
+ ctx2.bb.emit(Seq(
+ LOAD_LOCAL(monitor),
+ MONITOR_EXIT() setPos tree.pos
+ ))
+ ctx2
+ }, List(
+ // tree.tpe / fun.tpe is object, which is no longer true after this transformation
+ (NoSymbol, expectedType, exhCtx => {
+ exhCtx.bb.emit(Seq(
+ LOAD_LOCAL(monitor),
+ MONITOR_EXIT() setPos tree.pos,
+ THROW()
+ ))
+ exhCtx.bb.enterIgnoreMode
+ exhCtx
+ })), EmptyTree, tree)
+
+ debugLog("synchronized block end with block %s closed=%s".format(ctx1.bb, ctx1.bb.closed))
+ ctx1.exitSynchronized(monitor)
+
+ (ctx1, expectedType)
+ }
+
+ private def genLoadIf(tree: If, ctx: Context, expectedType: TypeKind): (Context, TypeKind) = {
+ val If(cond, thenp, elsep) = tree
+
+ var thenCtx = ctx.newBlock
+ var elseCtx = ctx.newBlock
+ val contCtx = ctx.newBlock
+
+ genCond(cond, ctx, thenCtx, elseCtx)
+
+ val ifKind = toTypeKind(tree.tpe)
+ val thenKind = toTypeKind(thenp.tpe)
+ val elseKind = if (elsep == EmptyTree) UNIT else toTypeKind(elsep.tpe)
+
+ // we need to drop unneeded results, if one branch gives
+ // unit and the other gives something on the stack, because
+ // the type of 'if' is scala.Any, and its erasure would be Object.
+ // But unboxed units are not Objects...
+ def hasUnitBranch = thenKind == UNIT || elseKind == UNIT
+ val resKind = if (hasUnitBranch) UNIT else ifKind
+
+ if (hasUnitBranch)
+ debugLog("Will drop result from an if branch")
+
+ thenCtx = genLoad(thenp, thenCtx, resKind)
+ elseCtx = genLoad(elsep, elseCtx, resKind)
+
+ assert(!settings.debug.value || expectedType == UNIT,
+ "I produce UNIT in a context where " + expectedType + " is expected!")
+
+ thenCtx.bb.emitOnly(JUMP(contCtx.bb))
+ elseCtx.bb.emitOnly(
+ if (elsep == EmptyTree) JUMP(contCtx.bb)
+ else JUMP(contCtx.bb) setPos tree.pos
+ )
+
+ (contCtx, resKind)
+ }
+ private def genLoadTry(tree: Try, ctx: Context, setGeneratedType: TypeKind => Unit): Context = {
+ val Try(block, catches, finalizer) = tree
+ val kind = toTypeKind(tree.tpe)
+
+ val caseHandlers =
+ for (CaseDef(pat, _, body) <- catches.reverse) yield {
+ def genWildcardHandler(sym: Symbol): (Symbol, TypeKind, Context => Context) =
+ (sym, kind, ctx => {
+ ctx.bb.emit(DROP(REFERENCE(sym)))
+ genLoad(body, ctx, kind)
+ })
+
+ pat match {
+ case Typed(Ident(nme.WILDCARD), tpt) => genWildcardHandler(tpt.tpe.typeSymbol)
+ case Ident(nme.WILDCARD) => genWildcardHandler(ThrowableClass)
+ case Bind(name, _) =>
+ val exception = ctx.method addLocal new Local(pat.symbol, toTypeKind(pat.symbol.tpe), false)
+
+ (pat.symbol.tpe.typeSymbol, kind, {
+ ctx: Context =>
+ ctx.bb.emit(STORE_LOCAL(exception), pat.pos);
+ genLoad(body, ctx, kind);
+ })
+ }
+ }
+
+ ctx.Try(
+ bodyCtx => {
+ setGeneratedType(kind)
+ genLoad(block, bodyCtx, kind)
+ },
+ caseHandlers,
+ finalizer,
+ tree)
+ }
+
+ private def genPrimitiveOp(tree: Apply, ctx: Context, expectedType: TypeKind): (Context, TypeKind) = {
+ val sym = tree.symbol
+ val Apply(fun @ Select(receiver, _), args) = tree
+ val code = scalaPrimitives.getPrimitive(sym, receiver.tpe)
+
+ if (scalaPrimitives.isArithmeticOp(code))
+ genArithmeticOp(tree, ctx, code)
+ else if (code == scalaPrimitives.CONCAT)
+ (genStringConcat(tree, ctx), STRING)
+ else if (isArrayOp(code))
+ genArrayOp(tree, ctx, code, expectedType)
+ else if (isLogicalOp(code) || isComparisonOp(code)) {
+ val trueCtx = ctx.newBlock
+ val falseCtx = ctx.newBlock
+ val afterCtx = ctx.newBlock
+ genCond(tree, ctx, trueCtx, falseCtx)
+ trueCtx.bb.emitOnly(
+ CONSTANT(Constant(true)) setPos tree.pos,
+ JUMP(afterCtx.bb)
+ )
+ falseCtx.bb.emitOnly(
+ CONSTANT(Constant(false)) setPos tree.pos,
+ JUMP(afterCtx.bb)
+ )
+ (afterCtx, BOOL)
+ }
+ else if (code == scalaPrimitives.SYNCHRONIZED)
+ genSynchronized(tree, ctx, expectedType)
+ else if (scalaPrimitives.isCoercion(code)) {
+ val ctx1 = genLoad(receiver, ctx, toTypeKind(receiver.tpe))
+ genCoercion(tree, ctx1, code)
+ (ctx1, scalaPrimitives.generatedKind(code))
}
+ else abort("Primitive operation not handled yet: " + sym.fullNameString + "(" +
+ fun.symbol.simpleName + ") " + " at: " + (tree.pos))
}
/**
@@ -210,186 +460,6 @@ abstract class GenICode extends SubComponent {
if (settings.debug.value)
log("at line: " + (if (tree.pos.isDefined) tree.pos.line else tree.pos))
- /**
- * Generate code for primitive arithmetic operations.
- */
- def genArithmeticOp(tree: Tree, ctx: Context, code: Int): Context = {
- val Apply(fun @ Select(larg, _), args) = tree
- var ctx1 = ctx
- var resKind = toTypeKind(larg.tpe)
-
- if (settings.debug.value) {
- assert(args.length <= 1,
- "Too many arguments for primitive function: " + fun.symbol)
- assert(resKind.isNumericType | resKind == BOOL,
- resKind.toString() + " is not a numeric or boolean type " +
- "[operation: " + fun.symbol + "]")
- }
-
- args match {
- // unary operation
- case Nil =>
- ctx1 = genLoad(larg, ctx1, resKind)
- code match {
- case scalaPrimitives.POS =>
- () // nothing
- case scalaPrimitives.NEG =>
- ctx1.bb.emit(CALL_PRIMITIVE(Negation(resKind)), larg.pos)
- case scalaPrimitives.NOT =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(NOT, resKind)), larg.pos)
- case _ =>
- abort("Unknown unary operation: " + fun.symbol.fullNameString +
- " code: " + code)
- }
- generatedType = resKind
-
- // binary operation
- case rarg :: Nil =>
- resKind = getMaxType(larg.tpe :: rarg.tpe :: Nil);
- if (scalaPrimitives.isShiftOp(code) || scalaPrimitives.isBitwiseOp(code))
- assert(resKind.isIntType | resKind == BOOL,
- resKind.toString() + " incompatible with arithmetic modulo operation: " + ctx1);
-
- ctx1 = genLoad(larg, ctx1, resKind);
- ctx1 = genLoad(rarg,
- ctx1, // check .NET size of shift arguments!
- if (scalaPrimitives.isShiftOp(code)) INT else resKind)
-
- generatedType = resKind
- code match {
- case scalaPrimitives.ADD =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(ADD, resKind)), tree.pos)
- case scalaPrimitives.SUB =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(SUB, resKind)), tree.pos)
- case scalaPrimitives.MUL =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(MUL, resKind)), tree.pos)
- case scalaPrimitives.DIV =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(DIV, resKind)), tree.pos)
- case scalaPrimitives.MOD =>
- ctx1.bb.emit(CALL_PRIMITIVE(Arithmetic(REM, resKind)), tree.pos)
- case scalaPrimitives.OR =>
- ctx1.bb.emit(CALL_PRIMITIVE(Logical(OR, resKind)), tree.pos)
- case scalaPrimitives.XOR =>
- ctx1.bb.emit(CALL_PRIMITIVE(Logical(XOR, resKind)), tree.pos)
- case scalaPrimitives.AND =>
- ctx1.bb.emit(CALL_PRIMITIVE(Logical(AND, resKind)), tree.pos)
- case scalaPrimitives.LSL =>
- ctx1.bb.emit(CALL_PRIMITIVE(Shift(LSL, resKind)), tree.pos)
- generatedType = resKind
- case scalaPrimitives.LSR =>
- ctx1.bb.emit(CALL_PRIMITIVE(Shift(LSR, resKind)), tree.pos)
- generatedType = resKind
- case scalaPrimitives.ASR =>
- ctx1.bb.emit(CALL_PRIMITIVE(Shift(ASR, resKind)), tree.pos)
- generatedType = resKind
- case _ =>
- abort("Unknown primitive: " + fun.symbol + "[" + code + "]")
- }
-
- case _ =>
- abort("Too many arguments for primitive function: " + tree)
- }
- ctx1
- }
-
- /** Generate primitive array operations.
- *
- * @param tree ...
- * @param ctx ...
- * @param code ...
- * @return ...
- */
- def genArrayOp(tree: Tree, ctx: Context, code: Int): Context = {
- import scalaPrimitives._
- val Apply(Select(arrayObj, _), args) = tree
- val k = toTypeKind(arrayObj.tpe)
- val ARRAY(elem) = k
- var ctx1 = genLoad(arrayObj, ctx, k)
-
- if (scalaPrimitives.isArrayGet(code)) {
- // load argument on stack
- if (settings.debug.value)
- assert(args.length == 1,
- "Too many arguments for array get operation: " + tree);
- ctx1 = genLoad(args.head, ctx1, INT)
- generatedType = elem
- } else if (scalaPrimitives.isArraySet(code)) {
- if (settings.debug.value)
- assert(args.length == 2,
- "Too many arguments for array set operation: " + tree);
- ctx1 = genLoad(args.head, ctx1, INT)
- ctx1 = genLoad(args.tail.head, ctx1, toTypeKind(args.tail.head.tpe))
- // the following line should really be here, but because of bugs in erasure
- // we pretend we generate whatever type is expected from us.
- //generatedType = UNIT
- } else
- generatedType = INT
-
- code match {
- case ZARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(BOOL)), tree.pos)
- case BARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(BYTE)), tree.pos)
- case SARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(SHORT)), tree.pos)
- case CARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(CHAR)), tree.pos)
- case IARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(INT)), tree.pos)
- case LARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(LONG)), tree.pos)
- case FARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(FLOAT)), tree.pos)
- case DARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(DOUBLE)), tree.pos)
- case OARRAY_LENGTH =>
- ctx1.bb.emit(CALL_PRIMITIVE(ArrayLength(ANY_REF_CLASS)), tree.pos)
-
- case ZARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(BOOL), tree.pos)
- case BARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(BYTE), tree.pos)
- case SARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(SHORT), tree.pos)
- case CARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(CHAR), tree.pos)
- case IARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(INT), tree.pos)
- case LARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(LONG), tree.pos)
- case FARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(FLOAT), tree.pos)
- case DARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(DOUBLE), tree.pos)
- case OARRAY_GET =>
- ctx1.bb.emit(LOAD_ARRAY_ITEM(ANY_REF_CLASS), tree.pos)
-
- case ZARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(BOOL), tree.pos)
- case BARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(BYTE), tree.pos)
- case SARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(SHORT), tree.pos)
- case CARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(CHAR), tree.pos)
- case IARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(INT), tree.pos)
- case LARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(LONG), tree.pos)
- case FARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(FLOAT), tree.pos)
- case DARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(DOUBLE), tree.pos)
- case OARRAY_SET =>
- ctx1.bb.emit(STORE_ARRAY_ITEM(ANY_REF_CLASS), tree.pos)
-
- case _ =>
- abort("Unknown operation on arrays: " + tree + " code: " + code)
- }
- ctx1
- }
-
- // genLoad
val resCtx: Context = tree match {
case LabelDef(name, params, rhs) =>
val ctx1 = ctx.newBlock
@@ -436,46 +506,10 @@ abstract class GenICode extends SubComponent {
generatedType = UNIT
ctx1
- case If(cond, thenp, elsep) =>
- var thenCtx = ctx.newBlock
- var elseCtx = ctx.newBlock
- val contCtx = ctx.newBlock
- genCond(cond, ctx, thenCtx, elseCtx)
- val ifKind = toTypeKind(tree.tpe)
-
- val thenKind = toTypeKind(thenp.tpe)
- val elseKind = if (elsep == EmptyTree) UNIT else toTypeKind(elsep.tpe)
-
- generatedType = ifKind
-
- // we need to drop unneeded results, if one branch gives
- // unit and the other gives something on the stack, because
- // the type of 'if' is scala.Any, and its erasure would be Object.
- // But unboxed units are not Objects...
- if (thenKind == UNIT || elseKind == UNIT) {
- if (settings.debug.value)
- log("Will drop result from an if branch");
- thenCtx = genLoad(thenp, thenCtx, UNIT)
- elseCtx = genLoad(elsep, elseCtx, UNIT)
- if (settings.debug.value)
- assert(expectedType == UNIT,
- "I produce UNIT in a context where " +
- expectedType + " is expected!")
- generatedType = UNIT
- } else {
- thenCtx = genLoad(thenp, thenCtx, ifKind)
- elseCtx = genLoad(elsep, elseCtx, ifKind)
- }
-
- thenCtx.bb.emit(JUMP(contCtx.bb))
- thenCtx.bb.close
- if (elsep == EmptyTree)
- elseCtx.bb.emit(JUMP(contCtx.bb), tree.pos)
- else
- elseCtx.bb.emit(JUMP(contCtx.bb))
- elseCtx.bb.close
-
- contCtx
+ case t @ If(cond, thenp, elsep) =>
+ val (newCtx, resKind) = genLoadIf(t, ctx, expectedType)
+ generatedType = resKind
+ newCtx
case Return(expr) =>
val returnedKind = toTypeKind(expr.tpe)
@@ -510,41 +544,7 @@ abstract class GenICode extends SubComponent {
generatedType = expectedType
ctx1
- case Try(block, catches, finalizer) =>
- val kind = toTypeKind(tree.tpe)
-
- var handlers = for (CaseDef(pat, _, body) <- catches.reverse)
- yield pat match {
- case Typed(Ident(nme.WILDCARD), tpt) => (tpt.tpe.typeSymbol, kind, {
- ctx: Context =>
- ctx.bb.emit(DROP(REFERENCE(tpt.tpe.typeSymbol)));
- genLoad(body, ctx, kind);
- })
-
- case Ident(nme.WILDCARD) => (ThrowableClass, kind, {
- ctx: Context =>
- ctx.bb.emit(DROP(REFERENCE(ThrowableClass)))
- genLoad(body, ctx, kind)
- })
-
- case Bind(name, _) =>
- val exception = ctx.method.addLocal(new Local(pat.symbol, toTypeKind(pat.symbol.tpe), false))
-
- (pat.symbol.tpe.typeSymbol, kind, {
- ctx: Context =>
- ctx.bb.emit(STORE_LOCAL(exception), pat.pos);
- genLoad(body, ctx, kind);
- })
- }
-
- ctx.Try(
- bodyCtx => {
- generatedType = kind; //toTypeKind(block.tpe);
- genLoad(block, bodyCtx, generatedType);
- },
- handlers,
- finalizer,
- tree)
+ case t @ Try(_, _, _) => genLoadTry(t, ctx, (x: TypeKind) => generatedType = x)
case Throw(expr) =>
val ctx1 = genLoad(expr, ctx, THROWABLE)
@@ -558,30 +558,27 @@ abstract class GenICode extends SubComponent {
case Apply(TypeApply(fun, targs), _) =>
val sym = fun.symbol
- var ctx1 = ctx
- var cast = false
-
- if (sym == definitions.Object_isInstanceOf)
- cast = false
- else if (sym == definitions.Object_asInstanceOf)
- cast = true
- else
- abort("Unexpected type application " + fun + "[sym: " + sym.fullNameString + "]" + " in: " + tree)
+ val cast = sym match {
+ case Object_isInstanceOf => false
+ case Object_asInstanceOf => true
+ case _ => abort("Unexpected type application " + fun + "[sym: " + sym.fullNameString + "]" + " in: " + tree)
+ }
val Select(obj, _) = fun
val l = toTypeKind(obj.tpe)
val r = toTypeKind(targs.head.tpe)
-
- ctx1 = genLoadQualifier(fun, ctx)
+ val ctx1 = genLoadQualifier(fun, ctx)
if (l.isValueType && r.isValueType)
genConversion(l, r, ctx1, cast)
else if (l.isValueType) {
ctx1.bb.emit(DROP(l), fun.pos)
if (cast) {
- ctx1.bb.emit(NEW(REFERENCE(definitions.getClass("ClassCastException"))))
- ctx1.bb.emit(DUP(ANY_REF_CLASS))
- ctx1.bb.emit(THROW())
+ ctx1.bb.emit(Seq(
+ NEW(REFERENCE(definitions.getClass("ClassCastException"))),
+ DUP(ANY_REF_CLASS),
+ THROW()
+ ))
} else
ctx1.bb.emit(CONSTANT(Constant(false)))
}
@@ -632,11 +629,9 @@ abstract class GenICode extends SubComponent {
assert(generatedType.isReferenceType || generatedType.isArrayType,
"Non reference type cannot be instantiated: " + generatedType)
- var ctx1 = ctx
-
generatedType match {
case arr @ ARRAY(elem) =>
- ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
+ val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
val dims = arr.dimensions
var elemKind = arr.elementKind
if (args.length > dims)
@@ -645,24 +640,25 @@ abstract class GenICode extends SubComponent {
if (args.length != dims)
for (i <- args.length until dims) elemKind = ARRAY(elemKind)
ctx1.bb.emit(CREATE_ARRAY(elemKind, args.length), tree.pos)
+ ctx1
case rt @ REFERENCE(cls) =>
if (settings.debug.value)
assert(ctor.owner == cls,
"Symbol " + ctor.owner.fullNameString + " is different than " + tpt)
val nw = NEW(rt)
- ctx1.bb.emit(nw, tree.pos)
- ctx1.bb.emit(DUP(generatedType))
- ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
+ ctx.bb.emit(nw, tree.pos)
+ ctx.bb.emit(DUP(generatedType))
+ val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx)
val init = CALL_METHOD(ctor, Static(true))
nw.init = init
ctx1.bb.emit(init, tree.pos)
+ ctx1
case _ =>
abort("Cannot instantiate " + tpt + "of kind: " + generatedType)
}
- ctx1
case Apply(fun @ _, List(expr)) if (definitions.isBox(fun.symbol)) =>
if (settings.debug.value)
@@ -690,7 +686,7 @@ abstract class GenICode extends SubComponent {
ctx1.bb.emit(UNBOX(boxType), expr.pos)
ctx1
- case Apply(fun, args) =>
+ case app @ Apply(fun, args) =>
val sym = fun.symbol
if (sym.isLabel) { // jump to a label
@@ -711,78 +707,12 @@ abstract class GenICode extends SubComponent {
}
}
val ctx1 = genLoadLabelArguments(args, label, ctx)
- if (label.anchored)
- ctx1.bb.emit(JUMP(label.block), tree.pos)
- else
- ctx1.bb.emit(PJUMP(label), tree.pos)
-
- ctx1.bb.close
+ ctx1.bb.emitOnly(if (label.anchored) JUMP(label.block) else PJUMP(label))
ctx1.newBlock
} else if (isPrimitive(sym)) { // primitive method call
- val Select(receiver, _) = fun
-
- val code = scalaPrimitives.getPrimitive(sym, receiver.tpe)
- var ctx1 = ctx
-
- if (scalaPrimitives.isArithmeticOp(code)) {
- ctx1 = genArithmeticOp(tree, ctx1, code)
- } else if (code == scalaPrimitives.CONCAT) {
- ctx1 = genStringConcat(tree, ctx1)
- generatedType = STRING
- } else if (isArrayOp(code)) {
- ctx1 = genArrayOp(tree, ctx1, code)
- } else if (isLogicalOp(code) || isComparisonOp(code)) {
-
- val trueCtx = ctx1.newBlock
- val falseCtx = ctx1.newBlock
- val afterCtx = ctx1.newBlock
- genCond(tree, ctx1, trueCtx, falseCtx)
- trueCtx.bb.emit(CONSTANT(Constant(true)), tree.pos)
- trueCtx.bb.emit(JUMP(afterCtx.bb))
- trueCtx.bb.close
- falseCtx.bb.emit(CONSTANT(Constant(false)), tree.pos)
- falseCtx.bb.emit(JUMP(afterCtx.bb))
- falseCtx.bb.close
- generatedType = BOOL
- ctx1 = afterCtx
- } else if (code == scalaPrimitives.SYNCHRONIZED) {
- 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))
- ctx1.bb.emit(MONITOR_ENTER(), tree.pos)
- ctx1.enterSynchronized(monitor)
-
- if (settings.debug.value)
- log("synchronized block start");
-
- ctx1 = ctx1.Try(
- bodyCtx => {
- val ctx1 = genLoad(args.head, bodyCtx, expectedType /* toTypeKind(tree.tpe.resultType) */)
- ctx1.bb.emit(LOAD_LOCAL(monitor))
- ctx1.bb.emit(MONITOR_EXIT(), tree.pos)
- ctx1
- }, List(
- // tree.tpe / fun.tpe is object, which is no longer true after this transformation
- (NoSymbol, expectedType, exhCtx => {
- exhCtx.bb.emit(LOAD_LOCAL(monitor))
- exhCtx.bb.emit(MONITOR_EXIT(), tree.pos)
- exhCtx.bb.emit(THROW())
- exhCtx.bb.enterIgnoreMode
- exhCtx
- })), EmptyTree, tree);
- if (settings.debug.value)
- log("synchronized block end with block " + ctx1.bb +
- " closed=" + ctx1.bb.closed);
- ctx1.exitSynchronized(monitor)
- } else if (scalaPrimitives.isCoercion(code)) {
- ctx1 = genLoad(receiver, ctx1, toTypeKind(receiver.tpe))
- genCoercion(tree, ctx1, code)
- generatedType = scalaPrimitives.generatedKind(code)
- } else
- abort("Primitive operation not handled yet: " + sym.fullNameString + "(" +
- fun.symbol.simpleName + ") " + " at: " + (tree.pos));
- ctx1
+ val (newCtx, resKind) = genPrimitiveOp(app, ctx, expectedType)
+ generatedType = resKind
+ newCtx
} else { // normal method call
if (settings.debug.value)
log("Gen CALL_METHOD with sym: " + sym + " isStaticSymbol: " + sym.isStaticMember);
@@ -837,10 +767,9 @@ abstract class GenICode extends SubComponent {
generatedType = REFERENCE(tree.symbol)
} else {
ctx.bb.emit(THIS(ctx.clazz.symbol), tree.pos)
- if (tree.symbol == ArrayClass)
- generatedType = REFERENCE(ObjectClass)
- else
- generatedType = REFERENCE(ctx.clazz.symbol)
+ generatedType = REFERENCE(
+ if (tree.symbol == ArrayClass) ObjectClass else ctx.clazz.symbol
+ )
}
ctx
@@ -961,31 +890,26 @@ abstract class GenICode extends SubComponent {
var tags: List[Int] = Nil
var default: BasicBlock = afterCtx.bb
- for (caze <- cases) caze match {
- case CaseDef(Literal(value), EmptyTree, body) =>
- tags = value.intValue :: tags
- val tmpCtx = ctx1.newBlock
- targets = tmpCtx.bb :: targets
-
- caseCtx = genLoad(body, tmpCtx , generatedType)
- caseCtx.bb.emit(JUMP(afterCtx.bb), caze.pos)
- caseCtx.bb.close
-
- case CaseDef(Ident(nme.WILDCARD), EmptyTree, body) =>
- val tmpCtx = ctx1.newBlock
- default = tmpCtx.bb
-
- caseCtx = genLoad(body, tmpCtx , generatedType)
- caseCtx.bb.emit(JUMP(afterCtx.bb), caze.pos)
- caseCtx.bb.close
+ for (caze @ CaseDef(pat, guard, body) <- cases) {
+ assert(guard == EmptyTree)
+ val tmpCtx = ctx1.newBlock
+ pat match {
+ case Literal(value) =>
+ tags = value.intValue :: tags
+ targets = tmpCtx.bb :: targets
+ case Ident(nme.WILDCARD) =>
+ default = tmpCtx.bb
+ case _ =>
+ abort("Invalid case statement in switch-like pattern match: " +
+ tree + " at: " + (tree.pos))
+ }
- case _ =>
- abort("Invalid case statement in switch-like pattern match: " +
- tree + " at: " + (tree.pos))
+ caseCtx = genLoad(body, tmpCtx, generatedType)
+ caseCtx.bb.emitOnly(JUMP(afterCtx.bb) setPos caze.pos)
}
- ctx1.bb.emit(SWITCH(tags.reverse map (x => List(x)),
- (default :: targets).reverse), tree.pos)
- ctx1.bb.close
+ ctx1.bb.emitOnly(
+ SWITCH(tags.reverse map (x => List(x)), (default :: targets).reverse) setPos tree.pos
+ )
afterCtx
case EmptyTree =>
@@ -994,13 +918,12 @@ abstract class GenICode extends SubComponent {
ctx
case _ =>
- abort("Unexpected tree in genLoad: " + tree + " at: " +
- (tree.pos))
+ abort("Unexpected tree in genLoad: " + tree + " at: " + tree.pos)
}
// emit conversion
if (generatedType != expectedType)
- adapt(generatedType, expectedType, resCtx, tree.pos);
+ adapt(generatedType, expectedType, resCtx, tree.pos)
resCtx
}
@@ -1143,7 +1066,7 @@ abstract class GenICode extends SubComponent {
*/
def genCoercion(tree: Tree, ctx: Context, code: Int) = {
import scalaPrimitives._
- code match {
+ (code: @switch) match {
case B2B => ()
case B2C => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, CHAR)), tree.pos)
case B2S => ctx.bb.emit(CALL_PRIMITIVE(Conversion(BYTE, SHORT)), tree.pos)
@@ -1501,9 +1424,8 @@ abstract class GenICode extends SubComponent {
assert(ctx.clazz.symbol eq cls,
"Classes are not the same: " + ctx.clazz.symbol + ", " + cls)
- for (f <- cls.info.decls.iterator)
- if (!f.isMethod && f.isTerm)
- ctx.clazz.addField(new IField(f));
+ for (f <- cls.info.decls ; if !f.isMethod && f.isTerm)
+ ctx.clazz addField new IField(f)
}
/**
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index 25c60c32b8..2ba0ee68b9 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -51,6 +51,25 @@ trait Definitions {
lazy val anyvalparam = List(AnyValClass.typeConstructor)
lazy val anyrefparam = List(AnyRefClass.typeConstructor)
+ // private parameter conveniences
+ private def booltype = BooleanClass.typeConstructor
+ private def boolparam = List(booltype)
+ private def bytetype = ByteClass.typeConstructor
+ private def byteparam = List(bytetype)
+ private def shorttype = ShortClass.typeConstructor
+ private def shortparam = List(shorttype)
+ private def inttype = IntClass.typeConstructor
+ private def intparam = List(inttype)
+ private def longtype = LongClass.typeConstructor
+ private def longparam = List(longtype)
+ private def floattype = FloatClass.typeConstructor
+ private def floatparam = List(floattype)
+ private def doubletype = DoubleClass.typeConstructor
+ private def doubleparam = List(doubletype)
+ private def chartype = CharClass.typeConstructor
+ private def charparam = List(chartype)
+ private def stringtype = StringClass.typeConstructor
+
// top types
lazy val AnyClass = newClass(ScalaPackageClass, nme.Any, Nil) setFlag (ABSTRACT)
lazy val AnyValClass = newClass(ScalaPackageClass, nme.AnyVal, anyparam) setFlag (ABSTRACT | SEALED)
@@ -351,8 +370,13 @@ trait Definitions {
var Object_== : Symbol = _
var Object_!= : Symbol = _
var Object_synchronized: Symbol = _
- var Object_isInstanceOf: Symbol = _
- var Object_asInstanceOf: Symbol = _
+ lazy val Object_isInstanceOf = newPolyMethod(
+ ObjectClass, "$isInstanceOf",
+ tparam => MethodType(List(), booltype)) setFlag FINAL
+ lazy val Object_asInstanceOf = newPolyMethod(
+ ObjectClass, "$asInstanceOf",
+ tparam => MethodType(List(), tparam.typeConstructor)) setFlag FINAL
+
def Object_getClass = getMember(ObjectClass, nme.getClass_)
def Object_clone = getMember(ObjectClass, nme.clone_)
def Object_finalize = getMember(ObjectClass, nme.finalize_)
@@ -572,26 +596,6 @@ trait Definitions {
/** Sets-up symbols etc. for value classes, and their boxed versions. This
* method is called once from within the body of init. */
private def initValueClasses() {
- val booltype = BooleanClass.typeConstructor
- val boolparam = List(booltype)
- val bytetype = ByteClass.typeConstructor
- val byteparam = List(bytetype)
- val chartype = CharClass.typeConstructor
- val charparam = List(chartype)
- val shorttype = ShortClass.typeConstructor
- val shortparam = List(shorttype)
- val inttype = IntClass.typeConstructor
- val intparam = List(inttype)
- val longtype = LongClass.typeConstructor
- val longparam = List(longtype)
-
- val floattype = FloatClass.typeConstructor
- val floatparam = List(floattype)
- val doubletype = DoubleClass.typeConstructor
- val doubleparam = List(doubletype)
-
- val stringtype = StringClass.typeConstructor
-
// init scala.Boolean
newParameterlessMethod(BooleanClass, nme.UNARY_!, booltype)
List(nme.EQ, nme.NE, nme.ZOR, nme.ZAND, nme.OR, nme.AND, nme.XOR) foreach {
@@ -619,7 +623,6 @@ trait Definitions {
newParameterlessMethod(clazz, nme.toChar, chartype)
newParameterlessMethod(clazz, nme.toInt, inttype)
newParameterlessMethod(clazz, nme.toLong, longtype)
-
newParameterlessMethod(clazz, nme.toFloat, floattype)
newParameterlessMethod(clazz, nme.toDouble, doubletype)
@@ -730,7 +733,7 @@ trait Definitions {
if (isInitialized) return
isInitialized = true
- EmptyPackageClass.setInfo(ClassInfoType(List(), new Scope, EmptyPackageClass))
+ EmptyPackageClass.setInfo(ClassInfoType(Nil, new Scope, EmptyPackageClass))
EmptyPackage.setInfo(EmptyPackageClass.tpe)
RootClass.info.decls.enter(EmptyPackage)
RootClass.info.decls.enter(RootPackage)
@@ -738,16 +741,13 @@ trait Definitions {
abbrvTag(UnitClass) = 'V'
initValueClasses()
- val booltype = BooleanClass.typeConstructor
// members of class scala.Any
Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype) setFlag FINAL
Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype) setFlag FINAL
Any_equals = newMethod(AnyClass, nme.equals_, anyparam, booltype)
- Any_hashCode = newMethod(
- AnyClass, nme.hashCode_, List(), IntClass.typeConstructor)
- Any_toString = newMethod(
- AnyClass, nme.toString_, List(), StringClass.typeConstructor)
+ Any_hashCode = newMethod(AnyClass, nme.hashCode_, Nil, inttype)
+ Any_toString = newMethod(AnyClass, nme.toString_, Nil, stringtype)
Any_isInstanceOf = newPolyMethod(
AnyClass, nme.isInstanceOf_, tparam => booltype) setFlag FINAL
@@ -762,16 +762,11 @@ trait Definitions {
Object_synchronized = newPolyMethodCon(
ObjectClass, nme.synchronized_,
tparam => msym => MethodType(msym.newSyntheticValueParams(List(tparam.typeConstructor)), tparam.typeConstructor)) setFlag FINAL
- Object_isInstanceOf = newPolyMethod(
- ObjectClass, "$isInstanceOf",
- tparam => MethodType(List(), booltype)) setFlag FINAL
- Object_asInstanceOf = newPolyMethod(
- ObjectClass, "$asInstanceOf",
- tparam => MethodType(List(), tparam.typeConstructor)) setFlag FINAL
+
String_+ = newMethod(
- StringClass, "+", anyparam, StringClass.typeConstructor) setFlag FINAL
+ StringClass, "+", anyparam, stringtype) setFlag FINAL
- val forced = List( // force initialization of every symbol that is enetred as a side effect
+ val forced = List( // force initialization of every symbol that is entered as a side effect
AnnotationDefaultAttr,
RepeatedParamClass,
JavaRepeatedParamClass,
@@ -791,7 +786,9 @@ trait Definitions {
NullClass,
NothingClass,
SingletonClass,
- EqualsPatternClass
+ EqualsPatternClass,
+ Object_isInstanceOf,
+ Object_asInstanceOf
)
// #2264