From af924f4d5ef381e3d26bf5044aa056e25ba215c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Fri, 15 Mar 2024 22:33:33 +0100 Subject: [PATCH 1/2] Add LinkedClass.hasDirectInstances. It exposes whether the given class is directly instantiated. This is required for the WebAssembly backend, which needs to build vtables for concrete classes only. --- .../main/scala/org/scalajs/linker/frontend/BaseLinker.scala | 1 + .../main/scala/org/scalajs/linker/standard/LinkedClass.scala | 1 + project/BinaryIncompatibilities.scala | 3 +++ 3 files changed, 5 insertions(+) diff --git a/linker/shared/src/main/scala/org/scalajs/linker/frontend/BaseLinker.scala b/linker/shared/src/main/scala/org/scalajs/linker/frontend/BaseLinker.scala index 692eb8a7f1..f120dff28a 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/frontend/BaseLinker.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/frontend/BaseLinker.scala @@ -166,6 +166,7 @@ private[frontend] object BaseLinker { classDef.pos, ancestors.toList, hasInstances = classInfo.isAnySubclassInstantiated, + hasDirectInstances = classInfo.isInstantiated, hasInstanceTests = classInfo.areInstanceTestsUsed, hasRuntimeTypeInfo = classInfo.isDataAccessed, fieldsRead = classInfo.fieldsRead.toSet, diff --git a/linker/shared/src/main/scala/org/scalajs/linker/standard/LinkedClass.scala b/linker/shared/src/main/scala/org/scalajs/linker/standard/LinkedClass.scala index 58b71fb725..afa257b289 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/standard/LinkedClass.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/standard/LinkedClass.scala @@ -55,6 +55,7 @@ final class LinkedClass( // Actual Linking info val ancestors: List[ClassName], val hasInstances: Boolean, + val hasDirectInstances: Boolean, val hasInstanceTests: Boolean, val hasRuntimeTypeInfo: Boolean, val fieldsRead: Set[FieldName], diff --git a/project/BinaryIncompatibilities.scala b/project/BinaryIncompatibilities.scala index 49cbe2d2a0..e37b343839 100644 --- a/project/BinaryIncompatibilities.scala +++ b/project/BinaryIncompatibilities.scala @@ -24,6 +24,9 @@ object BinaryIncompatibilities { ) val Linker = Seq( + // !!! Breaking, OK in minor release + ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.linker.standard.LinkedClass.this"), + // private, not an issue ProblemFilters.exclude[DirectMissingMethodProblem]("org.scalajs.linker.standard.CommonPhaseConfig.this"), ) From f05baed4b572756dfcf3069eada2b9eeafc7b6bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Fri, 15 Mar 2024 22:48:47 +0100 Subject: [PATCH 2/2] Only set `$c_C.prototype.$classData` if `C` has *direct* instances. It is not useful for classes that only have strict sub instances, i.e., classes that are effectively abstract. --- .../org/scalajs/linker/backend/emitter/ClassEmitter.scala | 4 ++-- .../scala/org/scalajs/linker/backend/emitter/Emitter.scala | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/ClassEmitter.scala b/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/ClassEmitter.scala index e2f2419835..2d0dd515ea 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/ClassEmitter.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/ClassEmitter.scala @@ -826,7 +826,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) { def genTypeData(className: ClassName, kind: ClassKind, superClass: Option[ClassIdent], ancestors: List[ClassName], - jsNativeLoadSpec: Option[JSNativeLoadSpec], hasInstances: Boolean)( + jsNativeLoadSpec: Option[JSNativeLoadSpec], hasDirectInstances: Boolean)( implicit moduleContext: ModuleContext, globalKnowledge: GlobalKnowledge, pos: Position): WithGlobals[List[js.Tree]] = { import TreeDSL._ @@ -847,7 +847,7 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) { val kindOrCtorParam = { if (isJSType) js.IntLiteral(2) else if (kind == ClassKind.Interface) js.IntLiteral(1) - else if (kind.isClass && hasInstances) globalVar(VarField.c, className) + else if (kind.isClass && hasDirectInstances) globalVar(VarField.c, className) else js.IntLiteral(0) } diff --git a/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/Emitter.scala b/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/Emitter.scala index cdf17260e8..9d49e5855b 100644 --- a/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/Emitter.scala +++ b/linker/shared/src/main/scala/org/scalajs/linker/backend/emitter/Emitter.scala @@ -716,14 +716,14 @@ final class Emitter[E >: Null <: js.Tree]( if (linkedClass.hasRuntimeTypeInfo) { main ++= extractWithGlobals(classTreeCache.typeData.getOrElseUpdate( - linkedClass.hasInstances, + linkedClass.hasDirectInstances, classEmitter.genTypeData( className, // invalidated by overall class cache (part of ancestors) kind, // invalidated by class version linkedClass.superClass, // invalidated by class version linkedClass.ancestors, // invalidated by overall class cache (identity) linkedClass.jsNativeLoadSpec, // invalidated by class version - linkedClass.hasInstances // invalidated directly (it is the input to `getOrElseUpdate`) + linkedClass.hasDirectInstances // invalidated directly (it is the input to `getOrElseUpdate`) )(moduleContext, classCache, linkedClass.pos).map(postTransform(_, 0)))) } }