From 25bc4018ca2a69f9edc432ec1cca35632857a57c Mon Sep 17 00:00:00 2001 From: overlookmotel Date: Mon, 4 Dec 2023 00:09:50 +0000 Subject: [PATCH] WIP 1 --- lib/instrument/tracking.js | 26 +++++++++++++-- lib/instrument/visitors/class.js | 10 +++--- lib/instrument/visitors/function.js | 52 ++++++++--------------------- 3 files changed, 43 insertions(+), 45 deletions(-) diff --git a/lib/instrument/tracking.js b/lib/instrument/tracking.js index e23c1bbf..0ddbfba3 100644 --- a/lib/instrument/tracking.js +++ b/lib/instrument/tracking.js @@ -8,8 +8,7 @@ // Export module.exports = { insertBlockVarsIntoBlockStatement, - insertTrackerCodeIntoFunctionBody, - insertTrackerCodeIntoFunctionParams + insertTrackerCodeIntoFunction }; // Modules @@ -50,6 +49,29 @@ function insertBlockVarsIntoBlockStatement(block, blockNode, state) { blockNode.body.unshift(...statementNodes); } +/** + * Insert tracker code, scope ID var and temp vars into function. + * If function has complex params, insert into params. Otherwise, into function body. + * @param {Object} fn - Function object + * @param {Object} fnNode - Function AST node + * @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} state - State object + * @returns {undefined} + */ +function insertTrackerCodeIntoFunction(fn, fnNode, paramsBlock, bodyBlock, trackerNode, state) { + const {firstComplexParamIndex} = fn; + if (firstComplexParamIndex === undefined) { + insertTrackerCodeIntoFunctionBody(fnNode, paramsBlock, bodyBlock, trackerNode, state); + } else { + insertTrackerCodeIntoFunctionParams( + fnNode, paramsBlock, bodyBlock, trackerNode, firstComplexParamIndex, state + ); + } +} + /** * Insert tracker code, scope ID var and temp vars into function body. * @param {Object} fnNode - Function AST node diff --git a/lib/instrument/visitors/class.js b/lib/instrument/visitors/class.js index 92479510..33299c06 100644 --- a/lib/instrument/visitors/class.js +++ b/lib/instrument/visitors/class.js @@ -17,7 +17,7 @@ const t = require('@babel/types'); // Imports const { createFunction, createAndEnterFunctionOrClassNameBlock, visitFunctionParams, visitFunctionBody, - removeUnnecessaryUseStrictDirectives, insertTrackerComment, instrumentFunctionOrClassConstructor + removeUnnecessaryUseStrictDirectives, insertTrackerComment, createTracker } = require('./function.js'), {visitMethod, getMethodName} = require('./method.js'), Expression = require('./expression.js'), @@ -28,6 +28,7 @@ const { createBlockId, createBlock, createBlockWithId, createAndEnterBlock, createBindingWithoutNameCheck, createThisBinding, createArgumentsBinding, createNewTargetBinding } = require('../blocks.js'), + {insertTrackerCodeIntoFunction} = require('../tracking.js'), {visitKey, visitKeyMaybe, visitKeyContainer} = require('../visit.js'), {createTempVarNode} = require('../internalVars.js'), {FN_TYPE_CLASS} = require('../../shared/constants.js'); @@ -447,8 +448,9 @@ function instrumentClass( parent[key] = classNode; // Add tracker code + block vars to constructor - instrumentFunctionOrClassConstructor( - constructorNode, fn, constructorParamsBlock, constructorBodyBlock, state + const trackerNode = createTracker(fn, state); + insertTrackerCodeIntoFunction( + fn, constructorNode, constructorParamsBlock, constructorBodyBlock, trackerNode, state ); // Insert tracking comment @@ -460,7 +462,7 @@ function instrumentClass( /** * Create empty class constructor node. - * It will be instrumented by `instrumentFunctionOrClassConstructor()`, same as a real constructor. + * It will be instrumented by `instrumentClass()`, same as a real constructor. * @param {Object} fn - Function object for class * @param {Object} state - State object * @returns {Object} - Class constructor AST node diff --git a/lib/instrument/visitors/function.js b/lib/instrument/visitors/function.js index 05e77b1d..e24a5c21 100644 --- a/lib/instrument/visitors/function.js +++ b/lib/instrument/visitors/function.js @@ -20,7 +20,7 @@ module.exports = { escapeFilename, withStrictModeState, hoistSloppyFunctionDeclarations, - instrumentFunctionOrClassConstructor, + createTracker, insertTrackerComment, createFunctionInfoFunction }; @@ -38,7 +38,7 @@ const Statement = require('./statement.js'), createBlock, createAndEnterBlock, createBinding, createThisBinding, createArgumentsBinding, createNewTargetBinding, getOrCreateExternalVar } = require('../blocks.js'), - {insertTrackerCodeIntoFunctionBody, insertTrackerCodeIntoFunctionParams} = require('../tracking.js'), + {insertTrackerCodeIntoFunction} = require('../tracking.js'), {createFnInfoVarNode} = require('../internalVars.js'), {insertComment, hasUseStrictDirective, stringLiteralWithSingleQuotes} = require('../utils.js'), {combineArraysWithDedup} = require('../../shared/functions.js'), @@ -613,27 +613,23 @@ function instrumentFunction(node, fn, parent, key, paramsBlock, bodyBlock, state // Restore to original place in AST parent[key] = node; - instrumentFunctionOrClassConstructor(node, fn, paramsBlock, bodyBlock, state); + // Insert tracker call and block vars (`livepack_scopeId` and `livepack_temp`) into function. + // NB: `bodyBlock` here may actually be params block if is an arrow function with no body. + const trackerNode = createTracker(fn, state); + insertTrackerCodeIntoFunction(fn, node, paramsBlock, bodyBlock, trackerNode, state); if (node.type === 'ArrowFunctionExpression') insertArrowFunctionTrackerComment(fn, node, state); } /** - * Instrument function, method or class constructor. - * - Insert `livepack_tracker()` call in function body. - * - Insert block vars (`livepack_scopeId`, `livepack_temp`) in function body or params. - * - Create function info function containing function AST, details of internal and external vars etc. - * - * @param {Object} node - Function, method, or class constructor AST node + * Create tracker call. + * Create scopes array, and also copy external vars down to parent function. * @param {Object} fn - Function object - * @param {Object} paramsBlock - Function's params block object - * @param {Object} bodyBlock - Function's body block object * @param {Object} state - State object - * @returns {undefined} + * @returns {Object} - AST node for tracker call */ -function instrumentFunctionOrClassConstructor(node, fn, paramsBlock, bodyBlock, state) { - // NB `bodyBlock` here may actually be params block if is an arrow function with no body. - // Sort scopes in ascending order of block ID. +function createTracker(fn, state) { + // Sort scopes in ascending order of block ID const scopes = [...fn.externalVars].map(([block, vars]) => ({block, vars})) .sort((scope1, scope2) => (scope1.block.id > scope2.block.id ? 1 : -1)); fn.scopes = scopes; @@ -650,31 +646,9 @@ function instrumentFunctionOrClassConstructor(node, fn, paramsBlock, bodyBlock, } } - // Insert tracker call and block vars (`livepack_scopeId` and `livepack_temp`) into function. - // If function has complex params, insert into params. Otherwise, into function body. - const trackerNode = createTrackerCall(fn.id, scopes, state); - - const {firstComplexParamIndex} = fn; - if (firstComplexParamIndex === undefined) { - insertTrackerCodeIntoFunctionBody(node, paramsBlock, bodyBlock, trackerNode, state); - } else { - insertTrackerCodeIntoFunctionParams( - node, paramsBlock, bodyBlock, trackerNode, firstComplexParamIndex, state - ); - } -} - -/** - * Create tracker call. - * @param {number} fnId - Function ID - * @param {Array} scopes - Array of scope objects in ascending order of block ID - * @param {Object} state - State object - * @returns {Object} - AST node for tracker call - */ -function createTrackerCall(fnId, scopes, state) { - // `livepack_tracker(livepack_getFnInfo_3, () => [[livepack_scopeId_2, x]]);` + // `livepack_tracker(livepack_getFnInfo_3, () => [[livepack_scopeId_2, x]])` return t.callExpression(state.trackerVarNode, [ - createFnInfoVarNode(fnId, state), + createFnInfoVarNode(fn.id, state), t.arrowFunctionExpression([], t.arrayExpression( scopes.map(scope => t.arrayExpression([ scope.block.varsBlock.scopeIdVarNode,