diff --git a/cli/asc.js b/cli/asc.js index 7832b2ba32..7f620c966e 100644 --- a/cli/asc.js +++ b/cli/asc.js @@ -574,6 +574,20 @@ exports.main = function main(argv, options, callback) { optimizeLevel = Math.min(Math.max(optimizeLevel, 0), 3); shrinkLevel = Math.min(Math.max(shrinkLevel, 0), 2); + try { + stats.compileTime += measure(() => { + assemblyscript.initializeProgram(program, compilerOptions); + }); + } catch(e) { + return callback(e); + } + + // Call afterInitialize transform hook + { + let error = applyTransform("afterInitialize", program); + if (error) return callback(error); + } + var module; stats.compileCount++; try { diff --git a/cli/transform.d.ts b/cli/transform.d.ts index e7afdc7ddd..330943be9c 100644 --- a/cli/transform.d.ts +++ b/cli/transform.d.ts @@ -35,6 +35,9 @@ export abstract class Transform { /** Called when parsing is complete, before a program is instantiated from the AST. */ afterParse?(parser: Parser): void; + /** Called after the program is instantiated. */ + afterInitialize?(program: Program): void; + /** Called when compilation is complete, before the module is being validated. */ afterCompile?(module: Module): void; } diff --git a/src/compiler.ts b/src/compiler.ts index 197ed9d50d..97adb56613 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -376,14 +376,19 @@ export class Compiler extends DiagnosticEmitter { module.setFeatures(featureFlags); } + initializeProgram(): void { + // initialize lookup maps, built-ins, imports, exports, etc. + this.program.initialize(this.options); + } + /** Performs compilation of the underlying {@link Program} to a {@link Module}. */ compile(): Module { var options = this.options; var module = this.module; var program = this.program; - // initialize lookup maps, built-ins, imports, exports, etc. - program.initialize(options); + // check and perform this program initialization if it hasn't been done + this.initializeProgram(); // set up the main start function var startFunctionInstance = program.makeNativeFunction(BuiltinNames.start, new Signature(program, [], Type.void)); diff --git a/src/index.ts b/src/index.ts index 23bf8d6074..bea16cf275 100644 --- a/src/index.ts +++ b/src/index.ts @@ -184,6 +184,11 @@ export function getDependee(program: Program, file: string): string | null { // Compiler +/** Initializes the program pre-emptively for transform hooks. */ +export function initializeProgram(program: Program, options: Options): void { + program.initialize(options); +} + /** Compiles the parsed sources to a module. */ export function compile(program: Program): Module { program.parser.finish(); diff --git a/src/program.ts b/src/program.ts index 5b7f48c53e..43f9cfbdb4 100644 --- a/src/program.ts +++ b/src/program.ts @@ -478,6 +478,8 @@ export class Program extends DiagnosticEmitter { nextClassId: u32 = 0; /** Next signature id. */ nextSignatureId: i32 = 0; + /** An indicator if the program has been initialized. */ + initialized: bool = false; /** Constructs a new program, optionally inheriting parser diagnostics. */ constructor( /** Compiler options. */ @@ -633,6 +635,10 @@ export class Program extends DiagnosticEmitter { /** Initializes the program and its elements prior to compilation. */ initialize(options: Options): void { + // Initialize only once + if (this.initialized) return; + + this.initialized = true; this.options = options; // register native types