Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: reducing ast node memory overhead #5133

Merged
merged 5 commits into from
Oct 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/ast/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ export const keys: {
Program: ['body']
};

export function getAndCreateKeys(esTreeNode: GenericEsTreeNode): string[] {
keys[esTreeNode.type] = Object.keys(esTreeNode).filter(
export function createKeysForNode(esTreeNode: GenericEsTreeNode): string[] {
return Object.keys(esTreeNode).filter(
key => typeof esTreeNode[key] === 'object' && key.charCodeAt(0) !== 95 /* _ */
);
return keys[esTreeNode.type];
}
2 changes: 1 addition & 1 deletion src/ast/nodes/ArrayExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default class ArrayExpression extends NodeBase {
element.deoptimizePath(UNKNOWN_PATH);
}
}
this.context.requestTreeshakingPass();
this.scope.context.requestTreeshakingPass();
}

private getObjectEntity(): ObjectEntity {
Expand Down
3 changes: 1 addition & 2 deletions src/ast/nodes/ArrowFunctionExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { OBJECT_PROTOTYPE } from './shared/ObjectPrototype';
import type { PatternNode } from './shared/Pattern';

export default class ArrowFunctionExpression extends FunctionBase {
declare async: boolean;
declare body: BlockStatement | ExpressionNode;
declare params: readonly PatternNode[];
declare preventChildBlockScope: true;
Expand All @@ -23,7 +22,7 @@ export default class ArrowFunctionExpression extends FunctionBase {
protected objectEntity: ObjectEntity | null = null;

createScope(parentScope: Scope): void {
this.scope = new ReturnValueScope(parentScope, this.context);
this.scope = new ReturnValueScope(parentScope, this.scope.context);
}

hasEffects(): boolean {
Expand Down
2 changes: 1 addition & 1 deletion src/ast/nodes/AssignmentExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,6 @@ export default class AssignmentExpression extends NodeBase {
this.deoptimized = true;
this.left.deoptimizePath(EMPTY_PATH);
this.right.deoptimizePath(UNKNOWN_PATH);
this.context.requestTreeshakingPass();
this.scope.context.requestTreeshakingPass();
}
}
2 changes: 1 addition & 1 deletion src/ast/nodes/AssignmentPattern.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ export default class AssignmentPattern extends NodeBase implements PatternNode {
this.deoptimized = true;
this.left.deoptimizePath(EMPTY_PATH);
this.right.deoptimizePath(UNKNOWN_PATH);
this.context.requestTreeshakingPass();
this.scope.context.requestTreeshakingPass();
}
}
4 changes: 2 additions & 2 deletions src/ast/nodes/AwaitExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ export default class AwaitExpression extends NodeBase {
if (!this.deoptimized) this.applyDeoptimizations();
if (!this.included) {
this.included = true;
checkTopLevelAwait: if (!this.context.usesTopLevelAwait) {
checkTopLevelAwait: if (!this.scope.context.usesTopLevelAwait) {
let parent = this.parent;
do {
if (parent instanceof FunctionNode || parent instanceof ArrowFunctionExpression)
break checkTopLevelAwait;
} while ((parent = (parent as Node).parent as Node));
this.context.usesTopLevelAwait = true;
this.scope.context.usesTopLevelAwait = true;
}
}
this.argument.include(context, includeChildrenRecursively);
Expand Down
21 changes: 16 additions & 5 deletions src/ast/nodes/BlockStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,29 @@ import { type RenderOptions, renderStatementList } from '../../utils/renderHelpe
import type { HasEffectsContext, InclusionContext } from '../ExecutionContext';
import BlockScope from '../scopes/BlockScope';
import type ChildScope from '../scopes/ChildScope';
import type Scope from '../scopes/Scope';
import ExpressionStatement from './ExpressionStatement';
import * as NodeType from './NodeType';
import { Flag, isFlagSet, setFlag } from './shared/BitFlags';
import { UNKNOWN_EXPRESSION } from './shared/Expression';
import { type IncludeChildren, type Node, StatementBase, type StatementNode } from './shared/Node';

export default class BlockStatement extends StatementBase {
declare body: readonly StatementNode[];
declare type: NodeType.tBlockStatement;

private declare deoptimizeBody: boolean;
private directlyIncluded = false;
private get deoptimizeBody(): boolean {
return isFlagSet(this.flags, Flag.deoptimizeBody);
}
private set deoptimizeBody(value: boolean) {
this.flags = setFlag(this.flags, Flag.deoptimizeBody, value);
}

private get directlyIncluded(): boolean {
return isFlagSet(this.flags, Flag.directlyIncluded);
}
private set directlyIncluded(value: boolean) {
this.flags = setFlag(this.flags, Flag.directlyIncluded, value);
}

addImplicitReturnExpressionToScope(): void {
const lastStatement = this.body[this.body.length - 1];
Expand All @@ -23,10 +34,10 @@ export default class BlockStatement extends StatementBase {
}
}

createScope(parentScope: Scope): void {
createScope(parentScope: ChildScope): void {
this.scope = (this.parent as Node).preventChildBlockScope
? (parentScope as ChildScope)
: new BlockScope(parentScope);
: new BlockScope(parentScope, this.scope.context);
}

hasEffects(context: HasEffectsContext): boolean {
Expand Down
15 changes: 11 additions & 4 deletions src/ast/nodes/CallExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import MemberExpression from './MemberExpression';
import type * as NodeType from './NodeType';
import type SpreadElement from './SpreadElement';
import type Super from './Super';
import { Flag, isFlagSet, setFlag } from './shared/BitFlags';
import CallExpressionBase from './shared/CallExpressionBase';
import { type ExpressionEntity, UNKNOWN_RETURN_EXPRESSION } from './shared/Expression';
import type { ChainElement, ExpressionNode, IncludeChildren } from './shared/Node';
Expand All @@ -24,20 +25,26 @@ export default class CallExpression
{
declare arguments: (ExpressionNode | SpreadElement)[];
declare callee: ExpressionNode | Super;
declare optional: boolean;
declare type: NodeType.tCallExpression;

get optional(): boolean {
return isFlagSet(this.flags, Flag.optional);
}
set optional(value: boolean) {
this.flags = setFlag(this.flags, Flag.optional, value);
}

bind(): void {
super.bind();
if (this.callee instanceof Identifier) {
const variable = this.scope.findVariable(this.callee.name);

if (variable.isNamespace) {
this.context.log(LOGLEVEL_WARN, logCannotCallNamespace(this.callee.name), this.start);
this.scope.context.log(LOGLEVEL_WARN, logCannotCallNamespace(this.callee.name), this.start);
}

if (this.callee.name === 'eval') {
this.context.log(LOGLEVEL_WARN, logEval(this.context.module.id), this.start);
this.scope.context.log(LOGLEVEL_WARN, logEval(this.scope.context.module.id), this.start);
}
}
this.interaction = {
Expand Down Expand Up @@ -114,7 +121,7 @@ export default class CallExpression
EMPTY_PATH,
SHARED_RECURSION_TRACKER
);
this.context.requestTreeshakingPass();
this.scope.context.requestTreeshakingPass();
}

protected getReturnExpression(
Expand Down
8 changes: 4 additions & 4 deletions src/ast/nodes/CatchClause.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import CatchScope from '../scopes/CatchScope';
import type Scope from '../scopes/Scope';
import type ChildScope from '../scopes/ChildScope';
import type BlockStatement from './BlockStatement';
import type * as NodeType from './NodeType';
import { UNKNOWN_EXPRESSION } from './shared/Expression';
Expand All @@ -13,8 +13,8 @@ export default class CatchClause extends NodeBase {
declare scope: CatchScope;
declare type: NodeType.tCatchClause;

createScope(parentScope: Scope): void {
this.scope = new CatchScope(parentScope, this.context);
createScope(parentScope: ChildScope): void {
this.scope = new CatchScope(parentScope, this.scope.context);
}

parseNode(esTreeNode: GenericEsTreeNode): void {
Expand All @@ -23,7 +23,7 @@ export default class CatchClause extends NodeBase {
// name instead of the variable
const { param } = esTreeNode;
if (param) {
(this.param as GenericEsTreeNode) = new (this.context.getNodeConstructor(param.type))(
(this.param as GenericEsTreeNode) = new (this.scope.context.getNodeConstructor(param.type))(
param,
this,
this.scope
Expand Down
11 changes: 6 additions & 5 deletions src/ast/nodes/ClassBody.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { InclusionContext } from '../ExecutionContext';
import type ChildScope from '../scopes/ChildScope';
import ClassBodyScope from '../scopes/ClassBodyScope';
import type Scope from '../scopes/Scope';

import type MethodDefinition from './MethodDefinition';
import type * as NodeType from './NodeType';
import type PropertyDefinition from './PropertyDefinition';
Expand All @@ -12,13 +13,13 @@ export default class ClassBody extends NodeBase {
declare scope: ClassBodyScope;
declare type: NodeType.tClassBody;

createScope(parentScope: Scope): void {
this.scope = new ClassBodyScope(parentScope, this.parent as ClassNode, this.context);
createScope(parentScope: ChildScope): void {
this.scope = new ClassBodyScope(parentScope, this.parent as ClassNode, this.scope.context);
}

include(context: InclusionContext, includeChildrenRecursively: IncludeChildren): void {
this.included = true;
this.context.includeVariableInModule(this.scope.thisVariable);
this.scope.context.includeVariableInModule(this.scope.thisVariable);
for (const definition of this.body) {
definition.include(context, includeChildrenRecursively);
}
Expand All @@ -28,7 +29,7 @@ export default class ClassBody extends NodeBase {
const body: NodeBase[] = (this.body = []);
for (const definition of esTreeNode.body) {
body.push(
new (this.context.getNodeConstructor(definition.type))(
new (this.scope.context.getNodeConstructor(definition.type))(
definition,
this,
definition.static ? this.scope : this.scope.instanceScope
Expand Down
9 changes: 8 additions & 1 deletion src/ast/nodes/ConditionalExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { ObjectPath, PathTracker } from '../utils/PathTracker';
import { EMPTY_PATH, SHARED_RECURSION_TRACKER, UNKNOWN_PATH } from '../utils/PathTracker';
import type * as NodeType from './NodeType';
import type SpreadElement from './SpreadElement';
import { Flag, isFlagSet, setFlag } from './shared/BitFlags';
import type { ExpressionEntity, LiteralValueOrUnknown } from './shared/Expression';
import { UnknownValue } from './shared/Expression';
import { MultiExpression } from './shared/MultiExpression';
Expand All @@ -25,8 +26,14 @@ export default class ConditionalExpression extends NodeBase implements Deoptimiz
declare test: ExpressionNode;
declare type: NodeType.tConditionalExpression;

get isBranchResolutionAnalysed(): boolean {
return isFlagSet(this.flags, Flag.isBranchResolutionAnalysed);
}
set isBranchResolutionAnalysed(value: boolean) {
this.flags = setFlag(this.flags, Flag.isBranchResolutionAnalysed, value);
}

private expressionsToBeDeoptimized: DeoptimizableEntity[] = [];
private isBranchResolutionAnalysed = false;
private usedBranch: ExpressionNode | null = null;

deoptimizeArgumentsOnInteractionAtPath(
Expand Down
2 changes: 1 addition & 1 deletion src/ast/nodes/ExportAllDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class ExportAllDeclaration extends NodeBase {
}

initialise(): void {
this.context.addExport(this);
this.scope.context.addExport(this);
}

render(code: MagicString, _options: RenderOptions, nodeRenderOptions?: NodeRenderOptions): void {
Expand Down
8 changes: 4 additions & 4 deletions src/ast/nodes/ExportDefaultDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default class ExportDefaultDeclaration extends NodeBase {
include(context: InclusionContext, includeChildrenRecursively: IncludeChildren): void {
super.include(context, includeChildrenRecursively);
if (includeChildrenRecursively) {
this.context.includeVariableInModule(this.variable);
this.scope.context.includeVariableInModule(this.variable);
}
}

Expand All @@ -53,11 +53,11 @@ export default class ExportDefaultDeclaration extends NodeBase {
this.declarationName =
(declaration.id && declaration.id.name) || (this.declaration as Identifier).name;
this.variable = this.scope.addExportDefaultDeclaration(
this.declarationName || this.context.getModuleName(),
this.declarationName || this.scope.context.getModuleName(),
this,
this.context
this.scope.context
);
this.context.addExport(this);
this.scope.context.addExport(this);
}

removeAnnotations(code: MagicString) {
Expand Down
2 changes: 1 addition & 1 deletion src/ast/nodes/ExportNamedDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default class ExportNamedDeclaration extends NodeBase {
}

initialise(): void {
this.context.addExport(this);
this.scope.context.addExport(this);
}

removeAnnotations(code: MagicString) {
Expand Down
4 changes: 2 additions & 2 deletions src/ast/nodes/ExpressionStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ export default class ExpressionStatement extends StatementBase {
this.directive !== 'use strict' &&
this.parent.type === NodeType.Program
) {
this.context.log(
this.scope.context.log(
LOGLEVEL_WARN,
// This is necessary, because either way (deleting or not) can lead to errors.
logModuleLevelDirective(this.directive, this.context.module.id),
logModuleLevelDirective(this.directive, this.scope.context.module.id),
this.start
);
}
Expand Down
8 changes: 4 additions & 4 deletions src/ast/nodes/ForInStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type MagicString from 'magic-string';
import { NO_SEMICOLON, type RenderOptions } from '../../utils/renderHelpers';
import type { HasEffectsContext, InclusionContext } from '../ExecutionContext';
import BlockScope from '../scopes/BlockScope';
import type Scope from '../scopes/Scope';
import type ChildScope from '../scopes/ChildScope';
import { EMPTY_PATH } from '../utils/PathTracker';
import type MemberExpression from './MemberExpression';
import type * as NodeType from './NodeType';
Expand All @@ -23,8 +23,8 @@ export default class ForInStatement extends StatementBase {
declare right: ExpressionNode;
declare type: NodeType.tForInStatement;

createScope(parentScope: Scope): void {
this.scope = new BlockScope(parentScope);
createScope(parentScope: ChildScope): void {
this.scope = new BlockScope(parentScope, this.scope.context);
}

hasEffects(context: HasEffectsContext): boolean {
Expand Down Expand Up @@ -60,6 +60,6 @@ export default class ForInStatement extends StatementBase {
protected applyDeoptimizations(): void {
this.deoptimized = true;
this.left.deoptimizePath(EMPTY_PATH);
this.context.requestTreeshakingPass();
this.scope.context.requestTreeshakingPass();
}
}
17 changes: 12 additions & 5 deletions src/ast/nodes/ForOfStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
import { NO_SEMICOLON, type RenderOptions } from '../../utils/renderHelpers';
import type { InclusionContext } from '../ExecutionContext';
import BlockScope from '../scopes/BlockScope';
import type Scope from '../scopes/Scope';
import type ChildScope from '../scopes/ChildScope';
import { EMPTY_PATH, UNKNOWN_PATH } from '../utils/PathTracker';
import type MemberExpression from './MemberExpression';
import type * as NodeType from './NodeType';
import type VariableDeclaration from './VariableDeclaration';
import { Flag, isFlagSet, setFlag } from './shared/BitFlags';
import { UNKNOWN_EXPRESSION } from './shared/Expression';
import {
type ExpressionNode,
Expand All @@ -18,14 +19,20 @@
import { includeLoopBody } from './shared/loops';

export default class ForOfStatement extends StatementBase {
declare await: boolean;
declare body: StatementNode;
declare left: VariableDeclaration | PatternNode | MemberExpression;
declare right: ExpressionNode;
declare type: NodeType.tForOfStatement;

createScope(parentScope: Scope): void {
this.scope = new BlockScope(parentScope);
get await(): boolean {
thebanjomatic marked this conversation as resolved.
Show resolved Hide resolved
return isFlagSet(this.flags, Flag.await);

Check warning on line 28 in src/ast/nodes/ForOfStatement.ts

View check run for this annotation

Codecov / codecov/patch

src/ast/nodes/ForOfStatement.ts#L28

Added line #L28 was not covered by tests
}
set await(value: boolean) {
this.flags = setFlag(this.flags, Flag.await, value);
}

createScope(parentScope: ChildScope): void {
this.scope = new BlockScope(parentScope, this.scope.context);
}

hasEffects(): boolean {
Expand Down Expand Up @@ -61,6 +68,6 @@
this.deoptimized = true;
this.left.deoptimizePath(EMPTY_PATH);
this.right.deoptimizePath(UNKNOWN_PATH);
this.context.requestTreeshakingPass();
this.scope.context.requestTreeshakingPass();
}
}
6 changes: 3 additions & 3 deletions src/ast/nodes/ForStatement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type MagicString from 'magic-string';
import { NO_SEMICOLON, type RenderOptions } from '../../utils/renderHelpers';
import type { HasEffectsContext, InclusionContext } from '../ExecutionContext';
import BlockScope from '../scopes/BlockScope';
import type Scope from '../scopes/Scope';
import type ChildScope from '../scopes/ChildScope';
import type * as NodeType from './NodeType';
import type VariableDeclaration from './VariableDeclaration';
import {
Expand All @@ -20,8 +20,8 @@ export default class ForStatement extends StatementBase {
declare type: NodeType.tForStatement;
declare update: ExpressionNode | null;

createScope(parentScope: Scope): void {
this.scope = new BlockScope(parentScope);
createScope(parentScope: ChildScope): void {
this.scope = new BlockScope(parentScope, this.scope.context);
}

hasEffects(context: HasEffectsContext): boolean {
Expand Down