@@ -68,6 +68,12 @@ class JSCodeGen()(implicit ctx: Context) {
6868 private val thisLocalVarIdent = new ScopedVar [Option [js.Ident ]]
6969 private val undefinedDefaultParams = new ScopedVar [mutable.Set [Symbol ]]
7070
71+ private def withNewLocalNameScope [A ](body : => A ): A = {
72+ withScopedVars(localNames := new LocalNameGenerator ) {
73+ body
74+ }
75+ }
76+
7177 /** Implicitly materializes the current local name generator. */
7278 private implicit def implicitLocalNames : LocalNameGenerator = localNames.get
7379
@@ -86,6 +92,10 @@ class JSCodeGen()(implicit ctx: Context) {
8692 private def freshLocalIdent (base : String )(implicit pos : Position ): js.Ident =
8793 localNames.get.freshLocalIdent(base)
8894
95+ /** Returns a new fresh local identifier. */
96+ private def freshLocalIdent (base : TermName )(implicit pos : Position ): js.Ident =
97+ localNames.get.freshLocalIdent(base)
98+
8999 // Compilation unit --------------------------------------------------------
90100
91101 def run (): Unit = {
@@ -287,9 +297,31 @@ class JSCodeGen()(implicit ctx: Context) {
287297 Nil
288298 }
289299
300+ // Static initializer
301+ val optStaticInitializer = {
302+ // Initialization of reflection data, if required
303+ val reflectInit = {
304+ val enableReflectiveInstantiation = {
305+ sym.baseClasses.exists { ancestor =>
306+ ancestor.hasAnnotation(jsdefn.EnableReflectiveInstantiationAnnot )
307+ }
308+ }
309+ if (enableReflectiveInstantiation)
310+ genRegisterReflectiveInstantiation(sym)
311+ else
312+ None
313+ }
314+
315+ val staticInitializerStats = reflectInit.toList
316+ if (staticInitializerStats.nonEmpty)
317+ Some (genStaticInitializerWithStats(js.Block (staticInitializerStats)))
318+ else
319+ None
320+ }
321+
290322 // Hashed definitions of the class
291323 val hashedDefs =
292- ir.Hashers .hashMemberDefs(generatedMembers ++ exports)
324+ ir.Hashers .hashMemberDefs(generatedMembers ++ exports ++ optStaticInitializer )
293325
294326 // The complete class definition
295327 val kind =
@@ -461,6 +493,92 @@ class JSCodeGen()(implicit ctx: Context) {
461493 }).toList
462494 }
463495
496+ // Static initializers -----------------------------------------------------
497+
498+ private def genStaticInitializerWithStats (stats : js.Tree )(
499+ implicit pos : Position ): js.MethodDef = {
500+ js.MethodDef (
501+ js.MemberFlags .empty.withNamespace(js.MemberNamespace .StaticConstructor ),
502+ js.Ident (ir.Definitions .StaticInitializerName ),
503+ Nil ,
504+ jstpe.NoType ,
505+ Some (stats))(
506+ OptimizerHints .empty, None )
507+ }
508+
509+ private def genRegisterReflectiveInstantiation (sym : Symbol )(
510+ implicit pos : Position ): Option [js.Tree ] = {
511+ if (isStaticModule(sym))
512+ genRegisterReflectiveInstantiationForModuleClass(sym)
513+ else if (sym.is(ModuleClass ))
514+ None // scala-js#3228
515+ else if (sym.is(Lifted ) && ! sym.originalOwner.isClass)
516+ None // scala-js#3227
517+ else
518+ genRegisterReflectiveInstantiationForNormalClass(sym)
519+ }
520+
521+ private def genRegisterReflectiveInstantiationForModuleClass (sym : Symbol )(
522+ implicit pos : Position ): Option [js.Tree ] = {
523+ val fqcnArg = js.StringLiteral (sym.fullName.toString)
524+ val runtimeClassArg = js.ClassOf (toTypeRef(sym.info))
525+ val loadModuleFunArg =
526+ js.Closure (arrow = true , Nil , Nil , genLoadModule(sym), Nil )
527+
528+ val stat = genApplyMethod(
529+ genLoadModule(jsdefn.ReflectModule ),
530+ jsdefn.Reflect_registerLoadableModuleClass ,
531+ List (fqcnArg, runtimeClassArg, loadModuleFunArg))
532+
533+ Some (stat)
534+ }
535+
536+ private def genRegisterReflectiveInstantiationForNormalClass (sym : Symbol )(
537+ implicit pos : Position ): Option [js.Tree ] = {
538+ val ctors =
539+ if (sym.is(Abstract )) Nil
540+ else sym.info.member(nme.CONSTRUCTOR ).alternatives.map(_.symbol).filter(m => ! m.is(Private | Protected ))
541+
542+ if (ctors.isEmpty) {
543+ None
544+ } else {
545+ val constructorsInfos = for {
546+ ctor <- ctors
547+ } yield {
548+ withNewLocalNameScope {
549+ val (parameterTypes, formalParams, actualParams) = (for {
550+ (paramName, paramInfo) <- ctor.info.paramNamess.flatten.zip(ctor.info.paramInfoss.flatten)
551+ } yield {
552+ val paramType = js.ClassOf (toTypeRef(paramInfo))
553+ val paramDef = js.ParamDef (freshLocalIdent(paramName), jstpe.AnyType ,
554+ mutable = false , rest = false )
555+ val actualParam = unbox(paramDef.ref, paramInfo)
556+ (paramType, paramDef, actualParam)
557+ }).unzip3
558+
559+ val paramTypesArray = js.JSArrayConstr (parameterTypes)
560+
561+ val newInstanceFun = js.Closure (arrow = true , Nil , formalParams, {
562+ js.New (encodeClassRef(sym), encodeMethodSym(ctor), actualParams)
563+ }, Nil )
564+
565+ js.JSArrayConstr (List (paramTypesArray, newInstanceFun))
566+ }
567+ }
568+
569+ val fqcnArg = js.StringLiteral (sym.fullName.toString)
570+ val runtimeClassArg = js.ClassOf (toTypeRef(sym.info))
571+ val ctorsInfosArg = js.JSArrayConstr (constructorsInfos)
572+
573+ val stat = genApplyMethod(
574+ genLoadModule(jsdefn.ReflectModule ),
575+ jsdefn.Reflect_registerInstantiatableClass ,
576+ List (fqcnArg, runtimeClassArg, ctorsInfosArg))
577+
578+ Some (stat)
579+ }
580+ }
581+
464582 // Generate a method -------------------------------------------------------
465583
466584 private def genMethod (dd : DefDef ): Option [js.MethodDef ] = {
0 commit comments