Skip to content

Commit

Permalink
fix(static-module-record): babelPlugin visitor to not skip declaratio…
Browse files Browse the repository at this point in the history
…ns in exports + benchmark setup (#1188)

* babelPlugin fix proposal and benchmarking setup

* remove debris

Co-authored-by: Michael FIG <mfig@agoric.com>

* more cleanup
  • Loading branch information
naugtur committed Jun 2, 2022
1 parent 86e65f4 commit aad89d0
Show file tree
Hide file tree
Showing 10 changed files with 897 additions and 83 deletions.
1 change: 1 addition & 0 deletions packages/static-module-record/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@endo/ses-ava": "^0.2.25",
"ava": "^3.12.1",
"babel-eslint": "^10.0.3",
"benchmark": "^2.1.4",
"c8": "^7.7.3",
"eslint": "^7.32.0",
"eslint-config-airbnb-base": "^14.0.0",
Expand Down
56 changes: 22 additions & 34 deletions packages/static-module-record/src/babelPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,6 @@ function makeModulePlugins(options) {
return node;
};

const prependReplacements = (replacements, node) => {
replacements.unshift(node);
};

const allowedHiddens = new WeakSet();
const rewrittenDecls = new WeakSet();
const hiddenIdentifier = hi => {
Expand Down Expand Up @@ -241,7 +237,7 @@ function makeModulePlugins(options) {
return replacements;
};

const rewriteDeclaration = path => {
const rewriteExportDeclaration = path => {
// Find all the declared identifiers.
if (rewrittenDecls.has(path.node)) {
return;
Expand All @@ -254,31 +250,19 @@ function makeModulePlugins(options) {

// Create the export calls.
const isConst = decl.kind === 'const';
const replacements = rewriteVars(
const additions = rewriteVars(
vids,
isConst,
decl.type === 'FunctionDeclaration'
? 'function'
: !isConst && decl.kind !== 'let',
);

if (replacements.length > 0) {
switch (decl.type) {
case 'VariableDeclaration': {
// We rewrote the declaration.
rewrittenDecls.add(decl);
prependReplacements(replacements, decl);
break;
}
case 'FunctionDeclaration': {
prependReplacements(replacements, decl);
break;
}
default: {
throw TypeError(`Unknown declaration type ${decl.type}`);
}
if (additions.length > 0) {
if (decl.type === 'VariableDeclaration') {
rewrittenDecls.add(decl);
}
path.replaceWithMultiple(replacements);
path.insertAfter(additions);
}
};

Expand Down Expand Up @@ -309,23 +293,22 @@ function makeModulePlugins(options) {
},
};

const moduleVisitor = (doAnalyze, doTransform) => ({
const importMetaVisitor = {
MetaProperty(path) {
if (
path.node.meta &&
path.node.meta.name === 'import' &&
path.node.property.name === 'meta'
) {
if (doAnalyze) {
importMeta.uttered = true;
}
if (doTransform) {
path.replaceWithMultiple([
replace(path.node, hiddenIdentifier(h.HIDDEN_META)),
]);
}
importMeta.uttered = true;
path.replaceWithMultiple([
replace(path.node, hiddenIdentifier(h.HIDDEN_META)),
]);
}
},
};

const moduleVisitor = (doAnalyze, doTransform) => ({
// We handle all the import and export productions.
ImportDeclaration(path) {
if (doAnalyze) {
Expand Down Expand Up @@ -473,7 +456,7 @@ function makeModulePlugins(options) {
}
if (doTransform) {
if (topLevelExported[name]) {
rewriteDeclaration(path);
rewriteExportDeclaration(path);
markExport(name);
}
}
Expand All @@ -496,7 +479,7 @@ function makeModulePlugins(options) {
if (doTransform) {
for (const { name } of vids) {
if (topLevelExported[name]) {
rewriteDeclaration(path);
rewriteExportDeclaration(path);
break;
}
}
Expand Down Expand Up @@ -614,7 +597,12 @@ function makeModulePlugins(options) {
},
};
case 1:
return { visitor: moduleVisitor(false, true) };
return {
visitor: {
...moduleVisitor(false, true),
...importMetaVisitor,
},
};
default:
throw TypeError(`Unrecognized module pass ${pass}`);
}
Expand Down
47 changes: 4 additions & 43 deletions packages/static-module-record/src/transform-analyze.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,10 @@
import * as babelParser from '@babel/parser';
import babelGenerate from '@agoric/babel-generator';
import babelTraverse from '@babel/traverse';
import babelTypes from '@babel/types';
import { makeTransformSource } from './transformSource.js';
import makeModulePlugins from './babelPlugin.js';

import * as h from './hidden.js';
import makeModulePlugins from './babelPlugin.js';

const { freeze } = Object;

const parseBabel = babelParser.default
? babelParser.default.parse
: babelParser.parse || babelParser;

const visitorFromPlugin = plugin => plugin({ types: babelTypes }).visitor;

const traverseBabel = babelTraverse.default || babelTraverse;
const generateBabel = babelGenerate.default || babelGenerate;

const makeTransformSource = (babel = null) => {
if (babel !== null) {
throw new Error(
`transform-analyze.js no longer allows injecting babel; use \`null\``,
);
}

const transformSource = (code, sourceOptions = {}) => {
// console.log(`transforming`, sourceOptions, code);
const { analyzePlugin, transformPlugin } = makeModulePlugins(sourceOptions);

const ast = parseBabel(code, { sourceType: sourceOptions.sourceType });

traverseBabel(ast, visitorFromPlugin(analyzePlugin));
traverseBabel(ast, visitorFromPlugin(transformPlugin));

const { code: transformedCode } = generateBabel(ast, {
retainLines: true,
compact: true,
verbatim: true,
});
return transformedCode;
};

return transformSource;
};

const makeCreateStaticRecord = transformSource =>
function createStaticRecord(moduleSource, url) {
// Transform the Module source code.
Expand Down Expand Up @@ -136,13 +97,13 @@ const makeCreateStaticRecord = transformSource =>
};

export const makeModuleAnalyzer = babel => {
const transformSource = makeTransformSource(babel);
const transformSource = makeTransformSource(makeModulePlugins, babel);
const createStaticRecord = makeCreateStaticRecord(transformSource);
return ({ string, url }) => createStaticRecord(string, url);
};

export const makeModuleTransformer = (babel, importer) => {
const transformSource = makeTransformSource(babel);
const transformSource = makeTransformSource(makeModulePlugins, babel);
const createStaticRecord = makeCreateStaticRecord(transformSource);
return {
rewrite(ss) {
Expand Down
39 changes: 39 additions & 0 deletions packages/static-module-record/src/transformSource.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import * as babelParser from '@babel/parser';
import babelGenerate from '@agoric/babel-generator';
import babelTraverse from '@babel/traverse';
import babelTypes from '@babel/types';

const parseBabel = babelParser.default
? babelParser.default.parse
: babelParser.parse || babelParser;

const visitorFromPlugin = plugin => plugin({ types: babelTypes }).visitor;

const traverseBabel = babelTraverse.default || babelTraverse;
const generateBabel = babelGenerate.default || babelGenerate;

export const makeTransformSource = (makeModulePlugins, babel = null) => {
if (babel !== null) {
throw new Error(
`transform-analyze.js no longer allows injecting babel; use \`null\``,
);
}

const transformSource = (code, sourceOptions = {}) => {
const { analyzePlugin, transformPlugin } = makeModulePlugins(sourceOptions);

const ast = parseBabel(code, { sourceType: sourceOptions.sourceType });

traverseBabel(ast, visitorFromPlugin(analyzePlugin));
traverseBabel(ast, visitorFromPlugin(transformPlugin));

const { code: transformedCode } = generateBabel(ast, {
retainLines: true,
compact: true,
verbatim: true,
});
return transformedCode;
};

return transformSource;
};
53 changes: 53 additions & 0 deletions packages/static-module-record/test/benchmark-babel-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Benchmark from 'benchmark';
import fs from 'fs';
import url from 'url';
import { makeTransformSource } from '../src/transformSource.js';
import makeModulePlugins from '../src/babelPlugin.js';

const suite = new Benchmark.Suite();

const resolveLocal = path => url.fileURLToPath(new URL(path, import.meta.url));
const cases = [
{
name: 'small',
fixture: fs.readFileSync(resolveLocal('./fixtures/small.js'), 'utf8'),
},
{
name: 'large',
fixture: fs.readFileSync(resolveLocal('./fixtures/large.js'), 'utf8'),
},
{
name: 'exportheavy',
fixture: fs.readFileSync(resolveLocal('./fixtures/exportheavy.js'), 'utf8'),
},
];

const transformSource = makeTransformSource(makeModulePlugins);
const freshOptions = () => {
return {
sourceType: 'module',
fixedExportMap: Object.create(null),
imports: Object.create(null),
exportAlls: [],
liveExportMap: Object.create(null),
hoistedDecls: [],
importSources: Object.create(null),
importDecls: [],
importMeta: { uttered: false },
};
};

cases.map(testCase =>
suite.add(testCase.name, () => {
transformSource(testCase.fixture, freshOptions());
}),
);

suite
.on('cycle', event => {
console.log(String(event.target));
})
.on('error', event => {
console.log(String(event.target), event.target.error);
})
.run();
55 changes: 55 additions & 0 deletions packages/static-module-record/test/fixtures/exportheavy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/* eslint-disable */
console.error("This is a code sample for trying out babel transforms, it's not meant to be run");

export { mapIterable, filterIterable } from './src/helpers/iter-helpers.js';
export {
PASS_STYLE,
isObject,
assertChecker,
getTag,
hasOwnPropertyOf,
} from './src/helpers/passStyle-helpers.js';

export { getErrorConstructor, toPassableError } from './src/helpers/error.js';
export { getInterfaceOf } from './src/helpers/remotable.js';

export {
nameForPassableSymbol,
passableSymbolForName,
} from './src/helpers/symbol.js';

export { passStyleOf, assertPassable } from './src/passStyleOf.js';

export { deeplyFulfilled } from './src/deeplyFulfilled.js';

export { makeTagged } from './src/makeTagged.js';
export { Remotable, Far, ToFarFunction } from './src/make-far.js';

export { QCLASS, makeMarshal } from './src/marshal.js';
export { stringify, parse } from './src/marshal-stringify.js';
// Works, but not yet used
// export { decodeToJustin } from './src/marshal-justin.js';

export {
assertRecord,
assertCopyArray,
assertRemotable,
isRemotable,
isRecord,
isCopyArray,
} from './src/typeGuards.js';

// eslint-disable-next-line import/export
export * from './src/types.js';


const { details: X } = assert;

// This is a pathological minimum, but exercised by the unit test.
export const MIN_DATA_BUFFER_LENGTH = 1;

// Calculate how big the transfer buffer needs to be.
export const TRANSFER_OVERHEAD_LENGTH =
BigUint64Array.BYTES_PER_ELEMENT + Int32Array.BYTES_PER_ELEMENT;
export const MIN_TRANSFER_BUFFER_LENGTH =
MIN_DATA_BUFFER_LENGTH + TRANSFER_OVERHEAD_LENGTH;
Loading

0 comments on commit aad89d0

Please sign in to comment.