diff --git a/Jakefile b/Jakefile index 324356a4af5..adecd9568db 100644 --- a/Jakefile +++ b/Jakefile @@ -252,6 +252,8 @@ function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOu options += " --stripInternal" } + // options += " --cacheDownlevelForOfLength"; + var cmd = host + " " + dir + compilerFilename + " " + options + " "; cmd = cmd + sources.join(" "); console.log(cmd + "\n"); diff --git a/bin/tsc.js b/bin/tsc.js index 47dd801eadc..87039731d93 100644 --- a/bin/tsc.js +++ b/bin/tsc.js @@ -11815,7 +11815,7 @@ var ts; } ts.bindSourceFile = bindSourceFile; function bindSourceFileWorker(file) { - var parent; + var _parent; var container; var blockScopeContainer; var lastContainer; @@ -11956,10 +11956,10 @@ var ts; if (symbolKind & 255504) { node.locals = {}; } - var saveParent = parent; + var saveParent = _parent; var saveContainer = container; var savedBlockScopeContainer = blockScopeContainer; - parent = node; + _parent = node; if (symbolKind & 262128) { container = node; if (lastContainer) { @@ -11972,7 +11972,7 @@ var ts; } ts.forEachChild(node, bind); container = saveContainer; - parent = saveParent; + _parent = saveParent; blockScopeContainer = savedBlockScopeContainer; } function bindDeclaration(node, symbolKind, symbolExcludes, isBlockScopeContainer) { @@ -12075,7 +12075,7 @@ var ts; return "__" + ts.indexOf(node.parent.parameters, node); } function bind(node) { - node.parent = parent; + node.parent = _parent; switch (node.kind) { case 127: bindDeclaration(node, 262144, 530912, false); @@ -12209,10 +12209,10 @@ var ts; bindChildren(node, 0, true); break; default: - var saveParent = parent; - parent = node; + var saveParent = _parent; + _parent = node; ts.forEachChild(node, bind); - parent = saveParent; + _parent = saveParent; } } function bindParameter(node) { @@ -24542,6 +24542,7 @@ var ts; var rhsIsIdentifier = node.expression.kind === 64; var counter = createTempVariable(node, true); var rhsReference = rhsIsIdentifier ? node.expression : createTempVariable(node, false); + var cachedLength = compilerOptions.cacheDownlevelForOfLength ? createTempVariable(node, false) : undefined; emitStart(node.expression); write("var "); emitNodeWithoutSourceMap(counter); @@ -24555,12 +24556,24 @@ var ts; emitNodeWithoutSourceMap(node.expression); emitEnd(node.expression); } + if (cachedLength) { + write(", "); + emitNodeWithoutSourceMap(cachedLength); + write(" = "); + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + } write("; "); emitStart(node.initializer); emitNodeWithoutSourceMap(counter); write(" < "); - emitNodeWithoutSourceMap(rhsReference); - write(".length"); + if (cachedLength) { + emitNodeWithoutSourceMap(cachedLength); + } + else { + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + } emitEnd(node.initializer); write("; "); emitStart(node.initializer); @@ -26921,6 +26934,12 @@ var ts; description: ts.Diagnostics.Preserve_new_lines_when_emitting_code, experimental: true }, + { + name: "cacheDownlevelForOfLength", + type: "boolean", + description: "Cache length access when downlevel emitting for-of statements", + experimental: true + }, { name: "target", shortName: "t", diff --git a/bin/tsserver.js b/bin/tsserver.js index fd087d9a138..c534380b8f3 100644 --- a/bin/tsserver.js +++ b/bin/tsserver.js @@ -7473,6 +7473,12 @@ var ts; description: ts.Diagnostics.Preserve_new_lines_when_emitting_code, experimental: true }, + { + name: "cacheDownlevelForOfLength", + type: "boolean", + description: "Cache length access when downlevel emitting for-of statements", + experimental: true + }, { name: "target", shortName: "t", @@ -12165,7 +12171,7 @@ var ts; } ts.bindSourceFile = bindSourceFile; function bindSourceFileWorker(file) { - var parent; + var _parent; var container; var blockScopeContainer; var lastContainer; @@ -12306,10 +12312,10 @@ var ts; if (symbolKind & 255504) { node.locals = {}; } - var saveParent = parent; + var saveParent = _parent; var saveContainer = container; var savedBlockScopeContainer = blockScopeContainer; - parent = node; + _parent = node; if (symbolKind & 262128) { container = node; if (lastContainer) { @@ -12322,7 +12328,7 @@ var ts; } ts.forEachChild(node, bind); container = saveContainer; - parent = saveParent; + _parent = saveParent; blockScopeContainer = savedBlockScopeContainer; } function bindDeclaration(node, symbolKind, symbolExcludes, isBlockScopeContainer) { @@ -12425,7 +12431,7 @@ var ts; return "__" + ts.indexOf(node.parent.parameters, node); } function bind(node) { - node.parent = parent; + node.parent = _parent; switch (node.kind) { case 127: bindDeclaration(node, 262144, 530912, false); @@ -12559,10 +12565,10 @@ var ts; bindChildren(node, 0, true); break; default: - var saveParent = parent; - parent = node; + var saveParent = _parent; + _parent = node; ts.forEachChild(node, bind); - parent = saveParent; + _parent = saveParent; } } function bindParameter(node) { @@ -24892,6 +24898,7 @@ var ts; var rhsIsIdentifier = node.expression.kind === 64; var counter = createTempVariable(node, true); var rhsReference = rhsIsIdentifier ? node.expression : createTempVariable(node, false); + var cachedLength = compilerOptions.cacheDownlevelForOfLength ? createTempVariable(node, false) : undefined; emitStart(node.expression); write("var "); emitNodeWithoutSourceMap(counter); @@ -24905,12 +24912,24 @@ var ts; emitNodeWithoutSourceMap(node.expression); emitEnd(node.expression); } + if (cachedLength) { + write(", "); + emitNodeWithoutSourceMap(cachedLength); + write(" = "); + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + } write("; "); emitStart(node.initializer); emitNodeWithoutSourceMap(counter); write(" < "); - emitNodeWithoutSourceMap(rhsReference); - write(".length"); + if (cachedLength) { + emitNodeWithoutSourceMap(cachedLength); + } + else { + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + } emitEnd(node.initializer); write("; "); emitStart(node.initializer); diff --git a/bin/typescript.d.ts b/bin/typescript.d.ts index 4319e2d1375..e6f4bf572d7 100644 --- a/bin/typescript.d.ts +++ b/bin/typescript.d.ts @@ -1202,6 +1202,7 @@ declare module "typescript" { watch?: boolean; stripInternal?: boolean; preserveNewLines?: boolean; + cacheDownlevelForOfLength?: boolean; [option: string]: string | number | boolean; } const enum ModuleKind { diff --git a/bin/typescript.js b/bin/typescript.js index 623e6341f90..cc1ec309618 100644 --- a/bin/typescript.js +++ b/bin/typescript.js @@ -12444,7 +12444,7 @@ var ts; } ts.bindSourceFile = bindSourceFile; function bindSourceFileWorker(file) { - var parent; + var _parent; var container; var blockScopeContainer; var lastContainer; @@ -12585,10 +12585,10 @@ var ts; if (symbolKind & 255504) { node.locals = {}; } - var saveParent = parent; + var saveParent = _parent; var saveContainer = container; var savedBlockScopeContainer = blockScopeContainer; - parent = node; + _parent = node; if (symbolKind & 262128) { container = node; if (lastContainer) { @@ -12601,7 +12601,7 @@ var ts; } ts.forEachChild(node, bind); container = saveContainer; - parent = saveParent; + _parent = saveParent; blockScopeContainer = savedBlockScopeContainer; } function bindDeclaration(node, symbolKind, symbolExcludes, isBlockScopeContainer) { @@ -12704,7 +12704,7 @@ var ts; return "__" + ts.indexOf(node.parent.parameters, node); } function bind(node) { - node.parent = parent; + node.parent = _parent; switch (node.kind) { case 127: bindDeclaration(node, 262144, 530912, false); @@ -12838,10 +12838,10 @@ var ts; bindChildren(node, 0, true); break; default: - var saveParent = parent; - parent = node; + var saveParent = _parent; + _parent = node; ts.forEachChild(node, bind); - parent = saveParent; + _parent = saveParent; } } function bindParameter(node) { @@ -25171,6 +25171,7 @@ var ts; var rhsIsIdentifier = node.expression.kind === 64; var counter = createTempVariable(node, true); var rhsReference = rhsIsIdentifier ? node.expression : createTempVariable(node, false); + var cachedLength = compilerOptions.cacheDownlevelForOfLength ? createTempVariable(node, false) : undefined; emitStart(node.expression); write("var "); emitNodeWithoutSourceMap(counter); @@ -25184,12 +25185,24 @@ var ts; emitNodeWithoutSourceMap(node.expression); emitEnd(node.expression); } + if (cachedLength) { + write(", "); + emitNodeWithoutSourceMap(cachedLength); + write(" = "); + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + } write("; "); emitStart(node.initializer); emitNodeWithoutSourceMap(counter); write(" < "); - emitNodeWithoutSourceMap(rhsReference); - write(".length"); + if (cachedLength) { + emitNodeWithoutSourceMap(cachedLength); + } + else { + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + } emitEnd(node.initializer); write("; "); emitStart(node.initializer); @@ -27550,6 +27563,12 @@ var ts; description: ts.Diagnostics.Preserve_new_lines_when_emitting_code, experimental: true }, + { + name: "cacheDownlevelForOfLength", + type: "boolean", + description: "Cache length access when downlevel emitting for-of statements", + experimental: true + }, { name: "target", shortName: "t", diff --git a/bin/typescriptServices.d.ts b/bin/typescriptServices.d.ts index d5293c99b3b..913bb206f63 100644 --- a/bin/typescriptServices.d.ts +++ b/bin/typescriptServices.d.ts @@ -1202,6 +1202,7 @@ declare module ts { watch?: boolean; stripInternal?: boolean; preserveNewLines?: boolean; + cacheDownlevelForOfLength?: boolean; [option: string]: string | number | boolean; } const enum ModuleKind { diff --git a/bin/typescriptServices.js b/bin/typescriptServices.js index 623e6341f90..cc1ec309618 100644 --- a/bin/typescriptServices.js +++ b/bin/typescriptServices.js @@ -12444,7 +12444,7 @@ var ts; } ts.bindSourceFile = bindSourceFile; function bindSourceFileWorker(file) { - var parent; + var _parent; var container; var blockScopeContainer; var lastContainer; @@ -12585,10 +12585,10 @@ var ts; if (symbolKind & 255504) { node.locals = {}; } - var saveParent = parent; + var saveParent = _parent; var saveContainer = container; var savedBlockScopeContainer = blockScopeContainer; - parent = node; + _parent = node; if (symbolKind & 262128) { container = node; if (lastContainer) { @@ -12601,7 +12601,7 @@ var ts; } ts.forEachChild(node, bind); container = saveContainer; - parent = saveParent; + _parent = saveParent; blockScopeContainer = savedBlockScopeContainer; } function bindDeclaration(node, symbolKind, symbolExcludes, isBlockScopeContainer) { @@ -12704,7 +12704,7 @@ var ts; return "__" + ts.indexOf(node.parent.parameters, node); } function bind(node) { - node.parent = parent; + node.parent = _parent; switch (node.kind) { case 127: bindDeclaration(node, 262144, 530912, false); @@ -12838,10 +12838,10 @@ var ts; bindChildren(node, 0, true); break; default: - var saveParent = parent; - parent = node; + var saveParent = _parent; + _parent = node; ts.forEachChild(node, bind); - parent = saveParent; + _parent = saveParent; } } function bindParameter(node) { @@ -25171,6 +25171,7 @@ var ts; var rhsIsIdentifier = node.expression.kind === 64; var counter = createTempVariable(node, true); var rhsReference = rhsIsIdentifier ? node.expression : createTempVariable(node, false); + var cachedLength = compilerOptions.cacheDownlevelForOfLength ? createTempVariable(node, false) : undefined; emitStart(node.expression); write("var "); emitNodeWithoutSourceMap(counter); @@ -25184,12 +25185,24 @@ var ts; emitNodeWithoutSourceMap(node.expression); emitEnd(node.expression); } + if (cachedLength) { + write(", "); + emitNodeWithoutSourceMap(cachedLength); + write(" = "); + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + } write("; "); emitStart(node.initializer); emitNodeWithoutSourceMap(counter); write(" < "); - emitNodeWithoutSourceMap(rhsReference); - write(".length"); + if (cachedLength) { + emitNodeWithoutSourceMap(cachedLength); + } + else { + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + } emitEnd(node.initializer); write("; "); emitStart(node.initializer); @@ -27550,6 +27563,12 @@ var ts; description: ts.Diagnostics.Preserve_new_lines_when_emitting_code, experimental: true }, + { + name: "cacheDownlevelForOfLength", + type: "boolean", + description: "Cache length access when downlevel emitting for-of statements", + experimental: true + }, { name: "target", shortName: "t", diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index e79d762524c..269f23492e2 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -146,6 +146,12 @@ module ts { description: Diagnostics.Preserve_new_lines_when_emitting_code, experimental: true }, + { + name: "cacheDownlevelForOfLength", + type: "boolean", + description: "Cache length access when downlevel emitting for-of statements", + experimental: true, + }, { name: "target", shortName: "t", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 525f56ca2c3..230b5eac310 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -3583,6 +3583,8 @@ module ts { let counter = createTempVariable(node, /*forLoopVariable*/ true); let rhsReference = rhsIsIdentifier ? node.expression : createTempVariable(node, /*forLoopVariable*/ false); + var cachedLength = compilerOptions.cacheDownlevelForOfLength ? createTempVariable(node, /*forLoopVariable:*/ false) : undefined; + // This is the let keyword for the counter and rhsReference. The let keyword for // the LHS will be emitted inside the body. emitStart(node.expression); @@ -3602,14 +3604,30 @@ module ts { emitNodeWithoutSourceMap(node.expression); emitEnd(node.expression); } + + if (cachedLength) { + write(", "); + emitNodeWithoutSourceMap(cachedLength); + write(" = "); + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + } + write("; "); // _i < _a.length; emitStart(node.initializer); emitNodeWithoutSourceMap(counter); write(" < "); - emitNodeWithoutSourceMap(rhsReference); - write(".length"); + + if (cachedLength) { + emitNodeWithoutSourceMap(cachedLength); + } + else { + emitNodeWithoutSourceMap(rhsReference); + write(".length"); + } + emitEnd(node.initializer); write("; "); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7301e087ae1..a2fde2c5768 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1560,6 +1560,7 @@ module ts { watch?: boolean; stripInternal?: boolean; preserveNewLines?: boolean; + cacheDownlevelForOfLength?: boolean; [option: string]: string | number | boolean; } diff --git a/tests/baselines/reference/APISample_compile.js b/tests/baselines/reference/APISample_compile.js index eb2153aafc7..8560d213641 100644 --- a/tests/baselines/reference/APISample_compile.js +++ b/tests/baselines/reference/APISample_compile.js @@ -1239,6 +1239,7 @@ declare module "typescript" { watch?: boolean; stripInternal?: boolean; preserveNewLines?: boolean; + cacheDownlevelForOfLength?: boolean; [option: string]: string | number | boolean; } const enum ModuleKind { diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index d09e4f983cc..018e48c30ba 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -3953,6 +3953,9 @@ declare module "typescript" { preserveNewLines?: boolean; >preserveNewLines : boolean + cacheDownlevelForOfLength?: boolean; +>cacheDownlevelForOfLength : boolean + [option: string]: string | number | boolean; >option : string } diff --git a/tests/baselines/reference/APISample_linter.js b/tests/baselines/reference/APISample_linter.js index 0c1f84bc359..62346784619 100644 --- a/tests/baselines/reference/APISample_linter.js +++ b/tests/baselines/reference/APISample_linter.js @@ -1270,6 +1270,7 @@ declare module "typescript" { watch?: boolean; stripInternal?: boolean; preserveNewLines?: boolean; + cacheDownlevelForOfLength?: boolean; [option: string]: string | number | boolean; } const enum ModuleKind { diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 53e61101078..442c8a6ca06 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -4099,6 +4099,9 @@ declare module "typescript" { preserveNewLines?: boolean; >preserveNewLines : boolean + cacheDownlevelForOfLength?: boolean; +>cacheDownlevelForOfLength : boolean + [option: string]: string | number | boolean; >option : string } diff --git a/tests/baselines/reference/APISample_transform.js b/tests/baselines/reference/APISample_transform.js index 5f62d8757c4..5c913a4d13d 100644 --- a/tests/baselines/reference/APISample_transform.js +++ b/tests/baselines/reference/APISample_transform.js @@ -1271,6 +1271,7 @@ declare module "typescript" { watch?: boolean; stripInternal?: boolean; preserveNewLines?: boolean; + cacheDownlevelForOfLength?: boolean; [option: string]: string | number | boolean; } const enum ModuleKind { diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index 381c90b8333..3673a5472a7 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -4049,6 +4049,9 @@ declare module "typescript" { preserveNewLines?: boolean; >preserveNewLines : boolean + cacheDownlevelForOfLength?: boolean; +>cacheDownlevelForOfLength : boolean + [option: string]: string | number | boolean; >option : string } diff --git a/tests/baselines/reference/APISample_watcher.js b/tests/baselines/reference/APISample_watcher.js index 240123d8177..0983fedbaff 100644 --- a/tests/baselines/reference/APISample_watcher.js +++ b/tests/baselines/reference/APISample_watcher.js @@ -1308,6 +1308,7 @@ declare module "typescript" { watch?: boolean; stripInternal?: boolean; preserveNewLines?: boolean; + cacheDownlevelForOfLength?: boolean; [option: string]: string | number | boolean; } const enum ModuleKind { diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index 0bbaee0062f..c4211de6ce6 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -4222,6 +4222,9 @@ declare module "typescript" { preserveNewLines?: boolean; >preserveNewLines : boolean + cacheDownlevelForOfLength?: boolean; +>cacheDownlevelForOfLength : boolean + [option: string]: string | number | boolean; >option : string }