diff --git a/src/serializer/GeneratorDAG.js b/src/serializer/GeneratorTree.js similarity index 73% rename from src/serializer/GeneratorDAG.js rename to src/serializer/GeneratorTree.js index de22ad554..5c4fb66b0 100644 --- a/src/serializer/GeneratorDAG.js +++ b/src/serializer/GeneratorTree.js @@ -13,14 +13,13 @@ import invariant from "../invariant.js"; import { FunctionValue, ObjectValue } from "../values/index.js"; import { Generator } from "../utils/generator.js"; -// This class maintains a DAG containing all generators known so far, +// This class maintains a tree containing all generators known so far, // and information about the most specific generator that created any // particular object. -// New sub-DAGs are added in chunks, at the beginning for the global generator, +// New sub-trees are added in chunks, at the beginning for the global generator, // and every time the visitor handles another additional function. -// NOTE: The serializer can only properly handle Generator trees, not actual DAGs. -export class GeneratorDAG { - parents: Map>; +export class GeneratorTree { + parents: Map; createdObjects: Map; constructor() { @@ -28,16 +27,10 @@ export class GeneratorDAG { this.createdObjects = new Map(); } - // DAG TODO: This function is dubious in the presence of actual dags. getParent(generator: Generator): Generator | FunctionValue | "GLOBAL" { - let a = this.parents.get(generator); - invariant(a !== undefined && a.length >= 1); - return a[0]; - } - - isParent(parent: Generator | FunctionValue | "GLOBAL", generator: Generator): boolean { - let a = this.parents.get(generator); - return a !== undefined && a.includes(parent); + let parent = this.parents.get(generator); + invariant(parent !== undefined); + return parent; } getCreator(value: ObjectValue): Generator | void { @@ -49,9 +42,8 @@ export class GeneratorDAG { } _add(parent: Generator | FunctionValue | "GLOBAL", generator: Generator): void { - let a = this.parents.get(generator); - if (a === undefined) this.parents.set(generator, (a = [])); - if (!a.includes(parent)) a.push(parent); + invariant(!this.parents.has(generator)); + this.parents.set(generator, parent); let effects = generator.effectsToApply; if (effects !== undefined) { invariant(parent instanceof FunctionValue); diff --git a/src/serializer/LazyObjectsSerializer.js b/src/serializer/LazyObjectsSerializer.js index eb09f9f55..a8a9f8ded 100644 --- a/src/serializer/LazyObjectsSerializer.js +++ b/src/serializer/LazyObjectsSerializer.js @@ -24,7 +24,7 @@ import { ResidualHeapSerializer } from "./ResidualHeapSerializer.js"; import { getOrDefault } from "./utils.js"; import type { ResidualOptimizedFunctions } from "./ResidualOptimizedFunctions"; import type { Referentializer } from "./Referentializer.js"; -import { GeneratorDAG } from "./GeneratorDAG.js"; +import { GeneratorTree } from "./GeneratorTree.js"; const LAZY_OBJECTS_SERIALIZER_BODY_TYPE = "LazyObjectInitializer"; @@ -49,7 +49,7 @@ export class LazyObjectsSerializer extends ResidualHeapSerializer { options: SerializerOptions, additionalFunctionValuesAndEffects: Map, referentializer: Referentializer, - generatorDAG: GeneratorDAG, + generatorTree: GeneratorTree, residualOptimizedFunctions: ResidualOptimizedFunctions ) { super( @@ -62,7 +62,7 @@ export class LazyObjectsSerializer extends ResidualHeapSerializer { options, additionalFunctionValuesAndEffects, referentializer, - generatorDAG, + generatorTree, residualOptimizedFunctions ); diff --git a/src/serializer/ResidualHeapSerializer.js b/src/serializer/ResidualHeapSerializer.js index 2e68772d6..e7f21f39b 100644 --- a/src/serializer/ResidualHeapSerializer.js +++ b/src/serializer/ResidualHeapSerializer.js @@ -81,7 +81,7 @@ import { ResidualReactElementSerializer } from "./ResidualReactElementSerializer import type { Binding } from "../environment.js"; import { GlobalEnvironmentRecord, DeclarativeEnvironmentRecord } from "../environment.js"; import type { Referentializer } from "./Referentializer.js"; -import { GeneratorDAG } from "./GeneratorDAG.js"; +import { GeneratorTree } from "./GeneratorTree.js"; import { type Replacement, getReplacement } from "./ResidualFunctionInstantiator.js"; import { describeValue } from "../utils.js"; import { getAsPropertyNameExpression } from "../utils/babelhelpers.js"; @@ -123,7 +123,7 @@ export class ResidualHeapSerializer { options: SerializerOptions, additionalFunctionValuesAndEffects: Map, referentializer: Referentializer, - generatorDAG: GeneratorDAG, + generatorTree: GeneratorTree, residualOptimizedFunctions: ResidualOptimizedFunctions ) { this.realm = realm; @@ -215,7 +215,7 @@ export class ResidualHeapSerializer { this.rewrittenAdditionalFunctions = new Map(); this.declarativeEnvironmentRecordsBindings = residualHeapInfo.declarativeEnvironmentRecordsBindings; this.globalBindings = residualHeapInfo.globalBindings; - this.generatorDAG = generatorDAG; + this.generatorTree = generatorTree; this.conditionalFeasibility = residualHeapInfo.conditionalFeasibility; this.additionalFunctionGenerators = new Map(); this.declaredGlobalLets = new Map(); @@ -274,7 +274,7 @@ export class ResidualHeapSerializer { // TODO: revisit this and fix additional functions to be capable of delaying initializations additionalFunctionValueNestedFunctions: Set; - generatorDAG: GeneratorDAG; + generatorTree: GeneratorTree; conditionalFeasibility: Map; additionalGeneratorRoots: Map>; @@ -888,7 +888,7 @@ export class ResidualHeapSerializer { generators = generators.filter(generator => { let s = generator; while (s instanceof Generator) { - s = this.generatorDAG.getParent(s); + s = this.generatorTree.getParent(s); } return s === "GLOBAL"; }); @@ -904,7 +904,7 @@ export class ResidualHeapSerializer { } const getGeneratorParent = g => { - let s = this.generatorDAG.getParent(g); + let s = this.generatorTree.getParent(g); return s instanceof Generator ? s : undefined; }; // This value is referenced from more than one generator. @@ -2132,7 +2132,7 @@ export class ResidualHeapSerializer { _annotateGeneratorStatements(generator: Generator, statements: Array): void { let comment = `generator "${generator.getName()}"`; - let parent = this.generatorDAG.getParent(generator); + let parent = this.generatorTree.getParent(generator); if (parent instanceof Generator) { comment = `${comment} with parent "${parent.getName()}"`; } else if (parent instanceof FunctionValue) { @@ -2574,7 +2574,7 @@ export class ResidualHeapSerializer { for (let s of scopes) if (s instanceof Generator) { let text = ""; - for (; s instanceof Generator; s = this.generatorDAG.getParent(s)) text += "=>" + s.getName(); + for (; s instanceof Generator; s = this.generatorTree.getParent(s)) text += "=>" + s.getName(); console.log(` ${text}`); } else { invariant(s instanceof FunctionValue); diff --git a/src/serializer/ResidualHeapVisitor.js b/src/serializer/ResidualHeapVisitor.js index bf20db785..ae8175268 100644 --- a/src/serializer/ResidualHeapVisitor.js +++ b/src/serializer/ResidualHeapVisitor.js @@ -65,7 +65,7 @@ import { import { createPathConditions, Environment, To } from "../singletons.js"; import { isReactElement, isReactPropsObject, valueIsReactLibraryObject } from "../react/utils.js"; import { ResidualReactElementVisitor } from "./ResidualReactElementVisitor.js"; -import { GeneratorDAG } from "./GeneratorDAG.js"; +import { GeneratorTree } from "./GeneratorTree.js"; import { PropertyDescriptor, AbstractJoinedDescriptor } from "../descriptors.js"; type BindingState = {| @@ -113,7 +113,7 @@ export class ResidualHeapVisitor { this.globalEnvironmentRecord = environment; this.additionalGeneratorRoots = new Map(); this.residualReactElementVisitor = new ResidualReactElementVisitor(this.realm, this); - this.generatorDAG = new GeneratorDAG(); + this.generatorTree = new GeneratorTree(); } realm: Realm; @@ -142,7 +142,7 @@ export class ResidualHeapVisitor { classMethodInstances: Map; // Parents will always be a generator, optimized function value or "GLOBAL" additionalGeneratorRoots: Map>; - generatorDAG: GeneratorDAG; + generatorTree: GeneratorTree; globalEnvironmentRecord: GlobalEnvironmentRecord; residualReactElementVisitor: ResidualReactElementVisitor; @@ -151,13 +151,13 @@ export class ResidualHeapVisitor { _getCommonScope(): FunctionValue | Generator { let s = this.scope; while (true) { - if (s instanceof Generator) s = this.generatorDAG.getParent(s); + if (s instanceof Generator) s = this.generatorTree.getParent(s); else if (s instanceof FunctionValue) { // Did we find an additional function? if (this.additionalFunctionValuesAndEffects.has(s)) return s; // Did the function itself get created by a generator we can chase? - s = this.generatorDAG.getCreator(s) || "GLOBAL"; + s = this.generatorTree.getCreator(s) || "GLOBAL"; } else { invariant(s === "GLOBAL"); let generator = this.globalGenerator; @@ -179,7 +179,7 @@ export class ResidualHeapVisitor { // created --- this causes the value later to be serialized in its // creation scope, ensuring that the value has the right creation / life time. _registerAdditionalRoot(value: ObjectValue): void { - let creationGenerator = this.generatorDAG.getCreator(value) || this.globalGenerator; + let creationGenerator = this.generatorTree.getCreator(value) || this.globalGenerator; let additionalFunction = this._getAdditionalFunctionOfScope() || "GLOBAL"; let targetAdditionalFunction; @@ -188,7 +188,7 @@ export class ResidualHeapVisitor { } else { let s = creationGenerator; while (s instanceof Generator) { - s = this.generatorDAG.getParent(s); + s = this.generatorTree.getParent(s); invariant(s !== undefined); } invariant(s === "GLOBAL" || s instanceof FunctionValue); @@ -206,7 +206,7 @@ export class ResidualHeapVisitor { additionalFVEffects.additionalRoots.add(value); this._visitInUnrelatedScope(creationGenerator, value); - usageScope = this.generatorDAG.getCreator(value) || this.globalGenerator; + usageScope = this.generatorTree.getCreator(value) || this.globalGenerator; } usageScope = this.scope; @@ -215,7 +215,7 @@ export class ResidualHeapVisitor { // applying effects; if so, store additional information that the serializer // can use to proactive serialize such objects from within the right generator let anyRelevantEffects = false; - for (let g = usageScope; g instanceof Generator; g = this.generatorDAG.getParent(g)) { + for (let g = usageScope; g instanceof Generator; g = this.generatorTree.getParent(g)) { if (g === creationGenerator) { if (anyRelevantEffects) { let s = this.additionalGeneratorRoots.get(g); @@ -1098,7 +1098,7 @@ export class ResidualHeapVisitor { if (this.preProcessValue(val)) this.visitValueProxy(val); this.postProcessValue(val); } else if (val instanceof FunctionValue) { - let creationGenerator = this.generatorDAG.getCreator(val) || this.globalGenerator; + let creationGenerator = this.generatorTree.getCreator(val) || this.globalGenerator; // 1. Visit function in its creation scope this._enqueueWithUnrelatedScope(creationGenerator, () => { @@ -1132,7 +1132,7 @@ export class ResidualHeapVisitor { let callbacks = { visitEquivalentValue: this.visitEquivalentValue.bind(this), visitGenerator: (generator, parent) => { - invariant(this.generatorDAG.isParent(parent, generator)); + invariant(this.generatorTree.getParent(generator) === parent); this.visitGenerator(generator, additionalFunctionInfo); }, canOmit: (value: Value): boolean => { @@ -1282,7 +1282,7 @@ export class ResidualHeapVisitor { this.additionalFunctionValueInfos.set(functionValue, additionalFunctionInfo); let effectsGenerator = additionalEffects.generator; - this.generatorDAG.add(functionValue, effectsGenerator); + this.generatorTree.add(functionValue, effectsGenerator); this.visitGenerator(effectsGenerator, additionalFunctionInfo); }; @@ -1294,7 +1294,7 @@ export class ResidualHeapVisitor { } visitRoots(): void { - this.generatorDAG.add("GLOBAL", this.globalGenerator); + this.generatorTree.add("GLOBAL", this.globalGenerator); this.visitGenerator(this.globalGenerator); for (let moduleValue of this.modules.initializedModules.values()) this.visitValue(moduleValue); @@ -1316,7 +1316,7 @@ export class ResidualHeapVisitor { let expected = 0; for (let { scope, action } of this.delayedActions) { let generator; - if (scope instanceof FunctionValue) generator = this.generatorDAG.getCreator(scope) || this.globalGenerator; + if (scope instanceof FunctionValue) generator = this.generatorTree.getCreator(scope) || this.globalGenerator; else if (scope === "GLOBAL") generator = this.globalGenerator; else { invariant(scope instanceof Generator); @@ -1370,10 +1370,10 @@ export class ResidualHeapVisitor { info.nestedEffectsRunners.push(runGeneratorAction); runGeneratorAction = undefined; } - s = this.generatorDAG.getParent(s); + s = this.generatorTree.getParent(s); } else if (s instanceof FunctionValue) { invariant(this.additionalFunctionValuesAndEffects.has(s)); - s = this.generatorDAG.getCreator(s) || "GLOBAL"; + s = this.generatorTree.getCreator(s) || "GLOBAL"; } invariant(s instanceof Generator || s instanceof FunctionValue || s === "GLOBAL"); } diff --git a/src/serializer/ResidualOptimizedFunctions.js b/src/serializer/ResidualOptimizedFunctions.js index e5376f197..7aa3de207 100644 --- a/src/serializer/ResidualOptimizedFunctions.js +++ b/src/serializer/ResidualOptimizedFunctions.js @@ -12,7 +12,7 @@ import { FunctionValue } from "../values/index.js"; import type { AdditionalFunctionEffects } from "./types"; import invariant from "../invariant.js"; -import { GeneratorDAG } from "./GeneratorDAG"; +import { GeneratorTree } from "./GeneratorTree"; import type { Scope } from "./types.js"; import { FunctionEnvironmentRecord } from "../environment"; import type { Value } from "../values/index"; @@ -20,16 +20,16 @@ import { Generator } from "../utils/generator"; export class ResidualOptimizedFunctions { constructor( - generatorDAG: GeneratorDAG, + generatorTree: GeneratorTree, optimizedFunctionsAndEffects: Map, residualValues: Map> ) { - this._generatorDAG = generatorDAG; + this._generatorTree = generatorTree; this._optimizedFunctionsAndEffects = optimizedFunctionsAndEffects; this._residualValues = residualValues; } - _generatorDAG: GeneratorDAG; + _generatorTree: GeneratorTree; _optimizedFunctionsAndEffects: Map; _residualValues: Map>; @@ -80,7 +80,7 @@ export class ResidualOptimizedFunctions { for (let scope of scopes) { let s = scope; while (s instanceof Generator) { - s = this._generatorDAG.getParent(s); + s = this._generatorTree.getParent(s); } if (s === "GLOBAL") return undefined; invariant(s instanceof FunctionValue); diff --git a/src/serializer/serializer.js b/src/serializer/serializer.js index f547c52ae..df786cfb1 100644 --- a/src/serializer/serializer.js +++ b/src/serializer/serializer.js @@ -193,7 +193,7 @@ export class Serializer { if (this.realm.react.verbose) { this.logger.logInformation(`Visiting evaluated nodes...`); } - let [residualHeapInfo, generatorDAG, inspector] = (() => { + let [residualHeapInfo, generatorTree, inspector] = (() => { let residualHeapVisitor = new ResidualHeapVisitor( this.realm, this.logger, @@ -201,12 +201,12 @@ export class Serializer { additionalFunctionValuesAndEffects ); statistics.deepTraversal.measure(() => residualHeapVisitor.visitRoots()); - return [residualHeapVisitor.toInfo(), residualHeapVisitor.generatorDAG, residualHeapVisitor.inspector]; + return [residualHeapVisitor.toInfo(), residualHeapVisitor.generatorTree, residualHeapVisitor.inspector]; })(); if (this.logger.hasErrors()) return undefined; let residualOptimizedFunctions = new ResidualOptimizedFunctions( - generatorDAG, + generatorTree, additionalFunctionValuesAndEffects, residualHeapInfo.values ); @@ -270,7 +270,7 @@ export class Serializer { this.options, additionalFunctionValuesAndEffects, referentializer, - generatorDAG, + generatorTree, residualOptimizedFunctions ).serialize(); }); @@ -293,7 +293,7 @@ export class Serializer { this.options, additionalFunctionValuesAndEffects, referentializer, - generatorDAG, + generatorTree, residualOptimizedFunctions ).serialize() );