Skip to content

Commit

Permalink
Move work of parsing functions into Babel plugin [perf]
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Jan 18, 2022
1 parent 9603079 commit ebf9322
Show file tree
Hide file tree
Showing 15 changed files with 2,531 additions and 1,204 deletions.
1 change: 1 addition & 0 deletions lib/babel/symbols.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

module.exports = {
FUNCTION_PROPS: Symbol('livepack.FUNCTION_PROPS'),
SUPER_BLOCK: Symbol('livepack.SUPER_BLOCK'),
NAME_BLOCK: Symbol('livepack.NAME_BLOCK'),
PARAMS_BLOCK: Symbol('livepack.PARAMS_BLOCK'),
BODY_BLOCK: Symbol('livepack.BODY_BLOCK'),
Expand Down
68 changes: 36 additions & 32 deletions lib/babel/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module.exports = {
getFunctionType,
insertTrackerComment,
createBlockId,
getOrCreateScope,
initBlockScope,
replaceWith,
addComment,
assertWithLocation
Expand All @@ -34,45 +34,45 @@ const {createScopeIdVarNode} = require('./internalVars.js');
* Record on current function, and all functions above,
* up until function where var originates (`bindingFunction`).
*
* @param {string} name - Var name
* @param {string} varName - Var name
* @param {Object} block - Block props object
* @param {boolean} isConst - `true` if var is a const
* @param {boolean} isConstInStrict - `true` if var is a const in strict mode only
* @param {boolean} isReadFrom - `true` if var is read from
* @param {boolean} isAssignedTo - `true` if var is written to
* @param {boolean} isFunction - `true` if var is reference to function name
* @param {boolean} shouldRecordTrail - `true` if should record trail to var
* @param {Object} state - State object
* @returns {Array<Object>} - Array of function props objects
*/
function recordVarUse(name, block, isConst, isConstInStrict, state) {
function recordVarUse(varName, block, isReadFrom, isAssignedTo, isFunction, shouldRecordTrail, state) {
// Init scope ID var on statement block which includes var definition
const scopeIdVarNode = getOrCreateScope(block, state);
initBlockScope(block, state);

const {id: blockId, name: blockName} = block,
const blockId = block.id,
fns = [];
let fn = state.currentFunction;
let fn = state.currentFunction,
firstVarProps;
while (true) { // eslint-disable-line no-constant-condition
// Record var on this function's scopes
const fnScopes = fn.scopes;
let scope = fnScopes.get(blockId);
const fnScopes = fn.scopes,
scope = fnScopes.get(blockId);
let vars;
if (!scope) {
scope = {
blockId,
scopeIdVarNode,
varNames: new Set(),
constNames: new Set(),
constInStrictNames: new Set(),
blockName
};
fnScopes.set(blockId, scope);
} else if (scope.varNames.has(name)) {
vars = Object.create(null);
fnScopes.set(blockId, {block, vars});
} else {
vars = scope.vars;

// Stop if already recorded on this function (and therefore also on parents)
break;
const varProps = vars[varName];
if (varProps) {
if (!firstVarProps) firstVarProps = varProps;
break;
}
}

scope.varNames.add(name);
if (isConst) {
scope.constNames.add(name);
} else if (isConstInStrict) {
scope.constInStrictNames.add(name);
}
const varProps = {isReadFrom: false, isAssignedTo: false, isFunction, trails: []};
vars[varName] = varProps;
if (!firstVarProps) firstVarProps = varProps;

// Add to array of functions
fns.push(fn);
Expand All @@ -85,6 +85,11 @@ function recordVarUse(name, block, isConst, isConstInStrict, state) {
if (fn.id <= blockId) break;
}

// Set read/written flags on first function scope only
if (isReadFrom) firstVarProps.isReadFrom = true;
if (isAssignedTo) firstVarProps.isAssignedTo = true;
if (shouldRecordTrail) firstVarProps.trails.push([...state.trail]);

// Return array of function props objects (used in `processArguments()` and `superVisitor()`)
return fns;
}
Expand Down Expand Up @@ -135,12 +140,11 @@ function createBlockId(state) {
* Init scope on statement block.
* @param {Object} block - Block props object
* @param {Object} state - State object
* @returns {Object} - `scopeId` var node (named e.g. 'scopeId_100')
* @returns {undefined}
*/
function getOrCreateScope(block, state) {
block = block.varsBlock;
return block.scopeIdVarNode // eslint-disable-line no-return-assign
|| (block.scopeIdVarNode = createScopeIdVarNode(block.id, state));
function initBlockScope(block, state) {
const {varsBlock} = block;
if (!varsBlock.scopeIdVarNode) varsBlock.scopeIdVarNode = createScopeIdVarNode(varsBlock.id, state);
}

/**
Expand Down

0 comments on commit ebf9322

Please sign in to comment.