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:
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user