Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Use standard loading mechanism for jl.Object in Analyzer #4890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ object Analysis {
def from: From
}

final case class MissingJavaLangObjectClass(from: From) extends Error
final case class CycleInInheritanceChain(encodedClassNames: List[ClassName], from: From) extends Error
final case class MissingClass(info: ClassInfo, from: From) extends Error

Expand Down Expand Up @@ -216,8 +215,6 @@ object Analysis {

def logError(error: Error, logger: Logger, level: Level): Unit = {
val headMsg = error match {
case MissingJavaLangObjectClass(_) =>
"Fatal error: java.lang.Object is missing"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sjrd, if you feel we need to keep this error, we have two alternatives:

  • Emit it in addition when the lookup of ObjectClass returns a nonExistentClass
  • Special case ClassInfo#link to emit a different error if className == ObjectClass (there is precedent for ClassInfo to behave differently if it is jlO, so it's not that bad).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The special error was only there because I thought it would crash the rest of the Analyzer if Object was missing. If it doesn't crash, it's fine.

Perhaps add a test where jl.Object is missing but there actually is another class? Currently the only test we have has no class at all.

case CycleInInheritanceChain(encodedClassNames, _) =>
("Fatal error: cycle in inheritance chain involving " +
encodedClassNames.map(_.nameString).mkString(", "))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,11 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
/* Load the java.lang.Object class, and validate it
* If it is missing or invalid, we're in deep trouble, and cannot continue.
*/
infoLoader.loadInfo(ObjectClass)(workQueue.ec) match {
case None =>
_errors += MissingJavaLangObjectClass(fromAnalyzer)

case Some(future) =>
workQueue.enqueue(future) { data =>
objectClassInfo = new ClassInfo(data,
unvalidatedSuperClass = None,
unvalidatedInterfaces = Nil, nonExistent = false)

objectClassInfo.link()
onSuccess()
}
lookupClass(ObjectClass) { clazz =>
if (!clazz.nonExistent) {
objectClassInfo = clazz
onSuccess()
}
}
}

Expand Down Expand Up @@ -352,7 +344,13 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
_classInfos.get(className) match {
case None =>
val loading = new LoadingClass(className)

_classInfos(className) = loading

// Request linking before scheduling the loading to avoid the task queue
// dropping to zero intermittently.
loading.requestLink(knownDescendants)(onSuccess)
loading.startLoad()

case Some(loading: LoadingClass) =>
loading.requestLink(knownDescendants)(onSuccess)
Expand All @@ -377,17 +375,6 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
private val promise = Promise[LoadingResult]()
private var knownDescendants = Set[LoadingClass](this)

_classInfos(className) = this

infoLoader.loadInfo(className)(workQueue.ec) match {
case Some(future) =>
workQueue.enqueue(future)(link(_, nonExistent = false))

case None =>
val data = createMissingClassInfo(className)
link(data, nonExistent = true)
}

def requestLink(knownDescendants: Set[LoadingClass])(onSuccess: LoadingResult => Unit): Unit = {
if (knownDescendants.contains(this)) {
onSuccess(CycleInfo(Nil, this))
Expand All @@ -397,6 +384,17 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
}
}

def startLoad(): Unit = {
infoLoader.loadInfo(className)(workQueue.ec) match {
case Some(future) =>
workQueue.enqueue(future)(link(_, nonExistent = false))

case None =>
val data = createMissingClassInfo(className)
link(data, nonExistent = true)
}
}

private def link(data: Infos.ClassInfo, nonExistent: Boolean): Unit = {
lookupAncestors(data.superClass.toList ++ data.interfaces) { classes =>
val (superClass, interfaces) =
Expand Down Expand Up @@ -461,15 +459,11 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
val isNativeJSClass =
kind == ClassKind.NativeJSClass || kind == ClassKind.NativeJSModuleClass

// Note: j.l.Object is special and is validated upfront

val superClass: Option[ClassInfo] =
if (className == ObjectClass) unvalidatedSuperClass
else validateSuperClass(unvalidatedSuperClass)
validateSuperClass(unvalidatedSuperClass)

val interfaces: List[ClassInfo] =
if (className == ObjectClass) unvalidatedInterfaces
else validateInterfaces(unvalidatedInterfaces)
validateInterfaces(unvalidatedInterfaces)

/** Ancestors of this class or interface.
*
Expand Down Expand Up @@ -497,6 +491,11 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
def from = FromClass(this)

kind match {
case _ if className == ObjectClass =>
assert(superClass.isEmpty)

None

case ClassKind.Class | ClassKind.ModuleClass | ClassKind.HijackedClass =>
val superCl = superClass.get // checked by ClassDef checker.
if (superCl.kind != ClassKind.Class) {
Expand Down Expand Up @@ -1479,8 +1478,12 @@ final class Analyzer(config: CommonPhaseConfig, initial: Boolean,
}

private def createMissingClassInfo(className: ClassName): Infos.ClassInfo = {
val superClass =
if (className == ObjectClass) None
else Some(ObjectClass)

new Infos.ClassInfoBuilder(className, ClassKind.Class,
superClass = Some(ObjectClass), interfaces = Nil, jsNativeLoadSpec = None)
superClass = superClass, interfaces = Nil, jsNativeLoadSpec = None)
.addMethod(makeSyntheticMethodInfo(NoArgConstructorName, MemberNamespace.Constructor))
.result()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,23 @@ class AnalyzerTest {
@Test
def missingJavaLangObject(): AsyncResult = await {
val analysis = computeAnalysis(Nil, stdlib = TestIRRepo.empty)
assertExactErrors(analysis, MissingJavaLangObjectClass(fromAnalyzer))
assertContainsError("MissingClass(jlObject)", analysis) {
case MissingClass(ClsInfo(name), fromAnalyzer) =>
name == ObjectClass.nameString
}
}

@Test
def missingJavaLangObjectButOthers(): AsyncResult = await {
val classDefs = Seq(classDef("A", superClass = Some(ObjectClass)))

val analysis = computeAnalysis(classDefs,
reqsFactory.classData("A"), stdlib = TestIRRepo.empty)

assertContainsError("MissingClass(jlObject)", analysis) {
case MissingClass(ClsInfo(name), fromAnalyzer) =>
name == ObjectClass.nameString
}
}

@Test
Expand Down