Traverse performance (#10480)
* perf: remove this.inList assignment * perf: convert NodePath.parentKey into accessor function * perf: compress shouldSkip/shouldStop/removed traverse flags * perf: lazy initialize this.skipKeys * perf: lazily initialize NodePath.data * add code comments before bit operations * remove unused typeAnnotation property # Conflicts: # packages/babel-traverse/src/path/index.js * early return when visitor keys are empty
This commit is contained in:
parent
e9c1bce50f
commit
b114486bc1
@ -31,6 +31,10 @@ export default function traverse(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!t.VISITOR_KEYS[parent.type]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
visitors.explode(opts);
|
visitors.explode(opts);
|
||||||
|
|
||||||
traverse.node(parent, opts, scope, state, parentPath);
|
traverse.node(parent, opts, scope, state, parentPath);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
// This file contains methods responsible for maintaining a TraversalContext.
|
// This file contains methods responsible for maintaining a TraversalContext.
|
||||||
|
|
||||||
import traverse from "../index";
|
import traverse from "../index";
|
||||||
|
import { SHOULD_SKIP, SHOULD_STOP } from "./index";
|
||||||
|
|
||||||
export function call(key): boolean {
|
export function call(key): boolean {
|
||||||
const opts = this.opts;
|
const opts = this.opts;
|
||||||
@ -43,7 +44,8 @@ export function _call(fns?: Array<Function>): boolean {
|
|||||||
// node has been replaced, it will have been requeued
|
// node has been replaced, it will have been requeued
|
||||||
if (this.node !== node) return true;
|
if (this.node !== node) return true;
|
||||||
|
|
||||||
if (this.shouldStop || this.shouldSkip || this.removed) return true;
|
// this.shouldSkip || this.shouldStop || this.removed
|
||||||
|
if (this._traverseFlags > 0) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -97,12 +99,15 @@ export function skip() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function skipKey(key) {
|
export function skipKey(key) {
|
||||||
|
if (this.skipKeys == null) {
|
||||||
|
this.skipKeys = {};
|
||||||
|
}
|
||||||
this.skipKeys[key] = true;
|
this.skipKeys[key] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function stop() {
|
export function stop() {
|
||||||
this.shouldStop = true;
|
// this.shouldSkip = true; this.shouldStop = true;
|
||||||
this.shouldSkip = true;
|
this._traverseFlags |= SHOULD_SKIP | SHOULD_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setScope() {
|
export function setScope() {
|
||||||
@ -122,10 +127,11 @@ export function setScope() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function setContext(context) {
|
export function setContext(context) {
|
||||||
this.shouldSkip = false;
|
if (this.skipKeys != null) {
|
||||||
this.shouldStop = false;
|
|
||||||
this.removed = false;
|
|
||||||
this.skipKeys = {};
|
this.skipKeys = {};
|
||||||
|
}
|
||||||
|
// this.shouldSkip = false; this.shouldStop = false; this.removed = false;
|
||||||
|
this._traverseFlags = 0;
|
||||||
|
|
||||||
if (context) {
|
if (context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@ -220,9 +226,7 @@ export function pushContext(context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function setup(parentPath, container, listKey, key) {
|
export function setup(parentPath, container, listKey, key) {
|
||||||
this.inList = !!listKey;
|
|
||||||
this.listKey = listKey;
|
this.listKey = listKey;
|
||||||
this.parentKey = listKey || key;
|
|
||||||
this.container = container;
|
this.container = container;
|
||||||
|
|
||||||
this.parentPath = parentPath || this.parentPath;
|
this.parentPath = parentPath || this.parentPath;
|
||||||
|
|||||||
@ -23,15 +23,18 @@ import * as NodePath_comments from "./comments";
|
|||||||
|
|
||||||
const debug = buildDebug("babel");
|
const debug = buildDebug("babel");
|
||||||
|
|
||||||
|
export const REMOVED = 1 << 0;
|
||||||
|
export const SHOULD_STOP = 1 << 1;
|
||||||
|
export const SHOULD_SKIP = 1 << 2;
|
||||||
|
|
||||||
export default class NodePath {
|
export default class NodePath {
|
||||||
constructor(hub: HubInterface, parent: Object) {
|
constructor(hub: HubInterface, parent: Object) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.hub = hub;
|
this.hub = hub;
|
||||||
this.contexts = [];
|
this.contexts = [];
|
||||||
this.data = Object.create(null);
|
this.data = null;
|
||||||
this.shouldSkip = false;
|
// this.shouldSkip = false; this.shouldStop = false; this.removed = false;
|
||||||
this.shouldStop = false;
|
this._traverseFlags = 0;
|
||||||
this.removed = false;
|
|
||||||
this.state = null;
|
this.state = null;
|
||||||
this.opts = null;
|
this.opts = null;
|
||||||
this.skipKeys = null;
|
this.skipKeys = null;
|
||||||
@ -39,13 +42,10 @@ export default class NodePath {
|
|||||||
this.context = null;
|
this.context = null;
|
||||||
this.container = null;
|
this.container = null;
|
||||||
this.listKey = null;
|
this.listKey = null;
|
||||||
this.inList = false;
|
|
||||||
this.parentKey = null;
|
|
||||||
this.key = null;
|
this.key = null;
|
||||||
this.node = null;
|
this.node = null;
|
||||||
this.scope = null;
|
this.scope = null;
|
||||||
this.type = null;
|
this.type = null;
|
||||||
this.typeAnnotation = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parent: Object;
|
parent: Object;
|
||||||
@ -57,18 +57,16 @@ export default class NodePath {
|
|||||||
removed: boolean;
|
removed: boolean;
|
||||||
state: any;
|
state: any;
|
||||||
opts: ?Object;
|
opts: ?Object;
|
||||||
|
_traverseFlags: number;
|
||||||
skipKeys: ?Object;
|
skipKeys: ?Object;
|
||||||
parentPath: ?NodePath;
|
parentPath: ?NodePath;
|
||||||
context: TraversalContext;
|
context: TraversalContext;
|
||||||
container: ?Object | Array<Object>;
|
container: ?Object | Array<Object>;
|
||||||
listKey: ?string;
|
listKey: ?string;
|
||||||
inList: boolean;
|
|
||||||
parentKey: ?string;
|
|
||||||
key: ?string;
|
key: ?string;
|
||||||
node: ?Object;
|
node: ?Object;
|
||||||
scope: Scope;
|
scope: Scope;
|
||||||
type: ?string;
|
type: ?string;
|
||||||
typeAnnotation: ?Object;
|
|
||||||
|
|
||||||
static get({ hub, parentPath, parent, container, listKey, key }): NodePath {
|
static get({ hub, parentPath, parent, container, listKey, key }): NodePath {
|
||||||
if (!hub && parentPath) {
|
if (!hub && parentPath) {
|
||||||
@ -111,10 +109,16 @@ export default class NodePath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setData(key: string, val: any): any {
|
setData(key: string, val: any): any {
|
||||||
|
if (this.data == null) {
|
||||||
|
this.data = Object.create(null);
|
||||||
|
}
|
||||||
return (this.data[key] = val);
|
return (this.data[key] = val);
|
||||||
}
|
}
|
||||||
|
|
||||||
getData(key: string, def?: any): any {
|
getData(key: string, def?: any): any {
|
||||||
|
if (this.data == null) {
|
||||||
|
this.data = Object.create(null);
|
||||||
|
}
|
||||||
let val = this.data[key];
|
let val = this.data[key];
|
||||||
if (val === undefined && def !== undefined) val = this.data[key] = def;
|
if (val === undefined && def !== undefined) val = this.data[key] = def;
|
||||||
return val;
|
return val;
|
||||||
@ -152,6 +156,49 @@ export default class NodePath {
|
|||||||
toString() {
|
toString() {
|
||||||
return generator(this.node).code;
|
return generator(this.node).code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get inList() {
|
||||||
|
return !!this.listKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
get parentKey() {
|
||||||
|
return this.listKey || this.key;
|
||||||
|
}
|
||||||
|
|
||||||
|
get shouldSkip() {
|
||||||
|
return !!(this._traverseFlags & SHOULD_SKIP);
|
||||||
|
}
|
||||||
|
|
||||||
|
set shouldSkip(v) {
|
||||||
|
if (v) {
|
||||||
|
this._traverseFlags |= SHOULD_SKIP;
|
||||||
|
} else {
|
||||||
|
this._traverseFlags &= ~SHOULD_SKIP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get shouldStop() {
|
||||||
|
return !!(this._traverseFlags & SHOULD_STOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
set shouldStop(v) {
|
||||||
|
if (v) {
|
||||||
|
this._traverseFlags |= SHOULD_STOP;
|
||||||
|
} else {
|
||||||
|
this._traverseFlags &= ~SHOULD_STOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get removed() {
|
||||||
|
return !!(this._traverseFlags & REMOVED);
|
||||||
|
}
|
||||||
|
set removed(v) {
|
||||||
|
if (v) {
|
||||||
|
this._traverseFlags |= REMOVED;
|
||||||
|
} else {
|
||||||
|
this._traverseFlags &= ~REMOVED;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(
|
Object.assign(
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
// This file contains methods responsible for removing a node.
|
// This file contains methods responsible for removing a node.
|
||||||
|
|
||||||
import { hooks } from "./lib/removal-hooks";
|
import { hooks } from "./lib/removal-hooks";
|
||||||
|
import { REMOVED, SHOULD_SKIP } from "./index";
|
||||||
|
|
||||||
export function remove() {
|
export function remove() {
|
||||||
this._assertUnremoved();
|
this._assertUnremoved();
|
||||||
@ -39,8 +40,8 @@ export function _remove() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function _markRemoved() {
|
export function _markRemoved() {
|
||||||
this.shouldSkip = true;
|
// this.shouldSkip = true; this.removed = true;
|
||||||
this.removed = true;
|
this._traverseFlags |= SHOULD_SKIP | REMOVED;
|
||||||
this.node = null;
|
this.node = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user