Skip to content

Commit 0cc6ebe

Browse files
committed
Update the compiler not to avoid emitting trivial constructors.
This is a follow up to the parent commit, which brings the compiler up to date with the requirements of the IR. Since constructors are not inherited anymore, the compiler is required to emit all constructors, including so-called trivial constructors. Naively, this would not change anything at this point, since missing constructors would be recreated by the linker. However, for module accessors with trivial constructors, the constructor now contains a StoreModule instruction, in addition to the super constructor call. We keep parity with the previous implementation by adding a corresponding optimization that gets rid of unnecessary StoreModule instructions. This optimization can be applied in a few more cases than what the compiler did, since it also supports any statements before the StoreModule, and any "trivial" statement after it.
1 parent 819c872 commit 0cc6ebe

File tree

2 files changed

+31
-30
lines changed

2 files changed

+31
-30
lines changed

compiler/src/main/scala/org/scalajs/core/compiler/GenJSCode.scala

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -744,8 +744,6 @@ abstract class GenJSCode extends plugins.PluginComponent
744744
OptimizerHints.empty, None))
745745
} else if (isRawJSCtorDefaultParam(sym)) {
746746
None
747-
} else if (isTrivialConstructor(sym, params, rhs)) {
748-
None
749747
} else if (sym.isClassConstructor && isHijackedBoxedClass(sym.owner)) {
750748
None
751749
} else {
@@ -825,33 +823,6 @@ abstract class GenJSCode extends plugins.PluginComponent
825823
"scala.runtime.ScalaRunTime.arrayElementClass"
826824
)
827825

828-
private def isTrivialConstructor(sym: Symbol, params: List[Symbol],
829-
rhs: Tree): Boolean = {
830-
if (!sym.isClassConstructor || isScalaJSDefinedJSClass(sym.owner)) {
831-
false
832-
} else {
833-
rhs match {
834-
// Shape of a constructor that only calls super
835-
case Block(List(Apply(fun @ Select(_: Super, _), args)), Literal(_)) =>
836-
val callee = fun.symbol
837-
implicit val dummyPos = NoPosition
838-
839-
// Does the callee have the same signature as sym
840-
if (encodeMethodSym(sym) == encodeMethodSym(callee)) {
841-
// Test whether args are trivial forwarders
842-
assert(args.size == params.size, "Argument count mismatch")
843-
params.zip(args) forall { case (param, arg) =>
844-
arg.symbol == param
845-
}
846-
} else {
847-
false
848-
}
849-
850-
case _ => false
851-
}
852-
}
853-
}
854-
855826
/** Patches the mutable flags of selected locals in a [[js.MethodDef]].
856827
*
857828
* @param patches Map from local name to new value of the mutable flags.

tools/shared/src/main/scala/org/scalajs/core/tools/optimizer/OptimizerCore.scala

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ private[optimizer] abstract class OptimizerCore(
101101
def optimize(thisType: Type, originalDef: MethodDef): LinkedMember[MethodDef] = {
102102
try {
103103
val MethodDef(static, name, params, resultType, body) = originalDef
104-
val (newParams, newBody) = try {
104+
val (newParams, newBody1) = try {
105105
transformIsolatedBody(Some(myself), thisType, params, resultType, body)
106106
} catch {
107107
case _: TooManyRollbacksException =>
@@ -111,6 +111,9 @@ private[optimizer] abstract class OptimizerCore(
111111
disableOptimisticOptimizations = true
112112
transformIsolatedBody(Some(myself), thisType, params, resultType, body)
113113
}
114+
val newBody =
115+
if (name.name == "init___") tryElimStoreModule(newBody1)
116+
else newBody1
114117
val m = MethodDef(static, name, newParams, resultType,
115118
newBody)(originalDef.optimizerHints, None)(originalDef.pos)
116119
val info = Infos.generateMethodInfo(m)
@@ -127,6 +130,33 @@ private[optimizer] abstract class OptimizerCore(
127130
}
128131
}
129132

133+
/** Try and eliminate a StoreModule followed only by trivial statements. */
134+
private def tryElimStoreModule(body: Tree): Tree = {
135+
implicit val pos = body.pos
136+
body match {
137+
case StoreModule(_, _) =>
138+
Skip()
139+
case Block(stats) =>
140+
val (before, from) = stats.span(!_.isInstanceOf[StoreModule])
141+
if (from.isEmpty) {
142+
body
143+
} else {
144+
val after = from.tail
145+
val afterIsTrivial = after.forall {
146+
case Assign(Select(This(), Ident(_, _)),
147+
_:Literal | _:VarRef) =>
148+
true
149+
case _ =>
150+
false
151+
}
152+
if (afterIsTrivial) Block(before ::: after)
153+
else body
154+
}
155+
case _ =>
156+
body
157+
}
158+
}
159+
130160
private def newSimpleState[A](initialValue: A): SimpleState[A] = {
131161
val state = new SimpleState[A](initialValue)
132162
statesInUse ::= state

0 commit comments

Comments
 (0)