Skip to content

Commit 13c3210

Browse files
authored
Merge pull request #9600 from dotty-staging/add-serializable-to-objects-in-backend
Mitigate #9596 for SJS: Make objects serializable only in the JVM back-end.
2 parents 80d9dcc + ab25d6b commit 13c3210

File tree

4 files changed

+29
-9
lines changed

4 files changed

+29
-9
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeSkelBuilder.scala

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,30 @@ trait BCodeSkelBuilder extends BCodeHelpers {
238238

239239
val ps = claszSymbol.info.parents
240240
val superClass: String = if (ps.isEmpty) ObjectReference.internalName else internalName(ps.head.widenDealias.typeSymbol)
241-
val interfaceNames = classBTypeFromSymbol(claszSymbol).info.interfaces map {
241+
val interfaceNames0 = classBTypeFromSymbol(claszSymbol).info.interfaces map {
242242
case classBType =>
243243
if (classBType.isNestedClass) { innerClassBufferASM += classBType }
244244
classBType.internalName
245245
}
246+
/* To avoid deadlocks when combining objects, lambdas and multi-threading,
247+
* lambdas in objects are compiled to instance methods of the module class
248+
* instead of static methods (see tests/run/deadlock.scala and
249+
* https://github.com/scala/scala-dev/issues/195 for details).
250+
* This has worked well for us so far but this is problematic for
251+
* serialization: serializing a lambda requires serializing all the values
252+
* it captures, if this lambda is in an object, this means serializing the
253+
* enclosing object, which fails if the object does not extend
254+
* Serializable.
255+
* Because serializing objects is basically free since #5775, it seems like
256+
* the simplest solution is to simply make all objects Serializable, this
257+
* certainly seems preferable to deadlocks.
258+
* This cannot be done earlier because Scala.js would not like it (#9596).
259+
*/
260+
val interfaceNames =
261+
if (claszSymbol.is(ModuleClass) && !interfaceNames0.contains("java/io/Serializable"))
262+
interfaceNames0 :+ "java/io/Serializable"
263+
else
264+
interfaceNames0
246265

247266
val flags = javaFlags(claszSymbol)
248267

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,8 +616,6 @@ object desugar {
616616
parents1 = enumClassTypeRef :: Nil
617617
if (isCaseClass | isCaseObject)
618618
parents1 = parents1 :+ scalaDot(str.Product.toTypeName) :+ scalaDot(nme.Serializable.toTypeName)
619-
else if (isObject)
620-
parents1 = parents1 :+ scalaDot(nme.Serializable.toTypeName)
621619
if (isEnum)
622620
parents1 = parents1 :+ ref(defn.EnumClass.typeRef)
623621

compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,15 +377,18 @@ class SyntheticMembers(thisPhase: DenotTransformer) {
377377
newSymbol(clazz, nme.writeReplace, Method | Private | Synthetic,
378378
MethodType(Nil, defn.AnyRefType), coord = clazz.coord).entered.asTerm
379379

380-
/** If this is a serializable static object `Foo`, add the method:
380+
/** If this is a static object `Foo`, add the method:
381381
*
382382
* private def writeReplace(): AnyRef =
383383
* new scala.runtime.ModuleSerializationProxy(classOf[Foo.type])
384384
*
385385
* unless an implementation already exists, otherwise do nothing.
386+
*
387+
* All static objects receive the `Serializable` flag in the back-end, so
388+
* we do that even for objects that are not serializable at this phase.
386389
*/
387390
def serializableObjectMethod(clazz: ClassSymbol)(using Context): List[Tree] =
388-
if clazz.is(Module) && clazz.isStatic && clazz.isSerializable && !hasWriteReplace(clazz) then
391+
if clazz.is(Module) && clazz.isStatic && !hasWriteReplace(clazz) then
389392
List(
390393
DefDef(writeReplaceDef(clazz),
391394
_ => New(defn.ModuleSerializationProxyClass.typeRef,

tests/run-macros/tasty-extractors-2.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ OrType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix(), "<root>")), "scala"), "Int")
2525
Inlined(None, Nil, Block(List(ClassDef("Foo", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, Nil)), Literal(Constant(()))))
2626
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
2727

28-
Inlined(None, Nil, Block(List(ValDef("Foo", TypeIdent("Foo$"), Some(Apply(Select(New(TypeIdent("Foo$")), "<init>"), Nil))), ClassDef("Foo$", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil), TypeSelect(Select(Ident("_root_"), "scala"), "Serializable")), Nil, Some(ValDef("_", Singleton(Ident("Foo")), None)), Nil)), Literal(Constant(()))))
28+
Inlined(None, Nil, Block(List(ValDef("Foo", TypeIdent("Foo$"), Some(Apply(Select(New(TypeIdent("Foo$")), "<init>"), Nil))), ClassDef("Foo$", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, Some(ValDef("_", Singleton(Ident("Foo")), None)), Nil)), Literal(Constant(()))))
2929
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
3030

3131
Inlined(None, Nil, Block(List(TypeDef("Foo", TypeBoundsTree(Inferred(), Inferred()))), Literal(Constant(()))))
@@ -49,7 +49,7 @@ TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
4949
Inlined(None, Nil, Block(List(ClassDef("Foo", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(DefDef("a", Nil, Nil, Inferred(), Some(Literal(Constant(0))))))), Literal(Constant(()))))
5050
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
5151

52-
Inlined(None, Nil, Block(List(ClassDef("Foo", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil), TypeSelect(Select(Ident("_root_"), "scala"), "Product"), TypeSelect(Select(Ident("_root_"), "scala"), "Serializable")), Nil, None, List(DefDef("copy", Nil, List(Nil), Inferred(), Some(Apply(Select(New(Inferred()), "<init>"), Nil))))), ValDef("Foo", TypeIdent("Foo$"), Some(Apply(Select(New(TypeIdent("Foo$")), "<init>"), Nil))), ClassDef("Foo$", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil), Applied(Inferred(), List(Inferred())), TypeSelect(Select(Ident("_root_"), "scala"), "Serializable")), Nil, Some(ValDef("_", Singleton(Ident("Foo")), None)), List(DefDef("apply", Nil, List(Nil), Inferred(), Some(Apply(Select(New(Inferred()), "<init>"), Nil))), DefDef("unapply", Nil, List(List(ValDef("x$1", Inferred(), None))), Singleton(Literal(Constant(true))), Some(Literal(Constant(true))))))), Literal(Constant(()))))
52+
Inlined(None, Nil, Block(List(ClassDef("Foo", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil), TypeSelect(Select(Ident("_root_"), "scala"), "Product"), TypeSelect(Select(Ident("_root_"), "scala"), "Serializable")), Nil, None, List(DefDef("copy", Nil, List(Nil), Inferred(), Some(Apply(Select(New(Inferred()), "<init>"), Nil))))), ValDef("Foo", TypeIdent("Foo$"), Some(Apply(Select(New(TypeIdent("Foo$")), "<init>"), Nil))), ClassDef("Foo$", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil), Applied(Inferred(), List(Inferred()))), Nil, Some(ValDef("_", Singleton(Ident("Foo")), None)), List(DefDef("apply", Nil, List(Nil), Inferred(), Some(Apply(Select(New(Inferred()), "<init>"), Nil))), DefDef("unapply", Nil, List(List(ValDef("x$1", Inferred(), None))), Singleton(Literal(Constant(true))), Some(Literal(Constant(true))))))), Literal(Constant(()))))
5353
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
5454

5555
Inlined(None, Nil, Block(List(ClassDef("Foo1", DefDef("<init>", Nil, List(List(ValDef("a", TypeIdent("Int"), None))), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(ValDef("a", Inferred(), None)))), Literal(Constant(()))))
@@ -58,13 +58,13 @@ TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
5858
Inlined(None, Nil, Block(List(ClassDef("Foo2", DefDef("<init>", Nil, List(List(ValDef("b", TypeIdent("Int"), None))), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(ValDef("b", Inferred(), None)))), Literal(Constant(()))))
5959
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
6060

61-
Inlined(None, Nil, Block(List(ClassDef("Foo3", DefDef("<init>", Nil, List(List(ValDef("a", TypeIdent("Int"), None))), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(ValDef("a", Inferred(), None))), ValDef("Foo3", TypeIdent("Foo3$"), Some(Apply(Select(New(TypeIdent("Foo3$")), "<init>"), Nil))), ClassDef("Foo3$", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil), TypeSelect(Select(Ident("_root_"), "scala"), "Serializable")), Nil, Some(ValDef("_", Singleton(Ident("Foo3")), None)), List(DefDef("$lessinit$greater$default$1", Nil, Nil, Inferred(), Some(Literal(Constant(5))))))), Literal(Constant(()))))
61+
Inlined(None, Nil, Block(List(ClassDef("Foo3", DefDef("<init>", Nil, List(List(ValDef("a", TypeIdent("Int"), None))), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(ValDef("a", Inferred(), None))), ValDef("Foo3", TypeIdent("Foo3$"), Some(Apply(Select(New(TypeIdent("Foo3$")), "<init>"), Nil))), ClassDef("Foo3$", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, Some(ValDef("_", Singleton(Ident("Foo3")), None)), List(DefDef("$lessinit$greater$default$1", Nil, Nil, Inferred(), Some(Literal(Constant(5))))))), Literal(Constant(()))))
6262
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
6363

6464
Inlined(None, Nil, Block(List(ClassDef("Foo4", DefDef("<init>", Nil, List(List(ValDef("a", TypeIdent("Int"), None)), List(ValDef("b", TypeIdent("Int"), None))), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(ValDef("a", Inferred(), None), ValDef("b", Inferred(), None)))), Literal(Constant(()))))
6565
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
6666

67-
Inlined(None, Nil, Block(List(ClassDef("Foo5", DefDef("<init>", Nil, List(List(ValDef("a", TypeIdent("Int"), None)), List(ValDef("b", TypeIdent("Int"), None))), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(ValDef("a", Inferred(), None), ValDef("b", Inferred(), None))), ValDef("Foo5", TypeIdent("Foo5$"), Some(Apply(Select(New(TypeIdent("Foo5$")), "<init>"), Nil))), ClassDef("Foo5$", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil), TypeSelect(Select(Ident("_root_"), "scala"), "Serializable")), Nil, Some(ValDef("_", Singleton(Ident("Foo5")), None)), List(DefDef("$lessinit$greater$default$2", Nil, List(List(ValDef("a", TypeIdent("Int"), None))), Inferred(), Some(Ident("a")))))), Literal(Constant(()))))
67+
Inlined(None, Nil, Block(List(ClassDef("Foo5", DefDef("<init>", Nil, List(List(ValDef("a", TypeIdent("Int"), None)), List(ValDef("b", TypeIdent("Int"), None))), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(ValDef("a", Inferred(), None), ValDef("b", Inferred(), None))), ValDef("Foo5", TypeIdent("Foo5$"), Some(Apply(Select(New(TypeIdent("Foo5$")), "<init>"), Nil))), ClassDef("Foo5$", DefDef("<init>", Nil, List(Nil), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, Some(ValDef("_", Singleton(Ident("Foo5")), None)), List(DefDef("$lessinit$greater$default$2", Nil, List(List(ValDef("a", TypeIdent("Int"), None))), Inferred(), Some(Ident("a")))))), Literal(Constant(()))))
6868
TypeRef(ThisType(TypeRef(NoPrefix(), "scala")), "Unit")
6969

7070
Inlined(None, Nil, Block(List(ClassDef("Foo6", DefDef("<init>", Nil, List(List(ValDef("a", TypeIdent("Int"), None)), List(ValDef("b", Singleton(Ident("a")), None))), Inferred(), None), List(Apply(Select(New(Inferred()), "<init>"), Nil)), Nil, None, List(ValDef("a", Inferred(), None), ValDef("b", Inferred(), None)))), Literal(Constant(()))))

0 commit comments

Comments
 (0)