Merge pull request #3393 from babel/cache
Move NodePath cache out of the AST
This commit is contained in:
commit
60d773f370
7
packages/babel-traverse/src/cache.js
Normal file
7
packages/babel-traverse/src/cache.js
Normal file
@ -0,0 +1,7 @@
|
||||
export let path = new WeakMap();
|
||||
export let scope = new WeakMap();
|
||||
|
||||
export function clear() {
|
||||
path = new WeakMap();
|
||||
scope = new WeakMap();
|
||||
}
|
||||
@ -5,6 +5,7 @@ import * as visitors from "./visitors";
|
||||
import * as messages from "babel-messages";
|
||||
import includes from "lodash/collection/includes";
|
||||
import * as t from "babel-types";
|
||||
import * as cache from "./cache";
|
||||
|
||||
export { default as NodePath } from "./path";
|
||||
export { default as Scope } from "./scope";
|
||||
@ -87,6 +88,8 @@ traverse.clearNode = function (node) {
|
||||
if (key[0] === "_" && node[key] != null) node[key] = undefined;
|
||||
}
|
||||
|
||||
cache.path.delete(node);
|
||||
|
||||
let syms: Array<Symbol> = Object.getOwnPropertySymbols(node);
|
||||
for (let sym of syms) {
|
||||
node[sym] = null;
|
||||
@ -124,3 +127,13 @@ traverse.hasType = function (tree: Object, scope: Object, type: Object, blacklis
|
||||
|
||||
return state.has;
|
||||
};
|
||||
|
||||
traverse.clearCache = function() {
|
||||
cache.clear();
|
||||
};
|
||||
|
||||
traverse.copyCache = function(source, destination) {
|
||||
if (cache.path.has(source)) {
|
||||
cache.path.set(destination, cache.path.get(source));
|
||||
}
|
||||
};
|
||||
|
||||
@ -1 +0,0 @@
|
||||
export const PATH_CACHE_KEY = "_paths"; //Symbol();
|
||||
@ -4,12 +4,12 @@ import type Hub from "../hub";
|
||||
import type TraversalContext from "../context";
|
||||
import * as virtualTypes from "./lib/virtual-types";
|
||||
import buildDebug from "debug";
|
||||
import { PATH_CACHE_KEY } from "./constants";
|
||||
import invariant from "invariant";
|
||||
import traverse from "../index";
|
||||
import assign from "lodash/object/assign";
|
||||
import Scope from "../scope";
|
||||
import * as t from "babel-types";
|
||||
import { path as pathCache } from "../cache";
|
||||
|
||||
let debug = buildDebug("babel");
|
||||
|
||||
@ -69,7 +69,11 @@ export default class NodePath {
|
||||
|
||||
let targetNode = container[key];
|
||||
|
||||
let paths = parent[PATH_CACHE_KEY] = parent[PATH_CACHE_KEY] || [];
|
||||
let paths = pathCache.get(parent) || [];
|
||||
if (!pathCache.has(parent)) {
|
||||
pathCache.set(parent, paths);
|
||||
}
|
||||
|
||||
let path;
|
||||
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/* eslint max-len: 0 */
|
||||
// This file contains methods that modify the path/node in some ways.
|
||||
|
||||
import { PATH_CACHE_KEY } from "./constants";
|
||||
import { path as pathCache } from "../cache";
|
||||
import PathHoister from "./lib/hoister";
|
||||
import NodePath from "./index";
|
||||
import * as t from "babel-types";
|
||||
@ -136,7 +136,7 @@ export function insertAfter(nodes) {
|
||||
export function updateSiblingKeys(fromIndex, incrementBy) {
|
||||
if (!this.parent) return;
|
||||
|
||||
let paths = this.parent[PATH_CACHE_KEY];
|
||||
let paths = pathCache.get(this.parent);
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
let path = paths[i];
|
||||
if (path.key >= fromIndex) {
|
||||
|
||||
@ -10,59 +10,25 @@ import * as messages from "babel-messages";
|
||||
import Binding from "./binding";
|
||||
import globals from "globals";
|
||||
import * as t from "babel-types";
|
||||
|
||||
//
|
||||
|
||||
const CACHE_SINGLE_KEY = Symbol();
|
||||
const CACHE_MULTIPLE_KEY = Symbol();
|
||||
import { scope as scopeCache } from "../cache";
|
||||
|
||||
/**
|
||||
* To avoid creating a new Scope instance for each traversal, we maintain a cache on the
|
||||
* node itself containing all scopes it has been associated with.
|
||||
*
|
||||
* We also optimise for the case of there being only a single scope associated with a node.
|
||||
*/
|
||||
|
||||
function getCache(node, parentScope, self) {
|
||||
let singleCache = node[CACHE_SINGLE_KEY];
|
||||
let scopes: Array<Scope> = scopeCache.get(node) || [];
|
||||
|
||||
if (singleCache) {
|
||||
// we've only ever associated one scope with this node so let's check it
|
||||
if (matchesParent(singleCache, parentScope)) {
|
||||
return singleCache;
|
||||
}
|
||||
} else if (!node[CACHE_MULTIPLE_KEY]) {
|
||||
// no scope has ever been associated with this node
|
||||
node[CACHE_SINGLE_KEY] = self;
|
||||
return;
|
||||
}
|
||||
|
||||
// looks like we have either a single scope association that was never matched or
|
||||
// multiple assocations, let's find the right one!
|
||||
return getCacheMultiple(node, parentScope, self, singleCache);
|
||||
}
|
||||
|
||||
function matchesParent(scope, parentScope) {
|
||||
if (scope.parent === parentScope) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function getCacheMultiple(node, parentScope, self, singleCache) {
|
||||
let scopes: Array<Scope> = node[CACHE_MULTIPLE_KEY] = node[CACHE_MULTIPLE_KEY] || [];
|
||||
|
||||
if (singleCache) {
|
||||
// we have a scope assocation miss so push it onto our scopes
|
||||
scopes.push(singleCache);
|
||||
node[CACHE_SINGLE_KEY] = null;
|
||||
}
|
||||
|
||||
// loop through and check each scope to see if it matches our parent
|
||||
for (let scope of scopes) {
|
||||
if (matchesParent(scope, parentScope)) return scope;
|
||||
if (scope.parent === parentScope) return scope;
|
||||
}
|
||||
|
||||
scopes.push(self);
|
||||
|
||||
if (!scopeCache.has(node)) {
|
||||
scopeCache.set(node, scopes);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@ -123,4 +123,26 @@ suite("traverse", function () {
|
||||
|
||||
assert.ok(!traverse.hasType(ast, null, "ArrowFunctionExpression"));
|
||||
});
|
||||
|
||||
test("clearCache", function () {
|
||||
var paths = [];
|
||||
traverse(ast, {
|
||||
enter: function (path) {
|
||||
paths.push(path);
|
||||
}
|
||||
});
|
||||
|
||||
traverse.clearCache();
|
||||
|
||||
var paths2 = [];
|
||||
traverse(ast, {
|
||||
enter: function (path) {
|
||||
paths2.push(path);
|
||||
}
|
||||
});
|
||||
|
||||
paths2.forEach(function (p, i) {
|
||||
assert.notStrictEqual(p, paths[i]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -372,6 +372,12 @@ function _inheritComments(key, child, parent) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Can't use import because of cyclic dependency between babel-traverse
|
||||
// and this module (babel-types). This require needs to appear after
|
||||
// we export the TYPES constant.
|
||||
const traverse = require("babel-traverse").default;
|
||||
|
||||
/**
|
||||
* Inherit all contextual properties from `parent` node to `child` node.
|
||||
*/
|
||||
@ -397,6 +403,7 @@ export function inherits(child: Object, parent: Object): Object {
|
||||
}
|
||||
|
||||
t.inheritsComments(child, parent);
|
||||
traverse.copyCache(parent, child);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user