Skip to content

Commit

Permalink
Traverse performance (#10480)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
JLHwung authored and nicolo-ribaudo committed Nov 5, 2019
1 parent e9c1bce commit b114486
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 21 deletions.
4 changes: 4 additions & 0 deletions packages/babel-traverse/src/index.js
Expand Up @@ -31,6 +31,10 @@ export default function traverse(
}
}

if (!t.VISITOR_KEYS[parent.type]) {
return;
}

visitors.explode(opts);

traverse.node(parent, opts, scope, state, parentPath);
Expand Down
22 changes: 13 additions & 9 deletions packages/babel-traverse/src/path/context.js
@@ -1,6 +1,7 @@
// This file contains methods responsible for maintaining a TraversalContext.

import traverse from "../index";
import { SHOULD_SKIP, SHOULD_STOP } from "./index";

export function call(key): boolean {
const opts = this.opts;
Expand Down Expand Up @@ -43,7 +44,8 @@ export function _call(fns?: Array<Function>): boolean {
// node has been replaced, it will have been requeued
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;
Expand Down Expand Up @@ -97,12 +99,15 @@ export function skip() {
}

export function skipKey(key) {
if (this.skipKeys == null) {
this.skipKeys = {};
}
this.skipKeys[key] = true;
}

export function stop() {
this.shouldStop = true;
this.shouldSkip = true;
// this.shouldSkip = true; this.shouldStop = true;
this._traverseFlags |= SHOULD_SKIP | SHOULD_STOP;
}

export function setScope() {
Expand All @@ -122,10 +127,11 @@ export function setScope() {
}

export function setContext(context) {
this.shouldSkip = false;
this.shouldStop = false;
this.removed = false;
this.skipKeys = {};
if (this.skipKeys != null) {
this.skipKeys = {};
}
// this.shouldSkip = false; this.shouldStop = false; this.removed = false;
this._traverseFlags = 0;

if (context) {
this.context = context;
Expand Down Expand Up @@ -220,9 +226,7 @@ export function pushContext(context) {
}

export function setup(parentPath, container, listKey, key) {
this.inList = !!listKey;
this.listKey = listKey;
this.parentKey = listKey || key;
this.container = container;

this.parentPath = parentPath || this.parentPath;
Expand Down
67 changes: 57 additions & 10 deletions packages/babel-traverse/src/path/index.js
Expand Up @@ -23,29 +23,29 @@ import * as NodePath_comments from "./comments";

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 {
constructor(hub: HubInterface, parent: Object) {
this.parent = parent;
this.hub = hub;
this.contexts = [];
this.data = Object.create(null);
this.shouldSkip = false;
this.shouldStop = false;
this.removed = false;
this.data = null;
// this.shouldSkip = false; this.shouldStop = false; this.removed = false;
this._traverseFlags = 0;
this.state = null;
this.opts = null;
this.skipKeys = null;
this.parentPath = null;
this.context = null;
this.container = null;
this.listKey = null;
this.inList = false;
this.parentKey = null;
this.key = null;
this.node = null;
this.scope = null;
this.type = null;
this.typeAnnotation = null;
}

parent: Object;
Expand All @@ -57,18 +57,16 @@ export default class NodePath {
removed: boolean;
state: any;
opts: ?Object;
_traverseFlags: number;
skipKeys: ?Object;
parentPath: ?NodePath;
context: TraversalContext;
container: ?Object | Array<Object>;
listKey: ?string;
inList: boolean;
parentKey: ?string;
key: ?string;
node: ?Object;
scope: Scope;
type: ?string;
typeAnnotation: ?Object;

static get({ hub, parentPath, parent, container, listKey, key }): NodePath {
if (!hub && parentPath) {
Expand Down Expand Up @@ -111,10 +109,16 @@ export default class NodePath {
}

setData(key: string, val: any): any {
if (this.data == null) {
this.data = Object.create(null);
}
return (this.data[key] = val);
}

getData(key: string, def?: any): any {
if (this.data == null) {
this.data = Object.create(null);
}
let val = this.data[key];
if (val === undefined && def !== undefined) val = this.data[key] = def;
return val;
Expand Down Expand Up @@ -152,6 +156,49 @@ export default class NodePath {
toString() {
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(
Expand Down
5 changes: 3 additions & 2 deletions packages/babel-traverse/src/path/removal.js
@@ -1,6 +1,7 @@
// This file contains methods responsible for removing a node.

import { hooks } from "./lib/removal-hooks";
import { REMOVED, SHOULD_SKIP } from "./index";

export function remove() {
this._assertUnremoved();
Expand Down Expand Up @@ -39,8 +40,8 @@ export function _remove() {
}

export function _markRemoved() {
this.shouldSkip = true;
this.removed = true;
// this.shouldSkip = true; this.removed = true;
this._traverseFlags |= SHOULD_SKIP | REMOVED;
this.node = null;
}

Expand Down

0 comments on commit b114486

Please sign in to comment.