Skip to content

Commit

Permalink
Add pureness flag to return expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Nov 22, 2022
1 parent 865c3c5 commit 8daf05e
Show file tree
Hide file tree
Showing 22 changed files with 161 additions and 105 deletions.
2 changes: 1 addition & 1 deletion src/ast/nodes/ArrayExpression.ts
Expand Up @@ -49,7 +49,7 @@ export default class ArrayExpression extends NodeBase {
interaction: NodeInteractionCalled,
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): ExpressionEntity {
): [expression: ExpressionEntity, isPure: boolean] {
return this.getObjectEntity().getReturnExpressionWhenCalledAtPath(
path,
interaction,
Expand Down
6 changes: 3 additions & 3 deletions src/ast/nodes/CallExpression.ts
Expand Up @@ -20,7 +20,7 @@ import type * as NodeType from './NodeType';
import type SpreadElement from './SpreadElement';
import type Super from './Super';
import CallExpressionBase from './shared/CallExpressionBase';
import { type ExpressionEntity, UNKNOWN_EXPRESSION } from './shared/Expression';
import { type ExpressionEntity, UNKNOWN_RETURN_EXPRESSION } from './shared/Expression';
import { type ExpressionNode, INCLUDE_PARAMETERS, type IncludeChildren } from './shared/Node';

export default class CallExpression extends CallExpressionBase implements DeoptimizableEntity {
Expand Down Expand Up @@ -120,9 +120,9 @@ export default class CallExpression extends CallExpressionBase implements Deopti

protected getReturnExpression(
recursionTracker: PathTracker = SHARED_RECURSION_TRACKER
): ExpressionEntity {
): [expression: ExpressionEntity, isPure: boolean] {
if (this.returnExpression === null) {
this.returnExpression = UNKNOWN_EXPRESSION;
this.returnExpression = UNKNOWN_RETURN_EXPRESSION;
return (this.returnExpression = this.callee.getReturnExpressionWhenCalledAtPath(
EMPTY_PATH,
this.interaction,
Expand Down
33 changes: 18 additions & 15 deletions src/ast/nodes/ConditionalExpression.ts
Expand Up @@ -80,23 +80,26 @@ export default class ConditionalExpression extends NodeBase implements Deoptimiz
interaction: NodeInteractionCalled,
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): ExpressionEntity {
): [expression: ExpressionEntity, isPure: boolean] {
const usedBranch = this.getUsedBranch();
if (!usedBranch)
return new MultiExpression([
this.consequent.getReturnExpressionWhenCalledAtPath(
path,
interaction,
recursionTracker,
origin
),
this.alternate.getReturnExpressionWhenCalledAtPath(
path,
interaction,
recursionTracker,
origin
)
]);
return [
new MultiExpression([
this.consequent.getReturnExpressionWhenCalledAtPath(
path,
interaction,
recursionTracker,
origin
)[0],
this.alternate.getReturnExpressionWhenCalledAtPath(
path,
interaction,
recursionTracker,
origin
)[0]
]),
false
];
this.expressionsToBeDeoptimized.push(origin);
return usedBranch.getReturnExpressionWhenCalledAtPath(
path,
Expand Down
2 changes: 1 addition & 1 deletion src/ast/nodes/Identifier.ts
Expand Up @@ -132,7 +132,7 @@ export default class Identifier extends NodeBase implements PatternNode {
interaction: NodeInteractionCalled,
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): ExpressionEntity {
): [expression: ExpressionEntity, isPure: boolean] {
return this.getVariableRespectingTDZ()!.getReturnExpressionWhenCalledAtPath(
path,
interaction,
Expand Down
8 changes: 5 additions & 3 deletions src/ast/nodes/Literal.ts
Expand Up @@ -17,7 +17,7 @@ import type * as NodeType from './NodeType';
import {
type ExpressionEntity,
type LiteralValueOrUnknown,
UNKNOWN_EXPRESSION,
UNKNOWN_RETURN_EXPRESSION,
UnknownValue
} from './shared/Expression';
import { type GenericEsTreeNode, NodeBase } from './shared/Node';
Expand Down Expand Up @@ -50,8 +50,10 @@ export default class Literal<T extends LiteralValue = LiteralValue> extends Node
return this.value;
}

getReturnExpressionWhenCalledAtPath(path: ObjectPath): ExpressionEntity {
if (path.length !== 1) return UNKNOWN_EXPRESSION;
getReturnExpressionWhenCalledAtPath(
path: ObjectPath
): [expression: ExpressionEntity, isPure: boolean] {
if (path.length !== 1) return UNKNOWN_RETURN_EXPRESSION;
return getMemberReturnExpressionWhenCalled(this.members, path[0]);
}

Expand Down
23 changes: 18 additions & 5 deletions src/ast/nodes/LogicalExpression.ts
Expand Up @@ -93,13 +93,26 @@ export default class LogicalExpression extends NodeBase implements Deoptimizable
interaction: NodeInteractionCalled,
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): ExpressionEntity {
): [expression: ExpressionEntity, isPure: boolean] {
const usedBranch = this.getUsedBranch();
if (!usedBranch)
return new MultiExpression([
this.left.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin),
this.right.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)
]);
return [
new MultiExpression([
this.left.getReturnExpressionWhenCalledAtPath(
path,
interaction,
recursionTracker,
origin
)[0],
this.right.getReturnExpressionWhenCalledAtPath(
path,
interaction,
recursionTracker,
origin
)[0]
]),
false
];
this.expressionsToBeDeoptimized.push(origin);
return usedBranch.getReturnExpressionWhenCalledAtPath(
path,
Expand Down
8 changes: 4 additions & 4 deletions src/ast/nodes/MemberExpression.ts
Expand Up @@ -38,7 +38,7 @@ import type Super from './Super';
import {
type ExpressionEntity,
type LiteralValueOrUnknown,
UNKNOWN_EXPRESSION,
UNKNOWN_RETURN_EXPRESSION,
UnknownValue
} from './shared/Expression';
import { type ExpressionNode, type IncludeChildren, NodeBase } from './shared/Node';
Expand Down Expand Up @@ -197,7 +197,7 @@ export default class MemberExpression extends NodeBase implements DeoptimizableE
interaction: NodeInteractionCalled,
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): ExpressionEntity {
): [expression: ExpressionEntity, isPure: boolean] {
if (this.variable) {
return this.variable.getReturnExpressionWhenCalledAtPath(
path,
Expand All @@ -207,7 +207,7 @@ export default class MemberExpression extends NodeBase implements DeoptimizableE
);
}
if (this.isUndefined) {
return UNDEFINED_EXPRESSION;
return [UNDEFINED_EXPRESSION, false];
}
this.expressionsToBeDeoptimized.push(origin);
if (path.length < MAX_PATH_DEPTH) {
Expand All @@ -218,7 +218,7 @@ export default class MemberExpression extends NodeBase implements DeoptimizableE
origin
);
}
return UNKNOWN_EXPRESSION;
return UNKNOWN_RETURN_EXPRESSION;
}

hasEffects(context: HasEffectsContext): boolean {
Expand Down
2 changes: 1 addition & 1 deletion src/ast/nodes/ObjectExpression.ts
Expand Up @@ -59,7 +59,7 @@ export default class ObjectExpression extends NodeBase implements DeoptimizableE
interaction: NodeInteractionCalled,
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): ExpressionEntity {
): [expression: ExpressionEntity, isPure: boolean] {
return this.getObjectEntity().getReturnExpressionWhenCalledAtPath(
path,
interaction,
Expand Down
6 changes: 3 additions & 3 deletions src/ast/nodes/PropertyDefinition.ts
Expand Up @@ -11,7 +11,7 @@ import type PrivateIdentifier from './PrivateIdentifier';
import {
type ExpressionEntity,
type LiteralValueOrUnknown,
UNKNOWN_EXPRESSION,
UNKNOWN_RETURN_EXPRESSION,
UnknownValue
} from './shared/Expression';
import { type ExpressionNode, NodeBase } from './shared/Node';
Expand Down Expand Up @@ -50,10 +50,10 @@ export default class PropertyDefinition extends NodeBase {
interaction: NodeInteractionCalled,
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): ExpressionEntity {
): [expression: ExpressionEntity, isPure: boolean] {
return this.value
? this.value.getReturnExpressionWhenCalledAtPath(path, interaction, recursionTracker, origin)
: UNKNOWN_EXPRESSION;
: UNKNOWN_RETURN_EXPRESSION;
}

hasEffects(context: HasEffectsContext): boolean {
Expand Down
8 changes: 4 additions & 4 deletions src/ast/nodes/TaggedTemplateExpression.ts
Expand Up @@ -12,7 +12,7 @@ import * as NodeType from './NodeType';
import type TemplateLiteral from './TemplateLiteral';
import CallExpressionBase from './shared/CallExpressionBase';
import type { ExpressionEntity } from './shared/Expression';
import { UNKNOWN_EXPRESSION } from './shared/Expression';
import { UNKNOWN_EXPRESSION, UNKNOWN_RETURN_EXPRESSION } from './shared/Expression';
import type { ExpressionNode, IncludeChildren } from './shared/Node';

export default class TaggedTemplateExpression extends CallExpressionBase {
Expand Down Expand Up @@ -56,7 +56,7 @@ export default class TaggedTemplateExpression extends CallExpressionBase {
this.quasi.include(context, includeChildrenRecursively);
}
this.tag.includeCallArguments(context, this.interaction.args);
const returnExpression = this.getReturnExpression();
const [returnExpression] = this.getReturnExpression();
if (!returnExpression.included) {
returnExpression.include(context, false);
}
Expand Down Expand Up @@ -94,9 +94,9 @@ export default class TaggedTemplateExpression extends CallExpressionBase {

protected getReturnExpression(
recursionTracker: PathTracker = SHARED_RECURSION_TRACKER
): ExpressionEntity {
): [expression: ExpressionEntity, isPure: boolean] {
if (this.returnExpression === null) {
this.returnExpression = UNKNOWN_EXPRESSION;
this.returnExpression = UNKNOWN_RETURN_EXPRESSION;
return (this.returnExpression = this.tag.getReturnExpressionWhenCalledAtPath(
EMPTY_PATH,
this.interaction,
Expand Down
8 changes: 5 additions & 3 deletions src/ast/nodes/TemplateLiteral.ts
Expand Up @@ -12,7 +12,7 @@ import {
import type * as NodeType from './NodeType';
import type TemplateElement from './TemplateElement';
import type { ExpressionEntity, LiteralValueOrUnknown } from './shared/Expression';
import { UNKNOWN_EXPRESSION, UnknownValue } from './shared/Expression';
import { UNKNOWN_RETURN_EXPRESSION, UnknownValue } from './shared/Expression';
import { type ExpressionNode, NodeBase } from './shared/Node';

export default class TemplateLiteral extends NodeBase {
Expand All @@ -29,9 +29,11 @@ export default class TemplateLiteral extends NodeBase {
return this.quasis[0].value.cooked;
}

getReturnExpressionWhenCalledAtPath(path: ObjectPath): ExpressionEntity {
getReturnExpressionWhenCalledAtPath(
path: ObjectPath
): [expression: ExpressionEntity, isPure: boolean] {
if (path.length !== 1) {
return UNKNOWN_EXPRESSION;
return UNKNOWN_RETURN_EXPRESSION;
}
return getMemberReturnExpressionWhenCalled(literalStringMembers, path[0]);
}
Expand Down
31 changes: 18 additions & 13 deletions src/ast/nodes/shared/CallExpressionBase.ts
Expand Up @@ -11,19 +11,20 @@ import {
type ExpressionEntity,
type LiteralValueOrUnknown,
UNKNOWN_EXPRESSION,
UNKNOWN_RETURN_EXPRESSION,
UnknownValue
} from './Expression';
import { NodeBase } from './Node';

export default abstract class CallExpressionBase extends NodeBase implements DeoptimizableEntity {
protected declare interaction: NodeInteractionCalled;
protected returnExpression: ExpressionEntity | null = null;
protected returnExpression: [expression: ExpressionEntity, isPure: boolean] | null = null;
private readonly deoptimizableDependentExpressions: DeoptimizableEntity[] = [];
private readonly expressionsToBeDeoptimized = new Set<ExpressionEntity>();

deoptimizeCache(): void {
if (this.returnExpression !== UNKNOWN_EXPRESSION) {
this.returnExpression = UNKNOWN_EXPRESSION;
if (this.returnExpression?.[0] !== UNKNOWN_EXPRESSION) {
this.returnExpression = UNKNOWN_RETURN_EXPRESSION;
for (const expression of this.deoptimizableDependentExpressions) {
expression.deoptimizeCache();
}
Expand All @@ -40,7 +41,7 @@ export default abstract class CallExpressionBase extends NodeBase implements Deo
) {
return;
}
const returnExpression = this.getReturnExpression();
const [returnExpression] = this.getReturnExpression();
if (returnExpression !== UNKNOWN_EXPRESSION) {
returnExpression.deoptimizePath(path);
}
Expand All @@ -51,7 +52,9 @@ export default abstract class CallExpressionBase extends NodeBase implements Deo
path: ObjectPath,
recursionTracker: PathTracker
): void {
const returnExpression = this.getReturnExpression(recursionTracker);
const [returnExpression, isPure] = this.getReturnExpression(recursionTracker);
// TODO Lukas test
if (isPure) return;
if (returnExpression === UNKNOWN_EXPRESSION) {
interaction.thisArg.deoptimizePath(UNKNOWN_PATH);
} else {
Expand All @@ -72,7 +75,7 @@ export default abstract class CallExpressionBase extends NodeBase implements Deo
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): LiteralValueOrUnknown {
const returnExpression = this.getReturnExpression(recursionTracker);
const [returnExpression] = this.getReturnExpression(recursionTracker);
if (returnExpression === UNKNOWN_EXPRESSION) {
return UnknownValue;
}
Expand All @@ -92,10 +95,10 @@ export default abstract class CallExpressionBase extends NodeBase implements Deo
interaction: NodeInteractionCalled,
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): ExpressionEntity {
const returnExpression = this.getReturnExpression(recursionTracker);
if (this.returnExpression === UNKNOWN_EXPRESSION) {
return UNKNOWN_EXPRESSION;
): [expression: ExpressionEntity, isPure: boolean] {
const [returnExpression] = this.getReturnExpression(recursionTracker);
if (returnExpression === UNKNOWN_EXPRESSION) {
return UNKNOWN_RETURN_EXPRESSION;
}
return recursionTracker.withTrackedEntityAtPath(
path,
Expand All @@ -109,7 +112,7 @@ export default abstract class CallExpressionBase extends NodeBase implements Deo
origin
);
},
UNKNOWN_EXPRESSION
UNKNOWN_RETURN_EXPRESSION
);
}

Expand Down Expand Up @@ -138,8 +141,10 @@ export default abstract class CallExpressionBase extends NodeBase implements Deo
) {
return false;
}
return this.getReturnExpression().hasEffectsOnInteractionAtPath(path, interaction, context);
return this.getReturnExpression()[0].hasEffectsOnInteractionAtPath(path, interaction, context);
}

protected abstract getReturnExpression(recursionTracker?: PathTracker): ExpressionEntity;
protected abstract getReturnExpression(
recursionTracker?: PathTracker
): [expression: ExpressionEntity, isPure: boolean];
}
2 changes: 1 addition & 1 deletion src/ast/nodes/shared/ClassNode.ts
Expand Up @@ -66,7 +66,7 @@ export default class ClassNode extends NodeBase implements DeoptimizableEntity {
interaction: NodeInteractionCalled,
recursionTracker: PathTracker,
origin: DeoptimizableEntity
): ExpressionEntity {
): [expression: ExpressionEntity, isPure: boolean] {
return this.getObjectEntity().getReturnExpressionWhenCalledAtPath(
path,
interaction,
Expand Down
9 changes: 7 additions & 2 deletions src/ast/nodes/shared/Expression.ts
Expand Up @@ -59,8 +59,8 @@ export class ExpressionEntity implements WritableEntity {
_interaction: NodeInteractionCalled,
_recursionTracker: PathTracker,
_origin: DeoptimizableEntity
): ExpressionEntity {
return UNKNOWN_EXPRESSION;
): [expression: ExpressionEntity, isPure: boolean] {
return UNKNOWN_RETURN_EXPRESSION;
}

hasEffectsOnInteractionAtPath(
Expand Down Expand Up @@ -95,3 +95,8 @@ export class ExpressionEntity implements WritableEntity {

export const UNKNOWN_EXPRESSION: ExpressionEntity =
new (class UnknownExpression extends ExpressionEntity {})();

export const UNKNOWN_RETURN_EXPRESSION: [expression: ExpressionEntity, isPure: boolean] = [
UNKNOWN_EXPRESSION,
false
];

0 comments on commit 8daf05e

Please sign in to comment.