Restore ContainsLexicalThsi flag for performance

This commit is contained in:
Ron Buckton 2019-03-06 11:34:28 -08:00
parent 86242eed87
commit 2fb0b85cf0
3 changed files with 39 additions and 91 deletions

View file

@ -3099,8 +3099,7 @@ namespace ts {
// If the this node contains a SpreadExpression, or is a super call, then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES2015;
// super property or element accesses could be inside lambdas, etc, and need a captured `this`,
// while super keyword for super calls (indicated by TransformFlags.Super) does not (since it can only be top-level in a constructor)
if (expression.transformFlags & TransformFlags.ContainsSuper) {
transformFlags |= TransformFlags.ContainsLexicalThis;
}
@ -3108,12 +3107,6 @@ namespace ts {
if (expression.kind === SyntaxKind.ImportKeyword) {
transformFlags |= TransformFlags.ContainsDynamicImport;
// A dynamic 'import()' call that contains a lexical 'this' will
// require a captured 'this' when emitting down-level.
if (subtreeFlags & TransformFlags.ContainsLexicalThis) {
transformFlags |= TransformFlags.ContainsCapturedLexicalThis;
}
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
@ -3236,12 +3229,6 @@ namespace ts {
|| node.typeParameters) {
transformFlags |= TransformFlags.AssertTypeScript;
}
if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) {
// A computed property name containing `this` might need to be rewritten,
// so propagate the ContainsLexicalThis flag upward.
transformFlags |= TransformFlags.ContainsLexicalThis;
}
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
@ -3259,12 +3246,6 @@ namespace ts {
transformFlags |= TransformFlags.AssertTypeScript;
}
if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) {
// A computed property name containing `this` might need to be rewritten,
// so propagate the ContainsLexicalThis flag upward.
transformFlags |= TransformFlags.ContainsLexicalThis;
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
return transformFlags & ~TransformFlags.ClassExcludes;
}
@ -3369,7 +3350,7 @@ namespace ts {
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
return transformFlags & ~TransformFlags.MethodOrAccessorExcludes;
return propagatePropertyNameFlags(node.name, transformFlags & ~TransformFlags.MethodOrAccessorExcludes);
}
function computeAccessor(node: AccessorDeclaration, subtreeFlags: TransformFlags) {
@ -3391,7 +3372,7 @@ namespace ts {
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
return transformFlags & ~TransformFlags.MethodOrAccessorExcludes;
return propagatePropertyNameFlags(node.name, transformFlags & ~TransformFlags.MethodOrAccessorExcludes);
}
function computePropertyDeclaration(node: PropertyDeclaration, subtreeFlags: TransformFlags) {
@ -3405,7 +3386,7 @@ namespace ts {
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
return transformFlags & ~TransformFlags.NodeExcludes;
return propagatePropertyNameFlags(node.name, transformFlags & ~TransformFlags.PropertyExcludes);
}
function computeFunctionDeclaration(node: FunctionDeclaration, subtreeFlags: TransformFlags) {
@ -3439,13 +3420,6 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2018;
}
// If a FunctionDeclaration's subtree has marked the container as needing to capture the
// lexical this, or the function contains parameters with initializers, then this node is
// ES6 syntax.
if (subtreeFlags & TransformFlags.ContainsCapturedLexicalThis) {
transformFlags |= TransformFlags.AssertES2015;
}
// If a FunctionDeclaration is generator function and is the body of a
// transformed async function, then this node can be transformed to a
// down-level generator.
@ -3481,14 +3455,6 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2018;
}
// If a FunctionExpression's subtree has marked the container as needing to capture the
// lexical this, or the function contains parameters with initializers, then this node is
// ES6 syntax.
if (subtreeFlags & TransformFlags.ContainsCapturedLexicalThis) {
transformFlags |= TransformFlags.AssertES2015;
}
// If a FunctionExpression is generator function and is the body of a
// transformed async function, then this node can be transformed to a
// down-level generator.
@ -3522,11 +3488,6 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2018;
}
// If an ArrowFunction contains a lexical this, its container must capture the lexical this.
if (subtreeFlags & TransformFlags.ContainsLexicalThis) {
transformFlags |= TransformFlags.ContainsCapturedLexicalThis;
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
return transformFlags & ~TransformFlags.ArrowFunctionExcludes;
}
@ -3810,17 +3771,6 @@ namespace ts {
// This is so that they can flow through PropertyName transforms unaffected.
// Instead, we mark the container as ES6, so that it can properly handle the transform.
transformFlags |= TransformFlags.ContainsComputedPropertyName;
if (subtreeFlags & TransformFlags.ContainsLexicalThis) {
// A computed method name like `[this.getName()](x: string) { ... }` needs to
// distinguish itself from the normal case of a method body containing `this`:
// `this` inside a method doesn't need to be rewritten (the method provides `this`),
// whereas `this` inside a computed name *might* need to be rewritten if the class/object
// is inside an arrow function:
// `_this = this; () => class K { [_this.getName()]() { ... } }`
// To make this distinction, use ContainsLexicalThisInComputedPropertyName
// instead of ContainsLexicalThis for computed property names
transformFlags |= TransformFlags.ContainsLexicalThisInComputedPropertyName;
}
break;
case SyntaxKind.SpreadElement:
@ -3839,7 +3789,6 @@ namespace ts {
case SyntaxKind.ThisKeyword:
// Mark this node and its ancestors as containing a lexical `this` keyword.
transformFlags |= TransformFlags.AssertES2015;
transformFlags |= TransformFlags.ContainsLexicalThis;
break;
@ -3876,12 +3825,6 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2015;
}
if (subtreeFlags & TransformFlags.ContainsLexicalThisInComputedPropertyName) {
// A computed property name containing `this` might need to be rewritten,
// so propagate the ContainsLexicalThis flag upward.
transformFlags |= TransformFlags.ContainsLexicalThis;
}
if (subtreeFlags & TransformFlags.ContainsObjectRestOrSpread) {
// If an ObjectLiteralExpression contains a spread element, then it
// is an ES2018 node.
@ -3906,10 +3849,6 @@ namespace ts {
break;
case SyntaxKind.SourceFile:
if (subtreeFlags & TransformFlags.ContainsCapturedLexicalThis) {
transformFlags |= TransformFlags.AssertES2015;
}
break;
case SyntaxKind.ReturnStatement:
@ -3927,6 +3866,10 @@ namespace ts {
return transformFlags & ~excludeFlags;
}
function propagatePropertyNameFlags(node: PropertyName, transformFlags: TransformFlags) {
return transformFlags | (node.transformFlags & TransformFlags.PropertyNamePropagatingFlags);
}
/**
* Gets the transform flags to exclude when unioning the transform flags of a subtree.
*

View file

@ -229,8 +229,7 @@ namespace ts {
//
NewTarget = 1 << 13, // Contains a 'new.target' meta-property
LexicalThis = 1 << 14, // Contains a lexical `this` reference.
CapturedLexicalThis = 1 << 15, // Contains a lexical `this` reference captured by an arrow function.
CapturedLexicalThis = 1 << 14, // Contains a lexical `this` reference captured by an arrow function.
//
// Subtree masks
@ -239,7 +238,7 @@ namespace ts {
SubtreeFactsMask = ~AncestorFactsMask,
ArrowFunctionSubtreeExcludes = None,
FunctionSubtreeExcludes = NewTarget | LexicalThis | CapturedLexicalThis,
FunctionSubtreeExcludes = NewTarget | CapturedLexicalThis,
}
export function transformES2015(context: TransformationContext) {
@ -565,7 +564,6 @@ namespace ts {
}
function visitThisKeyword(node: Node): Node {
hierarchyFacts |= HierarchyFacts.LexicalThis;
if (hierarchyFacts & HierarchyFacts.ArrowFunction) {
hierarchyFacts |= HierarchyFacts.CapturedLexicalThis;
}
@ -989,7 +987,7 @@ namespace ts {
insertCaptureNewTargetIfNeeded(prologue, constructor, /*copyOnWrite*/ false);
if (isDerivedClass) {
if (superCallExpression && statementOffset === constructor.body.statements.length && !(hierarchyFacts & HierarchyFacts.LexicalThis)) {
if (superCallExpression && statementOffset === constructor.body.statements.length && !(constructor.body.transformFlags & TransformFlags.ContainsLexicalThis)) {
// If the subclass constructor does *not* contain `this` and *ends* with a `super()` call, we will use the
// following representation:
//
@ -1693,6 +1691,10 @@ namespace ts {
* @param node An ArrowFunction node.
*/
function visitArrowFunction(node: ArrowFunction) {
if (node.transformFlags & TransformFlags.ContainsLexicalThis) {
hierarchyFacts |= HierarchyFacts.CapturedLexicalThis;
}
const savedConvertedLoopState = convertedLoopState;
convertedLoopState = undefined;
const ancestorFacts = enterSubtree(HierarchyFacts.ArrowFunctionExcludes, HierarchyFacts.ArrowFunctionIncludes);

View file

@ -5055,20 +5055,18 @@ namespace ts {
// Markers
// - Flags used to indicate that a subtree contains a specific transformation.
ContainsTypeScriptClassSyntax = 1 << 11, // Decorators, Property Initializers, Parameter Property Initializers
ContainsLexicalThis = 1 << 12,
ContainsCapturedLexicalThis = 1 << 13,
ContainsLexicalThisInComputedPropertyName = 1 << 14,
ContainsRestOrSpread = 1 << 15,
ContainsObjectRestOrSpread = 1 << 16,
ContainsComputedPropertyName = 1 << 17,
ContainsBlockScopedBinding = 1 << 18,
ContainsBindingPattern = 1 << 19,
ContainsYield = 1 << 20,
ContainsHoistedDeclarationOrCompletion = 1 << 21,
ContainsDynamicImport = 1 << 22,
Super = 1 << 23,
ContainsSuper = 1 << 24,
ContainsLexicalThis = 1 << 11,
ContainsTypeScriptClassSyntax = 1 << 12, // Decorators, Property Initializers, Parameter Property Initializers
ContainsRestOrSpread = 1 << 13,
ContainsObjectRestOrSpread = 1 << 14,
ContainsComputedPropertyName = 1 << 15,
ContainsBlockScopedBinding = 1 << 16,
ContainsBindingPattern = 1 << 17,
ContainsYield = 1 << 18,
ContainsHoistedDeclarationOrCompletion = 1 << 19,
ContainsDynamicImport = 1 << 20,
Super = 1 << 21,
ContainsSuper = 1 << 22,
// Please leave this as 1 << 29.
// It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system.
@ -5093,20 +5091,25 @@ namespace ts {
OuterExpressionExcludes = DestructuringAssignment | Generator | HasComputedFlags,
PropertyAccessExcludes = OuterExpressionExcludes | Super,
NodeExcludes = PropertyAccessExcludes | ContainsSuper,
ArrowFunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
FunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
ConstructorExcludes = NodeExcludes | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
MethodOrAccessorExcludes = NodeExcludes | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
ClassExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName,
ModuleExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion,
ArrowFunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
FunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
ConstructorExcludes = NodeExcludes | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
MethodOrAccessorExcludes = NodeExcludes | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
PropertyExcludes = NodeExcludes | ContainsLexicalThis,
ClassExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName,
ModuleExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion,
TypeExcludes = ~ContainsTypeScript,
ObjectLiteralExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName | ContainsObjectRestOrSpread,
ObjectLiteralExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName | ContainsObjectRestOrSpread,
ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsRestOrSpread,
VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern | ContainsObjectRestOrSpread,
ParameterExcludes = NodeExcludes,
CatchClauseExcludes = NodeExcludes | ContainsObjectRestOrSpread,
BindingPatternExcludes = NodeExcludes | ContainsRestOrSpread,
// Propagating flags
// - Bitmasks for flags that should propagate from a child
PropertyNamePropagatingFlags = ContainsLexicalThis,
// Masks
// - Additional bitmasks
}