Skip to content

Commit fbd6378

Browse files
authored
Merge pull request scala#7305 from diesalbla/jvm_wise_lub_reversed
JvmWiseLUB: A simple linear time algorithm.
2 parents a44dd81 + 1db68ac commit fbd6378

File tree

1 file changed

+24
-24
lines changed

1 file changed

+24
-24
lines changed

src/compiler/scala/tools/nsc/backend/jvm/BTypes.scala

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -662,10 +662,18 @@ abstract class BTypes {
662662

663663
def isInterface: Either[NoClassBTypeInfo, Boolean] = info.map(i => (i.flags & asm.Opcodes.ACC_INTERFACE) != 0)
664664

665-
def superClassesTransitive: Either[NoClassBTypeInfo, List[ClassBType]] = info.flatMap(i => i.superClass match {
666-
case None => Right(Nil)
667-
case Some(sc) => sc.superClassesTransitive.map(sc :: _)
668-
})
665+
/** The super class chain of this type, starting with Object, ending with `this`. */
666+
def superClassesChain: Either[NoClassBTypeInfo, List[ClassBType]] = try {
667+
var res = List(this)
668+
var sc = info.orThrow.superClass
669+
while (sc.nonEmpty) {
670+
res ::= sc.get
671+
sc = sc.get.info.orThrow.superClass
672+
}
673+
Right(res)
674+
} catch {
675+
case Invalid(noInfo: NoClassBTypeInfo) => Left(noInfo)
676+
}
669677

670678
/**
671679
* The prefix of the internal name until the last '/', or the empty string.
@@ -737,7 +745,7 @@ abstract class BTypes {
737745
* Background:
738746
* http://gallium.inria.fr/~xleroy/publi/bytecode-verification-JAR.pdf
739747
* http://comments.gmane.org/gmane.comp.java.vm.languages/2293
740-
* https://github.com/scala/bug/issues/3872
748+
* https://github.com/scala/bug/issues/3872#issuecomment-292386375
741749
*/
742750
def jvmWiseLUB(other: ClassBType): Either[NoClassBTypeInfo, ClassBType] = {
743751
def isNotNullOrNothing(c: ClassBType) = !c.isNullType && !c.isNothingType
@@ -758,14 +766,7 @@ abstract class BTypes {
758766
if (this.isSubtypeOf(other).orThrow) other else ObjectRef
759767

760768
case _ =>
761-
// TODO @lry I don't really understand the reasoning here.
762-
// Both this and other are classes. The code takes (transitively) all superclasses and
763-
// finds the first common one.
764-
// MOST LIKELY the answer can be found here, see the comments and links by Miguel:
765-
// - https://github.com/scala/bug/issues/3872
766-
// @jz Wouldn't it be better to walk the superclass chain of both types in reverse (starting from Object), and
767-
// finding the last common link? That would be O(N), whereas this looks O(N^2)
768-
firstCommonSuffix(this :: this.superClassesTransitive.orThrow, other :: other.superClassesTransitive.orThrow)
769+
firstCommonSuffix(superClassesChain.orThrow, other.superClassesChain.orThrow)
769770
}
770771

771772
assert(isNotNullOrNothing(res), s"jvmWiseLUB computed: $res")
@@ -774,17 +775,16 @@ abstract class BTypes {
774775
}
775776

776777
private def firstCommonSuffix(as: List[ClassBType], bs: List[ClassBType]): ClassBType = {
777-
var chainA = as
778-
var chainB = bs
779-
var fcs: ClassBType = null
780-
do {
781-
if (chainB contains chainA.head) fcs = chainA.head
782-
else if (chainA contains chainB.head) fcs = chainB.head
783-
else {
784-
chainA = chainA.tail
785-
chainB = chainB.tail
786-
}
787-
} while (fcs == null)
778+
// assert(as.head == ObjectRef, as.head)
779+
// assert(bs.head == ObjectRef, bs.head)
780+
var chainA = as.tail
781+
var chainB = bs.tail
782+
var fcs = ObjectRef
783+
while (chainA.nonEmpty && chainB.nonEmpty && chainA.head == chainB.head) {
784+
fcs = chainA.head
785+
chainA = chainA.tail
786+
chainB = chainB.tail
787+
}
788788
fcs
789789
}
790790
}

0 commit comments

Comments
 (0)