Skip to content

Commit 3e554a2

Browse files
authored
Merge pull request #4903 from gzm0/callsite-inline-js-export
Call-site inline single dispatch calls to JS methods
2 parents 9235e11 + febe9ee commit 3e554a2

File tree

5 files changed

+84
-31
lines changed

5 files changed

+84
-31
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3337,8 +3337,9 @@ abstract class GenJSCode[G <: Global with Singleton](val global: G)
33373337
}
33383338

33393339
def genApplyJSClassMethod(receiver: js.Tree, method: Symbol,
3340-
arguments: List[js.Tree])(implicit pos: Position): js.Tree = {
3341-
genApplyStatic(method, receiver :: arguments)
3340+
arguments: List[js.Tree], inline: Boolean = false)(
3341+
implicit pos: Position): js.Tree = {
3342+
genApplyStatic(method, receiver :: arguments, inline = inline)
33423343
}
33433344

33443345
def genApplyStatic(method: Symbol, arguments: List[js.Tree],

compiler/src/main/scala/org/scalajs/nscplugin/GenJSExports.scala

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
152152

153153
case Constructor | Method =>
154154
val methodDef = withNewLocalNameScope {
155-
genExportMethod(tups.map(_._2), JSName.Literal(info.jsName), static = true)
155+
genExportMethod(tups.map(_._2), JSName.Literal(info.jsName), static = true,
156+
allowCallsiteInlineSingle = false)
156157
}
157158

158159
js.TopLevelMethodExportDef(info.moduleID, methodDef)
@@ -191,11 +192,13 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
191192
kind match {
192193
case Method =>
193194
methodProps += genMemberExportOrDispatcher(
194-
JSName.Literal(info.jsName), isProp = false, alts, static = true)
195+
JSName.Literal(info.jsName), isProp = false, alts, static = true,
196+
allowCallsiteInlineSingle = false)
195197

196198
case Property =>
197199
methodProps += genMemberExportOrDispatcher(
198-
JSName.Literal(info.jsName), isProp = true, alts, static = true)
200+
JSName.Literal(info.jsName), isProp = true, alts, static = true,
201+
allowCallsiteInlineSingle = false)
199202

200203
case Field =>
201204
val sym = checkSingleField(tups)
@@ -244,7 +247,8 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
244247
s"Exported $kind $jsName conflicts with ${alts.head.fullName}")
245248
}
246249

247-
genMemberExportOrDispatcher(JSName.Literal(jsName), isProp, alts, static = false)
250+
genMemberExportOrDispatcher(JSName.Literal(jsName), isProp, alts,
251+
static = false, allowCallsiteInlineSingle = false)
248252
}
249253

250254
private def genJSClassDispatcher(classSym: Symbol, name: JSName): js.JSMethodPropDef = {
@@ -272,22 +276,24 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
272276
implicit val pos = alts.head.pos
273277
js.JSPropertyDef(js.MemberFlags.empty, genExpr(name), None, None)(Unversioned)
274278
} else {
275-
genMemberExportOrDispatcher(name, isProp, alts, static = false)
279+
genMemberExportOrDispatcher(name, isProp, alts, static = false,
280+
allowCallsiteInlineSingle = true)
276281
}
277282
}
278283

279284
def genMemberExportOrDispatcher(jsName: JSName, isProp: Boolean,
280-
alts: List[Symbol], static: Boolean): js.JSMethodPropDef = {
285+
alts: List[Symbol], static: Boolean,
286+
allowCallsiteInlineSingle: Boolean): js.JSMethodPropDef = {
281287
withNewLocalNameScope {
282288
if (isProp)
283-
genExportProperty(alts, jsName, static)
289+
genExportProperty(alts, jsName, static, allowCallsiteInlineSingle)
284290
else
285-
genExportMethod(alts, jsName, static)
291+
genExportMethod(alts, jsName, static, allowCallsiteInlineSingle)
286292
}
287293
}
288294

289295
private def genExportProperty(alts: List[Symbol], jsName: JSName,
290-
static: Boolean): js.JSPropertyDef = {
296+
static: Boolean, allowCallsiteInlineSingle: Boolean): js.JSPropertyDef = {
291297
assert(!alts.isEmpty,
292298
s"genExportProperty with empty alternatives for $jsName")
293299

@@ -307,7 +313,8 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
307313
reportCannotDisambiguateError(jsName, alts)
308314

309315
val getterBody = getter.headOption.map { getterSym =>
310-
genApplyForSym(new FormalArgsRegistry(0, false), getterSym, static)
316+
genApplyForSym(new FormalArgsRegistry(0, false), getterSym, static,
317+
inline = allowCallsiteInlineSingle)
311318
}
312319

313320
val setterArgAndBody = {
@@ -316,9 +323,18 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
316323
} else {
317324
val formalArgsRegistry = new FormalArgsRegistry(1, false)
318325
val (List(arg), None) = formalArgsRegistry.genFormalArgs()
319-
val body = genOverloadDispatchSameArgc(jsName, formalArgsRegistry,
320-
alts = setters.map(new ExportedSymbol(_, static)), jstpe.AnyType,
321-
paramIndex = 0)
326+
327+
val body = {
328+
if (setters.size == 1) {
329+
genApplyForSym(formalArgsRegistry, setters.head, static,
330+
inline = allowCallsiteInlineSingle)
331+
} else {
332+
genOverloadDispatchSameArgc(jsName, formalArgsRegistry,
333+
alts = setters.map(new ExportedSymbol(_, static)), jstpe.AnyType,
334+
paramIndex = 0)
335+
}
336+
}
337+
322338
Some((arg, body))
323339
}
324340
}
@@ -329,7 +345,7 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
329345
/** generates the exporter function (i.e. exporter for non-properties) for
330346
* a given name */
331347
private def genExportMethod(alts0: List[Symbol], jsName: JSName,
332-
static: Boolean): js.JSMethodDef = {
348+
static: Boolean, allowCallsiteInlineSingle: Boolean): js.JSMethodDef = {
333349
assert(alts0.nonEmpty,
334350
"need at least one alternative to generate exporter method")
335351

@@ -354,8 +370,20 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
354370

355371
val overloads = alts.map(new ExportedSymbol(_, static))
356372

357-
val (formalArgs, restParam, body) =
358-
genOverloadDispatch(jsName, overloads, jstpe.AnyType)
373+
val (formalArgs, restParam, body) = {
374+
if (overloads.size == 1) {
375+
val trg = overloads.head
376+
val minArgc = trg.params.lastIndexWhere(p => !p.hasDefault && !p.repeated) + 1
377+
val formalArgsRegistry = new FormalArgsRegistry(minArgc,
378+
needsRestParam = trg.params.size > minArgc)
379+
val body = genApplyForSym(formalArgsRegistry, trg.sym, static,
380+
inline = allowCallsiteInlineSingle)
381+
val (formalArgs, restParam) = formalArgsRegistry.genFormalArgs()
382+
(formalArgs, restParam, body)
383+
} else {
384+
genOverloadDispatch(jsName, overloads, jstpe.AnyType)
385+
}
386+
}
359387

360388
js.JSMethodDef(flags, genExpr(jsName), formalArgs, restParam, body)(
361389
OptimizerHints.empty, Unversioned)
@@ -633,13 +661,13 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
633661
* required.
634662
*/
635663
private def genApplyForSym(formalArgsRegistry: FormalArgsRegistry,
636-
sym: Symbol, static: Boolean): js.Tree = {
664+
sym: Symbol, static: Boolean, inline: Boolean): js.Tree = {
637665
if (isNonNativeJSClass(currentClassSym) &&
638666
sym.owner != currentClassSym.get) {
639667
assert(!static, s"nonsensical JS super call in static export of $sym")
640668
genApplyForSymJSSuperCall(formalArgsRegistry, sym)
641669
} else {
642-
genApplyForSymNonJSSuperCall(formalArgsRegistry, sym, static)
670+
genApplyForSymNonJSSuperCall(formalArgsRegistry, sym, static, inline)
643671
}
644672
}
645673

@@ -681,7 +709,7 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
681709

682710
private def genApplyForSymNonJSSuperCall(
683711
formalArgsRegistry: FormalArgsRegistry, sym: Symbol,
684-
static: Boolean): js.Tree = {
712+
static: Boolean, inline: Boolean): js.Tree = {
685713
implicit val pos = sym.pos
686714

687715
val varDefs = new mutable.ListBuffer[js.VarDef]
@@ -696,7 +724,7 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
696724

697725
val builtVarDefs = varDefs.result()
698726

699-
val jsResult = genResult(sym, builtVarDefs.map(_.ref), static)
727+
val jsResult = genResult(sym, builtVarDefs.map(_.ref), static, inline)
700728

701729
js.Block(builtVarDefs :+ jsResult)
702730
}
@@ -850,7 +878,7 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
850878

851879
/** Generate the final forwarding call to the exported method. */
852880
private def genResult(sym: Symbol, args: List[js.Tree],
853-
static: Boolean)(implicit pos: Position): js.Tree = {
881+
static: Boolean, inline: Boolean)(implicit pos: Position): js.Tree = {
854882
def receiver = {
855883
if (static)
856884
genLoadModule(sym.owner)
@@ -860,17 +888,18 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
860888

861889
if (isNonNativeJSClass(currentClassSym)) {
862890
assert(sym.owner == currentClassSym.get, sym.fullName)
863-
ensureResultBoxed(genApplyJSClassMethod(receiver, sym, args), sym)
891+
ensureResultBoxed(genApplyJSClassMethod(receiver, sym, args, inline = inline), sym)
864892
} else {
865893
if (sym.isClassConstructor)
866894
genNew(currentClassSym, sym, args)
867895
else if (sym.isPrivate)
868-
ensureResultBoxed(genApplyMethodStatically(receiver, sym, args), sym)
896+
ensureResultBoxed(genApplyMethodStatically(receiver, sym, args, inline = inline), sym)
869897
else
870-
ensureResultBoxed(genApplyMethod(receiver, sym, args), sym)
898+
ensureResultBoxed(genApplyMethod(receiver, sym, args, inline = inline), sym)
871899
}
872900
}
873901

902+
// Note: GenJSCode creates an anonymous subclass of Exported for JS class constructors.
874903
abstract class Exported(val sym: Symbol,
875904
// Parameters participating in overload resolution.
876905
val params: immutable.IndexedSeq[JSParamInfo]) {
@@ -895,7 +924,7 @@ trait GenJSExports[G <: Global with Singleton] extends SubComponent {
895924
private class ExportedSymbol(sym: Symbol, static: Boolean)
896925
extends Exported(sym, jsParamInfos(sym).toIndexedSeq) {
897926
def genBody(formalArgsRegistry: FormalArgsRegistry): js.Tree =
898-
genApplyForSym(formalArgsRegistry, sym, static)
927+
genApplyForSym(formalArgsRegistry, sym, static, inline = false)
899928
}
900929
}
901930

compiler/src/test/scala/org/scalajs/nscplugin/test/CallSiteInlineTest.scala

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@ import org.scalajs.ir.Names
2222
import org.scalajs.ir.Names._
2323

2424
class CallSiteInlineTest extends JSASTTest {
25-
object SMN {
26-
def unapply(ident: js.MethodIdent): Some[String] =
27-
Some(ident.name.simpleName.nameString)
28-
}
2925

3026
@Test
3127
def testInline: Unit = {

compiler/src/test/scala/org/scalajs/nscplugin/test/OptimizationTest.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package org.scalajs.nscplugin.test
1515
import util._
1616

1717
import org.junit.Test
18+
import org.junit.Assert._
1819

1920
import org.scalajs.ir.{Trees => js, Types => jstpe}
2021
import org.scalajs.ir.Names._
@@ -538,6 +539,27 @@ class OptimizationTest extends JSASTTest {
538539
case js.WrapAsThrowable(_) =>
539540
}
540541
}
542+
543+
@Test
544+
def callSiteInlineSingleDispatchJSMethods: Unit = {
545+
val fooName = SimpleMethodName("foo")
546+
val aName = ClassName("A")
547+
548+
val flags = {
549+
"""
550+
import scala.scalajs.js
551+
552+
class A extends js.Object {
553+
def foo(x: Int, y: Int = 2): Int = x + y
554+
}
555+
""".extractOne("foo dispatch call") {
556+
case js.ApplyStatic(flags, `aName`, SMN("foo"), _) =>
557+
flags
558+
}
559+
}
560+
561+
assertTrue(flags.inline)
562+
}
541563
}
542564

543565
object OptimizationTest {

compiler/src/test/scala/org/scalajs/nscplugin/test/util/JSASTTest.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ import ir.{Trees => js}
2828

2929
abstract class JSASTTest extends DirectTest {
3030

31+
object SMN {
32+
def unapply(ident: js.MethodIdent): Some[String] =
33+
Some(ident.name.simpleName.nameString)
34+
}
35+
3136
class JSAST(val clDefs: List[js.ClassDef]) {
3237
type Pat = PartialFunction[js.IRNode, Unit]
3338

0 commit comments

Comments
 (0)