Factory variables

Variables that are evaluated once, at compile-time.
Makes every variable access even faster than before.
Implementation a bit dirty, will clean up later.
This commit is contained in:
Thomas Weber committed 2020-07-13 23:52:18 -05:00
1 parent 22a80d579e
commit 9dfbdba2d3
3 files changed
+47 -13

No files matched your search

@@ -48,11 +48,11 @@ const findVariable = (util, id, name, type) => {
const stage = util.stage;
// Search for it by ID
if (target.variables.hasOwnProperty(id)) {
return `targetVariables["${util.safe(id)}"]`;
return util.compiler.getOrCreateFactoryVariable(`targetVariables["${util.safe(id)}"]`);
}
if (target.runtime && !target.isStage) {
if (!target.isStage) {
if (stage && stage.variables.hasOwnProperty(id)) {
return `stageVariables["${util.safe(id)}"]`;
return util.compiler.getOrCreateFactoryVariable(`stageVariables["${util.safe(id)}"]`);
}
}
// Search for it by name and type
@@ -60,16 +60,17 @@ const findVariable = (util, id, name, type) => {
if (target.variables.hasOwnProperty(varId)) {
const currVar = target.variables[varId];
if (currVar.name === name && currVar.type === type) {
return `targetVariables["${util.safe(varId)}"]`;
return util.compiler.getOrCreateFactoryVariable(`targetVariables["${util.safe(varId)}"]`);
}
}
}
if (target.runtime && !target.isStage) {
if (!target.isStage) {
if (stage) {
for (const varId in stage.variables) {
if (stage.variables.hasOwnProperty(varId)) {
const currVar = stage.variables[varId];
if (currVar.name === name && currVar.type === type) {
// FIXME: return the JS to evaluate it not the variable itself
return currVar;
}
}
+25 -2
View File
@@ -392,6 +392,15 @@ class Compiler {
*/
this.procedures = Object.assign({}, this.blocks._cache.compiledProcedures);
/**
* Factory variables.
* These variables will be setup once when the script factory runs.
* This is a map of Value to variable name.
* It may seem backwards but it makes tracking identical values very easy and efficient.
* @type {Object.<string, string>}
*/
this.factoryVariables = {};
/**
* Number of local variables created.
*/
@@ -498,8 +507,9 @@ class Compiler {
* @param {CompilerHints} hints
*/
compileScript(topBlock, hints) {
// blocks will read hints from here
// reset some data
this.hints = hints;
this.factoryVariables = {};
let script = '';
@@ -527,7 +537,7 @@ class Compiler {
script += '}';
const fn = execute.createScriptFactory(script);
const fn = execute.createScriptFactory(script, this);
log.info(`[${this.target.getName()}] compiled script`, script);
return fn;
}
@@ -540,6 +550,19 @@ class Compiler {
return 'a' + this.variableCount;
}
/**
* Create or get a factory variable.
* @param {string} value The value of the factory variable.
*/
getOrCreateFactoryVariable(value) {
if (this.factoryVariables.hasOwnProperty(value)) {
return this.factoryVariables[value];
}
const variableName = this.nextVariable();
this.factoryVariables[value] = variableName;
return variableName;
}
/**
* @returns {CompilationResult}
*/
+16 -6
View File
@@ -390,16 +390,26 @@ const execute = (_thread) => {
* Evaluate a continuation from its source code.
* Prepares the necessary environment.
* @param {string} source
* @param {Compiler} compiler
*/
const createScriptFactory = (source) => {
// we cache some very frequently accessed variables up here, it does a lot to help performance.
source = `(function f(target) {
const createScriptFactory = (_source, compiler) => {
let source = `(function f(target) {
var runtime = target.runtime;
var stage = runtime.getTargetForStage();
var stageVariables = stage.variables;
var targetVariables = target.variables;
return ${source};
});`;
var targetVariables = target.variables;`;
for (const data of Object.keys(compiler.factoryVariables)) {
const varName = compiler.factoryVariables[data];
source += `var ${varName} = ${data};\n`;
}
source += `return ${_source}; });`;
// try to get the GC to drop references to these variables, they have no reason to stick around at runtime and can be rather large
// TODO: see if this works or is necessary
_source = null;
compiler = null;
try {
return eval(source);