Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Move logic from ClassBody into ClassNode So that it sits in one place and is easier to extend. * Track static class fields and improve handling of class getters/setters This aims to improve tree-shaking of code that uses static class properties (#3989) and to improve detection of side effects through class getters/setters (#4016). The first part works by keeping a map of positively known static properties (methods and simple getters) in `ClassNode.staticPropertyMap`, along with a flag (`ClassNode.deoptimizedStatic`) that indicates that something happened that removed our confidence that we know anything about the class object. Access and calls to these known static properties are handled by routing the calls to `getLiteralValueAtPath`, `getReturnExpressionWhenCalledAtPath`, and `hasEffectsWhenCalledAtPath` to the known values in the properties. In contrast to `ObjectExpression`, this class does not try to keep track of multiple expressions associated with a property, since that doesn't come up a lot on classes. The handling of side effect detection through getters and setters is done by, _if_ the entire class object (or its prototype in case of access to the prototype) hasn't been deoptimized, scanning through the directly defined getters and setters to see if one exists (calling through to superclasses as appropriate). I believe that this is solid because any code that would be able to change the set of getters and setters on a class would cause the entire object to be deoptimized. * Remove ClassNode.deoptimizeCache * Keep a table for class property effects * Add comment explaining property map * Fix types * Make getReturnExpression and getLiteralValue more similar for objects * Use common logic for return expression and literal value * Use common logic for return access and call effects * Extract shared logic from ObjectExpression * Use an object for better performance * Simplify handling for setters and other properties * Small simplification * Work towards better class handling * merge ObjectPathHandler into ObjectEntity * Slightly refactor default values * Separate unknown nodes from other Nodes to avoid future circular dependencies * Introduce new prototype tracking * Improve coverage * Fix class deoptimization in arrow functions via this/super * Simplify and merge property and method definition * Improve coverage * Replace deoptimizeProperties by deoptimizing a double unknown path * Assume functions can add getters to parameters * Improve class.prototype handling * Assume created instance getters have side-effects * Base all expressions on a base class * Only deoptimize necessary paths when deoptimizing "this" * Handle deoptimizing "this" in getters * Handle deoptimizing "this" in setters * Unify this deoptimization * Simplify recursion tracking * Get rid of deoptimizations during bind phase * Get rid of unneeded double-binding checks * Inline deoptimizations into NodeBase for simple cases * Add more efficient way to create object entities * Add thisParameter to CallOptions * Move NodeEvents to separate file * Track array elements * Simplify namespace handling * Use Object.values and Object.entries instead of Object.keys where useful * Improve code and simplify literal handling * Improve coverage * Improve coverage * Improve coverage in conditional and logical expressions * Improve coverage * 2.49.0-0 * Fix test to support pre-release versions * Fix failed deoptimization of array props * 2.49.0-1 Co-authored-by: Lukas Taegert-Atkinson <lukas.taegert-atkinson@tngtech.com> Co-authored-by: Lukas Taegert-Atkinson <lukastaegert@users.noreply.github.com>
- Loading branch information
1 parent
07b3a02
commit d73b2ac
Showing
219 changed files
with
3,952 additions
and
1,701 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export const EVENT_ACCESSED = 0; | ||
export const EVENT_ASSIGNED = 1; | ||
export const EVENT_CALLED = 2; | ||
export type NodeEvent = typeof EVENT_ACCESSED | typeof EVENT_ASSIGNED | typeof EVENT_CALLED; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,94 @@ | ||
import { CallOptions } from '../CallOptions'; | ||
import { DeoptimizableEntity } from '../DeoptimizableEntity'; | ||
import { HasEffectsContext } from '../ExecutionContext'; | ||
import { ObjectPath, UNKNOWN_PATH } from '../utils/PathTracker'; | ||
import { | ||
arrayMembers, | ||
getMemberReturnExpressionWhenCalled, | ||
hasMemberEffectWhenCalled, | ||
UNKNOWN_EXPRESSION | ||
} from '../values'; | ||
import { NodeEvent } from '../NodeEvents'; | ||
import { ObjectPath, PathTracker, UnknownInteger } from '../utils/PathTracker'; | ||
import { UNDEFINED_EXPRESSION, UNKNOWN_LITERAL_NUMBER } from '../values'; | ||
import * as NodeType from './NodeType'; | ||
import { ARRAY_PROTOTYPE } from './shared/ArrayPrototype'; | ||
import { ExpressionEntity, LiteralValueOrUnknown } from './shared/Expression'; | ||
import { ExpressionNode, NodeBase } from './shared/Node'; | ||
import { ObjectEntity, ObjectProperty } from './shared/ObjectEntity'; | ||
import SpreadElement from './SpreadElement'; | ||
|
||
export default class ArrayExpression extends NodeBase { | ||
elements!: (ExpressionNode | SpreadElement | null)[]; | ||
type!: NodeType.tArrayExpression; | ||
private objectEntity: ObjectEntity | null = null; | ||
|
||
bind() { | ||
super.bind(); | ||
for (const element of this.elements) { | ||
if (element !== null) element.deoptimizePath(UNKNOWN_PATH); | ||
} | ||
deoptimizePath(path: ObjectPath) { | ||
this.getObjectEntity().deoptimizePath(path); | ||
} | ||
|
||
deoptimizeThisOnEventAtPath( | ||
event: NodeEvent, | ||
path: ObjectPath, | ||
thisParameter: ExpressionEntity, | ||
recursionTracker: PathTracker | ||
) { | ||
this.getObjectEntity().deoptimizeThisOnEventAtPath( | ||
event, | ||
path, | ||
thisParameter, | ||
recursionTracker | ||
); | ||
} | ||
|
||
getLiteralValueAtPath( | ||
path: ObjectPath, | ||
recursionTracker: PathTracker, | ||
origin: DeoptimizableEntity | ||
): LiteralValueOrUnknown { | ||
return this.getObjectEntity().getLiteralValueAtPath(path, recursionTracker, origin); | ||
} | ||
|
||
getReturnExpressionWhenCalledAtPath(path: ObjectPath) { | ||
if (path.length !== 1) return UNKNOWN_EXPRESSION; | ||
return getMemberReturnExpressionWhenCalled(arrayMembers, path[0]); | ||
getReturnExpressionWhenCalledAtPath( | ||
path: ObjectPath, | ||
callOptions: CallOptions, | ||
recursionTracker: PathTracker, | ||
origin: DeoptimizableEntity | ||
): ExpressionEntity { | ||
return this.getObjectEntity().getReturnExpressionWhenCalledAtPath( | ||
path, | ||
callOptions, | ||
recursionTracker, | ||
origin | ||
); | ||
} | ||
|
||
hasEffectsWhenAccessedAtPath(path: ObjectPath, context: HasEffectsContext) { | ||
return this.getObjectEntity().hasEffectsWhenAccessedAtPath(path, context); | ||
} | ||
|
||
hasEffectsWhenAccessedAtPath(path: ObjectPath) { | ||
return path.length > 1; | ||
hasEffectsWhenAssignedAtPath(path: ObjectPath, context: HasEffectsContext) { | ||
return this.getObjectEntity().hasEffectsWhenAssignedAtPath(path, context); | ||
} | ||
|
||
hasEffectsWhenCalledAtPath( | ||
path: ObjectPath, | ||
callOptions: CallOptions, | ||
context: HasEffectsContext | ||
): boolean { | ||
if (path.length === 1) { | ||
return hasMemberEffectWhenCalled(arrayMembers, path[0], this.included, callOptions, context); | ||
return this.getObjectEntity().hasEffectsWhenCalledAtPath(path, callOptions, context); | ||
} | ||
|
||
private getObjectEntity(): ObjectEntity { | ||
if (this.objectEntity !== null) { | ||
return this.objectEntity; | ||
} | ||
const properties: ObjectProperty[] = [ | ||
{ kind: 'init', key: 'length', property: UNKNOWN_LITERAL_NUMBER } | ||
]; | ||
for (let index = 0; index < this.elements.length; index++) { | ||
const element = this.elements[index]; | ||
if (element instanceof SpreadElement) { | ||
properties.unshift({ kind: 'init', key: UnknownInteger, property: element }); | ||
} else if (!element) { | ||
properties.push({ kind: 'init', key: String(index), property: UNDEFINED_EXPRESSION }); | ||
} else { | ||
properties.push({ kind: 'init', key: String(index), property: element }); | ||
} | ||
} | ||
return true; | ||
return (this.objectEntity = new ObjectEntity(properties, ARRAY_PROTOTYPE)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.