Optimize build speed
This commit is contained in:
parent
2ec275667e
commit
9ebfa830f6
15 changed files with 167 additions and 67 deletions
|
@ -1,35 +1,57 @@
|
|||
export class GlyphBuildExecutor {
|
||||
constructor() {
|
||||
this.currentBlockName = null;
|
||||
constructor(recursiveBuildFilter) {
|
||||
this.recursiveBuildFilter = recursiveBuildFilter;
|
||||
this.currentBlockId = null;
|
||||
this.dependencyManager = new DependencyManager();
|
||||
this.pendingGlyphBlocks = [];
|
||||
this.glyphBlockStore = {};
|
||||
}
|
||||
setGlyphToBlockDependency(glyph) {
|
||||
if (this.currentBlockName) {
|
||||
this.dependencyManager.glyphToBlock.set(glyph, this.currentBlockName);
|
||||
if (this.currentBlockId) {
|
||||
this.dependencyManager.glyphToBlock.set(glyph, this.currentBlockId);
|
||||
|
||||
let s = this.dependencyManager.blockToGlyph.get(this.currentBlockId);
|
||||
if (!s) {
|
||||
s = new Set();
|
||||
this.dependencyManager.blockToGlyph.set(this.currentBlockId, s);
|
||||
}
|
||||
s.add(glyph);
|
||||
}
|
||||
}
|
||||
defineGlyphBlock(capture, blockName, body) {
|
||||
const block = new GlyphBlock(capture, this, blockName, body);
|
||||
this.glyphBlockStore[blockName] = block;
|
||||
executePendingBlocks() {
|
||||
// if (!this.recursiveBuildFilter) {
|
||||
for (const block of this.pendingGlyphBlocks) block.resolve();
|
||||
// } else {
|
||||
// for (const block of this.pendingGlyphBlocks)
|
||||
// if (this.recursiveBuildFilter.blockIsNeeded(block.id)) block.resolve();
|
||||
// }
|
||||
}
|
||||
defineGlyphBlock(capture, id, body) {
|
||||
const block = new GlyphBlock(capture, this, id, body);
|
||||
if (this.glyphBlockStore[id]) throw new Error(`Duplicate glyph block: ${id}`);
|
||||
this.glyphBlockStore[id] = block;
|
||||
this.pendingGlyphBlocks.push(block);
|
||||
}
|
||||
}
|
||||
|
||||
export class RecursiveBuildFilter {
|
||||
constructor(glyphIdFilter) {
|
||||
constructor(glyphIdFilter, blockIdFilter) {
|
||||
this.glyphIdFilter = glyphIdFilter;
|
||||
this.blockIdFilter = blockIdFilter;
|
||||
}
|
||||
glyphIsNeeded(id) {
|
||||
return this.glyphIdFilter.has(id);
|
||||
}
|
||||
blockIsNeeded(id) {
|
||||
return this.blockIdFilter.has(id);
|
||||
}
|
||||
}
|
||||
|
||||
export class DependencyManager {
|
||||
constructor() {
|
||||
this.glyphToGlyph = new WeakMap();
|
||||
this.glyphToBlock = new WeakMap();
|
||||
this.blockToGlyph = new Map();
|
||||
}
|
||||
addDependency(dependent, dependency) {
|
||||
let s = this.glyphToGlyph.get(dependent);
|
||||
|
@ -39,12 +61,31 @@ export class DependencyManager {
|
|||
}
|
||||
s.add(dependency);
|
||||
}
|
||||
traverseDependencies(glyphs) {
|
||||
|
||||
traverseGlyphDependenciesImpl(glyphs, fBlockwiseExpand) {
|
||||
let state = new Map();
|
||||
const PENDING = 1,
|
||||
CHECKED = 2;
|
||||
|
||||
for (const glyph of glyphs) state.set(glyph, PENDING);
|
||||
|
||||
// When fBlockwiseExpand is true, we need to expand the initial glyph set
|
||||
// to include all glyphs in the same block.
|
||||
if (fBlockwiseExpand) {
|
||||
let blocks = new Set();
|
||||
for (const glyph of glyphs) {
|
||||
let b = this.glyphToBlock.get(glyph);
|
||||
if (b) blocks.add(b);
|
||||
}
|
||||
for (const b of blocks) {
|
||||
const glyphs = this.blockToGlyph.get(b);
|
||||
if (glyphs) {
|
||||
for (const g of glyphs) state.set(g, PENDING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse the dependency graph
|
||||
for (;;) {
|
||||
let found = false;
|
||||
for (const [glyph, s] of state) {
|
||||
|
@ -59,11 +100,24 @@ export class DependencyManager {
|
|||
if (!found) break;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
traverseDependencies(glyphs) {
|
||||
const gGlyphGraph = this.traverseGlyphDependenciesImpl(glyphs, false);
|
||||
const gBlockGraph = this.traverseGlyphDependenciesImpl(glyphs, true);
|
||||
|
||||
let glyphIdFilter = new Set();
|
||||
for (const g of state.keys()) {
|
||||
let blockIdFilter = new Set();
|
||||
for (const g of gGlyphGraph.keys()) {
|
||||
if (g.identifier) glyphIdFilter.add(g.identifier);
|
||||
}
|
||||
return new RecursiveBuildFilter(glyphIdFilter);
|
||||
for (const g of gBlockGraph.keys()) {
|
||||
let b = this.glyphToBlock.get(g);
|
||||
if (b) blockIdFilter.add(b);
|
||||
}
|
||||
|
||||
return new RecursiveBuildFilter(glyphIdFilter, blockIdFilter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,18 +125,18 @@ export class GlyphBlock {
|
|||
constructor(capture, execState, blockName, body) {
|
||||
this.capture = capture;
|
||||
this.execState = execState;
|
||||
this.blockName = blockName;
|
||||
this.id = blockName;
|
||||
this.body = body;
|
||||
this.resolved = 0;
|
||||
this.exports = {};
|
||||
}
|
||||
resolve() {
|
||||
if (this.resolved == 2) return this.exports;
|
||||
if (this.resolved == 1) throw new Error(`Circular dependency detected: ${this.blockName}`);
|
||||
if (this.resolved == 1) throw new Error(`Circular dependency detected: ${this.id}`);
|
||||
this.resolved = 1;
|
||||
|
||||
const prevBlockName = this.execState.currentBlockName;
|
||||
this.execState.currentBlockName = this.blockName;
|
||||
const prevBlockName = this.execState.currentBlockId;
|
||||
this.execState.currentBlockId = this.id;
|
||||
|
||||
const pendingApplications = [];
|
||||
const ExportCapture = fnObj => {
|
||||
|
@ -95,7 +149,7 @@ export class GlyphBlock {
|
|||
this.body(this.capture, ExportCapture);
|
||||
for (const f of pendingApplications) f();
|
||||
|
||||
this.execState.currentBlockName = prevBlockName;
|
||||
this.execState.currentBlockId = prevBlockName;
|
||||
this.resolved = 2;
|
||||
return this.exports;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue