Skip to content

Commit

Permalink
WIP 2
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Dec 4, 2023
1 parent 25bc401 commit f871333
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 24 deletions.
8 changes: 6 additions & 2 deletions lib/init/getScopeId.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@

'use strict';

const {defineProperties, getOwnPropertyDescriptors} = Object;
// Imports
const {dummySymbol} = require('../shared/tracker.js');

// Exports

module.exports = getScopeId;

const {defineProperties, getOwnPropertyDescriptors} = Object;

/**
* Get unique scope ID.
* @returns {number} - Scope ID
Expand All @@ -21,8 +24,9 @@ function getScopeId() {

let nextScopeId = 1;

// Add additional static methods
// Add additional static methods + properties
getScopeId.toRest = toRest;
getScopeId.dummySymbol = dummySymbol;

/**
* Convert object to array.
Expand Down
19 changes: 13 additions & 6 deletions lib/instrument/tracking.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function insertBlockVarsIntoBlockStatement(block, blockNode, state) {
* @param {Object} paramsBlock - Function params block object
* @param {Object} [bodyBlock] - Function body block object
* (`undefined` if arrow function with no body block)
* @param {Object} trackerNode - AST node for tracker call
* @param {Object} [trackerNode] - AST node for tracker call (or undefined if no tracker to insert)
* @param {Object} state - State object
* @returns {undefined}
*/
Expand All @@ -78,20 +78,24 @@ function insertTrackerCodeIntoFunction(fn, fnNode, paramsBlock, bodyBlock, track
* @param {Object} paramsBlock - Function params block object
* @param {Object} [bodyBlock] - Function body block object
* (`undefined` if arrow function with no body block)
* @param {Object} trackerNode - AST node for tracker call
* @param {Object} [trackerNode] - AST node for tracker call (or undefined if no tracker to insert)
* @param {Object} state - State object
* @returns {undefined}
*/
function insertTrackerCodeIntoFunctionBody(fnNode, paramsBlock, bodyBlock, trackerNode, state) {
// Exit if no tracker, scope ID var, or temp vars to insert
const block = bodyBlock || paramsBlock;
if (!trackerNode && !block.scopeIdVarNode) return;

// If body is not a block statement, convert it to one
let bodyNode = fnNode.body;
if (!bodyBlock) bodyNode = fnNode.body = t.blockStatement([t.returnStatement(bodyNode)]);

// Insert scope ID and temp var nodes
insertBlockVarsIntoBlockStatement(bodyBlock || paramsBlock, bodyNode, state);
insertBlockVarsIntoBlockStatement(block, bodyNode, state);

// Insert tracker call
bodyNode.body.unshift(t.expressionStatement(trackerNode));
if (trackerNode) bodyNode.body.unshift(t.expressionStatement(trackerNode));
}

/**
Expand Down Expand Up @@ -151,14 +155,18 @@ function insertTrackerCodeIntoFunctionBody(fnNode, paramsBlock, bodyBlock, track
function insertTrackerCodeIntoFunctionParams(
fnNode, paramsBlock, bodyBlock, trackerNode, firstComplexParamIndex, state
) {
// Exit if no tracker, scope ID var, or temp vars to insert
const {scopeIdVarNode} = paramsBlock;
if (!trackerNode && !scopeIdVarNode) return;

// Create object pattern to use as rest element.
// `{ [ livepack_tracker(...) ]: [] = [] }`
// Assignments will be added to each side of `[] = []` to init vars and assign to them.
const leftNodes = [],
rightNodes = [],
propNodes = [
t.objectProperty(
trackerNode,
trackerNode || t.memberExpression(state.getScopeIdVarNode, t.identifier('dummySymbol')),
t.assignmentPattern(t.arrayPattern(leftNodes), t.arrayExpression(rightNodes)),
true
)
Expand All @@ -171,7 +179,6 @@ function insertTrackerCodeIntoFunctionParams(
}

// Insert assignments for scope ID var node and temp var nodes
const {scopeIdVarNode} = paramsBlock;
if (scopeIdVarNode) {
addAssignment(scopeIdVarNode, t.callExpression(state.getScopeIdVarNode, []));

Expand Down
45 changes: 30 additions & 15 deletions lib/instrument/visitors/class.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const {
createThisBinding, createArgumentsBinding, createNewTargetBinding
} = require('../blocks.js'),
{insertTrackerCodeIntoFunction} = require('../tracking.js'),
{visitKey, visitKeyMaybe, visitKeyContainer} = require('../visit.js'),
{visitKey, visitKeyContainer} = require('../visit.js'),
{createTempVarNode} = require('../internalVars.js'),
{FN_TYPE_CLASS} = require('../../shared/constants.js');

Expand Down Expand Up @@ -111,7 +111,8 @@ function visitClass(classNode, parent, key, className, state) {
state.isStrict = true;

// Visit `extends` clause
if (classNode.superClass) {
const hasSuperClass = !!classNode.superClass;
if (hasSuperClass) {
fn.hasSuperClass = true;
visitKey(classNode, 'superClass', Expression, state);
}
Expand Down Expand Up @@ -178,7 +179,7 @@ function visitClass(classNode, parent, key, className, state) {
constructorParamsBlock.varsBlock = constructorBodyBlock;

// Visit constructor and prototype properties
let protoThisBlock;
let protoThisBlock, propForTrackerNode;
if (constructorNode || protoPropertyIndexes.length !== 0) {
// Enter function
state.currentFunction = fn;
Expand Down Expand Up @@ -207,8 +208,13 @@ function visitClass(classNode, parent, key, className, state) {
createNewTargetBinding(protoThisBlock);
state.currentThisBlock = protoThisBlock;

// If class does not extend a super class, prototype properties will be evaluated
// before class constructor, so tracker needs to go in 1st proto property which has a value
for (const index of protoPropertyIndexes) {
const propNode = memberNodes[index];
if (!propNode.value) continue;
visitKey(memberNodes, index, ClassPropertyMaybePrivate, state);
if (!hasSuperClass && !propForTrackerNode) propForTrackerNode = propNode;
}
}

Expand Down Expand Up @@ -287,7 +293,7 @@ function visitClass(classNode, parent, key, className, state) {
state.secondPass(
instrumentClass,
classNode, fn, parent, key, constructorNode, constructorParamsBlock, constructorBodyBlock,
superBlock, state
superBlock, propForTrackerNode, state
);
}

Expand Down Expand Up @@ -349,7 +355,7 @@ function ClassMethodMaybePrivate(node, state, parent, key) {
function ClassStaticPropertyOrBlock(node, state) {
if (node.type === 'StaticBlock') {
StaticBlock(node, state);
} else {
} else if (node.value) {
ClassPropertyMaybePrivate(node, state);
}
}
Expand All @@ -363,7 +369,7 @@ function ClassStaticPropertyOrBlock(node, state) {
*/
function ClassPropertyMaybePrivate(node, state) {
// Don't visit `key` as has been dealt with separately above
visitKeyMaybe(node, 'value', Expression, state);
visitKey(node, 'value', Expression, state);
}

/**
Expand Down Expand Up @@ -420,19 +426,34 @@ function serializeClassAst(classNode, constructorNode, constructorIndex) {
* @param {Object} constructorParamsBlock - Constructor params block object
* @param {Object} constructorBodyBlock - Constructor body block object
* @param {Object} superBlock - `super` target block object
* @param {Object} [propForTrackerNode] - Property node to insert tracker in
* @param {Object} state - State object
* @returns {undefined}
*/
function instrumentClass(
classNode, fn, parent, key, constructorNode, constructorParamsBlock, constructorBodyBlock,
superBlock, state
superBlock, propForTrackerNode, state
) {
// If class has no constructor, create one for tracker code to be inserted in
if (!constructorNode) {
// Create tracker
let trackerNode = createTracker(fn, state);

if (propForTrackerNode) {
// Insert tracker into property
propForTrackerNode.value = t.sequenceExpression([trackerNode, propForTrackerNode.value]);
trackerNode = undefined;
} else if (!constructorNode) {
// Class has no constructor - create one for tracker code to be inserted in
constructorNode = createClassConstructor(fn, state);
classNode.body.body.push(constructorNode);
}

// Add tracker code + block vars to constructor
if (constructorNode) {
insertTrackerCodeIntoFunction(
fn, constructorNode, constructorParamsBlock, constructorBodyBlock, trackerNode, state
);
}

// Insert `static {}` block to define temp var for `super` target if `super` used in class
const superVarNode = getSuperVarNode(superBlock);
if (superVarNode) {
Expand All @@ -447,12 +468,6 @@ function instrumentClass(
// Restore to original place in AST
parent[key] = classNode;

// Add tracker code + block vars to constructor
const trackerNode = createTracker(fn, state);
insertTrackerCodeIntoFunction(
fn, constructorNode, constructorParamsBlock, constructorBodyBlock, trackerNode, state
);

// Insert tracking comment
const commentHolderNode = classNode.id || classNode.superClass || classNode.body;
insertTrackerComment(fn.id, FN_TYPE_CLASS, commentHolderNode, 'leading', state);
Expand Down
3 changes: 2 additions & 1 deletion lib/shared/tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ module.exports = {
tracker,
activateTracker,
getTrackerResult,
trackerError
trackerError,
dummySymbol
};

let trackerIsActive = false,
Expand Down

0 comments on commit f871333

Please sign in to comment.