Skip to content

Commit

Permalink
Minor fixes from self review
Browse files Browse the repository at this point in the history
  • Loading branch information
gzm0 committed Sep 16, 2020
1 parent d3f4e45 commit e470882
Show file tree
Hide file tree
Showing 29 changed files with 211 additions and 200 deletions.
Expand Up @@ -31,7 +31,8 @@ import Fingerprint.FingerprintBuilder
* Instances of `ModuleInitializer` can be created with methods of
* [[ModuleInitializer$ the ModuleInitializer companion object]].
*
* The module which they belong to can be adjusted using [[withModuleID]].
* The module in which a `ModuleInitializer` is going to be placed can be
* adjusted using [[withModuleID]].
*/
final class ModuleInitializer private (
val initializer: ModuleInitializer.Initializer,
Expand Down
Expand Up @@ -24,9 +24,8 @@ import Fingerprint.FingerprintBuilder
* For internal modules (i.e. modules used to share code), the module ID is
* generated by the linker.
*
* Currently, all `with*` methods expect a pattern for a
* [[java.util.Formatter Formatter]] taking the module ID as sole string
* argument.
* Currently, all `with*` methods expect a [[java.util.Formatter Formatter]]
* pattern taking the module ID as sole string (`%s`) argument.
*/
final class OutputPatterns private (
private[interface] val jsFile: String,
Expand All @@ -39,7 +38,7 @@ final class OutputPatterns private (
def withJSFile(jsFile: String): OutputPatterns =
copy(jsFile = jsFile)

/** Pattern for file name of the source map file of the JS file. */
/** Pattern for the file name of the source map file of the JS file. */
def withSourceMapFile(sourceMapFile: String): OutputPatterns =
copy(sourceMapFile = sourceMapFile)

Expand Down
Expand Up @@ -65,9 +65,9 @@ object Report {

/** Serializes this [[Report]] to a byte array.
*
* A report serialized with the exact same binary version is guaranteed to
* deserializable using [[deserialize]]. If the binary version is different,
* no guarantee is given.
* A report serialized with the exact same linker version is guaranteed to
* deserializable using [[deserialize]]. If the linker version is different,
* no guarantee is given.
*/
def serialize(report: Report): Array[Byte] = {
val bytes = new ByteArrayOutputStream
Expand Down
Expand Up @@ -48,4 +48,3 @@ object NodeOutputDirectory {
private def getPath(name: String) = NodeFS.join(directory, name)
}
}

Expand Up @@ -177,15 +177,13 @@ private final class Analyzer(config: CommonPhaseConfig,
implicit val from = FromCore(origin)
withClass(moduleName) { clazz =>
objectClassInfo.staticDependencies += clazz.className

clazz.accessModule()
}

case InstantiateClass(origin, className, constructor) =>
implicit val from = FromCore(origin)
withMethod(className, constructor) { clazz =>
objectClassInfo.staticDependencies += clazz.className

clazz.instantiated()
clazz.callMethodStatically(MemberNamespace.Constructor, constructor)
}
Expand Down Expand Up @@ -219,8 +217,7 @@ private final class Analyzer(config: CommonPhaseConfig,
implicit val from = FromCore(origin)
withMethod(className, methodName) { clazz =>
objectClassInfo.staticDependencies += clazz.className
clazz.callMethodStatically(MemberNamespace.PublicStatic,
methodName)
clazz.callMethodStatically(MemberNamespace.PublicStatic, methodName)
}

case Optional(requirement) =>
Expand Down Expand Up @@ -288,7 +285,8 @@ private final class Analyzer(config: CommonPhaseConfig,
case Some(superClass) =>
classInfo.staticDependencies += superClass.className
loop(superClass)
case None =>

case None =>
}
}
loop(classInfo)
Expand Down Expand Up @@ -407,7 +405,7 @@ private final class Analyzer(config: CommonPhaseConfig,
}

private class ClassInfo(
data: Infos.ClassInfo,
val data: Infos.ClassInfo,
unvalidatedSuperClass: Option[ClassInfo],
unvalidatedInterfaces: List[ClassInfo],
val nonExistent: Boolean)
Expand Down Expand Up @@ -902,8 +900,8 @@ private final class Analyzer(config: CommonPhaseConfig,
implicit val from = FromExports

tryLookupStaticLikeMethod(MemberNamespace.StaticConstructor,
StaticInitializerName).foreach { initializer =>
initializer.reachStatic()(fromAnalyzer)
StaticInitializerName).foreach {
_.reachStatic()(fromAnalyzer)
}
}

Expand Down Expand Up @@ -994,9 +992,12 @@ private final class Analyzer(config: CommonPhaseConfig,
if (!isAnySubclassInstantiated && (isScalaClass || isJSType)) {
isAnySubclassInstantiated = true

staticDependencies ++= superClass
.filter(_.kind.isAnyNonNativeClass)
.map(_.className)
for {
clazz <- superClass
if clazz.kind.isAnyNonNativeClass
} {
staticDependencies += clazz.className
}

// Reach exported members
if (!isJSClass) {
Expand Down Expand Up @@ -1066,7 +1067,8 @@ private final class Analyzer(config: CommonPhaseConfig,
lookupMethod(methodName).reachStatic()
}

def useJSNativeMember(name: MethodName)(implicit from: From): Option[JSNativeLoadSpec] = {
def useJSNativeMember(name: MethodName)(
implicit from: From): Option[JSNativeLoadSpec] = {
val maybeJSNativeLoadSpec = data.jsNativeMembers.get(name)
if (jsNativeMembersUsed.add(name)) {
maybeJSNativeLoadSpec match {
Expand Down Expand Up @@ -1308,10 +1310,8 @@ private final class Analyzer(config: CommonPhaseConfig,
while (jsNativeMembersUsedIterator.hasNext) {
val (className, members) = jsNativeMembersUsedIterator.next()
lookupClass(className) { classInfo =>
for (member <- members) {
classInfo.useJSNativeMember(member)
.foreach(addLoadSpec(_))
}
for (member <- members)
classInfo.useJSNativeMember(member).foreach(addLoadSpec(_))
}
}
}
Expand Down
Expand Up @@ -388,7 +388,7 @@ object Infos {
def generateTopLevelExportInfo(enclosingClass: ClassName,
topLevelExportDef: TopLevelExportDef): TopLevelExportInfo = {
val info = new GenInfoTraverser().generateTopLevelExportInfo(enclosingClass,
topLevelExportDef)
topLevelExportDef)
new TopLevelExportInfo(enclosingClass, info,
new ModuleID(topLevelExportDef.moduleID),
topLevelExportDef.topLevelExportName)
Expand Down
Expand Up @@ -47,7 +47,7 @@ final class BasicLinkerBackend(config: LinkerBackendImpl.Config)
/** Emit the given [[standard.ModuleSet ModuleSet]] to the target output.
*
* @param moduleSet [[standard.ModuleSet ModuleSet]] to emit
* @param output File Directory write to
* @param output Directory to write to
*/
def emit(moduleSet: ModuleSet, output: OutputDirectory, logger: Logger)(
implicit ec: ExecutionContext): Future[Report] = {
Expand Down
Expand Up @@ -756,7 +756,8 @@ private[emitter] final class ClassEmitter(sjsGen: SJSGen) {
}
}

def genInstanceTests(tree: LinkedClass)(implicit moduleContext: ModuleContext,
def genInstanceTests(tree: LinkedClass)(
implicit moduleContext: ModuleContext,
globalKnowledge: GlobalKnowledge): WithGlobals[js.Tree] = {
for {
single <- genSingleInstanceTests(tree)
Expand Down
Expand Up @@ -48,11 +48,6 @@ private[emitter] object CoreJSLib {
val definitions: Tree,
val initialization: Tree)

def empty: Lib = {
implicit val noPosition: Position = Position.NoPosition
new Lib(Skip(), Skip())
}

private class CoreJSLibBuilder(sjsGen: SJSGen)(
implicit moduleContext: ModuleContext, globalKnowledge: GlobalKnowledge) {

Expand All @@ -71,15 +66,19 @@ private[emitter] object CoreJSLib {
private var trackedGlobalRefs = Set.empty[String]

private def globalRef(name: String): VarRef = {
trackGlobalRef(name)
varRef(name)
}

private def trackGlobalRef(name: String): Unit = {
// We never access dangerous global refs from the core JS lib
assert(!GlobalRefUtils.isDangerousGlobalRef(name))
if (trackAllGlobalRefs)
trackedGlobalRefs += name
varRef(name)
}

private def extractWithGlobals[A](withGlobals: WithGlobals[A]): A = {
trackedGlobalRefs ++= withGlobals.globalVarNames
withGlobals.globalVarNames.foreach(trackGlobalRef(_))
withGlobals.value
}

Expand Down Expand Up @@ -146,7 +145,6 @@ private[emitter] object CoreJSLib {
str("fileLevelThis") -> This()
)))


buf += extractWithGlobals(globalVarDef("linkingInfo", CoreVar, linkingInfo))
}

Expand Down
Expand Up @@ -170,90 +170,103 @@ final class Emitter(config: Emitter.Config) {

private def emitOnce(moduleSet: ModuleSet,
logger: Logger): WithGlobals[Map[ModuleID, js.Tree]] = {
// Genreate classes first so we can measure time separately.
val generatedClasses = logger.time("Emitter: Generate Classes") {
moduleSet.modules.map { module =>
val moduleContext = ModuleContext.fromModule(module)
val orderedClasses = module.classDefs.sortWith(compareClasses)
module.id -> orderedClasses.map(genClass(_, moduleContext))
}.toMap
}

var trackedGlobalRefs = Set.empty[String]
def extractWithGlobals[T](x: WithGlobals[T]) = {
trackedGlobalRefs = unionPreserveEmpty(trackedGlobalRefs, x.globalVarNames)
x.value
}

val moduleTrees = moduleSet.modules.map { module =>
val moduleContext = new ModuleContext(module.id, module.public)
val moduleTrees = logger.time("Emitter: Write trees") {
moduleSet.modules.map { module =>
val moduleContext = ModuleContext.fromModule(module)

val orderedClasses = module.classDefs.sortWith(compareClasses)
val generatedClasses = orderedClasses.map(genClass(_, moduleContext))
val moduleClasses = generatedClasses(module.id)

val topLevelExports = extractWithGlobals {
// We do not cache top level exports since typically there are few.
classEmitter.genTopLevelExports(module.topLevelExports)(
moduleContext, uncachedKnowledge)
}
val topLevelExports = extractWithGlobals {
// We do not cache top level exports since typically there are few.
classEmitter.genTopLevelExports(module.topLevelExports)(
moduleContext, uncachedKnowledge)
}

val coreJSLib = {
if (module.isRoot)
extractWithGlobals(state.coreJSLibCache.build(moduleContext))
else
CoreJSLib.empty
}
val (coreDefinitions, coreInitialization) = {
if (module.isRoot) {
val coreJSLib =
extractWithGlobals(state.coreJSLibCache.build(moduleContext))
(Iterator.single(coreJSLib.definitions), Iterator.single(coreJSLib.initialization))
} else {
(Iterator.empty, Iterator.empty)
}
}

def classIter = generatedClasses.iterator

// Emit everything in the appropriate order.
val defTrees = js.Block(
/* The definitions of the CoreJSLib, which depend on nothing.
* All classes potentially depend on it.
*/
Iterator.single(coreJSLib.definitions) ++

/* All class definitions, which depend on nothing but their
* superclasses.
*/
classIter.flatMap(_.main) ++

/* The initialization of the CoreJSLib, which depends on the
* definition of classes (n.b. the RuntimeLong class).
*/
Iterator.single(coreJSLib.initialization) ++

/* All static field definitions, which depend on nothing, except
* those of type Long which need $L0.
*/
classIter.flatMap(_.staticFields) ++

/* All static initializers, which in the worst case can observe some
* "zero" state of other static field definitions, but must not
* observe a *non-initialized* (undefined) state.
*/
classIter.flatMap(_.staticInitialization) ++

/* All the exports, during which some JS class creation can happen,
* causing JS static initializers to run. Those also must not observe
* a non-initialized state of other static fields.
*/
topLevelExports ++

/* Module initializers, which by spec run at the end. */
module.initializers.iterator.map(classEmitter.genModuleInitializer(_)(
moduleContext, uncachedKnowledge))
)(Position.NoPosition)

assert(!defTrees.isInstanceOf[js.Skip], {
val classNames = module.classDefs.map(_.fullName).mkString(", ")
f"Module ${module.id} is empty. Classes in this module: $classNames"
})

val allTrees = js.Block(
/* Module imports, which depend on nothing.
* All classes potentially depend on them.
*/
extractWithGlobals(genModuleImports(module)) ++
Iterator.single(defTrees)
)(Position.NoPosition)

classIter.foreach { genClass =>
trackedGlobalRefs = unionPreserveEmpty(trackedGlobalRefs, genClass.trackedGlobalRefs)
}
def classIter = moduleClasses

// Emit everything in the appropriate order.
val defTrees = js.Block(
/* The definitions of the CoreJSLib, which depend on nothing.
* All classes potentially depend on it.
*/
coreDefinitions ++

/* All class definitions, which depend on nothing but their
* superclasses.
*/
classIter.flatMap(_.main) ++

/* The initialization of the CoreJSLib, which depends on the
* definition of classes (n.b. the RuntimeLong class).
*/
coreInitialization ++

/* All static field definitions, which depend on nothing, except
* those of type Long which need $L0.
*/
classIter.flatMap(_.staticFields) ++

/* All static initializers, which in the worst case can observe some
* "zero" state of other static field definitions, but must not
* observe a *non-initialized* (undefined) state.
*/
classIter.flatMap(_.staticInitialization) ++

/* All the exports, during which some JS class creation can happen,
* causing JS static initializers to run. Those also must not observe
* a non-initialized state of other static fields.
*/
topLevelExports ++

/* Module initializers, which by spec run at the end. */
module.initializers.iterator.map(classEmitter.genModuleInitializer(_)(
moduleContext, uncachedKnowledge))
)(Position.NoPosition)

assert(!defTrees.isInstanceOf[js.Skip], {
val classNames = module.classDefs.map(_.fullName).mkString(", ")
f"Module ${module.id} is empty. Classes in this module: $classNames"
})

val allTrees = js.Block(
/* Module imports, which depend on nothing.
* All classes potentially depend on them.
*/
extractWithGlobals(genModuleImports(module)) ++
Iterator.single(defTrees)
)(Position.NoPosition)

classIter.foreach { genClass =>
trackedGlobalRefs = unionPreserveEmpty(trackedGlobalRefs, genClass.trackedGlobalRefs)
}

module.id -> allTrees
module.id -> allTrees
}
}

WithGlobals(moduleTrees.toMap, trackedGlobalRefs)
Expand Down Expand Up @@ -667,7 +680,7 @@ object Emitter {
semantics,
moduleKind,
esFeatures,
internalModulePattern = _.id,
internalModulePattern = "./" + _.id,
optimizeBracketSelects = true,
trackAllGlobalRefs = false)
}
Expand Down

0 comments on commit e470882

Please sign in to comment.