Skip to content
This repository has been archived by the owner on Jul 12, 2024. It is now read-only.

Commit

Permalink
Export top-level defs as function functions, not arrow functions.
Browse files Browse the repository at this point in the history
This is necessary for exported Scala classes to be instantiable
with `new ExportedClass()`.
  • Loading branch information
sjrd committed May 14, 2024
1 parent 489b870 commit 199fe7d
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1109,14 +1109,11 @@ class ClassEmitter(coreSpec: CoreSpec) {
resultType = AnyType
)

if (method.restParam.isEmpty) {
ctx.addExport(wamod.Export.Function(exportedName, functionName))
} else {
/* We cannot directly export the function. We will create a closure
* wrapper in the start function and export that instead.
*/
genDelayedTopLevelExport(exportedName)
}
/* We cannot directly export the function because it would not be considered
* a `function`. Instead, we will explicitly create a closure wrapper in the
* start function and export that instead.
*/
genDelayedTopLevelExport(exportedName)
}

private def transformTopLevelFieldExportDef(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,10 @@ object CoreWasmLib {
List(RefType.func, anyref, Int32),
List(RefType.any)
)

addHelperImport(genFunctionName.makeExportedDef, List(RefType.func), List(RefType.any))
addHelperImport(
genFunctionName.closureRestNoData,
genFunctionName.makeExportedDefRest,
List(RefType.func, Int32),
List(RefType.any)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,13 +190,14 @@ final class Emitter(config: Emitter.Config) {
instrs += wa.CALL(genFunctionName.loadModule(tle.owningClass))
instrs += wa.GLOBAL_SET(genGlobalName.forTopLevelExport(tle.exportName))
case TopLevelMethodExportDef(_, methodDef) =>
// We only need initialization if there is a restParam
instrs += ctx.refFuncWithDeclaration(genFunctionName.forExport(tle.exportName))
if (methodDef.restParam.isDefined) {
instrs += ctx.refFuncWithDeclaration(genFunctionName.forExport(tle.exportName))
instrs += wa.I32_CONST(methodDef.args.size)
instrs += wa.CALL(genFunctionName.closureRestNoData)
instrs += wa.GLOBAL_SET(genGlobalName.forTopLevelExport(tle.exportName))
instrs += wa.CALL(genFunctionName.makeExportedDefRest)
} else {
instrs += wa.CALL(genFunctionName.makeExportedDef)
}
instrs += wa.GLOBAL_SET(genGlobalName.forTopLevelExport(tle.exportName))
case TopLevelFieldExportDef(_, _, _) =>
// Nothing to do
()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,10 @@ const scalaJSHelpers = {
closureThis: (f, data) => function(...args) { return f(data, this, ...args); },
closureRest: (f, data, n) => ((...args) => f(data, ...args.slice(0, n), args.slice(n))),
closureThisRest: (f, data, n) => function(...args) { return f(data, this, ...args.slice(0, n), args.slice(n)); },
closureRestNoData: (f, n) => ((...args) => f(...args.slice(0, n), args.slice(n))),

// Top-level exported defs -- they must be `function`s but have no actual `this` nor `data`
makeExportedDef: (f) => function(...args) { return f(...args); },
makeExportedDefRest: (f, n) => function(...args) { return f(...args.slice(0, n), args.slice(n)); },

// Strings
emptyString: "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,9 @@ object VarGen {
val closureThis = make("closureThis")
val closureRest = make("closureRest")
val closureThisRest = make("closureThisRest")
val closureRestNoData = make("closureRestNoData")

val makeExportedDef = make("makeExportedDef")
val makeExportedDefRest = make("makeExportedDefRest")

val stringLength = make("stringLength")
val stringCharAt = make("stringCharAt")
Expand Down

0 comments on commit 199fe7d

Please sign in to comment.