Merge pull request #7944 from Microsoft/recordTempVariables

record temp variable introduced in spread calls
This commit is contained in:
Vladimir Matveev 2016-04-07 16:38:29 -07:00
commit 2413e5e3f9
7 changed files with 117 additions and 99 deletions

View File

@ -149,10 +149,13 @@ namespace ts {
return node;
}
export function createTempVariable(location?: TextRange): Identifier {
export function createTempVariable(recordTempVariable: (node: Identifier) => void, location?: TextRange): Identifier {
const name = <Identifier>createNode(SyntaxKind.Identifier, location);
name.autoGenerateKind = GeneratedIdentifierKind.Auto;
getNodeId(name);
if (recordTempVariable) {
recordTempVariable(name);
}
return name;
}
@ -1143,7 +1146,19 @@ namespace ts {
thisArg: Expression;
}
export function createCallBinding(expression: Expression, languageVersion?: ScriptTarget): CallBinding {
function shouldBeCapturedInTempVariable(node: Expression): boolean {
switch (skipParentheses(node).kind) {
case SyntaxKind.Identifier:
case SyntaxKind.ThisKeyword:
case SyntaxKind.NumericLiteral:
case SyntaxKind.StringLiteral:
return false;
default:
return true;
}
}
export function createCallBinding(expression: Expression, recordTempVariable: (temp: Identifier) => void, languageVersion?: ScriptTarget): CallBinding {
const callee = skipOuterExpressions(expression, OuterExpressionKinds.All);
let thisArg: Expression;
let target: LeftHandSideExpression;
@ -1158,32 +1173,44 @@ namespace ts {
else {
switch (callee.kind) {
case SyntaxKind.PropertyAccessExpression: {
// for `a.b()` target is `(_a = a).b` and thisArg is `_a`
thisArg = createTempVariable();
target = createPropertyAccess(
createAssignment(
thisArg,
(<PropertyAccessExpression>callee).expression,
/*location*/ (<PropertyAccessExpression>callee).expression
),
(<PropertyAccessExpression>callee).name,
if (shouldBeCapturedInTempVariable((<PropertyAccessExpression>callee).expression)) {
// for `a.b()` target is `(_a = a).b` and thisArg is `_a`
thisArg = createTempVariable(recordTempVariable);
target = createPropertyAccess(
createAssignment(
thisArg,
(<PropertyAccessExpression>callee).expression,
/*location*/(<PropertyAccessExpression>callee).expression
),
(<PropertyAccessExpression>callee).name,
/*location*/ callee
);
);
}
else {
thisArg = (<PropertyAccessExpression>callee).expression;
target = <PropertyAccessExpression>callee;
}
break;
}
case SyntaxKind.ElementAccessExpression: {
// for `a[b]()` target is `(_a = a)[b]` and thisArg is `_a`
thisArg = createTempVariable();
target = createElementAccess(
createAssignment(
thisArg,
(<ElementAccessExpression>callee).expression,
/*location*/ (<ElementAccessExpression>callee).expression
),
(<ElementAccessExpression>callee).argumentExpression,
if (shouldBeCapturedInTempVariable((<ElementAccessExpression>callee).expression)) {
// for `a[b]()` target is `(_a = a)[b]` and thisArg is `_a`
thisArg = createTempVariable(recordTempVariable);
target = createElementAccess(
createAssignment(
thisArg,
(<ElementAccessExpression>callee).expression,
/*location*/(<ElementAccessExpression>callee).expression
),
(<ElementAccessExpression>callee).argumentExpression,
/*location*/ callee
);
);
}
else {
thisArg = (<ElementAccessExpression>callee).expression;
target = <ElementAccessExpression>callee;
}
break;
}

View File

@ -66,8 +66,7 @@ namespace ts {
}
function emitTempVariableAssignment(value: Expression, location: TextRange) {
const name = createTempVariable();
recordTempVariable(name);
const name = createTempVariable(recordTempVariable);
emitAssignment(name, value, location);
return name;
}
@ -102,7 +101,7 @@ namespace ts {
}
function emitTempVariableAssignment(value: Expression, location: TextRange) {
const name = createTempVariable();
const name = createTempVariable(/*recordTempVariable*/ undefined);
emitAssignment(name, value, location);
return name;
}
@ -142,7 +141,7 @@ namespace ts {
}
function emitTempVariableAssignment(value: Expression, location: TextRange) {
const name = createTempVariable();
const name = createTempVariable(/*recordTempVariable*/ undefined);
emitAssignment(name, value, location, /*original*/ undefined);
return name;
}
@ -177,8 +176,7 @@ namespace ts {
}
function emitTempVariableAssignment(value: Expression, location: TextRange) {
const name = createTempVariable();
recordTempVariable(name);
const name = createTempVariable(recordTempVariable);
emitPendingAssignment(name, value, location, /*original*/ undefined);
return name;
}

View File

@ -1561,7 +1561,7 @@ namespace ts {
const counter = createLoopVariable();
const rhsReference = expression.kind === SyntaxKind.Identifier
? createUniqueName((<Identifier>expression).text)
: createTempVariable();
: createTempVariable(/*recordTempVariable*/ undefined);
// Initialize LHS
// var v = _a[_i];
@ -1596,7 +1596,7 @@ namespace ts {
/*modifiers*/ undefined,
createVariableDeclarationList([
createVariableDeclaration(
firstDeclaration ? firstDeclaration.name : createTempVariable(),
firstDeclaration ? firstDeclaration.name : createTempVariable(/*recordTempVariable*/ undefined),
createElementAccess(rhsReference, counter)
)
]),
@ -1686,8 +1686,7 @@ namespace ts {
// For computed properties, we need to create a unique handle to the object
// literal so we can modify it without risking internal assignments tainting the object.
const temp = createTempVariable();
hoistVariableDeclaration(temp);
const temp = createTempVariable(hoistVariableDeclaration);
// Write out the first non-computed properties, then emit the rest through indexing on the temp variable.
const expressions: Expression[] = [];
@ -2232,7 +2231,7 @@ namespace ts {
// We are here either because SuperKeyword was used somewhere in the expression, or
// because we contain a SpreadElementExpression.
const { target, thisArg } = createCallBinding(node.expression);
const { target, thisArg } = createCallBinding(node.expression, hoistVariableDeclaration);
if (node.transformFlags & TransformFlags.ContainsSpreadElementExpression) {
// [source]
// f(...a, b)
@ -2289,7 +2288,7 @@ namespace ts {
// [output]
// new ((_a = C).bind.apply(_a, [void 0].concat(a)))()
const { target, thisArg } = createCallBinding(createPropertyAccess(node.expression, "bind"));
const { target, thisArg } = createCallBinding(createPropertyAccess(node.expression, "bind"), hoistVariableDeclaration);
return createNew(
createFunctionApply(
visitNode(target, visitor, isExpression),
@ -2380,8 +2379,7 @@ namespace ts {
const tag = visitNode(node.tag, visitor, isExpression);
// Allocate storage for the template site object
const temp = createTempVariable();
hoistVariableDeclaration(temp);
const temp = createTempVariable(hoistVariableDeclaration);
// Build up the template arguments and the raw and cooked strings for the template.
const templateArguments: Expression[] = [temp];

View File

@ -44,11 +44,9 @@ namespace ts {
let value: Expression;
if (isElementAccessExpression(left)) {
// Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)`
const expressionTemp = createTempVariable();
hoistVariableDeclaration(expressionTemp);
const expressionTemp = createTempVariable(hoistVariableDeclaration);
const argumentExpressionTemp = createTempVariable();
hoistVariableDeclaration(argumentExpressionTemp);
const argumentExpressionTemp = createTempVariable(hoistVariableDeclaration);
target = createElementAccess(
createAssignment(expressionTemp, left.expression, /*location*/ left.expression),
@ -64,8 +62,7 @@ namespace ts {
}
else if (isPropertyAccessExpression(left)) {
// Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)`
const expressionTemp = createTempVariable();
hoistVariableDeclaration(expressionTemp);
const expressionTemp = createTempVariable(hoistVariableDeclaration);
target = createPropertyAccess(
createAssignment(expressionTemp, left.expression, /*location*/ left.expression),

View File

@ -674,8 +674,7 @@ namespace ts {
if (staticProperties.length > 0) {
const expressions: Expression[] = [];
const temp = createTempVariable();
hoistVariableDeclaration(temp);
const temp = createTempVariable(hoistVariableDeclaration);
// To preserve the behavior of the old emitter, we explicitly indent
// the body of a class with static initializers.
@ -1614,8 +1613,7 @@ namespace ts {
switch (resolver.getTypeReferenceSerializationKind(typeName)) {
case TypeReferenceSerializationKind.Unknown:
const serialized = serializeEntityNameAsExpression(typeName, /*useFallback*/ true);
const temp = createTempVariable();
hoistVariableDeclaration(temp);
const temp = createTempVariable(hoistVariableDeclaration);
return createLogicalOr(
createLogicalAnd(
createStrictEquality(
@ -1701,8 +1699,7 @@ namespace ts {
left = serializeEntityNameAsExpression(node.left, useFallback);
}
else if (useFallback) {
const temp = createTempVariable();
hoistVariableDeclaration(temp);
const temp = createTempVariable(hoistVariableDeclaration);
left = createLogicalAnd(
createAssignment(
temp,

View File

@ -129,52 +129,53 @@ var h;
var i;
// Basic expression
new f(1, 2, "string");
new ((_a = f).bind.apply(_a, [void 0, 1, 2].concat(a)))();
new ((_b = f).bind.apply(_b, [void 0, 1, 2].concat(a, ["string"])))();
new (f.bind.apply(f, [void 0, 1, 2].concat(a)))();
new (f.bind.apply(f, [void 0, 1, 2].concat(a, ["string"])))();
// Multiple spreads arguments
new ((_c = f2).bind.apply(_c, [void 0].concat(a, a)))();
new ((_d = f).bind.apply(_d, [void 0, 1, 2].concat(a, a)))();
new (f2.bind.apply(f2, [void 0].concat(a, a)))();
new (f.bind.apply(f, [void 0, 1, 2].concat(a, a)))();
// Call expression
new f(1, 2, "string")();
new ((_e = f).bind.apply(_e, [void 0, 1, 2].concat(a)))()();
new ((_f = f).bind.apply(_f, [void 0, 1, 2].concat(a, ["string"])))()();
new (f.bind.apply(f, [void 0, 1, 2].concat(a)))()();
new (f.bind.apply(f, [void 0, 1, 2].concat(a, ["string"])))()();
// Property access expression
new b.f(1, 2, "string");
new ((_g = b.f).bind.apply(_g, [void 0, 1, 2].concat(a)))();
new ((_h = b.f).bind.apply(_h, [void 0, 1, 2].concat(a, ["string"])))();
new ((_a = b.f).bind.apply(_a, [void 0, 1, 2].concat(a)))();
new ((_b = b.f).bind.apply(_b, [void 0, 1, 2].concat(a, ["string"])))();
// Parenthesised expression
new (b.f)(1, 2, "string");
new ((_j = (b.f)).bind.apply(_j, [void 0, 1, 2].concat(a)))();
new ((_k = (b.f)).bind.apply(_k, [void 0, 1, 2].concat(a, ["string"])))();
new ((_c = (b.f)).bind.apply(_c, [void 0, 1, 2].concat(a)))();
new ((_d = (b.f)).bind.apply(_d, [void 0, 1, 2].concat(a, ["string"])))();
// Element access expression
new d[1].f(1, 2, "string");
new ((_l = d[1].f).bind.apply(_l, [void 0, 1, 2].concat(a)))();
new ((_m = d[1].f).bind.apply(_m, [void 0, 1, 2].concat(a, ["string"])))();
new ((_e = d[1].f).bind.apply(_e, [void 0, 1, 2].concat(a)))();
new ((_f = d[1].f).bind.apply(_f, [void 0, 1, 2].concat(a, ["string"])))();
// Element access expression with a punctuated key
new e["a-b"].f(1, 2, "string");
new ((_o = e["a-b"].f).bind.apply(_o, [void 0, 1, 2].concat(a)))();
new ((_p = e["a-b"].f).bind.apply(_p, [void 0, 1, 2].concat(a, ["string"])))();
new ((_g = e["a-b"].f).bind.apply(_g, [void 0, 1, 2].concat(a)))();
new ((_h = e["a-b"].f).bind.apply(_h, [void 0, 1, 2].concat(a, ["string"])))();
// Basic expression
new B(1, 2, "string");
new ((_q = B).bind.apply(_q, [void 0, 1, 2].concat(a)))();
new ((_r = B).bind.apply(_r, [void 0, 1, 2].concat(a, ["string"])))();
new (B.bind.apply(B, [void 0, 1, 2].concat(a)))();
new (B.bind.apply(B, [void 0, 1, 2].concat(a, ["string"])))();
// Property access expression
new c["a-b"](1, 2, "string");
new ((_s = c["a-b"]).bind.apply(_s, [void 0, 1, 2].concat(a)))();
new ((_t = c["a-b"]).bind.apply(_t, [void 0, 1, 2].concat(a, ["string"])))();
new ((_j = c["a-b"]).bind.apply(_j, [void 0, 1, 2].concat(a)))();
new ((_k = c["a-b"]).bind.apply(_k, [void 0, 1, 2].concat(a, ["string"])))();
// Parenthesised expression
new (c["a-b"])(1, 2, "string");
new ((_u = (c["a-b"])).bind.apply(_u, [void 0, 1, 2].concat(a)))();
new ((_v = (c["a-b"])).bind.apply(_v, [void 0, 1, 2].concat(a, ["string"])))();
new ((_l = (c["a-b"])).bind.apply(_l, [void 0, 1, 2].concat(a)))();
new ((_m = (c["a-b"])).bind.apply(_m, [void 0, 1, 2].concat(a, ["string"])))();
// Element access expression
new g[1]["a-b"](1, 2, "string");
new ((_w = g[1]["a-b"]).bind.apply(_w, [void 0, 1, 2].concat(a)))();
new ((_x = g[1]["a-b"]).bind.apply(_x, [void 0, 1, 2].concat(a, ["string"])))();
new ((_o = g[1]["a-b"]).bind.apply(_o, [void 0, 1, 2].concat(a)))();
new ((_p = g[1]["a-b"]).bind.apply(_p, [void 0, 1, 2].concat(a, ["string"])))();
// Element access expression with a punctuated key
new h["a-b"]["a-b"](1, 2, "string");
new ((_y = h["a-b"]["a-b"]).bind.apply(_y, [void 0, 1, 2].concat(a)))();
new ((_z = h["a-b"]["a-b"]).bind.apply(_z, [void 0, 1, 2].concat(a, ["string"])))();
new ((_q = h["a-b"]["a-b"]).bind.apply(_q, [void 0, 1, 2].concat(a)))();
new ((_r = h["a-b"]["a-b"]).bind.apply(_r, [void 0, 1, 2].concat(a, ["string"])))();
// Element access expression with a number
new i["a-b"][1](1, 2, "string");
new ((_0 = i["a-b"][1]).bind.apply(_0, [void 0, 1, 2].concat(a)))();
new ((_1 = i["a-b"][1]).bind.apply(_1, [void 0, 1, 2].concat(a, ["string"])))();
new ((_s = i["a-b"][1]).bind.apply(_s, [void 0, 1, 2].concat(a)))();
new ((_t = i["a-b"][1]).bind.apply(_t, [void 0, 1, 2].concat(a, ["string"])))();
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;

View File

@ -128,53 +128,53 @@ var h;
var i;
// Basic expression
new f(1, 2, "string");
new (f.bind.apply(f, [void 0].concat([1, 2], a)))();
new (f.bind.apply(f, [void 0].concat([1, 2], a, ["string"])))();
new (f.bind.apply(f, [void 0, 1, 2].concat(a)))();
new (f.bind.apply(f, [void 0, 1, 2].concat(a, ["string"])))();
// Multiple spreads arguments
new (f2.bind.apply(f2, [void 0].concat(a, a)))();
new (f.bind.apply(f, [void 0].concat([1, 2], a, a)))();
new (f.bind.apply(f, [void 0, 1, 2].concat(a, a)))();
// Call expression
new f(1, 2, "string")();
new (f.bind.apply(f, [void 0].concat([1, 2], a)))()();
new (f.bind.apply(f, [void 0].concat([1, 2], a, ["string"])))()();
new (f.bind.apply(f, [void 0, 1, 2].concat(a)))()();
new (f.bind.apply(f, [void 0, 1, 2].concat(a, ["string"])))()();
// Property access expression
new b.f(1, 2, "string");
new ((_a = b.f).bind.apply(_a, [void 0].concat([1, 2], a)))();
new ((_b = b.f).bind.apply(_b, [void 0].concat([1, 2], a, ["string"])))();
new ((_a = b.f).bind.apply(_a, [void 0, 1, 2].concat(a)))();
new ((_b = b.f).bind.apply(_b, [void 0, 1, 2].concat(a, ["string"])))();
// Parenthesised expression
new (b.f)(1, 2, "string");
new ((_c = (b.f)).bind.apply(_c, [void 0].concat([1, 2], a)))();
new ((_d = (b.f)).bind.apply(_d, [void 0].concat([1, 2], a, ["string"])))();
new ((_c = (b.f)).bind.apply(_c, [void 0, 1, 2].concat(a)))();
new ((_d = (b.f)).bind.apply(_d, [void 0, 1, 2].concat(a, ["string"])))();
// Element access expression
new d[1].f(1, 2, "string");
new ((_e = d[1].f).bind.apply(_e, [void 0].concat([1, 2], a)))();
new ((_f = d[1].f).bind.apply(_f, [void 0].concat([1, 2], a, ["string"])))();
new ((_e = d[1].f).bind.apply(_e, [void 0, 1, 2].concat(a)))();
new ((_f = d[1].f).bind.apply(_f, [void 0, 1, 2].concat(a, ["string"])))();
// Element access expression with a punctuated key
new e["a-b"].f(1, 2, "string");
new ((_g = e["a-b"].f).bind.apply(_g, [void 0].concat([1, 2], a)))();
new ((_h = e["a-b"].f).bind.apply(_h, [void 0].concat([1, 2], a, ["string"])))();
new ((_g = e["a-b"].f).bind.apply(_g, [void 0, 1, 2].concat(a)))();
new ((_h = e["a-b"].f).bind.apply(_h, [void 0, 1, 2].concat(a, ["string"])))();
// Basic expression
new B(1, 2, "string");
new (B.bind.apply(B, [void 0].concat([1, 2], a)))();
new (B.bind.apply(B, [void 0].concat([1, 2], a, ["string"])))();
new (B.bind.apply(B, [void 0, 1, 2].concat(a)))();
new (B.bind.apply(B, [void 0, 1, 2].concat(a, ["string"])))();
// Property access expression
new c["a-b"](1, 2, "string");
new ((_j = c["a-b"]).bind.apply(_j, [void 0].concat([1, 2], a)))();
new ((_k = c["a-b"]).bind.apply(_k, [void 0].concat([1, 2], a, ["string"])))();
new ((_j = c["a-b"]).bind.apply(_j, [void 0, 1, 2].concat(a)))();
new ((_k = c["a-b"]).bind.apply(_k, [void 0, 1, 2].concat(a, ["string"])))();
// Parenthesised expression
new (c["a-b"])(1, 2, "string");
new ((_l = (c["a-b"])).bind.apply(_l, [void 0].concat([1, 2], a)))();
new ((_m = (c["a-b"])).bind.apply(_m, [void 0].concat([1, 2], a, ["string"])))();
new ((_l = (c["a-b"])).bind.apply(_l, [void 0, 1, 2].concat(a)))();
new ((_m = (c["a-b"])).bind.apply(_m, [void 0, 1, 2].concat(a, ["string"])))();
// Element access expression
new g[1]["a-b"](1, 2, "string");
new ((_o = g[1]["a-b"]).bind.apply(_o, [void 0].concat([1, 2], a)))();
new ((_p = g[1]["a-b"]).bind.apply(_p, [void 0].concat([1, 2], a, ["string"])))();
new ((_o = g[1]["a-b"]).bind.apply(_o, [void 0, 1, 2].concat(a)))();
new ((_p = g[1]["a-b"]).bind.apply(_p, [void 0, 1, 2].concat(a, ["string"])))();
// Element access expression with a punctuated key
new h["a-b"]["a-b"](1, 2, "string");
new ((_q = h["a-b"]["a-b"]).bind.apply(_q, [void 0].concat([1, 2], a)))();
new ((_r = h["a-b"]["a-b"]).bind.apply(_r, [void 0].concat([1, 2], a, ["string"])))();
new ((_q = h["a-b"]["a-b"]).bind.apply(_q, [void 0, 1, 2].concat(a)))();
new ((_r = h["a-b"]["a-b"]).bind.apply(_r, [void 0, 1, 2].concat(a, ["string"])))();
// Element access expression with a number
new i["a-b"][1](1, 2, "string");
new ((_s = i["a-b"][1]).bind.apply(_s, [void 0].concat([1, 2], a)))();
new ((_t = i["a-b"][1]).bind.apply(_t, [void 0].concat([1, 2], a, ["string"])))();
new ((_s = i["a-b"][1]).bind.apply(_s, [void 0, 1, 2].concat(a)))();
new ((_t = i["a-b"][1]).bind.apply(_t, [void 0, 1, 2].concat(a, ["string"])))();
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;