Use native maps when they're available - #11354

Merged
18 commits merged into
masterfrom
map4
Oct 27, 2016
Merged

Use native maps when they're available#11354
18 commits merged into
masterfrom
map4

Conversation

@ghost

@ghostDeleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown

The summary is that using native maps, the compiler works 5% faster and uses 5% less memory. Using shims, the performance is surprisingly less than 5% worse.

I was able to achieve good baseline performance by disabling Windows Defender in my work directory and using "High Performance" in Control Panel -> Hardware and Sound -> Power Options. There is much less variance this time around.

Benchmark numbers

This is from using our internal ts-perf tool.

map4

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.72s (± 1.10%)-0.07s (- 4.08%)1.70s1.74s
Bind Time0.69s (± 4.74%)0.52s (± 3.50%)-0.17s (- 24.86%)0.50s0.54s
Check Time3.37s (± 1.66%)2.91s (± 3.16%)-0.46s (- 13.69%)2.78s2.98s
Emit Time5.01s (± 4.73%)4.87s (± 1.35%)-0.14s (- 2.77%)4.79s4.94s
Total Time10.87s (± 2.34%)10.02s (± 1.18%)-0.84s (- 7.77%)9.86s10.12s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)356,928k (± 0.01%)-22,996k (- 6.05%)356,890k356,956k
Parse Time2.40s (± 0.75%)2.32s (± 2.13%)-0.08s (- 3.37%)2.28s2.39s
Bind Time0.92s (± 1.79%)0.71s (± 1.84%)-0.21s (- 22.52%)0.70s0.73s
Check Time4.26s (± 1.36%)3.84s (± 6.33%)-0.42s (- 9.94%)3.66s4.18s
Emit Time1.87s (± 2.44%)1.82s (± 3.16%)-0.05s (- 2.80%)1.77s1.89s
Total Time9.46s (± 1.19%)8.69s (± 3.96%)-0.77s (- 8.12%)8.42s9.16s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)190,504k (± 0.01%)-11,467k (- 5.68%)190,474k190,538k
Parse Time2.30s (± 0.89%)2.20s (± 2.07%)-0.09s (- 4.09%)2.17s2.27s
Bind Time0.72s (± 0.99%)0.57s (± 4.73%)-0.15s (- 21.33%)0.55s0.61s
Check Time3.48s (± 1.73%)3.27s (± 4.68%)-0.21s (- 6.08%)3.08s3.38s
Emit Time1.91s (± 3.15%)1.78s (± 8.00%)-0.13s (- 6.94%)1.65s1.94s
Total Time8.41s (± 0.61%)7.82s (± 1.68%)-0.59s (- 7.03%)7.71s7.99s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.15s (± 1.31%)-0.07s (- 6.06%)1.13s1.16s
Bind Time0.56s (± 2.96%)0.54s (± 4.08%)-0.02s (- 3.13%)0.52s0.57s
Check Time2.81s (± 1.48%)2.46s (± 1.85%)-0.35s (- 12.34%)2.43s2.53s
Emit Time3.11s (± 0.85%)3.19s (± 0.91%)+0.07s (+ 2.33%)3.15s3.22s
Total Time7.70s (± 0.84%)7.34s (± 1.14%)-0.37s (- 4.78%)7.28s7.46s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)309,449k (± 0.02%)-18,556k (- 5.66%)309,386k309,516k
Parse Time1.50s (± 1.02%)1.44s (± 0.88%)-0.07s (- 4.32%)1.42s1.45s
Bind Time0.73s (± 0.73%)0.58s (± 1.65%)-0.14s (- 19.89%)0.57s0.59s
Check Time3.89s (± 0.65%)3.56s (± 4.42%)-0.32s (- 8.27%)3.42s3.74s
Emit Time1.54s (± 0.91%)1.57s (± 4.86%)+0.03s (+ 2.25%)1.51s1.67s
Total Time7.65s (± 0.65%)7.16s (± 3.13%)-0.50s (- 6.48%)6.96s7.42s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)165,316k (± 0.01%)-9,433k (- 5.40%)165,292k165,344k
Parse Time1.41s (± 1.63%)1.33s (± 0.77%)-0.08s (- 5.36%)1.33s1.35s
Bind Time0.62s (± 5.95%)0.50s (± 3.40%)-0.12s (- 19.68%)0.48s0.52s
Check Time2.98s (± 0.64%)2.75s (± 0.96%)-0.23s (- 7.73%)2.71s2.77s
Emit Time1.35s (± 0.83%)1.35s (± 1.29%)+0.01s (+ 0.45%)1.33s1.37s
Total Time6.36s (± 1.07%)5.94s (± 0.82%)-0.42s (- 6.60%)5.88s5.98s

map4 with usingNativeMaps = false and usingNativeSets = false

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.80s (± 1.47%)+0.01s (+ 0.73%)1.77s1.82s
Bind Time0.69s (± 4.74%)0.71s (± 13.45%)+0.02s (+ 3.18%)0.66s0.86s
Check Time3.37s (± 1.66%)3.43s (± 3.44%)+0.06s (+ 1.68%)3.29s3.57s
Emit Time5.01s (± 4.73%)5.04s (± 4.80%)+0.03s (+ 0.66%)4.93s5.42s
Total Time10.87s (± 2.34%)10.98s (± 1.85%)+0.12s (+ 1.09%)10.83s11.29s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)383,279k (± 0.01%)+3,355k (+ 0.88%)383,241k383,338k
Parse Time2.40s (± 0.75%)2.39s (± 2.42%)-0.01s (- 0.29%)2.33s2.44s
Bind Time0.92s (± 1.79%)0.90s (± 4.74%)-0.02s (- 2.55%)0.86s0.96s
Check Time4.26s (± 1.36%)4.29s (± 0.29%)+0.03s (+ 0.66%)4.28s4.31s
Emit Time1.87s (± 2.44%)1.88s (± 1.90%)+0.01s (+ 0.51%)1.85s1.92s
Total Time9.46s (± 1.19%)9.47s (± 0.86%)+0.01s (+ 0.11%)9.36s9.54s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)203,972k (± 0.01%)+2,001k (+ 0.99%)203,951k203,991k
Parse Time2.30s (± 0.89%)2.29s (± 0.76%)-0.01s (- 0.52%)2.27s2.31s
Bind Time0.72s (± 0.99%)0.68s (± 1.41%)-0.04s (- 5.87%)0.67s0.69s
Check Time3.48s (± 1.73%)3.83s (± 1.77%)+0.35s (+ 10.19%)3.78s3.92s
Emit Time1.91s (± 3.15%)1.62s (± 3.72%)-0.29s (- 15.12%)1.58s1.71s
Total Time8.41s (± 0.61%)8.42s (± 1.66%)+0.01s (+ 0.12%)8.32s8.63s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.22s (± 5.54%)-0.01s (- 0.49%)1.17s1.28s
Bind Time0.56s (± 2.96%)0.58s (± 5.13%)+0.02s (+ 4.38%)0.57s0.63s
Check Time2.81s (± 1.48%)2.84s (± 3.00%)+0.03s (+ 1.03%)2.77s2.95s
Emit Time3.11s (± 0.85%)3.16s (± 1.84%)+0.05s (+ 1.56%)3.08s3.21s
Total Time7.70s (± 0.84%)7.81s (± 2.01%)+0.10s (+ 1.32%)7.60s7.94s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)329,980k (± 0.02%)+1,975k (+ 0.60%)329,913k330,079k
Parse Time1.50s (± 1.02%)1.49s (± 0.69%)-0.02s (- 1.13%)1.47s1.49s
Bind Time0.73s (± 0.73%)0.71s (± 3.11%)-0.01s (- 2.00%)0.68s0.73s
Check Time3.89s (± 0.65%)4.04s (± 1.24%)+0.15s (+ 3.87%)3.96s4.06s
Emit Time1.54s (± 0.91%)1.64s (± 0.63%)+0.10s (+ 6.55%)1.63s1.65s
Total Time7.65s (± 0.65%)7.87s (± 0.76%)+0.21s (+ 2.80%)7.79s7.92s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)175,835k (± 0.01%)+1,086k (+ 0.62%)175,822k175,855k
Parse Time1.41s (± 1.63%)1.39s (± 0.74%)-0.02s (- 1.10%)1.39s1.41s
Bind Time0.62s (± 5.95%)0.57s (± 3.30%)-0.05s (- 8.48%)0.56s0.59s
Check Time2.98s (± 0.64%)2.99s (± 1.14%)+0.02s (+ 0.60%)2.96s3.04s
Emit Time1.35s (± 0.83%)1.38s (± 4.53%)+0.03s (+ 2.52%)1.33s1.45s
Total Time6.36s (± 1.07%)6.34s (± 1.32%)-0.02s (- 0.25%)6.25s6.43s

Heap snapshot numbers

The memory usage tended to be about the same up until the beforeEmit event, AKA after checking.

Master had 365,935 KB total, map4 had 343,774 KB (94% as much), and map4 with shims had 368,978 KB (100% as much as master, 106% as much as map4).

(I added an event heapAfterBind to test the effects of that; map4 used 97% as much memory as master, meaning the real memory savings are during checking.)

For map4, the chrome heap snaprhot viewer shows Maps as accounting for 2% of all objects, with a shallow size equal to their retained size at 1%. However, this is misleading because most of them are mere 32KB wrapper objects which have internal _keys and _values (or table in some cases), which is what really takes up space. I wish there were a way we could include the size of those.

VSCode numbers

I also ran a simple test on the VSCode repo.

master

tsc -p src --noEmit --diagnostics (Run with 2.1.0-dev.20161005)

KindAmountSamples
Memory used737211 K736716, 733971, 743103, 742334, 729932
I/O read0.17 s0.27, 0.12, 0.20, 0.14, 0.14
Parse time5.22 s5.21, 5.18, 5.22, 5.22, 5.29
Bind time1.74 s1.77, 1.72, 1.74, 1.72, 1.75
Check time8.57 s8.69, 8.48, 8.54, 8.50, 8.63
Total time15.54 s15.67, 15.38, 15.51, 15.45, 15.67

map4

node ../TypeScript/built/local/tsc.js -p src --noEmit --diagnostics

KindRelativeAmountSamples
Memory used94%690972 K691500, 690621, 691097, 690872, 690772
I/O read:100%0.17 s0.16, 0.18, 0.20, 0.14, 0.16
Parse time96%5.02 s5.03, 4.95, 4.99, 4.96, 5.18
Bind time:83%1.44 s1.42, 1.40, 1.44, 1.42, 1.53
Check time97%8.34 s8.32, 8.27, 8.38, 8.42, 8.33
Total time95%14.81 s14.78, 14.62, 14.81, 14.80, 15.05

map4 with shims

Same command as for map4, after rebuilding with usingNativeMaps = false and usingNativeSets = false.

KindRelativeAmountSamples
Memory used101%744718 K745408, 744639, 744845, 745511, 743185
I/O read106%0.18 s0.22, 0.19, 0.20, 0.14, 0.17
Parse time99%5.19 s5.28, 5.18, 5.20, 5.17, 5.13
Bind time98%1.71 s1.72, 1.69, 1.70, 1.73, 1.72
Check time101%8.68 s8.58, 8.72, 8.68, 8.72, 8.73
Total time100%15.59 s15.59, 15.59, 15.58, 15.62, 15.57

@ghost

Deleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown
Author

Here is a performance test for doing the same map lookup once vs twice.

constBenchmark=require("benchmark")constcrypto=require("crypto")constN=10000constwords=[]for(leti=0;i<N;i++)words[i]=crypto.randomBytes(8).toString('hex')functioncreateMap(){constm=newMap()for(leti=0;i<N;i+=2)m.set(words[i],i)returnm}functioncreateObject(){consto=Object.create(null)o["__"]=undefineddeleteo["__"]for(leti=0;i<N;i+=2)o[words[i]]=ireturno}letcorrectSum=0for(leti=0;i<N;i+=2)correctSum+=iconstsuite=newBenchmark.Suitesuite.add("map has-then-get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++)if(map.has(words[i]))sum+=map.get(words[i])if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map just get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++){constx=map.get(words[i])if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object has-then-get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++)if(words[i]ino)sum+=o[words[i]]if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object just get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++){constx=o[words[i]]if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map double get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){sum+=map.get(words[i])sum+=map.get(words[i])}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("map single get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){constgot=map.get(words[i])sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("object double get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){sum+=o[words[i]]sum+=o[words[i]]}if(sum!==correctSum*2)thrownewError()returnsum})suite.add("object single get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){constgot=o[words[i]]sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.on("complete",function(){this.forEach(({name, stats})=>{console.log(`${name}: ${stats.mean*1000}ms`)})})suite.on("error",err=>{throwerr.target.error})suite.run()
map has-then-get: 1.0212332328457447ms
map just get: 0.911712559080547ms
object has-then-get: 1.9529671271167457ms
object just get: 1.9624182600334454ms
map double get: 0.7383946305889607ms
map single get: 0.651791347503374ms
object double get: 1.411747356033454ms
object single get: 1.3791293993025284ms

Looks like removing uses of has is useful for maps but not for objects. Removing double get is always good.

@ghostghost mentioned this pull request Oct 4, 2016
@ghost
ghost force-pushed the map4 branch 2 times, most recently from 1f080a8 to 6fc4eadCompareOctober 5, 2016 14:58
@ghost

Copy link
Copy Markdown
Author

This would be a breaking change. We have publicly exported maps because we have export type SymbolTable = Map<string, Symbol>;, which is the type of several public properties of Symbol.

Comment threadJakefile.js Outdated
}

var compilerSources = [
"dataStructures.ts",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be tempted to call this collections.ts, since we already have a types.ts and this is more specific.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of moving our array utilities to collections.ts?

Comment threadsrc/compiler/dataStructures.ts Outdated
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

/** Extra Map methods that may not be available, so we must provide fallbacks. */
interface FullyFeaturedMap<K, V> extends Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe call this ES6Map?

@ghostghost mentioned this pull request Oct 7, 2016
@yuit

Copy link
Copy Markdown
Contributor

Andy (Andrewkraft) (@Andy-MS) looks good for my end 👍 though it is a big change so I think it may be good idea to have Mohamed Hegazy (@mhegazy)Vladimir Matveev (@vladima)Nathan Shively-Sanders (@sandersn)Ron Buckton (@rbuckton) to check as well

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider merging the shims for NumberMap and StringMap.

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for stylistic consistency do not use classes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you share the numbers after removing classes?

@ghostDeleted user (ghost)Oct 12, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It ends up taking 20% longer. 🤕
Here are the measurements for running map4 with closure shims, with "Delta" relative to map4 with class shims.

Monaco - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used203,967k (± 0.01%)224,241k (± 0.01%)+20,274k (+ 9.94%)224,220k224,263k
Parse Time2.27s (± 0.39%)2.39s (± 3.65%)+0.12s (+ 5.30%)2.32s2.51s
Bind Time0.68s (± 1.17%)0.83s (± 1.52%)+0.15s (+ 21.41%)0.81s0.84s
Check Time3.86s (± 2.12%)4.72s (± 3.44%)+0.86s (+ 22.15%)4.55s4.89s
Emit Time1.62s (± 2.07%)2.30s (± 14.05%)+0.68s (+ 41.80%)2.04s2.72s
Total Time8.43s (± 1.26%)10.23s (± 3.36%)+1.80s (+ 21.34%)9.78s10.47s
TFS - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used175,828k (± 0.01%)188,541k (± 0.01%)+12,713k (+ 7.23%)188,529k188,551k
Parse Time1.40s (± 0.75%)1.51s (± 4.24%)+0.11s (+ 7.80%)1.46s1.60s
Bind Time0.57s (± 1.02%)0.68s (± 2.26%)+0.12s (+ 20.63%)0.67s0.70s
Check Time3.00s (± 0.53%)3.60s (± 3.55%)+0.60s (+ 19.88%)3.41s3.69s
Emit Time1.37s (± 1.09%)1.71s (± 5.74%)+0.34s (+ 25.18%)1.66s1.86s
Total Time6.33s (± 0.28%)7.50s (± 2.73%)+1.16s (+ 18.38%)7.24s7.71s

Here's the code I tested with (with equivalents for NumberMap and StringSet):

exportconstcreateStringMap: <T>(pairs?: [string,T][])=>Map<string,T>=usingNativeMaps
? <T>(pairs?: [string,T][])=>newMap(pairs)
: <T>(pairs?: [string,T][])=>{letdata=createDictionaryModeObject<T>();if(pairs){for(const[key,value]ofpairs){data[key]=value;}}return{clear(): void{data=createDictionaryModeObject<T>();},delete(key: string): void{deletedata[key];},get(key: string): T{returndata[key];},has(key: string): boolean{// tslint:disable-next-line:no-in-operatorreturnkeyindata;},set(key: string,value: T): void{data[key]=value;},forEach(action: (value: T,key: string)=>void): void{for(constkeyindata){action(data[key],key);}}}}

I bet this is allocating a different closure for each method, wheras a class just allocates space for data and shares a single prototype among all instances.

Comment threadsrc/compiler/collections.ts Outdated
// Map utilities
namespace ts {
/** Create a map containing a single entry key -> value. */
export function createMapWithEntry<T>(key: string, value: T): Map<string, T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider inlining this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or using the Map constructor optional parameter

Comment threadsrc/compiler/collections.ts Outdated
}

// Map utilities
namespace ts {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be marked internal. and consider using one closure for all of them

Comment threadsrc/compiler/program.ts Outdated

// If output has not been changed, and the file has no external modification
if (fingerprint.byteOrderMark === writeByteOrderMark &&
if (fingerprint !== undefined && fingerprint.byteOrderMark === writeByteOrderMark &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just if (figureprint

@mhegazy

Copy link
Copy Markdown
Contributor

Can you also share the perf numbers once it is in.

@mhegazy

Copy link
Copy Markdown
Contributor

Ron Buckton (@rbuckton) any more comments?

@rbucktonRon Buckton (rbuckton) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few non-blocking review comments, but this looks fine to me.

Comment threadsrc/compiler/collections.ts Outdated
declare const Map: { new<K, V>(pairs?: [K, V][]): Map<K, V> } | undefined;
const usingNativeMaps = typeof Map !== "undefined";
// tslint:disable-next-line:no-in-operator
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term "fully-featured" is a bit ambiguous. Maybe usingES6NativeMaps?

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using an object.
* `pairs` is an optional list of entries to add to the new map.
*/
export const StringMap: { new<T>(pairs?: [string, T][]): Map<string, T>; } = usingNativeMaps ? Map : ShimMap;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love for us to be able to just call this Map instead of StringMap or NumberMap, but its a bit messy to avoid colliding with the global Map

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or stick with createMap<K extends string | number, V>() and createSet<T extends string | number>()

Comment threadsrc/compiler/collections.ts Outdated
* Creates a sorted array of keys.
* Sorts keys according to the iteration order they would have if they were in an object, instead of from a Map.
* This is so that tests run consistently whether or not we have a Map shim in place.
* The difference between Map iteration order and V8 object insertion order is that V8 moves natrual-number-like keys to the front.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"natural"

Comment threadsrc/compiler/collections.ts Outdated
}

delete(value: string) {
delete this.data[value];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Sets return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
}

delete(key: K): void {
delete this.data[key as string];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Maps return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
However, `forEach` will iterate over strings because values are stringified before being put in the map.
*/

constructor(pairs?: [K, V][]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-ES6 native maps don't support constructor arguments.

delete(key: K): void {
delete this.data[key as string];
delete(key: K): boolean {
const had = this.has(key);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this. Just do return delete this.data[key as string].

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deletealways returns true in strict mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. That's unfortunate...and odd.

delete(value: string) {
delete this.data[value];
delete(value: string): boolean {
const had = this.has(value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, you can just do return delete this.data[value] since a delete expression returns boolean

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard

@ghost
ghost merged commit adfdae0 into masterOct 27, 2016
@ghost
ghost deleted the map4 branch October 27, 2016 20:27
@ghost

Copy link
Copy Markdown
Author

Will do a final performance comparison tomorrow.

ghost pushed a commit that referenced this pull request Oct 27, 2016
This reverts commit adfdae0, reversing
changes made to aad663c.
ghost pushed a commit that referenced this pull request Oct 27, 2016
Revert "Merge pull request #11354 from Microsoft/map4"
Mohamed Hegazy (mhegazy) added a commit that referenced this pull request Nov 10, 2016
* Use a single ShimMap class, and indicate that iteration always yields string keys (which it did before too)
* Remove emacs-added newline at end of baseline
* Remove space at end of line in baseline
* Add numeric indexer to strings and remove lint
* Update baselines with spread string's numeric indexers
* Reset baseline line number to the locally incorrect value
* Remove trailing newline from baseline again
* Respond to PR comments
* Refactor getTypeFromTypeLiteral, from PR comments
* Fix lint
* Use same literal comparison rules for switch/===
switch was missing the rule for converting literal types to the literal
base type if needed.
* Add switch comparability test and update baselines
* Push eitherIsNotLiteral check into isTypeEqualityComparableTo
Since all callers need this check -- it's how equality is supposed to
work everywhere.
* Update baselines
There are more literal types in error messages because error reporting
no longer has the advantage of calls to getBaseLiteralType
* Adds ES5 to ES3 transformer for reserved words
* Minor cleanup
* Cleaned up emit of enum declaration
* Return both ts and js results from module resolution, and don't have moduleNameResolver responsible for omitting files based on compiler options
* Instead of getResolutionOrDiagnostic, use getResolutionDiagnostic and avoid using resolution.resolvedFileName if the diagnostic is defined.
* Remove "ResolvedModuleFromHost" type and just make `resolvedTsFileName` and `resolvedJsFileName` optional properties
(but still automatically infer one of them to supply if the host supplied neither)
* Remove type inference for spread types
* Update inference test for spread types
* Make spread assignability and apparent type stricter
Assignability now does not allow properties to the left of a type
parameter.
Apparent type now only returns the apparent type of the right-most
spread member.
* Update tests w/spread assignability+apparent type
* Moved AMD/CJS/UMD transform to end
* Spread no longer distributes intersections
* Update spread w/intersection tests
* Move System module transform to end.
* Update baseline
* Revert baseline change due to stale output
* Resolve all-object intersections inside spreads
This means that getSpreadType will return an object type, even when
spreading two intersections, as long as those intersections contain
nothing but object types themselves.
* Update and improve spread intersection tests
* Simplify expression in resolveObjectIntersection
* Update baselines with new index signature rules
* Move n-ary spread handling into separate function.
To be moved to callers in the next step.
* Move multiple-spread handling out of getSpreadType
* Clean up and reorder getSpreadType body
* Respond to PR comments
* Error for call/construct signatures in spread type
1. Simplify the error reporting code to handle all kinds of signatures.
2. Remove index signature handling code when creating a spread type
since it's an error anyway.
* Update baselines with new spread type index errors
* Explain writeSpreadType a little better
* Add more commentary to getSpreadType
* Initial implementation of 'keyof T' type operator
* Introduce PropertyNameType
* Move most of resolveModuleNameForLsHost to lsHost
* Simplify isImplicitGlob test
* Initial implementation of 'T[K]' property access types
* add a fallback logic for older versions of node that don't support 'homedir' (#11845)
* add a fallback logic for older versions of node that don't support 'homedir'
* try os.homedir first
* For JavaScript files, we report semantic errors for using TypeScript-only constructs from within a JavaScript file as syntactic errors.
* Don't require `resolvedTsFileName` and `resolvedJsFileName`, just `resolvedFileName` and `extension`. Also, change search order to do all TS searching before searching for JS.
* Fix#10108 (Completion suggestion for object literal with getter) (#11808)
* Fix#10108 (Completion suggestion for object literal with getter)
* completions for setter
* Move helper functions to core (fix build)
* Support parametric property access expressions + some renaming
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives (#11872)
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives
* pass proper value for current directory when compiling .d.ts files
* Fix bug: Return a resolution diagnostic for a `.jsx` import if `--allowJs` is turned off
* Remove a comment about a parameter that no longer exists
* Fix bug: We want to test for existence of the enum value, not whether it's non-zero
* Fix: test for presence, not absence
* Allow untyped imports
* Simplify for loops in fourslash.ts
* Rename to zipWith
* Change diagnostic message
* Make `extension` property of `ResolvedModule` optional; introduce `ResolvedModuleFull` interface for when the extension is provided.
* Consider index signatures in type produced by 'keyof T'
* Respond to PR comments
* Refactor getIndexedAccessType to be reusable from checkIndexedAccess
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Revert "Merge pull request #11354 from Microsoft/map4"
This reverts commit adfdae0, reversing
changes made to aad663c.
* Rename Experimental transform to ESNext
1. Spread/rest are no longer experimental.
2. We need a place to put stage 3 ES features.
* Changes from CR feedback
* disable CoS for inferred projects (#11909)
* Updating test due to CR changes. The order of the diagnostic messages has changed due to concatenation changes
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* Rename TransformFlags.Experimental -> ESNext
* enable non-ts extensions in inferred projects by default
* update CFG to properly handle do statements
* do not inline async IIFEs in control flow graph
* Minor fixes
* cache type for empty type literal (#11934)
cache type for empty type literal
* Improved error messages for invalid assignments to identifiers
* Accept new baselines
* Improved error messages for invalid assignments to properties
* Accept new baselines
* Improve more error messages
* Accept new baselines
* Fix realPathMap in test harness: Must be used in `directoryExists`
* Add helper function
* Update generated files (#11963)
* Move eitherIsNotLiteral check into switch and === checks
This improves error messages
* Forbid augmentation of untyped module (#11962)
* Forbid augmentation of untyped module
* Just use `undefined` for untyped modules
* Unify checking of indexed access expressions and indexed access types
* Accept new baselines
* Accept additional baselines
* Make `cachingInServerLSHost` tests work with `runtests-browser`
* Get literal type only once
* Update baselines
* Add missed test update
* Improve unification by moving more logic to getIndexedAccessType
* Add test cases to report errors for decorators in js file
* Report all the js file errors and skip only the nodes that are not allowed in js
Fixes#11800
* Fix 'keyof any' to produce 'string | number'
* Fix#11396: Make error message referene `Promise` explicitly (#11982)
* Simplify the checking for async function return type
* Fix#11396: Make error message referene `Promise` explicitly
* Minor fixes
* Adding tests
* Test case for property used in destructuring variable declaration
* Mark property referenced in the destructuring as referenced
Fixes#11324
* Spread types handle nested index [access] types
Nested index [access] types are treated as assignable to themselves only,
just like type parameters.
* Test index [access] types inside spread types
* module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program (#11999)
module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program
* Parse, bind and check rest elements
* Downlevel emit of rest elements
* Add rest tests
* Update baselines
* Remove spread types, leaving spread syntax/emit
Spreads are still typed, but cannot be created from a non-object type.
Tests still need to be updated.
* Fix lint
* Lock tslint version to 4.0.0-dev.0, because 4.0.0-dev.1 complains about unnecessary semicolons following properties
* Remove spread type tests from spread tests
* Spread handles index signatures from singleton spreads
I broke it when simplifying the logic earlier.
* Correct assignability for keyof types and type parameters
* Update tests
* Accept new baselines
* Update objectRestAssignment test and baselines
* Fix linting errors
* Update objectRestAssignment test
Missed previously, just got the baselines
* Improve readability of ES next destructuring emit
* Ensure transformFlags are correct before visiting a node.
* Port #12027, #11980 and #11932 to master (#12037)
* add test for the fix for overwrite emitting error
* cr feedback
* Address PR comments
1. Remove extra line in __rest shim.
2. Improve __rest vs __assign check for destructuring assignment.
* Move convertForOf to factory for esnext and es2015
Saves a lot of duplicated code
* Update improved baselines
* Move transformFunctionBody to factory
It is shared by es2015 and esNext transformers.
This commit just adds a convertObjectRest flag to be passed on to
flattenDestructuring functions, as well as adding necessary parameters
to use the code outside a transformer.
* Spread any types to any
* add missing bind calls to properly set parent on token nodes (#12057)
* Cache generic signature instantiations
* Accept new baselines
* Properly instantiate aliasTypeArguments
* Add regression test
* Revert incorrect logic from #11392
* Accept new baselines
* Rename SpreadElementExpression -> SpreadAssignment
and SpreadExpression (formerly SpreadElementExpression) -> SpreadElement
* Add SpreadAssignment to visitors
1. visitNode
2. reduceNode
3. emit
This fixes an emit bug for setters.
* Add --target esnext
Currently, this disables the rest and spread transforms. This will
change as proposals enter and leave stage 3.
* Add --target esnext tests and update baselines
* Revert unneeded change and comments per PR
* Rename variable in checkSwitchStatement per PR
* Do not emit __rest for --target esnext
* Add `realpath` implementation for lshost
* Create spread property types eagerly
This avoids the need for a synthetic symbol and later code called from
getTypeOfSymbol.
* Set spread type symbols in checkObjectLiteral
Instead of getSpreadType.
Also clean up special-case handling inside getSpreadType to be more
readable.
* Ports #12051 and #12032 into master (#12090)
* use local registry to check if typings package exist (#12014)
use local registry to check if typings package exist
* enable sending telemetry events to tsserver client (#12035)
enable sending telemetry events
* Address more PR comments
* return empty file watcher in case if target directory does not exist (#12091)
* return empty file watcher in case if target directory does not exist
* linter
* property handle missing config files in external projects (#12094)
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Port fix for #12069 (#12095)
* reduce set of files being watched, increase polling interval (#12054) (#12092)
* Update authors for release-2.1
* Include declaration file emit
* use createHash from ServerHost instead of explicit require (#12043)
* use createHash from ServerHost instead of explicit require
* added missing method in ServerHost stub
* (signature help) type parameter lists are never variadic (#12112)
* Handle abstract and const modifiers
* Downlevel array destructuring to ES6 in object rest
Previously array destructuring inside an object destructuring with an
object rest would downlevel the array destructuring to ES5. This breaks
if the code that targets ES2015 is using iterators instead of arrays
since iterators don't support [0] or .slice that the ES5 emit uses.
* Improve nested destructuring test for ESNext emit
Now with object destructuring inside array destructuring inside object
destructuring! Each with their own array/object rest!
Also updates baselines.
* Add support for taking in jsxFactory option and report errors for invalid combinations
* Treat `| undefined` like optionality in spread type
* Add strictNullChecks test for object spread
* Verify that jsxFactory is either identifier or qualified name
* Resolve first identifier of the jsxFactory as part of type check
* When emitting use jsx factory entity expression if provided
* Transpile unit test case
* Enabled test case for source map
* Add test cases for when jsxFactory cannot be resolved
* Parse the jsxFactory again in the checker instead of using cached value in the program
* Adds error message for incompatible assignment of identically named type
Fixes issue #12050
* Updated condition for more readability
* Report errors for import helpers missing __rest
* Correctly check spread assignments in strict mode
Previously it crashed in the binder.
* Test error for import helpers with no __rest
* synthesize complete import declaration for tslib (#12151)
* Add ES2017 string padding (#12152)
* add es2017.string.d.ts for String.prototype.{padStart,padEnd}
* append es2017.string.d.ts into es2017.d.ts
* add es2017.string into commandLineParser
* append es2017.string into error message for unit tests of commandLineParser
* append es2017.string into Gulpfile
* append es2017.string into Jakefile
* Exclude js files in non-configured projects compile-on-save emitting (#12118)
* Exclude js files in non-configured projects CoS emitting
* remove unnecessary method
* Merge release-2.1 into master (#12157)
* Update LKG
* Update version
* Update LKG
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* Update LKG
* Fix emit inferred type which is a generic type-alias both fully and partially fill type parameters
* Add tests and baselines
* Skip trying to use alias if there is target type
* Update baselines
* Add diagnostics to remind adding tsconfig file for certain external project (#11932)
* Add diagnostics for certain external project
* Show tsconfig suggestion
* fix lint error
* Address pr
* fix comment
* Update error message
* Flag for not overwrite js files by default without generating errors (#11980)
* WIP
* Properly naming things
* refactor
* apply the option to all files and check out options
* Fix typo
* Update LKG
* lockLinter
* use local registry to check if typings package exist (#12014) (#12032)
use local registry to check if typings package exist
* Add test for #11980 (#12027)
* add test for the fix for overwrite emitting error
* cr feedback
* enable sending telemetry events to tsserver client (#12034) (#12051)
enable sending telemetry events
* Update LKG
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Update LKG
* Update version
* Update LKG
* Do not emit "use strict" when targeting es6 or higher or module kind is es2015 and the file is external module
* Add tests and baselines
* [Release 2.1] fix11754 global augmentation (#12133)
* Exclude global augmentation from module resolution logic
* Address PR: check using string literal instead of NodeFlags.globalAugmentation
* Remove comment
@ghostghost mentioned this pull request Dec 7, 2016
@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
This pull request was closed.
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@yuit@mhegazy@rbuckton@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Use native maps when they're available - #11354

Merged
18 commits merged into
masterfrom
map4
Oct 27, 2016
Merged

Use native maps when they're available#11354
18 commits merged into
masterfrom
map4

Conversation

@ghost

@ghostDeleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown

The summary is that using native maps, the compiler works 5% faster and uses 5% less memory. Using shims, the performance is surprisingly less than 5% worse.

I was able to achieve good baseline performance by disabling Windows Defender in my work directory and using "High Performance" in Control Panel -> Hardware and Sound -> Power Options. There is much less variance this time around.

Benchmark numbers

This is from using our internal ts-perf tool.

map4

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.72s (± 1.10%)-0.07s (- 4.08%)1.70s1.74s
Bind Time0.69s (± 4.74%)0.52s (± 3.50%)-0.17s (- 24.86%)0.50s0.54s
Check Time3.37s (± 1.66%)2.91s (± 3.16%)-0.46s (- 13.69%)2.78s2.98s
Emit Time5.01s (± 4.73%)4.87s (± 1.35%)-0.14s (- 2.77%)4.79s4.94s
Total Time10.87s (± 2.34%)10.02s (± 1.18%)-0.84s (- 7.77%)9.86s10.12s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)356,928k (± 0.01%)-22,996k (- 6.05%)356,890k356,956k
Parse Time2.40s (± 0.75%)2.32s (± 2.13%)-0.08s (- 3.37%)2.28s2.39s
Bind Time0.92s (± 1.79%)0.71s (± 1.84%)-0.21s (- 22.52%)0.70s0.73s
Check Time4.26s (± 1.36%)3.84s (± 6.33%)-0.42s (- 9.94%)3.66s4.18s
Emit Time1.87s (± 2.44%)1.82s (± 3.16%)-0.05s (- 2.80%)1.77s1.89s
Total Time9.46s (± 1.19%)8.69s (± 3.96%)-0.77s (- 8.12%)8.42s9.16s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)190,504k (± 0.01%)-11,467k (- 5.68%)190,474k190,538k
Parse Time2.30s (± 0.89%)2.20s (± 2.07%)-0.09s (- 4.09%)2.17s2.27s
Bind Time0.72s (± 0.99%)0.57s (± 4.73%)-0.15s (- 21.33%)0.55s0.61s
Check Time3.48s (± 1.73%)3.27s (± 4.68%)-0.21s (- 6.08%)3.08s3.38s
Emit Time1.91s (± 3.15%)1.78s (± 8.00%)-0.13s (- 6.94%)1.65s1.94s
Total Time8.41s (± 0.61%)7.82s (± 1.68%)-0.59s (- 7.03%)7.71s7.99s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.15s (± 1.31%)-0.07s (- 6.06%)1.13s1.16s
Bind Time0.56s (± 2.96%)0.54s (± 4.08%)-0.02s (- 3.13%)0.52s0.57s
Check Time2.81s (± 1.48%)2.46s (± 1.85%)-0.35s (- 12.34%)2.43s2.53s
Emit Time3.11s (± 0.85%)3.19s (± 0.91%)+0.07s (+ 2.33%)3.15s3.22s
Total Time7.70s (± 0.84%)7.34s (± 1.14%)-0.37s (- 4.78%)7.28s7.46s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)309,449k (± 0.02%)-18,556k (- 5.66%)309,386k309,516k
Parse Time1.50s (± 1.02%)1.44s (± 0.88%)-0.07s (- 4.32%)1.42s1.45s
Bind Time0.73s (± 0.73%)0.58s (± 1.65%)-0.14s (- 19.89%)0.57s0.59s
Check Time3.89s (± 0.65%)3.56s (± 4.42%)-0.32s (- 8.27%)3.42s3.74s
Emit Time1.54s (± 0.91%)1.57s (± 4.86%)+0.03s (+ 2.25%)1.51s1.67s
Total Time7.65s (± 0.65%)7.16s (± 3.13%)-0.50s (- 6.48%)6.96s7.42s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)165,316k (± 0.01%)-9,433k (- 5.40%)165,292k165,344k
Parse Time1.41s (± 1.63%)1.33s (± 0.77%)-0.08s (- 5.36%)1.33s1.35s
Bind Time0.62s (± 5.95%)0.50s (± 3.40%)-0.12s (- 19.68%)0.48s0.52s
Check Time2.98s (± 0.64%)2.75s (± 0.96%)-0.23s (- 7.73%)2.71s2.77s
Emit Time1.35s (± 0.83%)1.35s (± 1.29%)+0.01s (+ 0.45%)1.33s1.37s
Total Time6.36s (± 1.07%)5.94s (± 0.82%)-0.42s (- 6.60%)5.88s5.98s

map4 with usingNativeMaps = false and usingNativeSets = false

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.80s (± 1.47%)+0.01s (+ 0.73%)1.77s1.82s
Bind Time0.69s (± 4.74%)0.71s (± 13.45%)+0.02s (+ 3.18%)0.66s0.86s
Check Time3.37s (± 1.66%)3.43s (± 3.44%)+0.06s (+ 1.68%)3.29s3.57s
Emit Time5.01s (± 4.73%)5.04s (± 4.80%)+0.03s (+ 0.66%)4.93s5.42s
Total Time10.87s (± 2.34%)10.98s (± 1.85%)+0.12s (+ 1.09%)10.83s11.29s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)383,279k (± 0.01%)+3,355k (+ 0.88%)383,241k383,338k
Parse Time2.40s (± 0.75%)2.39s (± 2.42%)-0.01s (- 0.29%)2.33s2.44s
Bind Time0.92s (± 1.79%)0.90s (± 4.74%)-0.02s (- 2.55%)0.86s0.96s
Check Time4.26s (± 1.36%)4.29s (± 0.29%)+0.03s (+ 0.66%)4.28s4.31s
Emit Time1.87s (± 2.44%)1.88s (± 1.90%)+0.01s (+ 0.51%)1.85s1.92s
Total Time9.46s (± 1.19%)9.47s (± 0.86%)+0.01s (+ 0.11%)9.36s9.54s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)203,972k (± 0.01%)+2,001k (+ 0.99%)203,951k203,991k
Parse Time2.30s (± 0.89%)2.29s (± 0.76%)-0.01s (- 0.52%)2.27s2.31s
Bind Time0.72s (± 0.99%)0.68s (± 1.41%)-0.04s (- 5.87%)0.67s0.69s
Check Time3.48s (± 1.73%)3.83s (± 1.77%)+0.35s (+ 10.19%)3.78s3.92s
Emit Time1.91s (± 3.15%)1.62s (± 3.72%)-0.29s (- 15.12%)1.58s1.71s
Total Time8.41s (± 0.61%)8.42s (± 1.66%)+0.01s (+ 0.12%)8.32s8.63s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.22s (± 5.54%)-0.01s (- 0.49%)1.17s1.28s
Bind Time0.56s (± 2.96%)0.58s (± 5.13%)+0.02s (+ 4.38%)0.57s0.63s
Check Time2.81s (± 1.48%)2.84s (± 3.00%)+0.03s (+ 1.03%)2.77s2.95s
Emit Time3.11s (± 0.85%)3.16s (± 1.84%)+0.05s (+ 1.56%)3.08s3.21s
Total Time7.70s (± 0.84%)7.81s (± 2.01%)+0.10s (+ 1.32%)7.60s7.94s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)329,980k (± 0.02%)+1,975k (+ 0.60%)329,913k330,079k
Parse Time1.50s (± 1.02%)1.49s (± 0.69%)-0.02s (- 1.13%)1.47s1.49s
Bind Time0.73s (± 0.73%)0.71s (± 3.11%)-0.01s (- 2.00%)0.68s0.73s
Check Time3.89s (± 0.65%)4.04s (± 1.24%)+0.15s (+ 3.87%)3.96s4.06s
Emit Time1.54s (± 0.91%)1.64s (± 0.63%)+0.10s (+ 6.55%)1.63s1.65s
Total Time7.65s (± 0.65%)7.87s (± 0.76%)+0.21s (+ 2.80%)7.79s7.92s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)175,835k (± 0.01%)+1,086k (+ 0.62%)175,822k175,855k
Parse Time1.41s (± 1.63%)1.39s (± 0.74%)-0.02s (- 1.10%)1.39s1.41s
Bind Time0.62s (± 5.95%)0.57s (± 3.30%)-0.05s (- 8.48%)0.56s0.59s
Check Time2.98s (± 0.64%)2.99s (± 1.14%)+0.02s (+ 0.60%)2.96s3.04s
Emit Time1.35s (± 0.83%)1.38s (± 4.53%)+0.03s (+ 2.52%)1.33s1.45s
Total Time6.36s (± 1.07%)6.34s (± 1.32%)-0.02s (- 0.25%)6.25s6.43s

Heap snapshot numbers

The memory usage tended to be about the same up until the beforeEmit event, AKA after checking.

Master had 365,935 KB total, map4 had 343,774 KB (94% as much), and map4 with shims had 368,978 KB (100% as much as master, 106% as much as map4).

(I added an event heapAfterBind to test the effects of that; map4 used 97% as much memory as master, meaning the real memory savings are during checking.)

For map4, the chrome heap snaprhot viewer shows Maps as accounting for 2% of all objects, with a shallow size equal to their retained size at 1%. However, this is misleading because most of them are mere 32KB wrapper objects which have internal _keys and _values (or table in some cases), which is what really takes up space. I wish there were a way we could include the size of those.

VSCode numbers

I also ran a simple test on the VSCode repo.

master

tsc -p src --noEmit --diagnostics (Run with 2.1.0-dev.20161005)

KindAmountSamples
Memory used737211 K736716, 733971, 743103, 742334, 729932
I/O read0.17 s0.27, 0.12, 0.20, 0.14, 0.14
Parse time5.22 s5.21, 5.18, 5.22, 5.22, 5.29
Bind time1.74 s1.77, 1.72, 1.74, 1.72, 1.75
Check time8.57 s8.69, 8.48, 8.54, 8.50, 8.63
Total time15.54 s15.67, 15.38, 15.51, 15.45, 15.67

map4

node ../TypeScript/built/local/tsc.js -p src --noEmit --diagnostics

KindRelativeAmountSamples
Memory used94%690972 K691500, 690621, 691097, 690872, 690772
I/O read:100%0.17 s0.16, 0.18, 0.20, 0.14, 0.16
Parse time96%5.02 s5.03, 4.95, 4.99, 4.96, 5.18
Bind time:83%1.44 s1.42, 1.40, 1.44, 1.42, 1.53
Check time97%8.34 s8.32, 8.27, 8.38, 8.42, 8.33
Total time95%14.81 s14.78, 14.62, 14.81, 14.80, 15.05

map4 with shims

Same command as for map4, after rebuilding with usingNativeMaps = false and usingNativeSets = false.

KindRelativeAmountSamples
Memory used101%744718 K745408, 744639, 744845, 745511, 743185
I/O read106%0.18 s0.22, 0.19, 0.20, 0.14, 0.17
Parse time99%5.19 s5.28, 5.18, 5.20, 5.17, 5.13
Bind time98%1.71 s1.72, 1.69, 1.70, 1.73, 1.72
Check time101%8.68 s8.58, 8.72, 8.68, 8.72, 8.73
Total time100%15.59 s15.59, 15.59, 15.58, 15.62, 15.57

@ghost

Deleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown
Author

Here is a performance test for doing the same map lookup once vs twice.

constBenchmark=require("benchmark")constcrypto=require("crypto")constN=10000constwords=[]for(leti=0;i<N;i++)words[i]=crypto.randomBytes(8).toString('hex')functioncreateMap(){constm=newMap()for(leti=0;i<N;i+=2)m.set(words[i],i)returnm}functioncreateObject(){consto=Object.create(null)o["__"]=undefineddeleteo["__"]for(leti=0;i<N;i+=2)o[words[i]]=ireturno}letcorrectSum=0for(leti=0;i<N;i+=2)correctSum+=iconstsuite=newBenchmark.Suitesuite.add("map has-then-get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++)if(map.has(words[i]))sum+=map.get(words[i])if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map just get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++){constx=map.get(words[i])if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object has-then-get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++)if(words[i]ino)sum+=o[words[i]]if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object just get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++){constx=o[words[i]]if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map double get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){sum+=map.get(words[i])sum+=map.get(words[i])}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("map single get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){constgot=map.get(words[i])sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("object double get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){sum+=o[words[i]]sum+=o[words[i]]}if(sum!==correctSum*2)thrownewError()returnsum})suite.add("object single get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){constgot=o[words[i]]sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.on("complete",function(){this.forEach(({name, stats})=>{console.log(`${name}: ${stats.mean*1000}ms`)})})suite.on("error",err=>{throwerr.target.error})suite.run()
map has-then-get: 1.0212332328457447ms
map just get: 0.911712559080547ms
object has-then-get: 1.9529671271167457ms
object just get: 1.9624182600334454ms
map double get: 0.7383946305889607ms
map single get: 0.651791347503374ms
object double get: 1.411747356033454ms
object single get: 1.3791293993025284ms

Looks like removing uses of has is useful for maps but not for objects. Removing double get is always good.

@ghostghost mentioned this pull request Oct 4, 2016
@ghost
ghost force-pushed the map4 branch 2 times, most recently from 1f080a8 to 6fc4eadCompareOctober 5, 2016 14:58
@ghost

Copy link
Copy Markdown
Author

This would be a breaking change. We have publicly exported maps because we have export type SymbolTable = Map<string, Symbol>;, which is the type of several public properties of Symbol.

Comment threadJakefile.js Outdated
}

var compilerSources = [
"dataStructures.ts",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be tempted to call this collections.ts, since we already have a types.ts and this is more specific.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of moving our array utilities to collections.ts?

Comment threadsrc/compiler/dataStructures.ts Outdated
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

/** Extra Map methods that may not be available, so we must provide fallbacks. */
interface FullyFeaturedMap<K, V> extends Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe call this ES6Map?

@ghostghost mentioned this pull request Oct 7, 2016
@yuit

Copy link
Copy Markdown
Contributor

Andy (Andrewkraft) (@Andy-MS) looks good for my end 👍 though it is a big change so I think it may be good idea to have Mohamed Hegazy (@mhegazy)Vladimir Matveev (@vladima)Nathan Shively-Sanders (@sandersn)Ron Buckton (@rbuckton) to check as well

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider merging the shims for NumberMap and StringMap.

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for stylistic consistency do not use classes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you share the numbers after removing classes?

@ghostDeleted user (ghost)Oct 12, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It ends up taking 20% longer. 🤕
Here are the measurements for running map4 with closure shims, with "Delta" relative to map4 with class shims.

Monaco - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used203,967k (± 0.01%)224,241k (± 0.01%)+20,274k (+ 9.94%)224,220k224,263k
Parse Time2.27s (± 0.39%)2.39s (± 3.65%)+0.12s (+ 5.30%)2.32s2.51s
Bind Time0.68s (± 1.17%)0.83s (± 1.52%)+0.15s (+ 21.41%)0.81s0.84s
Check Time3.86s (± 2.12%)4.72s (± 3.44%)+0.86s (+ 22.15%)4.55s4.89s
Emit Time1.62s (± 2.07%)2.30s (± 14.05%)+0.68s (+ 41.80%)2.04s2.72s
Total Time8.43s (± 1.26%)10.23s (± 3.36%)+1.80s (+ 21.34%)9.78s10.47s
TFS - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used175,828k (± 0.01%)188,541k (± 0.01%)+12,713k (+ 7.23%)188,529k188,551k
Parse Time1.40s (± 0.75%)1.51s (± 4.24%)+0.11s (+ 7.80%)1.46s1.60s
Bind Time0.57s (± 1.02%)0.68s (± 2.26%)+0.12s (+ 20.63%)0.67s0.70s
Check Time3.00s (± 0.53%)3.60s (± 3.55%)+0.60s (+ 19.88%)3.41s3.69s
Emit Time1.37s (± 1.09%)1.71s (± 5.74%)+0.34s (+ 25.18%)1.66s1.86s
Total Time6.33s (± 0.28%)7.50s (± 2.73%)+1.16s (+ 18.38%)7.24s7.71s

Here's the code I tested with (with equivalents for NumberMap and StringSet):

exportconstcreateStringMap: <T>(pairs?: [string,T][])=>Map<string,T>=usingNativeMaps
? <T>(pairs?: [string,T][])=>newMap(pairs)
: <T>(pairs?: [string,T][])=>{letdata=createDictionaryModeObject<T>();if(pairs){for(const[key,value]ofpairs){data[key]=value;}}return{clear(): void{data=createDictionaryModeObject<T>();},delete(key: string): void{deletedata[key];},get(key: string): T{returndata[key];},has(key: string): boolean{// tslint:disable-next-line:no-in-operatorreturnkeyindata;},set(key: string,value: T): void{data[key]=value;},forEach(action: (value: T,key: string)=>void): void{for(constkeyindata){action(data[key],key);}}}}

I bet this is allocating a different closure for each method, wheras a class just allocates space for data and shares a single prototype among all instances.

Comment threadsrc/compiler/collections.ts Outdated
// Map utilities
namespace ts {
/** Create a map containing a single entry key -> value. */
export function createMapWithEntry<T>(key: string, value: T): Map<string, T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider inlining this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or using the Map constructor optional parameter

Comment threadsrc/compiler/collections.ts Outdated
}

// Map utilities
namespace ts {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be marked internal. and consider using one closure for all of them

Comment threadsrc/compiler/program.ts Outdated

// If output has not been changed, and the file has no external modification
if (fingerprint.byteOrderMark === writeByteOrderMark &&
if (fingerprint !== undefined && fingerprint.byteOrderMark === writeByteOrderMark &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just if (figureprint

@mhegazy

Copy link
Copy Markdown
Contributor

Can you also share the perf numbers once it is in.

@mhegazy

Copy link
Copy Markdown
Contributor

Ron Buckton (@rbuckton) any more comments?

@rbucktonRon Buckton (rbuckton) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few non-blocking review comments, but this looks fine to me.

Comment threadsrc/compiler/collections.ts Outdated
declare const Map: { new<K, V>(pairs?: [K, V][]): Map<K, V> } | undefined;
const usingNativeMaps = typeof Map !== "undefined";
// tslint:disable-next-line:no-in-operator
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term "fully-featured" is a bit ambiguous. Maybe usingES6NativeMaps?

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using an object.
* `pairs` is an optional list of entries to add to the new map.
*/
export const StringMap: { new<T>(pairs?: [string, T][]): Map<string, T>; } = usingNativeMaps ? Map : ShimMap;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love for us to be able to just call this Map instead of StringMap or NumberMap, but its a bit messy to avoid colliding with the global Map

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or stick with createMap<K extends string | number, V>() and createSet<T extends string | number>()

Comment threadsrc/compiler/collections.ts Outdated
* Creates a sorted array of keys.
* Sorts keys according to the iteration order they would have if they were in an object, instead of from a Map.
* This is so that tests run consistently whether or not we have a Map shim in place.
* The difference between Map iteration order and V8 object insertion order is that V8 moves natrual-number-like keys to the front.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"natural"

Comment threadsrc/compiler/collections.ts Outdated
}

delete(value: string) {
delete this.data[value];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Sets return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
}

delete(key: K): void {
delete this.data[key as string];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Maps return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
However, `forEach` will iterate over strings because values are stringified before being put in the map.
*/

constructor(pairs?: [K, V][]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-ES6 native maps don't support constructor arguments.

delete(key: K): void {
delete this.data[key as string];
delete(key: K): boolean {
const had = this.has(key);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this. Just do return delete this.data[key as string].

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deletealways returns true in strict mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. That's unfortunate...and odd.

delete(value: string) {
delete this.data[value];
delete(value: string): boolean {
const had = this.has(value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, you can just do return delete this.data[value] since a delete expression returns boolean

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard

@ghost
ghost merged commit adfdae0 into masterOct 27, 2016
@ghost
ghost deleted the map4 branch October 27, 2016 20:27
@ghost

Copy link
Copy Markdown
Author

Will do a final performance comparison tomorrow.

ghost pushed a commit that referenced this pull request Oct 27, 2016
This reverts commit adfdae0, reversing
changes made to aad663c.
ghost pushed a commit that referenced this pull request Oct 27, 2016
Revert "Merge pull request #11354 from Microsoft/map4"
Mohamed Hegazy (mhegazy) added a commit that referenced this pull request Nov 10, 2016
* Use a single ShimMap class, and indicate that iteration always yields string keys (which it did before too)
* Remove emacs-added newline at end of baseline
* Remove space at end of line in baseline
* Add numeric indexer to strings and remove lint
* Update baselines with spread string's numeric indexers
* Reset baseline line number to the locally incorrect value
* Remove trailing newline from baseline again
* Respond to PR comments
* Refactor getTypeFromTypeLiteral, from PR comments
* Fix lint
* Use same literal comparison rules for switch/===
switch was missing the rule for converting literal types to the literal
base type if needed.
* Add switch comparability test and update baselines
* Push eitherIsNotLiteral check into isTypeEqualityComparableTo
Since all callers need this check -- it's how equality is supposed to
work everywhere.
* Update baselines
There are more literal types in error messages because error reporting
no longer has the advantage of calls to getBaseLiteralType
* Adds ES5 to ES3 transformer for reserved words
* Minor cleanup
* Cleaned up emit of enum declaration
* Return both ts and js results from module resolution, and don't have moduleNameResolver responsible for omitting files based on compiler options
* Instead of getResolutionOrDiagnostic, use getResolutionDiagnostic and avoid using resolution.resolvedFileName if the diagnostic is defined.
* Remove "ResolvedModuleFromHost" type and just make `resolvedTsFileName` and `resolvedJsFileName` optional properties
(but still automatically infer one of them to supply if the host supplied neither)
* Remove type inference for spread types
* Update inference test for spread types
* Make spread assignability and apparent type stricter
Assignability now does not allow properties to the left of a type
parameter.
Apparent type now only returns the apparent type of the right-most
spread member.
* Update tests w/spread assignability+apparent type
* Moved AMD/CJS/UMD transform to end
* Spread no longer distributes intersections
* Update spread w/intersection tests
* Move System module transform to end.
* Update baseline
* Revert baseline change due to stale output
* Resolve all-object intersections inside spreads
This means that getSpreadType will return an object type, even when
spreading two intersections, as long as those intersections contain
nothing but object types themselves.
* Update and improve spread intersection tests
* Simplify expression in resolveObjectIntersection
* Update baselines with new index signature rules
* Move n-ary spread handling into separate function.
To be moved to callers in the next step.
* Move multiple-spread handling out of getSpreadType
* Clean up and reorder getSpreadType body
* Respond to PR comments
* Error for call/construct signatures in spread type
1. Simplify the error reporting code to handle all kinds of signatures.
2. Remove index signature handling code when creating a spread type
since it's an error anyway.
* Update baselines with new spread type index errors
* Explain writeSpreadType a little better
* Add more commentary to getSpreadType
* Initial implementation of 'keyof T' type operator
* Introduce PropertyNameType
* Move most of resolveModuleNameForLsHost to lsHost
* Simplify isImplicitGlob test
* Initial implementation of 'T[K]' property access types
* add a fallback logic for older versions of node that don't support 'homedir' (#11845)
* add a fallback logic for older versions of node that don't support 'homedir'
* try os.homedir first
* For JavaScript files, we report semantic errors for using TypeScript-only constructs from within a JavaScript file as syntactic errors.
* Don't require `resolvedTsFileName` and `resolvedJsFileName`, just `resolvedFileName` and `extension`. Also, change search order to do all TS searching before searching for JS.
* Fix#10108 (Completion suggestion for object literal with getter) (#11808)
* Fix#10108 (Completion suggestion for object literal with getter)
* completions for setter
* Move helper functions to core (fix build)
* Support parametric property access expressions + some renaming
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives (#11872)
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives
* pass proper value for current directory when compiling .d.ts files
* Fix bug: Return a resolution diagnostic for a `.jsx` import if `--allowJs` is turned off
* Remove a comment about a parameter that no longer exists
* Fix bug: We want to test for existence of the enum value, not whether it's non-zero
* Fix: test for presence, not absence
* Allow untyped imports
* Simplify for loops in fourslash.ts
* Rename to zipWith
* Change diagnostic message
* Make `extension` property of `ResolvedModule` optional; introduce `ResolvedModuleFull` interface for when the extension is provided.
* Consider index signatures in type produced by 'keyof T'
* Respond to PR comments
* Refactor getIndexedAccessType to be reusable from checkIndexedAccess
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Revert "Merge pull request #11354 from Microsoft/map4"
This reverts commit adfdae0, reversing
changes made to aad663c.
* Rename Experimental transform to ESNext
1. Spread/rest are no longer experimental.
2. We need a place to put stage 3 ES features.
* Changes from CR feedback
* disable CoS for inferred projects (#11909)
* Updating test due to CR changes. The order of the diagnostic messages has changed due to concatenation changes
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* Rename TransformFlags.Experimental -> ESNext
* enable non-ts extensions in inferred projects by default
* update CFG to properly handle do statements
* do not inline async IIFEs in control flow graph
* Minor fixes
* cache type for empty type literal (#11934)
cache type for empty type literal
* Improved error messages for invalid assignments to identifiers
* Accept new baselines
* Improved error messages for invalid assignments to properties
* Accept new baselines
* Improve more error messages
* Accept new baselines
* Fix realPathMap in test harness: Must be used in `directoryExists`
* Add helper function
* Update generated files (#11963)
* Move eitherIsNotLiteral check into switch and === checks
This improves error messages
* Forbid augmentation of untyped module (#11962)
* Forbid augmentation of untyped module
* Just use `undefined` for untyped modules
* Unify checking of indexed access expressions and indexed access types
* Accept new baselines
* Accept additional baselines
* Make `cachingInServerLSHost` tests work with `runtests-browser`
* Get literal type only once
* Update baselines
* Add missed test update
* Improve unification by moving more logic to getIndexedAccessType
* Add test cases to report errors for decorators in js file
* Report all the js file errors and skip only the nodes that are not allowed in js
Fixes#11800
* Fix 'keyof any' to produce 'string | number'
* Fix#11396: Make error message referene `Promise` explicitly (#11982)
* Simplify the checking for async function return type
* Fix#11396: Make error message referene `Promise` explicitly
* Minor fixes
* Adding tests
* Test case for property used in destructuring variable declaration
* Mark property referenced in the destructuring as referenced
Fixes#11324
* Spread types handle nested index [access] types
Nested index [access] types are treated as assignable to themselves only,
just like type parameters.
* Test index [access] types inside spread types
* module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program (#11999)
module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program
* Parse, bind and check rest elements
* Downlevel emit of rest elements
* Add rest tests
* Update baselines
* Remove spread types, leaving spread syntax/emit
Spreads are still typed, but cannot be created from a non-object type.
Tests still need to be updated.
* Fix lint
* Lock tslint version to 4.0.0-dev.0, because 4.0.0-dev.1 complains about unnecessary semicolons following properties
* Remove spread type tests from spread tests
* Spread handles index signatures from singleton spreads
I broke it when simplifying the logic earlier.
* Correct assignability for keyof types and type parameters
* Update tests
* Accept new baselines
* Update objectRestAssignment test and baselines
* Fix linting errors
* Update objectRestAssignment test
Missed previously, just got the baselines
* Improve readability of ES next destructuring emit
* Ensure transformFlags are correct before visiting a node.
* Port #12027, #11980 and #11932 to master (#12037)
* add test for the fix for overwrite emitting error
* cr feedback
* Address PR comments
1. Remove extra line in __rest shim.
2. Improve __rest vs __assign check for destructuring assignment.
* Move convertForOf to factory for esnext and es2015
Saves a lot of duplicated code
* Update improved baselines
* Move transformFunctionBody to factory
It is shared by es2015 and esNext transformers.
This commit just adds a convertObjectRest flag to be passed on to
flattenDestructuring functions, as well as adding necessary parameters
to use the code outside a transformer.
* Spread any types to any
* add missing bind calls to properly set parent on token nodes (#12057)
* Cache generic signature instantiations
* Accept new baselines
* Properly instantiate aliasTypeArguments
* Add regression test
* Revert incorrect logic from #11392
* Accept new baselines
* Rename SpreadElementExpression -> SpreadAssignment
and SpreadExpression (formerly SpreadElementExpression) -> SpreadElement
* Add SpreadAssignment to visitors
1. visitNode
2. reduceNode
3. emit
This fixes an emit bug for setters.
* Add --target esnext
Currently, this disables the rest and spread transforms. This will
change as proposals enter and leave stage 3.
* Add --target esnext tests and update baselines
* Revert unneeded change and comments per PR
* Rename variable in checkSwitchStatement per PR
* Do not emit __rest for --target esnext
* Add `realpath` implementation for lshost
* Create spread property types eagerly
This avoids the need for a synthetic symbol and later code called from
getTypeOfSymbol.
* Set spread type symbols in checkObjectLiteral
Instead of getSpreadType.
Also clean up special-case handling inside getSpreadType to be more
readable.
* Ports #12051 and #12032 into master (#12090)
* use local registry to check if typings package exist (#12014)
use local registry to check if typings package exist
* enable sending telemetry events to tsserver client (#12035)
enable sending telemetry events
* Address more PR comments
* return empty file watcher in case if target directory does not exist (#12091)
* return empty file watcher in case if target directory does not exist
* linter
* property handle missing config files in external projects (#12094)
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Port fix for #12069 (#12095)
* reduce set of files being watched, increase polling interval (#12054) (#12092)
* Update authors for release-2.1
* Include declaration file emit
* use createHash from ServerHost instead of explicit require (#12043)
* use createHash from ServerHost instead of explicit require
* added missing method in ServerHost stub
* (signature help) type parameter lists are never variadic (#12112)
* Handle abstract and const modifiers
* Downlevel array destructuring to ES6 in object rest
Previously array destructuring inside an object destructuring with an
object rest would downlevel the array destructuring to ES5. This breaks
if the code that targets ES2015 is using iterators instead of arrays
since iterators don't support [0] or .slice that the ES5 emit uses.
* Improve nested destructuring test for ESNext emit
Now with object destructuring inside array destructuring inside object
destructuring! Each with their own array/object rest!
Also updates baselines.
* Add support for taking in jsxFactory option and report errors for invalid combinations
* Treat `| undefined` like optionality in spread type
* Add strictNullChecks test for object spread
* Verify that jsxFactory is either identifier or qualified name
* Resolve first identifier of the jsxFactory as part of type check
* When emitting use jsx factory entity expression if provided
* Transpile unit test case
* Enabled test case for source map
* Add test cases for when jsxFactory cannot be resolved
* Parse the jsxFactory again in the checker instead of using cached value in the program
* Adds error message for incompatible assignment of identically named type
Fixes issue #12050
* Updated condition for more readability
* Report errors for import helpers missing __rest
* Correctly check spread assignments in strict mode
Previously it crashed in the binder.
* Test error for import helpers with no __rest
* synthesize complete import declaration for tslib (#12151)
* Add ES2017 string padding (#12152)
* add es2017.string.d.ts for String.prototype.{padStart,padEnd}
* append es2017.string.d.ts into es2017.d.ts
* add es2017.string into commandLineParser
* append es2017.string into error message for unit tests of commandLineParser
* append es2017.string into Gulpfile
* append es2017.string into Jakefile
* Exclude js files in non-configured projects compile-on-save emitting (#12118)
* Exclude js files in non-configured projects CoS emitting
* remove unnecessary method
* Merge release-2.1 into master (#12157)
* Update LKG
* Update version
* Update LKG
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* Update LKG
* Fix emit inferred type which is a generic type-alias both fully and partially fill type parameters
* Add tests and baselines
* Skip trying to use alias if there is target type
* Update baselines
* Add diagnostics to remind adding tsconfig file for certain external project (#11932)
* Add diagnostics for certain external project
* Show tsconfig suggestion
* fix lint error
* Address pr
* fix comment
* Update error message
* Flag for not overwrite js files by default without generating errors (#11980)
* WIP
* Properly naming things
* refactor
* apply the option to all files and check out options
* Fix typo
* Update LKG
* lockLinter
* use local registry to check if typings package exist (#12014) (#12032)
use local registry to check if typings package exist
* Add test for #11980 (#12027)
* add test for the fix for overwrite emitting error
* cr feedback
* enable sending telemetry events to tsserver client (#12034) (#12051)
enable sending telemetry events
* Update LKG
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Update LKG
* Update version
* Update LKG
* Do not emit "use strict" when targeting es6 or higher or module kind is es2015 and the file is external module
* Add tests and baselines
* [Release 2.1] fix11754 global augmentation (#12133)
* Exclude global augmentation from module resolution logic
* Address PR: check using string literal instead of NodeFlags.globalAugmentation
* Remove comment
@ghostghost mentioned this pull request Dec 7, 2016
@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
This pull request was closed.
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@yuit@mhegazy@rbuckton@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Use native maps when they're available - #11354

Merged
18 commits merged into
masterfrom
map4
Oct 27, 2016
Merged

Use native maps when they're available#11354
18 commits merged into
masterfrom
map4

Conversation

@ghost

@ghostDeleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown

The summary is that using native maps, the compiler works 5% faster and uses 5% less memory. Using shims, the performance is surprisingly less than 5% worse.

I was able to achieve good baseline performance by disabling Windows Defender in my work directory and using "High Performance" in Control Panel -> Hardware and Sound -> Power Options. There is much less variance this time around.

Benchmark numbers

This is from using our internal ts-perf tool.

map4

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.72s (± 1.10%)-0.07s (- 4.08%)1.70s1.74s
Bind Time0.69s (± 4.74%)0.52s (± 3.50%)-0.17s (- 24.86%)0.50s0.54s
Check Time3.37s (± 1.66%)2.91s (± 3.16%)-0.46s (- 13.69%)2.78s2.98s
Emit Time5.01s (± 4.73%)4.87s (± 1.35%)-0.14s (- 2.77%)4.79s4.94s
Total Time10.87s (± 2.34%)10.02s (± 1.18%)-0.84s (- 7.77%)9.86s10.12s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)356,928k (± 0.01%)-22,996k (- 6.05%)356,890k356,956k
Parse Time2.40s (± 0.75%)2.32s (± 2.13%)-0.08s (- 3.37%)2.28s2.39s
Bind Time0.92s (± 1.79%)0.71s (± 1.84%)-0.21s (- 22.52%)0.70s0.73s
Check Time4.26s (± 1.36%)3.84s (± 6.33%)-0.42s (- 9.94%)3.66s4.18s
Emit Time1.87s (± 2.44%)1.82s (± 3.16%)-0.05s (- 2.80%)1.77s1.89s
Total Time9.46s (± 1.19%)8.69s (± 3.96%)-0.77s (- 8.12%)8.42s9.16s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)190,504k (± 0.01%)-11,467k (- 5.68%)190,474k190,538k
Parse Time2.30s (± 0.89%)2.20s (± 2.07%)-0.09s (- 4.09%)2.17s2.27s
Bind Time0.72s (± 0.99%)0.57s (± 4.73%)-0.15s (- 21.33%)0.55s0.61s
Check Time3.48s (± 1.73%)3.27s (± 4.68%)-0.21s (- 6.08%)3.08s3.38s
Emit Time1.91s (± 3.15%)1.78s (± 8.00%)-0.13s (- 6.94%)1.65s1.94s
Total Time8.41s (± 0.61%)7.82s (± 1.68%)-0.59s (- 7.03%)7.71s7.99s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.15s (± 1.31%)-0.07s (- 6.06%)1.13s1.16s
Bind Time0.56s (± 2.96%)0.54s (± 4.08%)-0.02s (- 3.13%)0.52s0.57s
Check Time2.81s (± 1.48%)2.46s (± 1.85%)-0.35s (- 12.34%)2.43s2.53s
Emit Time3.11s (± 0.85%)3.19s (± 0.91%)+0.07s (+ 2.33%)3.15s3.22s
Total Time7.70s (± 0.84%)7.34s (± 1.14%)-0.37s (- 4.78%)7.28s7.46s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)309,449k (± 0.02%)-18,556k (- 5.66%)309,386k309,516k
Parse Time1.50s (± 1.02%)1.44s (± 0.88%)-0.07s (- 4.32%)1.42s1.45s
Bind Time0.73s (± 0.73%)0.58s (± 1.65%)-0.14s (- 19.89%)0.57s0.59s
Check Time3.89s (± 0.65%)3.56s (± 4.42%)-0.32s (- 8.27%)3.42s3.74s
Emit Time1.54s (± 0.91%)1.57s (± 4.86%)+0.03s (+ 2.25%)1.51s1.67s
Total Time7.65s (± 0.65%)7.16s (± 3.13%)-0.50s (- 6.48%)6.96s7.42s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)165,316k (± 0.01%)-9,433k (- 5.40%)165,292k165,344k
Parse Time1.41s (± 1.63%)1.33s (± 0.77%)-0.08s (- 5.36%)1.33s1.35s
Bind Time0.62s (± 5.95%)0.50s (± 3.40%)-0.12s (- 19.68%)0.48s0.52s
Check Time2.98s (± 0.64%)2.75s (± 0.96%)-0.23s (- 7.73%)2.71s2.77s
Emit Time1.35s (± 0.83%)1.35s (± 1.29%)+0.01s (+ 0.45%)1.33s1.37s
Total Time6.36s (± 1.07%)5.94s (± 0.82%)-0.42s (- 6.60%)5.88s5.98s

map4 with usingNativeMaps = false and usingNativeSets = false

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.80s (± 1.47%)+0.01s (+ 0.73%)1.77s1.82s
Bind Time0.69s (± 4.74%)0.71s (± 13.45%)+0.02s (+ 3.18%)0.66s0.86s
Check Time3.37s (± 1.66%)3.43s (± 3.44%)+0.06s (+ 1.68%)3.29s3.57s
Emit Time5.01s (± 4.73%)5.04s (± 4.80%)+0.03s (+ 0.66%)4.93s5.42s
Total Time10.87s (± 2.34%)10.98s (± 1.85%)+0.12s (+ 1.09%)10.83s11.29s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)383,279k (± 0.01%)+3,355k (+ 0.88%)383,241k383,338k
Parse Time2.40s (± 0.75%)2.39s (± 2.42%)-0.01s (- 0.29%)2.33s2.44s
Bind Time0.92s (± 1.79%)0.90s (± 4.74%)-0.02s (- 2.55%)0.86s0.96s
Check Time4.26s (± 1.36%)4.29s (± 0.29%)+0.03s (+ 0.66%)4.28s4.31s
Emit Time1.87s (± 2.44%)1.88s (± 1.90%)+0.01s (+ 0.51%)1.85s1.92s
Total Time9.46s (± 1.19%)9.47s (± 0.86%)+0.01s (+ 0.11%)9.36s9.54s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)203,972k (± 0.01%)+2,001k (+ 0.99%)203,951k203,991k
Parse Time2.30s (± 0.89%)2.29s (± 0.76%)-0.01s (- 0.52%)2.27s2.31s
Bind Time0.72s (± 0.99%)0.68s (± 1.41%)-0.04s (- 5.87%)0.67s0.69s
Check Time3.48s (± 1.73%)3.83s (± 1.77%)+0.35s (+ 10.19%)3.78s3.92s
Emit Time1.91s (± 3.15%)1.62s (± 3.72%)-0.29s (- 15.12%)1.58s1.71s
Total Time8.41s (± 0.61%)8.42s (± 1.66%)+0.01s (+ 0.12%)8.32s8.63s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.22s (± 5.54%)-0.01s (- 0.49%)1.17s1.28s
Bind Time0.56s (± 2.96%)0.58s (± 5.13%)+0.02s (+ 4.38%)0.57s0.63s
Check Time2.81s (± 1.48%)2.84s (± 3.00%)+0.03s (+ 1.03%)2.77s2.95s
Emit Time3.11s (± 0.85%)3.16s (± 1.84%)+0.05s (+ 1.56%)3.08s3.21s
Total Time7.70s (± 0.84%)7.81s (± 2.01%)+0.10s (+ 1.32%)7.60s7.94s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)329,980k (± 0.02%)+1,975k (+ 0.60%)329,913k330,079k
Parse Time1.50s (± 1.02%)1.49s (± 0.69%)-0.02s (- 1.13%)1.47s1.49s
Bind Time0.73s (± 0.73%)0.71s (± 3.11%)-0.01s (- 2.00%)0.68s0.73s
Check Time3.89s (± 0.65%)4.04s (± 1.24%)+0.15s (+ 3.87%)3.96s4.06s
Emit Time1.54s (± 0.91%)1.64s (± 0.63%)+0.10s (+ 6.55%)1.63s1.65s
Total Time7.65s (± 0.65%)7.87s (± 0.76%)+0.21s (+ 2.80%)7.79s7.92s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)175,835k (± 0.01%)+1,086k (+ 0.62%)175,822k175,855k
Parse Time1.41s (± 1.63%)1.39s (± 0.74%)-0.02s (- 1.10%)1.39s1.41s
Bind Time0.62s (± 5.95%)0.57s (± 3.30%)-0.05s (- 8.48%)0.56s0.59s
Check Time2.98s (± 0.64%)2.99s (± 1.14%)+0.02s (+ 0.60%)2.96s3.04s
Emit Time1.35s (± 0.83%)1.38s (± 4.53%)+0.03s (+ 2.52%)1.33s1.45s
Total Time6.36s (± 1.07%)6.34s (± 1.32%)-0.02s (- 0.25%)6.25s6.43s

Heap snapshot numbers

The memory usage tended to be about the same up until the beforeEmit event, AKA after checking.

Master had 365,935 KB total, map4 had 343,774 KB (94% as much), and map4 with shims had 368,978 KB (100% as much as master, 106% as much as map4).

(I added an event heapAfterBind to test the effects of that; map4 used 97% as much memory as master, meaning the real memory savings are during checking.)

For map4, the chrome heap snaprhot viewer shows Maps as accounting for 2% of all objects, with a shallow size equal to their retained size at 1%. However, this is misleading because most of them are mere 32KB wrapper objects which have internal _keys and _values (or table in some cases), which is what really takes up space. I wish there were a way we could include the size of those.

VSCode numbers

I also ran a simple test on the VSCode repo.

master

tsc -p src --noEmit --diagnostics (Run with 2.1.0-dev.20161005)

KindAmountSamples
Memory used737211 K736716, 733971, 743103, 742334, 729932
I/O read0.17 s0.27, 0.12, 0.20, 0.14, 0.14
Parse time5.22 s5.21, 5.18, 5.22, 5.22, 5.29
Bind time1.74 s1.77, 1.72, 1.74, 1.72, 1.75
Check time8.57 s8.69, 8.48, 8.54, 8.50, 8.63
Total time15.54 s15.67, 15.38, 15.51, 15.45, 15.67

map4

node ../TypeScript/built/local/tsc.js -p src --noEmit --diagnostics

KindRelativeAmountSamples
Memory used94%690972 K691500, 690621, 691097, 690872, 690772
I/O read:100%0.17 s0.16, 0.18, 0.20, 0.14, 0.16
Parse time96%5.02 s5.03, 4.95, 4.99, 4.96, 5.18
Bind time:83%1.44 s1.42, 1.40, 1.44, 1.42, 1.53
Check time97%8.34 s8.32, 8.27, 8.38, 8.42, 8.33
Total time95%14.81 s14.78, 14.62, 14.81, 14.80, 15.05

map4 with shims

Same command as for map4, after rebuilding with usingNativeMaps = false and usingNativeSets = false.

KindRelativeAmountSamples
Memory used101%744718 K745408, 744639, 744845, 745511, 743185
I/O read106%0.18 s0.22, 0.19, 0.20, 0.14, 0.17
Parse time99%5.19 s5.28, 5.18, 5.20, 5.17, 5.13
Bind time98%1.71 s1.72, 1.69, 1.70, 1.73, 1.72
Check time101%8.68 s8.58, 8.72, 8.68, 8.72, 8.73
Total time100%15.59 s15.59, 15.59, 15.58, 15.62, 15.57

@ghost

Deleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown
Author

Here is a performance test for doing the same map lookup once vs twice.

constBenchmark=require("benchmark")constcrypto=require("crypto")constN=10000constwords=[]for(leti=0;i<N;i++)words[i]=crypto.randomBytes(8).toString('hex')functioncreateMap(){constm=newMap()for(leti=0;i<N;i+=2)m.set(words[i],i)returnm}functioncreateObject(){consto=Object.create(null)o["__"]=undefineddeleteo["__"]for(leti=0;i<N;i+=2)o[words[i]]=ireturno}letcorrectSum=0for(leti=0;i<N;i+=2)correctSum+=iconstsuite=newBenchmark.Suitesuite.add("map has-then-get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++)if(map.has(words[i]))sum+=map.get(words[i])if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map just get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++){constx=map.get(words[i])if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object has-then-get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++)if(words[i]ino)sum+=o[words[i]]if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object just get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++){constx=o[words[i]]if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map double get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){sum+=map.get(words[i])sum+=map.get(words[i])}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("map single get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){constgot=map.get(words[i])sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("object double get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){sum+=o[words[i]]sum+=o[words[i]]}if(sum!==correctSum*2)thrownewError()returnsum})suite.add("object single get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){constgot=o[words[i]]sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.on("complete",function(){this.forEach(({name, stats})=>{console.log(`${name}: ${stats.mean*1000}ms`)})})suite.on("error",err=>{throwerr.target.error})suite.run()
map has-then-get: 1.0212332328457447ms
map just get: 0.911712559080547ms
object has-then-get: 1.9529671271167457ms
object just get: 1.9624182600334454ms
map double get: 0.7383946305889607ms
map single get: 0.651791347503374ms
object double get: 1.411747356033454ms
object single get: 1.3791293993025284ms

Looks like removing uses of has is useful for maps but not for objects. Removing double get is always good.

@ghostghost mentioned this pull request Oct 4, 2016
@ghost
ghost force-pushed the map4 branch 2 times, most recently from 1f080a8 to 6fc4eadCompareOctober 5, 2016 14:58
@ghost

Copy link
Copy Markdown
Author

This would be a breaking change. We have publicly exported maps because we have export type SymbolTable = Map<string, Symbol>;, which is the type of several public properties of Symbol.

Comment threadJakefile.js Outdated
}

var compilerSources = [
"dataStructures.ts",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be tempted to call this collections.ts, since we already have a types.ts and this is more specific.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of moving our array utilities to collections.ts?

Comment threadsrc/compiler/dataStructures.ts Outdated
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

/** Extra Map methods that may not be available, so we must provide fallbacks. */
interface FullyFeaturedMap<K, V> extends Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe call this ES6Map?

@ghostghost mentioned this pull request Oct 7, 2016
@yuit

Copy link
Copy Markdown
Contributor

Andy (Andrewkraft) (@Andy-MS) looks good for my end 👍 though it is a big change so I think it may be good idea to have Mohamed Hegazy (@mhegazy)Vladimir Matveev (@vladima)Nathan Shively-Sanders (@sandersn)Ron Buckton (@rbuckton) to check as well

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider merging the shims for NumberMap and StringMap.

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for stylistic consistency do not use classes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you share the numbers after removing classes?

@ghostDeleted user (ghost)Oct 12, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It ends up taking 20% longer. 🤕
Here are the measurements for running map4 with closure shims, with "Delta" relative to map4 with class shims.

Monaco - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used203,967k (± 0.01%)224,241k (± 0.01%)+20,274k (+ 9.94%)224,220k224,263k
Parse Time2.27s (± 0.39%)2.39s (± 3.65%)+0.12s (+ 5.30%)2.32s2.51s
Bind Time0.68s (± 1.17%)0.83s (± 1.52%)+0.15s (+ 21.41%)0.81s0.84s
Check Time3.86s (± 2.12%)4.72s (± 3.44%)+0.86s (+ 22.15%)4.55s4.89s
Emit Time1.62s (± 2.07%)2.30s (± 14.05%)+0.68s (+ 41.80%)2.04s2.72s
Total Time8.43s (± 1.26%)10.23s (± 3.36%)+1.80s (+ 21.34%)9.78s10.47s
TFS - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used175,828k (± 0.01%)188,541k (± 0.01%)+12,713k (+ 7.23%)188,529k188,551k
Parse Time1.40s (± 0.75%)1.51s (± 4.24%)+0.11s (+ 7.80%)1.46s1.60s
Bind Time0.57s (± 1.02%)0.68s (± 2.26%)+0.12s (+ 20.63%)0.67s0.70s
Check Time3.00s (± 0.53%)3.60s (± 3.55%)+0.60s (+ 19.88%)3.41s3.69s
Emit Time1.37s (± 1.09%)1.71s (± 5.74%)+0.34s (+ 25.18%)1.66s1.86s
Total Time6.33s (± 0.28%)7.50s (± 2.73%)+1.16s (+ 18.38%)7.24s7.71s

Here's the code I tested with (with equivalents for NumberMap and StringSet):

exportconstcreateStringMap: <T>(pairs?: [string,T][])=>Map<string,T>=usingNativeMaps
? <T>(pairs?: [string,T][])=>newMap(pairs)
: <T>(pairs?: [string,T][])=>{letdata=createDictionaryModeObject<T>();if(pairs){for(const[key,value]ofpairs){data[key]=value;}}return{clear(): void{data=createDictionaryModeObject<T>();},delete(key: string): void{deletedata[key];},get(key: string): T{returndata[key];},has(key: string): boolean{// tslint:disable-next-line:no-in-operatorreturnkeyindata;},set(key: string,value: T): void{data[key]=value;},forEach(action: (value: T,key: string)=>void): void{for(constkeyindata){action(data[key],key);}}}}

I bet this is allocating a different closure for each method, wheras a class just allocates space for data and shares a single prototype among all instances.

Comment threadsrc/compiler/collections.ts Outdated
// Map utilities
namespace ts {
/** Create a map containing a single entry key -> value. */
export function createMapWithEntry<T>(key: string, value: T): Map<string, T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider inlining this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or using the Map constructor optional parameter

Comment threadsrc/compiler/collections.ts Outdated
}

// Map utilities
namespace ts {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be marked internal. and consider using one closure for all of them

Comment threadsrc/compiler/program.ts Outdated

// If output has not been changed, and the file has no external modification
if (fingerprint.byteOrderMark === writeByteOrderMark &&
if (fingerprint !== undefined && fingerprint.byteOrderMark === writeByteOrderMark &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just if (figureprint

@mhegazy

Copy link
Copy Markdown
Contributor

Can you also share the perf numbers once it is in.

@mhegazy

Copy link
Copy Markdown
Contributor

Ron Buckton (@rbuckton) any more comments?

@rbucktonRon Buckton (rbuckton) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few non-blocking review comments, but this looks fine to me.

Comment threadsrc/compiler/collections.ts Outdated
declare const Map: { new<K, V>(pairs?: [K, V][]): Map<K, V> } | undefined;
const usingNativeMaps = typeof Map !== "undefined";
// tslint:disable-next-line:no-in-operator
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term "fully-featured" is a bit ambiguous. Maybe usingES6NativeMaps?

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using an object.
* `pairs` is an optional list of entries to add to the new map.
*/
export const StringMap: { new<T>(pairs?: [string, T][]): Map<string, T>; } = usingNativeMaps ? Map : ShimMap;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love for us to be able to just call this Map instead of StringMap or NumberMap, but its a bit messy to avoid colliding with the global Map

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or stick with createMap<K extends string | number, V>() and createSet<T extends string | number>()

Comment threadsrc/compiler/collections.ts Outdated
* Creates a sorted array of keys.
* Sorts keys according to the iteration order they would have if they were in an object, instead of from a Map.
* This is so that tests run consistently whether or not we have a Map shim in place.
* The difference between Map iteration order and V8 object insertion order is that V8 moves natrual-number-like keys to the front.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"natural"

Comment threadsrc/compiler/collections.ts Outdated
}

delete(value: string) {
delete this.data[value];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Sets return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
}

delete(key: K): void {
delete this.data[key as string];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Maps return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
However, `forEach` will iterate over strings because values are stringified before being put in the map.
*/

constructor(pairs?: [K, V][]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-ES6 native maps don't support constructor arguments.

delete(key: K): void {
delete this.data[key as string];
delete(key: K): boolean {
const had = this.has(key);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this. Just do return delete this.data[key as string].

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deletealways returns true in strict mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. That's unfortunate...and odd.

delete(value: string) {
delete this.data[value];
delete(value: string): boolean {
const had = this.has(value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, you can just do return delete this.data[value] since a delete expression returns boolean

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard

@ghost
ghost merged commit adfdae0 into masterOct 27, 2016
@ghost
ghost deleted the map4 branch October 27, 2016 20:27
@ghost

Copy link
Copy Markdown
Author

Will do a final performance comparison tomorrow.

ghost pushed a commit that referenced this pull request Oct 27, 2016
This reverts commit adfdae0, reversing
changes made to aad663c.
ghost pushed a commit that referenced this pull request Oct 27, 2016
Revert "Merge pull request #11354 from Microsoft/map4"
Mohamed Hegazy (mhegazy) added a commit that referenced this pull request Nov 10, 2016
* Use a single ShimMap class, and indicate that iteration always yields string keys (which it did before too)
* Remove emacs-added newline at end of baseline
* Remove space at end of line in baseline
* Add numeric indexer to strings and remove lint
* Update baselines with spread string's numeric indexers
* Reset baseline line number to the locally incorrect value
* Remove trailing newline from baseline again
* Respond to PR comments
* Refactor getTypeFromTypeLiteral, from PR comments
* Fix lint
* Use same literal comparison rules for switch/===
switch was missing the rule for converting literal types to the literal
base type if needed.
* Add switch comparability test and update baselines
* Push eitherIsNotLiteral check into isTypeEqualityComparableTo
Since all callers need this check -- it's how equality is supposed to
work everywhere.
* Update baselines
There are more literal types in error messages because error reporting
no longer has the advantage of calls to getBaseLiteralType
* Adds ES5 to ES3 transformer for reserved words
* Minor cleanup
* Cleaned up emit of enum declaration
* Return both ts and js results from module resolution, and don't have moduleNameResolver responsible for omitting files based on compiler options
* Instead of getResolutionOrDiagnostic, use getResolutionDiagnostic and avoid using resolution.resolvedFileName if the diagnostic is defined.
* Remove "ResolvedModuleFromHost" type and just make `resolvedTsFileName` and `resolvedJsFileName` optional properties
(but still automatically infer one of them to supply if the host supplied neither)
* Remove type inference for spread types
* Update inference test for spread types
* Make spread assignability and apparent type stricter
Assignability now does not allow properties to the left of a type
parameter.
Apparent type now only returns the apparent type of the right-most
spread member.
* Update tests w/spread assignability+apparent type
* Moved AMD/CJS/UMD transform to end
* Spread no longer distributes intersections
* Update spread w/intersection tests
* Move System module transform to end.
* Update baseline
* Revert baseline change due to stale output
* Resolve all-object intersections inside spreads
This means that getSpreadType will return an object type, even when
spreading two intersections, as long as those intersections contain
nothing but object types themselves.
* Update and improve spread intersection tests
* Simplify expression in resolveObjectIntersection
* Update baselines with new index signature rules
* Move n-ary spread handling into separate function.
To be moved to callers in the next step.
* Move multiple-spread handling out of getSpreadType
* Clean up and reorder getSpreadType body
* Respond to PR comments
* Error for call/construct signatures in spread type
1. Simplify the error reporting code to handle all kinds of signatures.
2. Remove index signature handling code when creating a spread type
since it's an error anyway.
* Update baselines with new spread type index errors
* Explain writeSpreadType a little better
* Add more commentary to getSpreadType
* Initial implementation of 'keyof T' type operator
* Introduce PropertyNameType
* Move most of resolveModuleNameForLsHost to lsHost
* Simplify isImplicitGlob test
* Initial implementation of 'T[K]' property access types
* add a fallback logic for older versions of node that don't support 'homedir' (#11845)
* add a fallback logic for older versions of node that don't support 'homedir'
* try os.homedir first
* For JavaScript files, we report semantic errors for using TypeScript-only constructs from within a JavaScript file as syntactic errors.
* Don't require `resolvedTsFileName` and `resolvedJsFileName`, just `resolvedFileName` and `extension`. Also, change search order to do all TS searching before searching for JS.
* Fix#10108 (Completion suggestion for object literal with getter) (#11808)
* Fix#10108 (Completion suggestion for object literal with getter)
* completions for setter
* Move helper functions to core (fix build)
* Support parametric property access expressions + some renaming
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives (#11872)
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives
* pass proper value for current directory when compiling .d.ts files
* Fix bug: Return a resolution diagnostic for a `.jsx` import if `--allowJs` is turned off
* Remove a comment about a parameter that no longer exists
* Fix bug: We want to test for existence of the enum value, not whether it's non-zero
* Fix: test for presence, not absence
* Allow untyped imports
* Simplify for loops in fourslash.ts
* Rename to zipWith
* Change diagnostic message
* Make `extension` property of `ResolvedModule` optional; introduce `ResolvedModuleFull` interface for when the extension is provided.
* Consider index signatures in type produced by 'keyof T'
* Respond to PR comments
* Refactor getIndexedAccessType to be reusable from checkIndexedAccess
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Revert "Merge pull request #11354 from Microsoft/map4"
This reverts commit adfdae0, reversing
changes made to aad663c.
* Rename Experimental transform to ESNext
1. Spread/rest are no longer experimental.
2. We need a place to put stage 3 ES features.
* Changes from CR feedback
* disable CoS for inferred projects (#11909)
* Updating test due to CR changes. The order of the diagnostic messages has changed due to concatenation changes
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* Rename TransformFlags.Experimental -> ESNext
* enable non-ts extensions in inferred projects by default
* update CFG to properly handle do statements
* do not inline async IIFEs in control flow graph
* Minor fixes
* cache type for empty type literal (#11934)
cache type for empty type literal
* Improved error messages for invalid assignments to identifiers
* Accept new baselines
* Improved error messages for invalid assignments to properties
* Accept new baselines
* Improve more error messages
* Accept new baselines
* Fix realPathMap in test harness: Must be used in `directoryExists`
* Add helper function
* Update generated files (#11963)
* Move eitherIsNotLiteral check into switch and === checks
This improves error messages
* Forbid augmentation of untyped module (#11962)
* Forbid augmentation of untyped module
* Just use `undefined` for untyped modules
* Unify checking of indexed access expressions and indexed access types
* Accept new baselines
* Accept additional baselines
* Make `cachingInServerLSHost` tests work with `runtests-browser`
* Get literal type only once
* Update baselines
* Add missed test update
* Improve unification by moving more logic to getIndexedAccessType
* Add test cases to report errors for decorators in js file
* Report all the js file errors and skip only the nodes that are not allowed in js
Fixes#11800
* Fix 'keyof any' to produce 'string | number'
* Fix#11396: Make error message referene `Promise` explicitly (#11982)
* Simplify the checking for async function return type
* Fix#11396: Make error message referene `Promise` explicitly
* Minor fixes
* Adding tests
* Test case for property used in destructuring variable declaration
* Mark property referenced in the destructuring as referenced
Fixes#11324
* Spread types handle nested index [access] types
Nested index [access] types are treated as assignable to themselves only,
just like type parameters.
* Test index [access] types inside spread types
* module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program (#11999)
module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program
* Parse, bind and check rest elements
* Downlevel emit of rest elements
* Add rest tests
* Update baselines
* Remove spread types, leaving spread syntax/emit
Spreads are still typed, but cannot be created from a non-object type.
Tests still need to be updated.
* Fix lint
* Lock tslint version to 4.0.0-dev.0, because 4.0.0-dev.1 complains about unnecessary semicolons following properties
* Remove spread type tests from spread tests
* Spread handles index signatures from singleton spreads
I broke it when simplifying the logic earlier.
* Correct assignability for keyof types and type parameters
* Update tests
* Accept new baselines
* Update objectRestAssignment test and baselines
* Fix linting errors
* Update objectRestAssignment test
Missed previously, just got the baselines
* Improve readability of ES next destructuring emit
* Ensure transformFlags are correct before visiting a node.
* Port #12027, #11980 and #11932 to master (#12037)
* add test for the fix for overwrite emitting error
* cr feedback
* Address PR comments
1. Remove extra line in __rest shim.
2. Improve __rest vs __assign check for destructuring assignment.
* Move convertForOf to factory for esnext and es2015
Saves a lot of duplicated code
* Update improved baselines
* Move transformFunctionBody to factory
It is shared by es2015 and esNext transformers.
This commit just adds a convertObjectRest flag to be passed on to
flattenDestructuring functions, as well as adding necessary parameters
to use the code outside a transformer.
* Spread any types to any
* add missing bind calls to properly set parent on token nodes (#12057)
* Cache generic signature instantiations
* Accept new baselines
* Properly instantiate aliasTypeArguments
* Add regression test
* Revert incorrect logic from #11392
* Accept new baselines
* Rename SpreadElementExpression -> SpreadAssignment
and SpreadExpression (formerly SpreadElementExpression) -> SpreadElement
* Add SpreadAssignment to visitors
1. visitNode
2. reduceNode
3. emit
This fixes an emit bug for setters.
* Add --target esnext
Currently, this disables the rest and spread transforms. This will
change as proposals enter and leave stage 3.
* Add --target esnext tests and update baselines
* Revert unneeded change and comments per PR
* Rename variable in checkSwitchStatement per PR
* Do not emit __rest for --target esnext
* Add `realpath` implementation for lshost
* Create spread property types eagerly
This avoids the need for a synthetic symbol and later code called from
getTypeOfSymbol.
* Set spread type symbols in checkObjectLiteral
Instead of getSpreadType.
Also clean up special-case handling inside getSpreadType to be more
readable.
* Ports #12051 and #12032 into master (#12090)
* use local registry to check if typings package exist (#12014)
use local registry to check if typings package exist
* enable sending telemetry events to tsserver client (#12035)
enable sending telemetry events
* Address more PR comments
* return empty file watcher in case if target directory does not exist (#12091)
* return empty file watcher in case if target directory does not exist
* linter
* property handle missing config files in external projects (#12094)
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Port fix for #12069 (#12095)
* reduce set of files being watched, increase polling interval (#12054) (#12092)
* Update authors for release-2.1
* Include declaration file emit
* use createHash from ServerHost instead of explicit require (#12043)
* use createHash from ServerHost instead of explicit require
* added missing method in ServerHost stub
* (signature help) type parameter lists are never variadic (#12112)
* Handle abstract and const modifiers
* Downlevel array destructuring to ES6 in object rest
Previously array destructuring inside an object destructuring with an
object rest would downlevel the array destructuring to ES5. This breaks
if the code that targets ES2015 is using iterators instead of arrays
since iterators don't support [0] or .slice that the ES5 emit uses.
* Improve nested destructuring test for ESNext emit
Now with object destructuring inside array destructuring inside object
destructuring! Each with their own array/object rest!
Also updates baselines.
* Add support for taking in jsxFactory option and report errors for invalid combinations
* Treat `| undefined` like optionality in spread type
* Add strictNullChecks test for object spread
* Verify that jsxFactory is either identifier or qualified name
* Resolve first identifier of the jsxFactory as part of type check
* When emitting use jsx factory entity expression if provided
* Transpile unit test case
* Enabled test case for source map
* Add test cases for when jsxFactory cannot be resolved
* Parse the jsxFactory again in the checker instead of using cached value in the program
* Adds error message for incompatible assignment of identically named type
Fixes issue #12050
* Updated condition for more readability
* Report errors for import helpers missing __rest
* Correctly check spread assignments in strict mode
Previously it crashed in the binder.
* Test error for import helpers with no __rest
* synthesize complete import declaration for tslib (#12151)
* Add ES2017 string padding (#12152)
* add es2017.string.d.ts for String.prototype.{padStart,padEnd}
* append es2017.string.d.ts into es2017.d.ts
* add es2017.string into commandLineParser
* append es2017.string into error message for unit tests of commandLineParser
* append es2017.string into Gulpfile
* append es2017.string into Jakefile
* Exclude js files in non-configured projects compile-on-save emitting (#12118)
* Exclude js files in non-configured projects CoS emitting
* remove unnecessary method
* Merge release-2.1 into master (#12157)
* Update LKG
* Update version
* Update LKG
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* Update LKG
* Fix emit inferred type which is a generic type-alias both fully and partially fill type parameters
* Add tests and baselines
* Skip trying to use alias if there is target type
* Update baselines
* Add diagnostics to remind adding tsconfig file for certain external project (#11932)
* Add diagnostics for certain external project
* Show tsconfig suggestion
* fix lint error
* Address pr
* fix comment
* Update error message
* Flag for not overwrite js files by default without generating errors (#11980)
* WIP
* Properly naming things
* refactor
* apply the option to all files and check out options
* Fix typo
* Update LKG
* lockLinter
* use local registry to check if typings package exist (#12014) (#12032)
use local registry to check if typings package exist
* Add test for #11980 (#12027)
* add test for the fix for overwrite emitting error
* cr feedback
* enable sending telemetry events to tsserver client (#12034) (#12051)
enable sending telemetry events
* Update LKG
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Update LKG
* Update version
* Update LKG
* Do not emit "use strict" when targeting es6 or higher or module kind is es2015 and the file is external module
* Add tests and baselines
* [Release 2.1] fix11754 global augmentation (#12133)
* Exclude global augmentation from module resolution logic
* Address PR: check using string literal instead of NodeFlags.globalAugmentation
* Remove comment
@ghostghost mentioned this pull request Dec 7, 2016
@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
This pull request was closed.
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@yuit@mhegazy@rbuckton@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Use native maps when they're available - #11354

Merged
18 commits merged into
masterfrom
map4
Oct 27, 2016
Merged

Use native maps when they're available#11354
18 commits merged into
masterfrom
map4

Conversation

@ghost

@ghostDeleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown

The summary is that using native maps, the compiler works 5% faster and uses 5% less memory. Using shims, the performance is surprisingly less than 5% worse.

I was able to achieve good baseline performance by disabling Windows Defender in my work directory and using "High Performance" in Control Panel -> Hardware and Sound -> Power Options. There is much less variance this time around.

Benchmark numbers

This is from using our internal ts-perf tool.

map4

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.72s (± 1.10%)-0.07s (- 4.08%)1.70s1.74s
Bind Time0.69s (± 4.74%)0.52s (± 3.50%)-0.17s (- 24.86%)0.50s0.54s
Check Time3.37s (± 1.66%)2.91s (± 3.16%)-0.46s (- 13.69%)2.78s2.98s
Emit Time5.01s (± 4.73%)4.87s (± 1.35%)-0.14s (- 2.77%)4.79s4.94s
Total Time10.87s (± 2.34%)10.02s (± 1.18%)-0.84s (- 7.77%)9.86s10.12s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)356,928k (± 0.01%)-22,996k (- 6.05%)356,890k356,956k
Parse Time2.40s (± 0.75%)2.32s (± 2.13%)-0.08s (- 3.37%)2.28s2.39s
Bind Time0.92s (± 1.79%)0.71s (± 1.84%)-0.21s (- 22.52%)0.70s0.73s
Check Time4.26s (± 1.36%)3.84s (± 6.33%)-0.42s (- 9.94%)3.66s4.18s
Emit Time1.87s (± 2.44%)1.82s (± 3.16%)-0.05s (- 2.80%)1.77s1.89s
Total Time9.46s (± 1.19%)8.69s (± 3.96%)-0.77s (- 8.12%)8.42s9.16s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)190,504k (± 0.01%)-11,467k (- 5.68%)190,474k190,538k
Parse Time2.30s (± 0.89%)2.20s (± 2.07%)-0.09s (- 4.09%)2.17s2.27s
Bind Time0.72s (± 0.99%)0.57s (± 4.73%)-0.15s (- 21.33%)0.55s0.61s
Check Time3.48s (± 1.73%)3.27s (± 4.68%)-0.21s (- 6.08%)3.08s3.38s
Emit Time1.91s (± 3.15%)1.78s (± 8.00%)-0.13s (- 6.94%)1.65s1.94s
Total Time8.41s (± 0.61%)7.82s (± 1.68%)-0.59s (- 7.03%)7.71s7.99s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.15s (± 1.31%)-0.07s (- 6.06%)1.13s1.16s
Bind Time0.56s (± 2.96%)0.54s (± 4.08%)-0.02s (- 3.13%)0.52s0.57s
Check Time2.81s (± 1.48%)2.46s (± 1.85%)-0.35s (- 12.34%)2.43s2.53s
Emit Time3.11s (± 0.85%)3.19s (± 0.91%)+0.07s (+ 2.33%)3.15s3.22s
Total Time7.70s (± 0.84%)7.34s (± 1.14%)-0.37s (- 4.78%)7.28s7.46s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)309,449k (± 0.02%)-18,556k (- 5.66%)309,386k309,516k
Parse Time1.50s (± 1.02%)1.44s (± 0.88%)-0.07s (- 4.32%)1.42s1.45s
Bind Time0.73s (± 0.73%)0.58s (± 1.65%)-0.14s (- 19.89%)0.57s0.59s
Check Time3.89s (± 0.65%)3.56s (± 4.42%)-0.32s (- 8.27%)3.42s3.74s
Emit Time1.54s (± 0.91%)1.57s (± 4.86%)+0.03s (+ 2.25%)1.51s1.67s
Total Time7.65s (± 0.65%)7.16s (± 3.13%)-0.50s (- 6.48%)6.96s7.42s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)165,316k (± 0.01%)-9,433k (- 5.40%)165,292k165,344k
Parse Time1.41s (± 1.63%)1.33s (± 0.77%)-0.08s (- 5.36%)1.33s1.35s
Bind Time0.62s (± 5.95%)0.50s (± 3.40%)-0.12s (- 19.68%)0.48s0.52s
Check Time2.98s (± 0.64%)2.75s (± 0.96%)-0.23s (- 7.73%)2.71s2.77s
Emit Time1.35s (± 0.83%)1.35s (± 1.29%)+0.01s (+ 0.45%)1.33s1.37s
Total Time6.36s (± 1.07%)5.94s (± 0.82%)-0.42s (- 6.60%)5.88s5.98s

map4 with usingNativeMaps = false and usingNativeSets = false

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.80s (± 1.47%)+0.01s (+ 0.73%)1.77s1.82s
Bind Time0.69s (± 4.74%)0.71s (± 13.45%)+0.02s (+ 3.18%)0.66s0.86s
Check Time3.37s (± 1.66%)3.43s (± 3.44%)+0.06s (+ 1.68%)3.29s3.57s
Emit Time5.01s (± 4.73%)5.04s (± 4.80%)+0.03s (+ 0.66%)4.93s5.42s
Total Time10.87s (± 2.34%)10.98s (± 1.85%)+0.12s (+ 1.09%)10.83s11.29s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)383,279k (± 0.01%)+3,355k (+ 0.88%)383,241k383,338k
Parse Time2.40s (± 0.75%)2.39s (± 2.42%)-0.01s (- 0.29%)2.33s2.44s
Bind Time0.92s (± 1.79%)0.90s (± 4.74%)-0.02s (- 2.55%)0.86s0.96s
Check Time4.26s (± 1.36%)4.29s (± 0.29%)+0.03s (+ 0.66%)4.28s4.31s
Emit Time1.87s (± 2.44%)1.88s (± 1.90%)+0.01s (+ 0.51%)1.85s1.92s
Total Time9.46s (± 1.19%)9.47s (± 0.86%)+0.01s (+ 0.11%)9.36s9.54s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)203,972k (± 0.01%)+2,001k (+ 0.99%)203,951k203,991k
Parse Time2.30s (± 0.89%)2.29s (± 0.76%)-0.01s (- 0.52%)2.27s2.31s
Bind Time0.72s (± 0.99%)0.68s (± 1.41%)-0.04s (- 5.87%)0.67s0.69s
Check Time3.48s (± 1.73%)3.83s (± 1.77%)+0.35s (+ 10.19%)3.78s3.92s
Emit Time1.91s (± 3.15%)1.62s (± 3.72%)-0.29s (- 15.12%)1.58s1.71s
Total Time8.41s (± 0.61%)8.42s (± 1.66%)+0.01s (+ 0.12%)8.32s8.63s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.22s (± 5.54%)-0.01s (- 0.49%)1.17s1.28s
Bind Time0.56s (± 2.96%)0.58s (± 5.13%)+0.02s (+ 4.38%)0.57s0.63s
Check Time2.81s (± 1.48%)2.84s (± 3.00%)+0.03s (+ 1.03%)2.77s2.95s
Emit Time3.11s (± 0.85%)3.16s (± 1.84%)+0.05s (+ 1.56%)3.08s3.21s
Total Time7.70s (± 0.84%)7.81s (± 2.01%)+0.10s (+ 1.32%)7.60s7.94s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)329,980k (± 0.02%)+1,975k (+ 0.60%)329,913k330,079k
Parse Time1.50s (± 1.02%)1.49s (± 0.69%)-0.02s (- 1.13%)1.47s1.49s
Bind Time0.73s (± 0.73%)0.71s (± 3.11%)-0.01s (- 2.00%)0.68s0.73s
Check Time3.89s (± 0.65%)4.04s (± 1.24%)+0.15s (+ 3.87%)3.96s4.06s
Emit Time1.54s (± 0.91%)1.64s (± 0.63%)+0.10s (+ 6.55%)1.63s1.65s
Total Time7.65s (± 0.65%)7.87s (± 0.76%)+0.21s (+ 2.80%)7.79s7.92s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)175,835k (± 0.01%)+1,086k (+ 0.62%)175,822k175,855k
Parse Time1.41s (± 1.63%)1.39s (± 0.74%)-0.02s (- 1.10%)1.39s1.41s
Bind Time0.62s (± 5.95%)0.57s (± 3.30%)-0.05s (- 8.48%)0.56s0.59s
Check Time2.98s (± 0.64%)2.99s (± 1.14%)+0.02s (+ 0.60%)2.96s3.04s
Emit Time1.35s (± 0.83%)1.38s (± 4.53%)+0.03s (+ 2.52%)1.33s1.45s
Total Time6.36s (± 1.07%)6.34s (± 1.32%)-0.02s (- 0.25%)6.25s6.43s

Heap snapshot numbers

The memory usage tended to be about the same up until the beforeEmit event, AKA after checking.

Master had 365,935 KB total, map4 had 343,774 KB (94% as much), and map4 with shims had 368,978 KB (100% as much as master, 106% as much as map4).

(I added an event heapAfterBind to test the effects of that; map4 used 97% as much memory as master, meaning the real memory savings are during checking.)

For map4, the chrome heap snaprhot viewer shows Maps as accounting for 2% of all objects, with a shallow size equal to their retained size at 1%. However, this is misleading because most of them are mere 32KB wrapper objects which have internal _keys and _values (or table in some cases), which is what really takes up space. I wish there were a way we could include the size of those.

VSCode numbers

I also ran a simple test on the VSCode repo.

master

tsc -p src --noEmit --diagnostics (Run with 2.1.0-dev.20161005)

KindAmountSamples
Memory used737211 K736716, 733971, 743103, 742334, 729932
I/O read0.17 s0.27, 0.12, 0.20, 0.14, 0.14
Parse time5.22 s5.21, 5.18, 5.22, 5.22, 5.29
Bind time1.74 s1.77, 1.72, 1.74, 1.72, 1.75
Check time8.57 s8.69, 8.48, 8.54, 8.50, 8.63
Total time15.54 s15.67, 15.38, 15.51, 15.45, 15.67

map4

node ../TypeScript/built/local/tsc.js -p src --noEmit --diagnostics

KindRelativeAmountSamples
Memory used94%690972 K691500, 690621, 691097, 690872, 690772
I/O read:100%0.17 s0.16, 0.18, 0.20, 0.14, 0.16
Parse time96%5.02 s5.03, 4.95, 4.99, 4.96, 5.18
Bind time:83%1.44 s1.42, 1.40, 1.44, 1.42, 1.53
Check time97%8.34 s8.32, 8.27, 8.38, 8.42, 8.33
Total time95%14.81 s14.78, 14.62, 14.81, 14.80, 15.05

map4 with shims

Same command as for map4, after rebuilding with usingNativeMaps = false and usingNativeSets = false.

KindRelativeAmountSamples
Memory used101%744718 K745408, 744639, 744845, 745511, 743185
I/O read106%0.18 s0.22, 0.19, 0.20, 0.14, 0.17
Parse time99%5.19 s5.28, 5.18, 5.20, 5.17, 5.13
Bind time98%1.71 s1.72, 1.69, 1.70, 1.73, 1.72
Check time101%8.68 s8.58, 8.72, 8.68, 8.72, 8.73
Total time100%15.59 s15.59, 15.59, 15.58, 15.62, 15.57

@ghost

Deleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown
Author

Here is a performance test for doing the same map lookup once vs twice.

constBenchmark=require("benchmark")constcrypto=require("crypto")constN=10000constwords=[]for(leti=0;i<N;i++)words[i]=crypto.randomBytes(8).toString('hex')functioncreateMap(){constm=newMap()for(leti=0;i<N;i+=2)m.set(words[i],i)returnm}functioncreateObject(){consto=Object.create(null)o["__"]=undefineddeleteo["__"]for(leti=0;i<N;i+=2)o[words[i]]=ireturno}letcorrectSum=0for(leti=0;i<N;i+=2)correctSum+=iconstsuite=newBenchmark.Suitesuite.add("map has-then-get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++)if(map.has(words[i]))sum+=map.get(words[i])if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map just get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++){constx=map.get(words[i])if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object has-then-get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++)if(words[i]ino)sum+=o[words[i]]if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object just get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++){constx=o[words[i]]if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map double get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){sum+=map.get(words[i])sum+=map.get(words[i])}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("map single get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){constgot=map.get(words[i])sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("object double get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){sum+=o[words[i]]sum+=o[words[i]]}if(sum!==correctSum*2)thrownewError()returnsum})suite.add("object single get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){constgot=o[words[i]]sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.on("complete",function(){this.forEach(({name, stats})=>{console.log(`${name}: ${stats.mean*1000}ms`)})})suite.on("error",err=>{throwerr.target.error})suite.run()
map has-then-get: 1.0212332328457447ms
map just get: 0.911712559080547ms
object has-then-get: 1.9529671271167457ms
object just get: 1.9624182600334454ms
map double get: 0.7383946305889607ms
map single get: 0.651791347503374ms
object double get: 1.411747356033454ms
object single get: 1.3791293993025284ms

Looks like removing uses of has is useful for maps but not for objects. Removing double get is always good.

@ghostghost mentioned this pull request Oct 4, 2016
@ghost
ghost force-pushed the map4 branch 2 times, most recently from 1f080a8 to 6fc4eadCompareOctober 5, 2016 14:58
@ghost

Copy link
Copy Markdown
Author

This would be a breaking change. We have publicly exported maps because we have export type SymbolTable = Map<string, Symbol>;, which is the type of several public properties of Symbol.

Comment threadJakefile.js Outdated
}

var compilerSources = [
"dataStructures.ts",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be tempted to call this collections.ts, since we already have a types.ts and this is more specific.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of moving our array utilities to collections.ts?

Comment threadsrc/compiler/dataStructures.ts Outdated
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

/** Extra Map methods that may not be available, so we must provide fallbacks. */
interface FullyFeaturedMap<K, V> extends Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe call this ES6Map?

@ghostghost mentioned this pull request Oct 7, 2016
@yuit

Copy link
Copy Markdown
Contributor

Andy (Andrewkraft) (@Andy-MS) looks good for my end 👍 though it is a big change so I think it may be good idea to have Mohamed Hegazy (@mhegazy)Vladimir Matveev (@vladima)Nathan Shively-Sanders (@sandersn)Ron Buckton (@rbuckton) to check as well

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider merging the shims for NumberMap and StringMap.

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for stylistic consistency do not use classes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you share the numbers after removing classes?

@ghostDeleted user (ghost)Oct 12, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It ends up taking 20% longer. 🤕
Here are the measurements for running map4 with closure shims, with "Delta" relative to map4 with class shims.

Monaco - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used203,967k (± 0.01%)224,241k (± 0.01%)+20,274k (+ 9.94%)224,220k224,263k
Parse Time2.27s (± 0.39%)2.39s (± 3.65%)+0.12s (+ 5.30%)2.32s2.51s
Bind Time0.68s (± 1.17%)0.83s (± 1.52%)+0.15s (+ 21.41%)0.81s0.84s
Check Time3.86s (± 2.12%)4.72s (± 3.44%)+0.86s (+ 22.15%)4.55s4.89s
Emit Time1.62s (± 2.07%)2.30s (± 14.05%)+0.68s (+ 41.80%)2.04s2.72s
Total Time8.43s (± 1.26%)10.23s (± 3.36%)+1.80s (+ 21.34%)9.78s10.47s
TFS - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used175,828k (± 0.01%)188,541k (± 0.01%)+12,713k (+ 7.23%)188,529k188,551k
Parse Time1.40s (± 0.75%)1.51s (± 4.24%)+0.11s (+ 7.80%)1.46s1.60s
Bind Time0.57s (± 1.02%)0.68s (± 2.26%)+0.12s (+ 20.63%)0.67s0.70s
Check Time3.00s (± 0.53%)3.60s (± 3.55%)+0.60s (+ 19.88%)3.41s3.69s
Emit Time1.37s (± 1.09%)1.71s (± 5.74%)+0.34s (+ 25.18%)1.66s1.86s
Total Time6.33s (± 0.28%)7.50s (± 2.73%)+1.16s (+ 18.38%)7.24s7.71s

Here's the code I tested with (with equivalents for NumberMap and StringSet):

exportconstcreateStringMap: <T>(pairs?: [string,T][])=>Map<string,T>=usingNativeMaps
? <T>(pairs?: [string,T][])=>newMap(pairs)
: <T>(pairs?: [string,T][])=>{letdata=createDictionaryModeObject<T>();if(pairs){for(const[key,value]ofpairs){data[key]=value;}}return{clear(): void{data=createDictionaryModeObject<T>();},delete(key: string): void{deletedata[key];},get(key: string): T{returndata[key];},has(key: string): boolean{// tslint:disable-next-line:no-in-operatorreturnkeyindata;},set(key: string,value: T): void{data[key]=value;},forEach(action: (value: T,key: string)=>void): void{for(constkeyindata){action(data[key],key);}}}}

I bet this is allocating a different closure for each method, wheras a class just allocates space for data and shares a single prototype among all instances.

Comment threadsrc/compiler/collections.ts Outdated
// Map utilities
namespace ts {
/** Create a map containing a single entry key -> value. */
export function createMapWithEntry<T>(key: string, value: T): Map<string, T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider inlining this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or using the Map constructor optional parameter

Comment threadsrc/compiler/collections.ts Outdated
}

// Map utilities
namespace ts {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be marked internal. and consider using one closure for all of them

Comment threadsrc/compiler/program.ts Outdated

// If output has not been changed, and the file has no external modification
if (fingerprint.byteOrderMark === writeByteOrderMark &&
if (fingerprint !== undefined && fingerprint.byteOrderMark === writeByteOrderMark &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just if (figureprint

@mhegazy

Copy link
Copy Markdown
Contributor

Can you also share the perf numbers once it is in.

@mhegazy

Copy link
Copy Markdown
Contributor

Ron Buckton (@rbuckton) any more comments?

@rbucktonRon Buckton (rbuckton) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few non-blocking review comments, but this looks fine to me.

Comment threadsrc/compiler/collections.ts Outdated
declare const Map: { new<K, V>(pairs?: [K, V][]): Map<K, V> } | undefined;
const usingNativeMaps = typeof Map !== "undefined";
// tslint:disable-next-line:no-in-operator
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term "fully-featured" is a bit ambiguous. Maybe usingES6NativeMaps?

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using an object.
* `pairs` is an optional list of entries to add to the new map.
*/
export const StringMap: { new<T>(pairs?: [string, T][]): Map<string, T>; } = usingNativeMaps ? Map : ShimMap;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love for us to be able to just call this Map instead of StringMap or NumberMap, but its a bit messy to avoid colliding with the global Map

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or stick with createMap<K extends string | number, V>() and createSet<T extends string | number>()

Comment threadsrc/compiler/collections.ts Outdated
* Creates a sorted array of keys.
* Sorts keys according to the iteration order they would have if they were in an object, instead of from a Map.
* This is so that tests run consistently whether or not we have a Map shim in place.
* The difference between Map iteration order and V8 object insertion order is that V8 moves natrual-number-like keys to the front.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"natural"

Comment threadsrc/compiler/collections.ts Outdated
}

delete(value: string) {
delete this.data[value];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Sets return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
}

delete(key: K): void {
delete this.data[key as string];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Maps return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
However, `forEach` will iterate over strings because values are stringified before being put in the map.
*/

constructor(pairs?: [K, V][]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-ES6 native maps don't support constructor arguments.

delete(key: K): void {
delete this.data[key as string];
delete(key: K): boolean {
const had = this.has(key);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this. Just do return delete this.data[key as string].

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deletealways returns true in strict mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. That's unfortunate...and odd.

delete(value: string) {
delete this.data[value];
delete(value: string): boolean {
const had = this.has(value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, you can just do return delete this.data[value] since a delete expression returns boolean

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard

@ghost
ghost merged commit adfdae0 into masterOct 27, 2016
@ghost
ghost deleted the map4 branch October 27, 2016 20:27
@ghost

Copy link
Copy Markdown
Author

Will do a final performance comparison tomorrow.

ghost pushed a commit that referenced this pull request Oct 27, 2016
This reverts commit adfdae0, reversing
changes made to aad663c.
ghost pushed a commit that referenced this pull request Oct 27, 2016
Revert "Merge pull request #11354 from Microsoft/map4"
Mohamed Hegazy (mhegazy) added a commit that referenced this pull request Nov 10, 2016
* Use a single ShimMap class, and indicate that iteration always yields string keys (which it did before too)
* Remove emacs-added newline at end of baseline
* Remove space at end of line in baseline
* Add numeric indexer to strings and remove lint
* Update baselines with spread string's numeric indexers
* Reset baseline line number to the locally incorrect value
* Remove trailing newline from baseline again
* Respond to PR comments
* Refactor getTypeFromTypeLiteral, from PR comments
* Fix lint
* Use same literal comparison rules for switch/===
switch was missing the rule for converting literal types to the literal
base type if needed.
* Add switch comparability test and update baselines
* Push eitherIsNotLiteral check into isTypeEqualityComparableTo
Since all callers need this check -- it's how equality is supposed to
work everywhere.
* Update baselines
There are more literal types in error messages because error reporting
no longer has the advantage of calls to getBaseLiteralType
* Adds ES5 to ES3 transformer for reserved words
* Minor cleanup
* Cleaned up emit of enum declaration
* Return both ts and js results from module resolution, and don't have moduleNameResolver responsible for omitting files based on compiler options
* Instead of getResolutionOrDiagnostic, use getResolutionDiagnostic and avoid using resolution.resolvedFileName if the diagnostic is defined.
* Remove "ResolvedModuleFromHost" type and just make `resolvedTsFileName` and `resolvedJsFileName` optional properties
(but still automatically infer one of them to supply if the host supplied neither)
* Remove type inference for spread types
* Update inference test for spread types
* Make spread assignability and apparent type stricter
Assignability now does not allow properties to the left of a type
parameter.
Apparent type now only returns the apparent type of the right-most
spread member.
* Update tests w/spread assignability+apparent type
* Moved AMD/CJS/UMD transform to end
* Spread no longer distributes intersections
* Update spread w/intersection tests
* Move System module transform to end.
* Update baseline
* Revert baseline change due to stale output
* Resolve all-object intersections inside spreads
This means that getSpreadType will return an object type, even when
spreading two intersections, as long as those intersections contain
nothing but object types themselves.
* Update and improve spread intersection tests
* Simplify expression in resolveObjectIntersection
* Update baselines with new index signature rules
* Move n-ary spread handling into separate function.
To be moved to callers in the next step.
* Move multiple-spread handling out of getSpreadType
* Clean up and reorder getSpreadType body
* Respond to PR comments
* Error for call/construct signatures in spread type
1. Simplify the error reporting code to handle all kinds of signatures.
2. Remove index signature handling code when creating a spread type
since it's an error anyway.
* Update baselines with new spread type index errors
* Explain writeSpreadType a little better
* Add more commentary to getSpreadType
* Initial implementation of 'keyof T' type operator
* Introduce PropertyNameType
* Move most of resolveModuleNameForLsHost to lsHost
* Simplify isImplicitGlob test
* Initial implementation of 'T[K]' property access types
* add a fallback logic for older versions of node that don't support 'homedir' (#11845)
* add a fallback logic for older versions of node that don't support 'homedir'
* try os.homedir first
* For JavaScript files, we report semantic errors for using TypeScript-only constructs from within a JavaScript file as syntactic errors.
* Don't require `resolvedTsFileName` and `resolvedJsFileName`, just `resolvedFileName` and `extension`. Also, change search order to do all TS searching before searching for JS.
* Fix#10108 (Completion suggestion for object literal with getter) (#11808)
* Fix#10108 (Completion suggestion for object literal with getter)
* completions for setter
* Move helper functions to core (fix build)
* Support parametric property access expressions + some renaming
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives (#11872)
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives
* pass proper value for current directory when compiling .d.ts files
* Fix bug: Return a resolution diagnostic for a `.jsx` import if `--allowJs` is turned off
* Remove a comment about a parameter that no longer exists
* Fix bug: We want to test for existence of the enum value, not whether it's non-zero
* Fix: test for presence, not absence
* Allow untyped imports
* Simplify for loops in fourslash.ts
* Rename to zipWith
* Change diagnostic message
* Make `extension` property of `ResolvedModule` optional; introduce `ResolvedModuleFull` interface for when the extension is provided.
* Consider index signatures in type produced by 'keyof T'
* Respond to PR comments
* Refactor getIndexedAccessType to be reusable from checkIndexedAccess
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Revert "Merge pull request #11354 from Microsoft/map4"
This reverts commit adfdae0, reversing
changes made to aad663c.
* Rename Experimental transform to ESNext
1. Spread/rest are no longer experimental.
2. We need a place to put stage 3 ES features.
* Changes from CR feedback
* disable CoS for inferred projects (#11909)
* Updating test due to CR changes. The order of the diagnostic messages has changed due to concatenation changes
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* Rename TransformFlags.Experimental -> ESNext
* enable non-ts extensions in inferred projects by default
* update CFG to properly handle do statements
* do not inline async IIFEs in control flow graph
* Minor fixes
* cache type for empty type literal (#11934)
cache type for empty type literal
* Improved error messages for invalid assignments to identifiers
* Accept new baselines
* Improved error messages for invalid assignments to properties
* Accept new baselines
* Improve more error messages
* Accept new baselines
* Fix realPathMap in test harness: Must be used in `directoryExists`
* Add helper function
* Update generated files (#11963)
* Move eitherIsNotLiteral check into switch and === checks
This improves error messages
* Forbid augmentation of untyped module (#11962)
* Forbid augmentation of untyped module
* Just use `undefined` for untyped modules
* Unify checking of indexed access expressions and indexed access types
* Accept new baselines
* Accept additional baselines
* Make `cachingInServerLSHost` tests work with `runtests-browser`
* Get literal type only once
* Update baselines
* Add missed test update
* Improve unification by moving more logic to getIndexedAccessType
* Add test cases to report errors for decorators in js file
* Report all the js file errors and skip only the nodes that are not allowed in js
Fixes#11800
* Fix 'keyof any' to produce 'string | number'
* Fix#11396: Make error message referene `Promise` explicitly (#11982)
* Simplify the checking for async function return type
* Fix#11396: Make error message referene `Promise` explicitly
* Minor fixes
* Adding tests
* Test case for property used in destructuring variable declaration
* Mark property referenced in the destructuring as referenced
Fixes#11324
* Spread types handle nested index [access] types
Nested index [access] types are treated as assignable to themselves only,
just like type parameters.
* Test index [access] types inside spread types
* module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program (#11999)
module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program
* Parse, bind and check rest elements
* Downlevel emit of rest elements
* Add rest tests
* Update baselines
* Remove spread types, leaving spread syntax/emit
Spreads are still typed, but cannot be created from a non-object type.
Tests still need to be updated.
* Fix lint
* Lock tslint version to 4.0.0-dev.0, because 4.0.0-dev.1 complains about unnecessary semicolons following properties
* Remove spread type tests from spread tests
* Spread handles index signatures from singleton spreads
I broke it when simplifying the logic earlier.
* Correct assignability for keyof types and type parameters
* Update tests
* Accept new baselines
* Update objectRestAssignment test and baselines
* Fix linting errors
* Update objectRestAssignment test
Missed previously, just got the baselines
* Improve readability of ES next destructuring emit
* Ensure transformFlags are correct before visiting a node.
* Port #12027, #11980 and #11932 to master (#12037)
* add test for the fix for overwrite emitting error
* cr feedback
* Address PR comments
1. Remove extra line in __rest shim.
2. Improve __rest vs __assign check for destructuring assignment.
* Move convertForOf to factory for esnext and es2015
Saves a lot of duplicated code
* Update improved baselines
* Move transformFunctionBody to factory
It is shared by es2015 and esNext transformers.
This commit just adds a convertObjectRest flag to be passed on to
flattenDestructuring functions, as well as adding necessary parameters
to use the code outside a transformer.
* Spread any types to any
* add missing bind calls to properly set parent on token nodes (#12057)
* Cache generic signature instantiations
* Accept new baselines
* Properly instantiate aliasTypeArguments
* Add regression test
* Revert incorrect logic from #11392
* Accept new baselines
* Rename SpreadElementExpression -> SpreadAssignment
and SpreadExpression (formerly SpreadElementExpression) -> SpreadElement
* Add SpreadAssignment to visitors
1. visitNode
2. reduceNode
3. emit
This fixes an emit bug for setters.
* Add --target esnext
Currently, this disables the rest and spread transforms. This will
change as proposals enter and leave stage 3.
* Add --target esnext tests and update baselines
* Revert unneeded change and comments per PR
* Rename variable in checkSwitchStatement per PR
* Do not emit __rest for --target esnext
* Add `realpath` implementation for lshost
* Create spread property types eagerly
This avoids the need for a synthetic symbol and later code called from
getTypeOfSymbol.
* Set spread type symbols in checkObjectLiteral
Instead of getSpreadType.
Also clean up special-case handling inside getSpreadType to be more
readable.
* Ports #12051 and #12032 into master (#12090)
* use local registry to check if typings package exist (#12014)
use local registry to check if typings package exist
* enable sending telemetry events to tsserver client (#12035)
enable sending telemetry events
* Address more PR comments
* return empty file watcher in case if target directory does not exist (#12091)
* return empty file watcher in case if target directory does not exist
* linter
* property handle missing config files in external projects (#12094)
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Port fix for #12069 (#12095)
* reduce set of files being watched, increase polling interval (#12054) (#12092)
* Update authors for release-2.1
* Include declaration file emit
* use createHash from ServerHost instead of explicit require (#12043)
* use createHash from ServerHost instead of explicit require
* added missing method in ServerHost stub
* (signature help) type parameter lists are never variadic (#12112)
* Handle abstract and const modifiers
* Downlevel array destructuring to ES6 in object rest
Previously array destructuring inside an object destructuring with an
object rest would downlevel the array destructuring to ES5. This breaks
if the code that targets ES2015 is using iterators instead of arrays
since iterators don't support [0] or .slice that the ES5 emit uses.
* Improve nested destructuring test for ESNext emit
Now with object destructuring inside array destructuring inside object
destructuring! Each with their own array/object rest!
Also updates baselines.
* Add support for taking in jsxFactory option and report errors for invalid combinations
* Treat `| undefined` like optionality in spread type
* Add strictNullChecks test for object spread
* Verify that jsxFactory is either identifier or qualified name
* Resolve first identifier of the jsxFactory as part of type check
* When emitting use jsx factory entity expression if provided
* Transpile unit test case
* Enabled test case for source map
* Add test cases for when jsxFactory cannot be resolved
* Parse the jsxFactory again in the checker instead of using cached value in the program
* Adds error message for incompatible assignment of identically named type
Fixes issue #12050
* Updated condition for more readability
* Report errors for import helpers missing __rest
* Correctly check spread assignments in strict mode
Previously it crashed in the binder.
* Test error for import helpers with no __rest
* synthesize complete import declaration for tslib (#12151)
* Add ES2017 string padding (#12152)
* add es2017.string.d.ts for String.prototype.{padStart,padEnd}
* append es2017.string.d.ts into es2017.d.ts
* add es2017.string into commandLineParser
* append es2017.string into error message for unit tests of commandLineParser
* append es2017.string into Gulpfile
* append es2017.string into Jakefile
* Exclude js files in non-configured projects compile-on-save emitting (#12118)
* Exclude js files in non-configured projects CoS emitting
* remove unnecessary method
* Merge release-2.1 into master (#12157)
* Update LKG
* Update version
* Update LKG
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* Update LKG
* Fix emit inferred type which is a generic type-alias both fully and partially fill type parameters
* Add tests and baselines
* Skip trying to use alias if there is target type
* Update baselines
* Add diagnostics to remind adding tsconfig file for certain external project (#11932)
* Add diagnostics for certain external project
* Show tsconfig suggestion
* fix lint error
* Address pr
* fix comment
* Update error message
* Flag for not overwrite js files by default without generating errors (#11980)
* WIP
* Properly naming things
* refactor
* apply the option to all files and check out options
* Fix typo
* Update LKG
* lockLinter
* use local registry to check if typings package exist (#12014) (#12032)
use local registry to check if typings package exist
* Add test for #11980 (#12027)
* add test for the fix for overwrite emitting error
* cr feedback
* enable sending telemetry events to tsserver client (#12034) (#12051)
enable sending telemetry events
* Update LKG
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Update LKG
* Update version
* Update LKG
* Do not emit "use strict" when targeting es6 or higher or module kind is es2015 and the file is external module
* Add tests and baselines
* [Release 2.1] fix11754 global augmentation (#12133)
* Exclude global augmentation from module resolution logic
* Address PR: check using string literal instead of NodeFlags.globalAugmentation
* Remove comment
@ghostghost mentioned this pull request Dec 7, 2016
@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
This pull request was closed.
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@yuit@mhegazy@rbuckton@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Use native maps when they're available - #11354

Merged
18 commits merged into
masterfrom
map4
Oct 27, 2016
Merged

Use native maps when they're available#11354
18 commits merged into
masterfrom
map4

Conversation

@ghost

@ghostDeleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown

The summary is that using native maps, the compiler works 5% faster and uses 5% less memory. Using shims, the performance is surprisingly less than 5% worse.

I was able to achieve good baseline performance by disabling Windows Defender in my work directory and using "High Performance" in Control Panel -> Hardware and Sound -> Power Options. There is much less variance this time around.

Benchmark numbers

This is from using our internal ts-perf tool.

map4

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.72s (± 1.10%)-0.07s (- 4.08%)1.70s1.74s
Bind Time0.69s (± 4.74%)0.52s (± 3.50%)-0.17s (- 24.86%)0.50s0.54s
Check Time3.37s (± 1.66%)2.91s (± 3.16%)-0.46s (- 13.69%)2.78s2.98s
Emit Time5.01s (± 4.73%)4.87s (± 1.35%)-0.14s (- 2.77%)4.79s4.94s
Total Time10.87s (± 2.34%)10.02s (± 1.18%)-0.84s (- 7.77%)9.86s10.12s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)356,928k (± 0.01%)-22,996k (- 6.05%)356,890k356,956k
Parse Time2.40s (± 0.75%)2.32s (± 2.13%)-0.08s (- 3.37%)2.28s2.39s
Bind Time0.92s (± 1.79%)0.71s (± 1.84%)-0.21s (- 22.52%)0.70s0.73s
Check Time4.26s (± 1.36%)3.84s (± 6.33%)-0.42s (- 9.94%)3.66s4.18s
Emit Time1.87s (± 2.44%)1.82s (± 3.16%)-0.05s (- 2.80%)1.77s1.89s
Total Time9.46s (± 1.19%)8.69s (± 3.96%)-0.77s (- 8.12%)8.42s9.16s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)190,504k (± 0.01%)-11,467k (- 5.68%)190,474k190,538k
Parse Time2.30s (± 0.89%)2.20s (± 2.07%)-0.09s (- 4.09%)2.17s2.27s
Bind Time0.72s (± 0.99%)0.57s (± 4.73%)-0.15s (- 21.33%)0.55s0.61s
Check Time3.48s (± 1.73%)3.27s (± 4.68%)-0.21s (- 6.08%)3.08s3.38s
Emit Time1.91s (± 3.15%)1.78s (± 8.00%)-0.13s (- 6.94%)1.65s1.94s
Total Time8.41s (± 0.61%)7.82s (± 1.68%)-0.59s (- 7.03%)7.71s7.99s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.15s (± 1.31%)-0.07s (- 6.06%)1.13s1.16s
Bind Time0.56s (± 2.96%)0.54s (± 4.08%)-0.02s (- 3.13%)0.52s0.57s
Check Time2.81s (± 1.48%)2.46s (± 1.85%)-0.35s (- 12.34%)2.43s2.53s
Emit Time3.11s (± 0.85%)3.19s (± 0.91%)+0.07s (+ 2.33%)3.15s3.22s
Total Time7.70s (± 0.84%)7.34s (± 1.14%)-0.37s (- 4.78%)7.28s7.46s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)309,449k (± 0.02%)-18,556k (- 5.66%)309,386k309,516k
Parse Time1.50s (± 1.02%)1.44s (± 0.88%)-0.07s (- 4.32%)1.42s1.45s
Bind Time0.73s (± 0.73%)0.58s (± 1.65%)-0.14s (- 19.89%)0.57s0.59s
Check Time3.89s (± 0.65%)3.56s (± 4.42%)-0.32s (- 8.27%)3.42s3.74s
Emit Time1.54s (± 0.91%)1.57s (± 4.86%)+0.03s (+ 2.25%)1.51s1.67s
Total Time7.65s (± 0.65%)7.16s (± 3.13%)-0.50s (- 6.48%)6.96s7.42s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)165,316k (± 0.01%)-9,433k (- 5.40%)165,292k165,344k
Parse Time1.41s (± 1.63%)1.33s (± 0.77%)-0.08s (- 5.36%)1.33s1.35s
Bind Time0.62s (± 5.95%)0.50s (± 3.40%)-0.12s (- 19.68%)0.48s0.52s
Check Time2.98s (± 0.64%)2.75s (± 0.96%)-0.23s (- 7.73%)2.71s2.77s
Emit Time1.35s (± 0.83%)1.35s (± 1.29%)+0.01s (+ 0.45%)1.33s1.37s
Total Time6.36s (± 1.07%)5.94s (± 0.82%)-0.42s (- 6.60%)5.88s5.98s

map4 with usingNativeMaps = false and usingNativeSets = false

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.80s (± 1.47%)+0.01s (+ 0.73%)1.77s1.82s
Bind Time0.69s (± 4.74%)0.71s (± 13.45%)+0.02s (+ 3.18%)0.66s0.86s
Check Time3.37s (± 1.66%)3.43s (± 3.44%)+0.06s (+ 1.68%)3.29s3.57s
Emit Time5.01s (± 4.73%)5.04s (± 4.80%)+0.03s (+ 0.66%)4.93s5.42s
Total Time10.87s (± 2.34%)10.98s (± 1.85%)+0.12s (+ 1.09%)10.83s11.29s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)383,279k (± 0.01%)+3,355k (+ 0.88%)383,241k383,338k
Parse Time2.40s (± 0.75%)2.39s (± 2.42%)-0.01s (- 0.29%)2.33s2.44s
Bind Time0.92s (± 1.79%)0.90s (± 4.74%)-0.02s (- 2.55%)0.86s0.96s
Check Time4.26s (± 1.36%)4.29s (± 0.29%)+0.03s (+ 0.66%)4.28s4.31s
Emit Time1.87s (± 2.44%)1.88s (± 1.90%)+0.01s (+ 0.51%)1.85s1.92s
Total Time9.46s (± 1.19%)9.47s (± 0.86%)+0.01s (+ 0.11%)9.36s9.54s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)203,972k (± 0.01%)+2,001k (+ 0.99%)203,951k203,991k
Parse Time2.30s (± 0.89%)2.29s (± 0.76%)-0.01s (- 0.52%)2.27s2.31s
Bind Time0.72s (± 0.99%)0.68s (± 1.41%)-0.04s (- 5.87%)0.67s0.69s
Check Time3.48s (± 1.73%)3.83s (± 1.77%)+0.35s (+ 10.19%)3.78s3.92s
Emit Time1.91s (± 3.15%)1.62s (± 3.72%)-0.29s (- 15.12%)1.58s1.71s
Total Time8.41s (± 0.61%)8.42s (± 1.66%)+0.01s (+ 0.12%)8.32s8.63s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.22s (± 5.54%)-0.01s (- 0.49%)1.17s1.28s
Bind Time0.56s (± 2.96%)0.58s (± 5.13%)+0.02s (+ 4.38%)0.57s0.63s
Check Time2.81s (± 1.48%)2.84s (± 3.00%)+0.03s (+ 1.03%)2.77s2.95s
Emit Time3.11s (± 0.85%)3.16s (± 1.84%)+0.05s (+ 1.56%)3.08s3.21s
Total Time7.70s (± 0.84%)7.81s (± 2.01%)+0.10s (+ 1.32%)7.60s7.94s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)329,980k (± 0.02%)+1,975k (+ 0.60%)329,913k330,079k
Parse Time1.50s (± 1.02%)1.49s (± 0.69%)-0.02s (- 1.13%)1.47s1.49s
Bind Time0.73s (± 0.73%)0.71s (± 3.11%)-0.01s (- 2.00%)0.68s0.73s
Check Time3.89s (± 0.65%)4.04s (± 1.24%)+0.15s (+ 3.87%)3.96s4.06s
Emit Time1.54s (± 0.91%)1.64s (± 0.63%)+0.10s (+ 6.55%)1.63s1.65s
Total Time7.65s (± 0.65%)7.87s (± 0.76%)+0.21s (+ 2.80%)7.79s7.92s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)175,835k (± 0.01%)+1,086k (+ 0.62%)175,822k175,855k
Parse Time1.41s (± 1.63%)1.39s (± 0.74%)-0.02s (- 1.10%)1.39s1.41s
Bind Time0.62s (± 5.95%)0.57s (± 3.30%)-0.05s (- 8.48%)0.56s0.59s
Check Time2.98s (± 0.64%)2.99s (± 1.14%)+0.02s (+ 0.60%)2.96s3.04s
Emit Time1.35s (± 0.83%)1.38s (± 4.53%)+0.03s (+ 2.52%)1.33s1.45s
Total Time6.36s (± 1.07%)6.34s (± 1.32%)-0.02s (- 0.25%)6.25s6.43s

Heap snapshot numbers

The memory usage tended to be about the same up until the beforeEmit event, AKA after checking.

Master had 365,935 KB total, map4 had 343,774 KB (94% as much), and map4 with shims had 368,978 KB (100% as much as master, 106% as much as map4).

(I added an event heapAfterBind to test the effects of that; map4 used 97% as much memory as master, meaning the real memory savings are during checking.)

For map4, the chrome heap snaprhot viewer shows Maps as accounting for 2% of all objects, with a shallow size equal to their retained size at 1%. However, this is misleading because most of them are mere 32KB wrapper objects which have internal _keys and _values (or table in some cases), which is what really takes up space. I wish there were a way we could include the size of those.

VSCode numbers

I also ran a simple test on the VSCode repo.

master

tsc -p src --noEmit --diagnostics (Run with 2.1.0-dev.20161005)

KindAmountSamples
Memory used737211 K736716, 733971, 743103, 742334, 729932
I/O read0.17 s0.27, 0.12, 0.20, 0.14, 0.14
Parse time5.22 s5.21, 5.18, 5.22, 5.22, 5.29
Bind time1.74 s1.77, 1.72, 1.74, 1.72, 1.75
Check time8.57 s8.69, 8.48, 8.54, 8.50, 8.63
Total time15.54 s15.67, 15.38, 15.51, 15.45, 15.67

map4

node ../TypeScript/built/local/tsc.js -p src --noEmit --diagnostics

KindRelativeAmountSamples
Memory used94%690972 K691500, 690621, 691097, 690872, 690772
I/O read:100%0.17 s0.16, 0.18, 0.20, 0.14, 0.16
Parse time96%5.02 s5.03, 4.95, 4.99, 4.96, 5.18
Bind time:83%1.44 s1.42, 1.40, 1.44, 1.42, 1.53
Check time97%8.34 s8.32, 8.27, 8.38, 8.42, 8.33
Total time95%14.81 s14.78, 14.62, 14.81, 14.80, 15.05

map4 with shims

Same command as for map4, after rebuilding with usingNativeMaps = false and usingNativeSets = false.

KindRelativeAmountSamples
Memory used101%744718 K745408, 744639, 744845, 745511, 743185
I/O read106%0.18 s0.22, 0.19, 0.20, 0.14, 0.17
Parse time99%5.19 s5.28, 5.18, 5.20, 5.17, 5.13
Bind time98%1.71 s1.72, 1.69, 1.70, 1.73, 1.72
Check time101%8.68 s8.58, 8.72, 8.68, 8.72, 8.73
Total time100%15.59 s15.59, 15.59, 15.58, 15.62, 15.57

@ghost

Deleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown
Author

Here is a performance test for doing the same map lookup once vs twice.

constBenchmark=require("benchmark")constcrypto=require("crypto")constN=10000constwords=[]for(leti=0;i<N;i++)words[i]=crypto.randomBytes(8).toString('hex')functioncreateMap(){constm=newMap()for(leti=0;i<N;i+=2)m.set(words[i],i)returnm}functioncreateObject(){consto=Object.create(null)o["__"]=undefineddeleteo["__"]for(leti=0;i<N;i+=2)o[words[i]]=ireturno}letcorrectSum=0for(leti=0;i<N;i+=2)correctSum+=iconstsuite=newBenchmark.Suitesuite.add("map has-then-get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++)if(map.has(words[i]))sum+=map.get(words[i])if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map just get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++){constx=map.get(words[i])if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object has-then-get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++)if(words[i]ino)sum+=o[words[i]]if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object just get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++){constx=o[words[i]]if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map double get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){sum+=map.get(words[i])sum+=map.get(words[i])}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("map single get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){constgot=map.get(words[i])sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("object double get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){sum+=o[words[i]]sum+=o[words[i]]}if(sum!==correctSum*2)thrownewError()returnsum})suite.add("object single get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){constgot=o[words[i]]sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.on("complete",function(){this.forEach(({name, stats})=>{console.log(`${name}: ${stats.mean*1000}ms`)})})suite.on("error",err=>{throwerr.target.error})suite.run()
map has-then-get: 1.0212332328457447ms
map just get: 0.911712559080547ms
object has-then-get: 1.9529671271167457ms
object just get: 1.9624182600334454ms
map double get: 0.7383946305889607ms
map single get: 0.651791347503374ms
object double get: 1.411747356033454ms
object single get: 1.3791293993025284ms

Looks like removing uses of has is useful for maps but not for objects. Removing double get is always good.

@ghostghost mentioned this pull request Oct 4, 2016
@ghost
ghost force-pushed the map4 branch 2 times, most recently from 1f080a8 to 6fc4eadCompareOctober 5, 2016 14:58
@ghost

Copy link
Copy Markdown
Author

This would be a breaking change. We have publicly exported maps because we have export type SymbolTable = Map<string, Symbol>;, which is the type of several public properties of Symbol.

Comment threadJakefile.js Outdated
}

var compilerSources = [
"dataStructures.ts",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be tempted to call this collections.ts, since we already have a types.ts and this is more specific.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of moving our array utilities to collections.ts?

Comment threadsrc/compiler/dataStructures.ts Outdated
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

/** Extra Map methods that may not be available, so we must provide fallbacks. */
interface FullyFeaturedMap<K, V> extends Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe call this ES6Map?

@ghostghost mentioned this pull request Oct 7, 2016
@yuit

Copy link
Copy Markdown
Contributor

Andy (Andrewkraft) (@Andy-MS) looks good for my end 👍 though it is a big change so I think it may be good idea to have Mohamed Hegazy (@mhegazy)Vladimir Matveev (@vladima)Nathan Shively-Sanders (@sandersn)Ron Buckton (@rbuckton) to check as well

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider merging the shims for NumberMap and StringMap.

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for stylistic consistency do not use classes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you share the numbers after removing classes?

@ghostDeleted user (ghost)Oct 12, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It ends up taking 20% longer. 🤕
Here are the measurements for running map4 with closure shims, with "Delta" relative to map4 with class shims.

Monaco - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used203,967k (± 0.01%)224,241k (± 0.01%)+20,274k (+ 9.94%)224,220k224,263k
Parse Time2.27s (± 0.39%)2.39s (± 3.65%)+0.12s (+ 5.30%)2.32s2.51s
Bind Time0.68s (± 1.17%)0.83s (± 1.52%)+0.15s (+ 21.41%)0.81s0.84s
Check Time3.86s (± 2.12%)4.72s (± 3.44%)+0.86s (+ 22.15%)4.55s4.89s
Emit Time1.62s (± 2.07%)2.30s (± 14.05%)+0.68s (+ 41.80%)2.04s2.72s
Total Time8.43s (± 1.26%)10.23s (± 3.36%)+1.80s (+ 21.34%)9.78s10.47s
TFS - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used175,828k (± 0.01%)188,541k (± 0.01%)+12,713k (+ 7.23%)188,529k188,551k
Parse Time1.40s (± 0.75%)1.51s (± 4.24%)+0.11s (+ 7.80%)1.46s1.60s
Bind Time0.57s (± 1.02%)0.68s (± 2.26%)+0.12s (+ 20.63%)0.67s0.70s
Check Time3.00s (± 0.53%)3.60s (± 3.55%)+0.60s (+ 19.88%)3.41s3.69s
Emit Time1.37s (± 1.09%)1.71s (± 5.74%)+0.34s (+ 25.18%)1.66s1.86s
Total Time6.33s (± 0.28%)7.50s (± 2.73%)+1.16s (+ 18.38%)7.24s7.71s

Here's the code I tested with (with equivalents for NumberMap and StringSet):

exportconstcreateStringMap: <T>(pairs?: [string,T][])=>Map<string,T>=usingNativeMaps
? <T>(pairs?: [string,T][])=>newMap(pairs)
: <T>(pairs?: [string,T][])=>{letdata=createDictionaryModeObject<T>();if(pairs){for(const[key,value]ofpairs){data[key]=value;}}return{clear(): void{data=createDictionaryModeObject<T>();},delete(key: string): void{deletedata[key];},get(key: string): T{returndata[key];},has(key: string): boolean{// tslint:disable-next-line:no-in-operatorreturnkeyindata;},set(key: string,value: T): void{data[key]=value;},forEach(action: (value: T,key: string)=>void): void{for(constkeyindata){action(data[key],key);}}}}

I bet this is allocating a different closure for each method, wheras a class just allocates space for data and shares a single prototype among all instances.

Comment threadsrc/compiler/collections.ts Outdated
// Map utilities
namespace ts {
/** Create a map containing a single entry key -> value. */
export function createMapWithEntry<T>(key: string, value: T): Map<string, T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider inlining this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or using the Map constructor optional parameter

Comment threadsrc/compiler/collections.ts Outdated
}

// Map utilities
namespace ts {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be marked internal. and consider using one closure for all of them

Comment threadsrc/compiler/program.ts Outdated

// If output has not been changed, and the file has no external modification
if (fingerprint.byteOrderMark === writeByteOrderMark &&
if (fingerprint !== undefined && fingerprint.byteOrderMark === writeByteOrderMark &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just if (figureprint

@mhegazy

Copy link
Copy Markdown
Contributor

Can you also share the perf numbers once it is in.

@mhegazy

Copy link
Copy Markdown
Contributor

Ron Buckton (@rbuckton) any more comments?

@rbucktonRon Buckton (rbuckton) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few non-blocking review comments, but this looks fine to me.

Comment threadsrc/compiler/collections.ts Outdated
declare const Map: { new<K, V>(pairs?: [K, V][]): Map<K, V> } | undefined;
const usingNativeMaps = typeof Map !== "undefined";
// tslint:disable-next-line:no-in-operator
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term "fully-featured" is a bit ambiguous. Maybe usingES6NativeMaps?

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using an object.
* `pairs` is an optional list of entries to add to the new map.
*/
export const StringMap: { new<T>(pairs?: [string, T][]): Map<string, T>; } = usingNativeMaps ? Map : ShimMap;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love for us to be able to just call this Map instead of StringMap or NumberMap, but its a bit messy to avoid colliding with the global Map

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or stick with createMap<K extends string | number, V>() and createSet<T extends string | number>()

Comment threadsrc/compiler/collections.ts Outdated
* Creates a sorted array of keys.
* Sorts keys according to the iteration order they would have if they were in an object, instead of from a Map.
* This is so that tests run consistently whether or not we have a Map shim in place.
* The difference between Map iteration order and V8 object insertion order is that V8 moves natrual-number-like keys to the front.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"natural"

Comment threadsrc/compiler/collections.ts Outdated
}

delete(value: string) {
delete this.data[value];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Sets return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
}

delete(key: K): void {
delete this.data[key as string];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Maps return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
However, `forEach` will iterate over strings because values are stringified before being put in the map.
*/

constructor(pairs?: [K, V][]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-ES6 native maps don't support constructor arguments.

delete(key: K): void {
delete this.data[key as string];
delete(key: K): boolean {
const had = this.has(key);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this. Just do return delete this.data[key as string].

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deletealways returns true in strict mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. That's unfortunate...and odd.

delete(value: string) {
delete this.data[value];
delete(value: string): boolean {
const had = this.has(value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, you can just do return delete this.data[value] since a delete expression returns boolean

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard

@ghost
ghost merged commit adfdae0 into masterOct 27, 2016
@ghost
ghost deleted the map4 branch October 27, 2016 20:27
@ghost

Copy link
Copy Markdown
Author

Will do a final performance comparison tomorrow.

ghost pushed a commit that referenced this pull request Oct 27, 2016
This reverts commit adfdae0, reversing
changes made to aad663c.
ghost pushed a commit that referenced this pull request Oct 27, 2016
Revert "Merge pull request #11354 from Microsoft/map4"
Mohamed Hegazy (mhegazy) added a commit that referenced this pull request Nov 10, 2016
* Use a single ShimMap class, and indicate that iteration always yields string keys (which it did before too)
* Remove emacs-added newline at end of baseline
* Remove space at end of line in baseline
* Add numeric indexer to strings and remove lint
* Update baselines with spread string's numeric indexers
* Reset baseline line number to the locally incorrect value
* Remove trailing newline from baseline again
* Respond to PR comments
* Refactor getTypeFromTypeLiteral, from PR comments
* Fix lint
* Use same literal comparison rules for switch/===
switch was missing the rule for converting literal types to the literal
base type if needed.
* Add switch comparability test and update baselines
* Push eitherIsNotLiteral check into isTypeEqualityComparableTo
Since all callers need this check -- it's how equality is supposed to
work everywhere.
* Update baselines
There are more literal types in error messages because error reporting
no longer has the advantage of calls to getBaseLiteralType
* Adds ES5 to ES3 transformer for reserved words
* Minor cleanup
* Cleaned up emit of enum declaration
* Return both ts and js results from module resolution, and don't have moduleNameResolver responsible for omitting files based on compiler options
* Instead of getResolutionOrDiagnostic, use getResolutionDiagnostic and avoid using resolution.resolvedFileName if the diagnostic is defined.
* Remove "ResolvedModuleFromHost" type and just make `resolvedTsFileName` and `resolvedJsFileName` optional properties
(but still automatically infer one of them to supply if the host supplied neither)
* Remove type inference for spread types
* Update inference test for spread types
* Make spread assignability and apparent type stricter
Assignability now does not allow properties to the left of a type
parameter.
Apparent type now only returns the apparent type of the right-most
spread member.
* Update tests w/spread assignability+apparent type
* Moved AMD/CJS/UMD transform to end
* Spread no longer distributes intersections
* Update spread w/intersection tests
* Move System module transform to end.
* Update baseline
* Revert baseline change due to stale output
* Resolve all-object intersections inside spreads
This means that getSpreadType will return an object type, even when
spreading two intersections, as long as those intersections contain
nothing but object types themselves.
* Update and improve spread intersection tests
* Simplify expression in resolveObjectIntersection
* Update baselines with new index signature rules
* Move n-ary spread handling into separate function.
To be moved to callers in the next step.
* Move multiple-spread handling out of getSpreadType
* Clean up and reorder getSpreadType body
* Respond to PR comments
* Error for call/construct signatures in spread type
1. Simplify the error reporting code to handle all kinds of signatures.
2. Remove index signature handling code when creating a spread type
since it's an error anyway.
* Update baselines with new spread type index errors
* Explain writeSpreadType a little better
* Add more commentary to getSpreadType
* Initial implementation of 'keyof T' type operator
* Introduce PropertyNameType
* Move most of resolveModuleNameForLsHost to lsHost
* Simplify isImplicitGlob test
* Initial implementation of 'T[K]' property access types
* add a fallback logic for older versions of node that don't support 'homedir' (#11845)
* add a fallback logic for older versions of node that don't support 'homedir'
* try os.homedir first
* For JavaScript files, we report semantic errors for using TypeScript-only constructs from within a JavaScript file as syntactic errors.
* Don't require `resolvedTsFileName` and `resolvedJsFileName`, just `resolvedFileName` and `extension`. Also, change search order to do all TS searching before searching for JS.
* Fix#10108 (Completion suggestion for object literal with getter) (#11808)
* Fix#10108 (Completion suggestion for object literal with getter)
* completions for setter
* Move helper functions to core (fix build)
* Support parametric property access expressions + some renaming
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives (#11872)
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives
* pass proper value for current directory when compiling .d.ts files
* Fix bug: Return a resolution diagnostic for a `.jsx` import if `--allowJs` is turned off
* Remove a comment about a parameter that no longer exists
* Fix bug: We want to test for existence of the enum value, not whether it's non-zero
* Fix: test for presence, not absence
* Allow untyped imports
* Simplify for loops in fourslash.ts
* Rename to zipWith
* Change diagnostic message
* Make `extension` property of `ResolvedModule` optional; introduce `ResolvedModuleFull` interface for when the extension is provided.
* Consider index signatures in type produced by 'keyof T'
* Respond to PR comments
* Refactor getIndexedAccessType to be reusable from checkIndexedAccess
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Revert "Merge pull request #11354 from Microsoft/map4"
This reverts commit adfdae0, reversing
changes made to aad663c.
* Rename Experimental transform to ESNext
1. Spread/rest are no longer experimental.
2. We need a place to put stage 3 ES features.
* Changes from CR feedback
* disable CoS for inferred projects (#11909)
* Updating test due to CR changes. The order of the diagnostic messages has changed due to concatenation changes
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* Rename TransformFlags.Experimental -> ESNext
* enable non-ts extensions in inferred projects by default
* update CFG to properly handle do statements
* do not inline async IIFEs in control flow graph
* Minor fixes
* cache type for empty type literal (#11934)
cache type for empty type literal
* Improved error messages for invalid assignments to identifiers
* Accept new baselines
* Improved error messages for invalid assignments to properties
* Accept new baselines
* Improve more error messages
* Accept new baselines
* Fix realPathMap in test harness: Must be used in `directoryExists`
* Add helper function
* Update generated files (#11963)
* Move eitherIsNotLiteral check into switch and === checks
This improves error messages
* Forbid augmentation of untyped module (#11962)
* Forbid augmentation of untyped module
* Just use `undefined` for untyped modules
* Unify checking of indexed access expressions and indexed access types
* Accept new baselines
* Accept additional baselines
* Make `cachingInServerLSHost` tests work with `runtests-browser`
* Get literal type only once
* Update baselines
* Add missed test update
* Improve unification by moving more logic to getIndexedAccessType
* Add test cases to report errors for decorators in js file
* Report all the js file errors and skip only the nodes that are not allowed in js
Fixes#11800
* Fix 'keyof any' to produce 'string | number'
* Fix#11396: Make error message referene `Promise` explicitly (#11982)
* Simplify the checking for async function return type
* Fix#11396: Make error message referene `Promise` explicitly
* Minor fixes
* Adding tests
* Test case for property used in destructuring variable declaration
* Mark property referenced in the destructuring as referenced
Fixes#11324
* Spread types handle nested index [access] types
Nested index [access] types are treated as assignable to themselves only,
just like type parameters.
* Test index [access] types inside spread types
* module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program (#11999)
module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program
* Parse, bind and check rest elements
* Downlevel emit of rest elements
* Add rest tests
* Update baselines
* Remove spread types, leaving spread syntax/emit
Spreads are still typed, but cannot be created from a non-object type.
Tests still need to be updated.
* Fix lint
* Lock tslint version to 4.0.0-dev.0, because 4.0.0-dev.1 complains about unnecessary semicolons following properties
* Remove spread type tests from spread tests
* Spread handles index signatures from singleton spreads
I broke it when simplifying the logic earlier.
* Correct assignability for keyof types and type parameters
* Update tests
* Accept new baselines
* Update objectRestAssignment test and baselines
* Fix linting errors
* Update objectRestAssignment test
Missed previously, just got the baselines
* Improve readability of ES next destructuring emit
* Ensure transformFlags are correct before visiting a node.
* Port #12027, #11980 and #11932 to master (#12037)
* add test for the fix for overwrite emitting error
* cr feedback
* Address PR comments
1. Remove extra line in __rest shim.
2. Improve __rest vs __assign check for destructuring assignment.
* Move convertForOf to factory for esnext and es2015
Saves a lot of duplicated code
* Update improved baselines
* Move transformFunctionBody to factory
It is shared by es2015 and esNext transformers.
This commit just adds a convertObjectRest flag to be passed on to
flattenDestructuring functions, as well as adding necessary parameters
to use the code outside a transformer.
* Spread any types to any
* add missing bind calls to properly set parent on token nodes (#12057)
* Cache generic signature instantiations
* Accept new baselines
* Properly instantiate aliasTypeArguments
* Add regression test
* Revert incorrect logic from #11392
* Accept new baselines
* Rename SpreadElementExpression -> SpreadAssignment
and SpreadExpression (formerly SpreadElementExpression) -> SpreadElement
* Add SpreadAssignment to visitors
1. visitNode
2. reduceNode
3. emit
This fixes an emit bug for setters.
* Add --target esnext
Currently, this disables the rest and spread transforms. This will
change as proposals enter and leave stage 3.
* Add --target esnext tests and update baselines
* Revert unneeded change and comments per PR
* Rename variable in checkSwitchStatement per PR
* Do not emit __rest for --target esnext
* Add `realpath` implementation for lshost
* Create spread property types eagerly
This avoids the need for a synthetic symbol and later code called from
getTypeOfSymbol.
* Set spread type symbols in checkObjectLiteral
Instead of getSpreadType.
Also clean up special-case handling inside getSpreadType to be more
readable.
* Ports #12051 and #12032 into master (#12090)
* use local registry to check if typings package exist (#12014)
use local registry to check if typings package exist
* enable sending telemetry events to tsserver client (#12035)
enable sending telemetry events
* Address more PR comments
* return empty file watcher in case if target directory does not exist (#12091)
* return empty file watcher in case if target directory does not exist
* linter
* property handle missing config files in external projects (#12094)
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Port fix for #12069 (#12095)
* reduce set of files being watched, increase polling interval (#12054) (#12092)
* Update authors for release-2.1
* Include declaration file emit
* use createHash from ServerHost instead of explicit require (#12043)
* use createHash from ServerHost instead of explicit require
* added missing method in ServerHost stub
* (signature help) type parameter lists are never variadic (#12112)
* Handle abstract and const modifiers
* Downlevel array destructuring to ES6 in object rest
Previously array destructuring inside an object destructuring with an
object rest would downlevel the array destructuring to ES5. This breaks
if the code that targets ES2015 is using iterators instead of arrays
since iterators don't support [0] or .slice that the ES5 emit uses.
* Improve nested destructuring test for ESNext emit
Now with object destructuring inside array destructuring inside object
destructuring! Each with their own array/object rest!
Also updates baselines.
* Add support for taking in jsxFactory option and report errors for invalid combinations
* Treat `| undefined` like optionality in spread type
* Add strictNullChecks test for object spread
* Verify that jsxFactory is either identifier or qualified name
* Resolve first identifier of the jsxFactory as part of type check
* When emitting use jsx factory entity expression if provided
* Transpile unit test case
* Enabled test case for source map
* Add test cases for when jsxFactory cannot be resolved
* Parse the jsxFactory again in the checker instead of using cached value in the program
* Adds error message for incompatible assignment of identically named type
Fixes issue #12050
* Updated condition for more readability
* Report errors for import helpers missing __rest
* Correctly check spread assignments in strict mode
Previously it crashed in the binder.
* Test error for import helpers with no __rest
* synthesize complete import declaration for tslib (#12151)
* Add ES2017 string padding (#12152)
* add es2017.string.d.ts for String.prototype.{padStart,padEnd}
* append es2017.string.d.ts into es2017.d.ts
* add es2017.string into commandLineParser
* append es2017.string into error message for unit tests of commandLineParser
* append es2017.string into Gulpfile
* append es2017.string into Jakefile
* Exclude js files in non-configured projects compile-on-save emitting (#12118)
* Exclude js files in non-configured projects CoS emitting
* remove unnecessary method
* Merge release-2.1 into master (#12157)
* Update LKG
* Update version
* Update LKG
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* Update LKG
* Fix emit inferred type which is a generic type-alias both fully and partially fill type parameters
* Add tests and baselines
* Skip trying to use alias if there is target type
* Update baselines
* Add diagnostics to remind adding tsconfig file for certain external project (#11932)
* Add diagnostics for certain external project
* Show tsconfig suggestion
* fix lint error
* Address pr
* fix comment
* Update error message
* Flag for not overwrite js files by default without generating errors (#11980)
* WIP
* Properly naming things
* refactor
* apply the option to all files and check out options
* Fix typo
* Update LKG
* lockLinter
* use local registry to check if typings package exist (#12014) (#12032)
use local registry to check if typings package exist
* Add test for #11980 (#12027)
* add test for the fix for overwrite emitting error
* cr feedback
* enable sending telemetry events to tsserver client (#12034) (#12051)
enable sending telemetry events
* Update LKG
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Update LKG
* Update version
* Update LKG
* Do not emit "use strict" when targeting es6 or higher or module kind is es2015 and the file is external module
* Add tests and baselines
* [Release 2.1] fix11754 global augmentation (#12133)
* Exclude global augmentation from module resolution logic
* Address PR: check using string literal instead of NodeFlags.globalAugmentation
* Remove comment
@ghostghost mentioned this pull request Dec 7, 2016
@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
This pull request was closed.
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@yuit@mhegazy@rbuckton@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Use native maps when they're available - #11354

Merged
18 commits merged into
masterfrom
map4
Oct 27, 2016
Merged

Use native maps when they're available#11354
18 commits merged into
masterfrom
map4

Conversation

@ghost

@ghostDeleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown

The summary is that using native maps, the compiler works 5% faster and uses 5% less memory. Using shims, the performance is surprisingly less than 5% worse.

I was able to achieve good baseline performance by disabling Windows Defender in my work directory and using "High Performance" in Control Panel -> Hardware and Sound -> Power Options. There is much less variance this time around.

Benchmark numbers

This is from using our internal ts-perf tool.

map4

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.72s (± 1.10%)-0.07s (- 4.08%)1.70s1.74s
Bind Time0.69s (± 4.74%)0.52s (± 3.50%)-0.17s (- 24.86%)0.50s0.54s
Check Time3.37s (± 1.66%)2.91s (± 3.16%)-0.46s (- 13.69%)2.78s2.98s
Emit Time5.01s (± 4.73%)4.87s (± 1.35%)-0.14s (- 2.77%)4.79s4.94s
Total Time10.87s (± 2.34%)10.02s (± 1.18%)-0.84s (- 7.77%)9.86s10.12s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)356,928k (± 0.01%)-22,996k (- 6.05%)356,890k356,956k
Parse Time2.40s (± 0.75%)2.32s (± 2.13%)-0.08s (- 3.37%)2.28s2.39s
Bind Time0.92s (± 1.79%)0.71s (± 1.84%)-0.21s (- 22.52%)0.70s0.73s
Check Time4.26s (± 1.36%)3.84s (± 6.33%)-0.42s (- 9.94%)3.66s4.18s
Emit Time1.87s (± 2.44%)1.82s (± 3.16%)-0.05s (- 2.80%)1.77s1.89s
Total Time9.46s (± 1.19%)8.69s (± 3.96%)-0.77s (- 8.12%)8.42s9.16s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)190,504k (± 0.01%)-11,467k (- 5.68%)190,474k190,538k
Parse Time2.30s (± 0.89%)2.20s (± 2.07%)-0.09s (- 4.09%)2.17s2.27s
Bind Time0.72s (± 0.99%)0.57s (± 4.73%)-0.15s (- 21.33%)0.55s0.61s
Check Time3.48s (± 1.73%)3.27s (± 4.68%)-0.21s (- 6.08%)3.08s3.38s
Emit Time1.91s (± 3.15%)1.78s (± 8.00%)-0.13s (- 6.94%)1.65s1.94s
Total Time8.41s (± 0.61%)7.82s (± 1.68%)-0.59s (- 7.03%)7.71s7.99s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.15s (± 1.31%)-0.07s (- 6.06%)1.13s1.16s
Bind Time0.56s (± 2.96%)0.54s (± 4.08%)-0.02s (- 3.13%)0.52s0.57s
Check Time2.81s (± 1.48%)2.46s (± 1.85%)-0.35s (- 12.34%)2.43s2.53s
Emit Time3.11s (± 0.85%)3.19s (± 0.91%)+0.07s (+ 2.33%)3.15s3.22s
Total Time7.70s (± 0.84%)7.34s (± 1.14%)-0.37s (- 4.78%)7.28s7.46s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)309,449k (± 0.02%)-18,556k (- 5.66%)309,386k309,516k
Parse Time1.50s (± 1.02%)1.44s (± 0.88%)-0.07s (- 4.32%)1.42s1.45s
Bind Time0.73s (± 0.73%)0.58s (± 1.65%)-0.14s (- 19.89%)0.57s0.59s
Check Time3.89s (± 0.65%)3.56s (± 4.42%)-0.32s (- 8.27%)3.42s3.74s
Emit Time1.54s (± 0.91%)1.57s (± 4.86%)+0.03s (+ 2.25%)1.51s1.67s
Total Time7.65s (± 0.65%)7.16s (± 3.13%)-0.50s (- 6.48%)6.96s7.42s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)165,316k (± 0.01%)-9,433k (- 5.40%)165,292k165,344k
Parse Time1.41s (± 1.63%)1.33s (± 0.77%)-0.08s (- 5.36%)1.33s1.35s
Bind Time0.62s (± 5.95%)0.50s (± 3.40%)-0.12s (- 19.68%)0.48s0.52s
Check Time2.98s (± 0.64%)2.75s (± 0.96%)-0.23s (- 7.73%)2.71s2.77s
Emit Time1.35s (± 0.83%)1.35s (± 1.29%)+0.01s (+ 0.45%)1.33s1.37s
Total Time6.36s (± 1.07%)5.94s (± 0.82%)-0.42s (- 6.60%)5.88s5.98s

map4 with usingNativeMaps = false and usingNativeSets = false

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.80s (± 1.47%)+0.01s (+ 0.73%)1.77s1.82s
Bind Time0.69s (± 4.74%)0.71s (± 13.45%)+0.02s (+ 3.18%)0.66s0.86s
Check Time3.37s (± 1.66%)3.43s (± 3.44%)+0.06s (+ 1.68%)3.29s3.57s
Emit Time5.01s (± 4.73%)5.04s (± 4.80%)+0.03s (+ 0.66%)4.93s5.42s
Total Time10.87s (± 2.34%)10.98s (± 1.85%)+0.12s (+ 1.09%)10.83s11.29s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)383,279k (± 0.01%)+3,355k (+ 0.88%)383,241k383,338k
Parse Time2.40s (± 0.75%)2.39s (± 2.42%)-0.01s (- 0.29%)2.33s2.44s
Bind Time0.92s (± 1.79%)0.90s (± 4.74%)-0.02s (- 2.55%)0.86s0.96s
Check Time4.26s (± 1.36%)4.29s (± 0.29%)+0.03s (+ 0.66%)4.28s4.31s
Emit Time1.87s (± 2.44%)1.88s (± 1.90%)+0.01s (+ 0.51%)1.85s1.92s
Total Time9.46s (± 1.19%)9.47s (± 0.86%)+0.01s (+ 0.11%)9.36s9.54s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)203,972k (± 0.01%)+2,001k (+ 0.99%)203,951k203,991k
Parse Time2.30s (± 0.89%)2.29s (± 0.76%)-0.01s (- 0.52%)2.27s2.31s
Bind Time0.72s (± 0.99%)0.68s (± 1.41%)-0.04s (- 5.87%)0.67s0.69s
Check Time3.48s (± 1.73%)3.83s (± 1.77%)+0.35s (+ 10.19%)3.78s3.92s
Emit Time1.91s (± 3.15%)1.62s (± 3.72%)-0.29s (- 15.12%)1.58s1.71s
Total Time8.41s (± 0.61%)8.42s (± 1.66%)+0.01s (+ 0.12%)8.32s8.63s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.22s (± 5.54%)-0.01s (- 0.49%)1.17s1.28s
Bind Time0.56s (± 2.96%)0.58s (± 5.13%)+0.02s (+ 4.38%)0.57s0.63s
Check Time2.81s (± 1.48%)2.84s (± 3.00%)+0.03s (+ 1.03%)2.77s2.95s
Emit Time3.11s (± 0.85%)3.16s (± 1.84%)+0.05s (+ 1.56%)3.08s3.21s
Total Time7.70s (± 0.84%)7.81s (± 2.01%)+0.10s (+ 1.32%)7.60s7.94s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)329,980k (± 0.02%)+1,975k (+ 0.60%)329,913k330,079k
Parse Time1.50s (± 1.02%)1.49s (± 0.69%)-0.02s (- 1.13%)1.47s1.49s
Bind Time0.73s (± 0.73%)0.71s (± 3.11%)-0.01s (- 2.00%)0.68s0.73s
Check Time3.89s (± 0.65%)4.04s (± 1.24%)+0.15s (+ 3.87%)3.96s4.06s
Emit Time1.54s (± 0.91%)1.64s (± 0.63%)+0.10s (+ 6.55%)1.63s1.65s
Total Time7.65s (± 0.65%)7.87s (± 0.76%)+0.21s (+ 2.80%)7.79s7.92s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)175,835k (± 0.01%)+1,086k (+ 0.62%)175,822k175,855k
Parse Time1.41s (± 1.63%)1.39s (± 0.74%)-0.02s (- 1.10%)1.39s1.41s
Bind Time0.62s (± 5.95%)0.57s (± 3.30%)-0.05s (- 8.48%)0.56s0.59s
Check Time2.98s (± 0.64%)2.99s (± 1.14%)+0.02s (+ 0.60%)2.96s3.04s
Emit Time1.35s (± 0.83%)1.38s (± 4.53%)+0.03s (+ 2.52%)1.33s1.45s
Total Time6.36s (± 1.07%)6.34s (± 1.32%)-0.02s (- 0.25%)6.25s6.43s

Heap snapshot numbers

The memory usage tended to be about the same up until the beforeEmit event, AKA after checking.

Master had 365,935 KB total, map4 had 343,774 KB (94% as much), and map4 with shims had 368,978 KB (100% as much as master, 106% as much as map4).

(I added an event heapAfterBind to test the effects of that; map4 used 97% as much memory as master, meaning the real memory savings are during checking.)

For map4, the chrome heap snaprhot viewer shows Maps as accounting for 2% of all objects, with a shallow size equal to their retained size at 1%. However, this is misleading because most of them are mere 32KB wrapper objects which have internal _keys and _values (or table in some cases), which is what really takes up space. I wish there were a way we could include the size of those.

VSCode numbers

I also ran a simple test on the VSCode repo.

master

tsc -p src --noEmit --diagnostics (Run with 2.1.0-dev.20161005)

KindAmountSamples
Memory used737211 K736716, 733971, 743103, 742334, 729932
I/O read0.17 s0.27, 0.12, 0.20, 0.14, 0.14
Parse time5.22 s5.21, 5.18, 5.22, 5.22, 5.29
Bind time1.74 s1.77, 1.72, 1.74, 1.72, 1.75
Check time8.57 s8.69, 8.48, 8.54, 8.50, 8.63
Total time15.54 s15.67, 15.38, 15.51, 15.45, 15.67

map4

node ../TypeScript/built/local/tsc.js -p src --noEmit --diagnostics

KindRelativeAmountSamples
Memory used94%690972 K691500, 690621, 691097, 690872, 690772
I/O read:100%0.17 s0.16, 0.18, 0.20, 0.14, 0.16
Parse time96%5.02 s5.03, 4.95, 4.99, 4.96, 5.18
Bind time:83%1.44 s1.42, 1.40, 1.44, 1.42, 1.53
Check time97%8.34 s8.32, 8.27, 8.38, 8.42, 8.33
Total time95%14.81 s14.78, 14.62, 14.81, 14.80, 15.05

map4 with shims

Same command as for map4, after rebuilding with usingNativeMaps = false and usingNativeSets = false.

KindRelativeAmountSamples
Memory used101%744718 K745408, 744639, 744845, 745511, 743185
I/O read106%0.18 s0.22, 0.19, 0.20, 0.14, 0.17
Parse time99%5.19 s5.28, 5.18, 5.20, 5.17, 5.13
Bind time98%1.71 s1.72, 1.69, 1.70, 1.73, 1.72
Check time101%8.68 s8.58, 8.72, 8.68, 8.72, 8.73
Total time100%15.59 s15.59, 15.59, 15.58, 15.62, 15.57

@ghost

Deleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown
Author

Here is a performance test for doing the same map lookup once vs twice.

constBenchmark=require("benchmark")constcrypto=require("crypto")constN=10000constwords=[]for(leti=0;i<N;i++)words[i]=crypto.randomBytes(8).toString('hex')functioncreateMap(){constm=newMap()for(leti=0;i<N;i+=2)m.set(words[i],i)returnm}functioncreateObject(){consto=Object.create(null)o["__"]=undefineddeleteo["__"]for(leti=0;i<N;i+=2)o[words[i]]=ireturno}letcorrectSum=0for(leti=0;i<N;i+=2)correctSum+=iconstsuite=newBenchmark.Suitesuite.add("map has-then-get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++)if(map.has(words[i]))sum+=map.get(words[i])if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map just get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++){constx=map.get(words[i])if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object has-then-get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++)if(words[i]ino)sum+=o[words[i]]if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object just get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++){constx=o[words[i]]if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map double get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){sum+=map.get(words[i])sum+=map.get(words[i])}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("map single get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){constgot=map.get(words[i])sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("object double get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){sum+=o[words[i]]sum+=o[words[i]]}if(sum!==correctSum*2)thrownewError()returnsum})suite.add("object single get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){constgot=o[words[i]]sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.on("complete",function(){this.forEach(({name, stats})=>{console.log(`${name}: ${stats.mean*1000}ms`)})})suite.on("error",err=>{throwerr.target.error})suite.run()
map has-then-get: 1.0212332328457447ms
map just get: 0.911712559080547ms
object has-then-get: 1.9529671271167457ms
object just get: 1.9624182600334454ms
map double get: 0.7383946305889607ms
map single get: 0.651791347503374ms
object double get: 1.411747356033454ms
object single get: 1.3791293993025284ms

Looks like removing uses of has is useful for maps but not for objects. Removing double get is always good.

@ghostghost mentioned this pull request Oct 4, 2016
@ghost
ghost force-pushed the map4 branch 2 times, most recently from 1f080a8 to 6fc4eadCompareOctober 5, 2016 14:58
@ghost

Copy link
Copy Markdown
Author

This would be a breaking change. We have publicly exported maps because we have export type SymbolTable = Map<string, Symbol>;, which is the type of several public properties of Symbol.

Comment threadJakefile.js Outdated
}

var compilerSources = [
"dataStructures.ts",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be tempted to call this collections.ts, since we already have a types.ts and this is more specific.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of moving our array utilities to collections.ts?

Comment threadsrc/compiler/dataStructures.ts Outdated
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

/** Extra Map methods that may not be available, so we must provide fallbacks. */
interface FullyFeaturedMap<K, V> extends Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe call this ES6Map?

@ghostghost mentioned this pull request Oct 7, 2016
@yuit

Copy link
Copy Markdown
Contributor

Andy (Andrewkraft) (@Andy-MS) looks good for my end 👍 though it is a big change so I think it may be good idea to have Mohamed Hegazy (@mhegazy)Vladimir Matveev (@vladima)Nathan Shively-Sanders (@sandersn)Ron Buckton (@rbuckton) to check as well

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider merging the shims for NumberMap and StringMap.

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for stylistic consistency do not use classes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you share the numbers after removing classes?

@ghostDeleted user (ghost)Oct 12, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It ends up taking 20% longer. 🤕
Here are the measurements for running map4 with closure shims, with "Delta" relative to map4 with class shims.

Monaco - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used203,967k (± 0.01%)224,241k (± 0.01%)+20,274k (+ 9.94%)224,220k224,263k
Parse Time2.27s (± 0.39%)2.39s (± 3.65%)+0.12s (+ 5.30%)2.32s2.51s
Bind Time0.68s (± 1.17%)0.83s (± 1.52%)+0.15s (+ 21.41%)0.81s0.84s
Check Time3.86s (± 2.12%)4.72s (± 3.44%)+0.86s (+ 22.15%)4.55s4.89s
Emit Time1.62s (± 2.07%)2.30s (± 14.05%)+0.68s (+ 41.80%)2.04s2.72s
Total Time8.43s (± 1.26%)10.23s (± 3.36%)+1.80s (+ 21.34%)9.78s10.47s
TFS - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used175,828k (± 0.01%)188,541k (± 0.01%)+12,713k (+ 7.23%)188,529k188,551k
Parse Time1.40s (± 0.75%)1.51s (± 4.24%)+0.11s (+ 7.80%)1.46s1.60s
Bind Time0.57s (± 1.02%)0.68s (± 2.26%)+0.12s (+ 20.63%)0.67s0.70s
Check Time3.00s (± 0.53%)3.60s (± 3.55%)+0.60s (+ 19.88%)3.41s3.69s
Emit Time1.37s (± 1.09%)1.71s (± 5.74%)+0.34s (+ 25.18%)1.66s1.86s
Total Time6.33s (± 0.28%)7.50s (± 2.73%)+1.16s (+ 18.38%)7.24s7.71s

Here's the code I tested with (with equivalents for NumberMap and StringSet):

exportconstcreateStringMap: <T>(pairs?: [string,T][])=>Map<string,T>=usingNativeMaps
? <T>(pairs?: [string,T][])=>newMap(pairs)
: <T>(pairs?: [string,T][])=>{letdata=createDictionaryModeObject<T>();if(pairs){for(const[key,value]ofpairs){data[key]=value;}}return{clear(): void{data=createDictionaryModeObject<T>();},delete(key: string): void{deletedata[key];},get(key: string): T{returndata[key];},has(key: string): boolean{// tslint:disable-next-line:no-in-operatorreturnkeyindata;},set(key: string,value: T): void{data[key]=value;},forEach(action: (value: T,key: string)=>void): void{for(constkeyindata){action(data[key],key);}}}}

I bet this is allocating a different closure for each method, wheras a class just allocates space for data and shares a single prototype among all instances.

Comment threadsrc/compiler/collections.ts Outdated
// Map utilities
namespace ts {
/** Create a map containing a single entry key -> value. */
export function createMapWithEntry<T>(key: string, value: T): Map<string, T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider inlining this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or using the Map constructor optional parameter

Comment threadsrc/compiler/collections.ts Outdated
}

// Map utilities
namespace ts {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be marked internal. and consider using one closure for all of them

Comment threadsrc/compiler/program.ts Outdated

// If output has not been changed, and the file has no external modification
if (fingerprint.byteOrderMark === writeByteOrderMark &&
if (fingerprint !== undefined && fingerprint.byteOrderMark === writeByteOrderMark &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just if (figureprint

@mhegazy

Copy link
Copy Markdown
Contributor

Can you also share the perf numbers once it is in.

@mhegazy

Copy link
Copy Markdown
Contributor

Ron Buckton (@rbuckton) any more comments?

@rbucktonRon Buckton (rbuckton) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few non-blocking review comments, but this looks fine to me.

Comment threadsrc/compiler/collections.ts Outdated
declare const Map: { new<K, V>(pairs?: [K, V][]): Map<K, V> } | undefined;
const usingNativeMaps = typeof Map !== "undefined";
// tslint:disable-next-line:no-in-operator
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term "fully-featured" is a bit ambiguous. Maybe usingES6NativeMaps?

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using an object.
* `pairs` is an optional list of entries to add to the new map.
*/
export const StringMap: { new<T>(pairs?: [string, T][]): Map<string, T>; } = usingNativeMaps ? Map : ShimMap;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love for us to be able to just call this Map instead of StringMap or NumberMap, but its a bit messy to avoid colliding with the global Map

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or stick with createMap<K extends string | number, V>() and createSet<T extends string | number>()

Comment threadsrc/compiler/collections.ts Outdated
* Creates a sorted array of keys.
* Sorts keys according to the iteration order they would have if they were in an object, instead of from a Map.
* This is so that tests run consistently whether or not we have a Map shim in place.
* The difference between Map iteration order and V8 object insertion order is that V8 moves natrual-number-like keys to the front.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"natural"

Comment threadsrc/compiler/collections.ts Outdated
}

delete(value: string) {
delete this.data[value];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Sets return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
}

delete(key: K): void {
delete this.data[key as string];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Maps return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
However, `forEach` will iterate over strings because values are stringified before being put in the map.
*/

constructor(pairs?: [K, V][]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-ES6 native maps don't support constructor arguments.

delete(key: K): void {
delete this.data[key as string];
delete(key: K): boolean {
const had = this.has(key);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this. Just do return delete this.data[key as string].

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deletealways returns true in strict mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. That's unfortunate...and odd.

delete(value: string) {
delete this.data[value];
delete(value: string): boolean {
const had = this.has(value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, you can just do return delete this.data[value] since a delete expression returns boolean

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard

@ghost
ghost merged commit adfdae0 into masterOct 27, 2016
@ghost
ghost deleted the map4 branch October 27, 2016 20:27
@ghost

Copy link
Copy Markdown
Author

Will do a final performance comparison tomorrow.

ghost pushed a commit that referenced this pull request Oct 27, 2016
This reverts commit adfdae0, reversing
changes made to aad663c.
ghost pushed a commit that referenced this pull request Oct 27, 2016
Revert "Merge pull request #11354 from Microsoft/map4"
Mohamed Hegazy (mhegazy) added a commit that referenced this pull request Nov 10, 2016
* Use a single ShimMap class, and indicate that iteration always yields string keys (which it did before too)
* Remove emacs-added newline at end of baseline
* Remove space at end of line in baseline
* Add numeric indexer to strings and remove lint
* Update baselines with spread string's numeric indexers
* Reset baseline line number to the locally incorrect value
* Remove trailing newline from baseline again
* Respond to PR comments
* Refactor getTypeFromTypeLiteral, from PR comments
* Fix lint
* Use same literal comparison rules for switch/===
switch was missing the rule for converting literal types to the literal
base type if needed.
* Add switch comparability test and update baselines
* Push eitherIsNotLiteral check into isTypeEqualityComparableTo
Since all callers need this check -- it's how equality is supposed to
work everywhere.
* Update baselines
There are more literal types in error messages because error reporting
no longer has the advantage of calls to getBaseLiteralType
* Adds ES5 to ES3 transformer for reserved words
* Minor cleanup
* Cleaned up emit of enum declaration
* Return both ts and js results from module resolution, and don't have moduleNameResolver responsible for omitting files based on compiler options
* Instead of getResolutionOrDiagnostic, use getResolutionDiagnostic and avoid using resolution.resolvedFileName if the diagnostic is defined.
* Remove "ResolvedModuleFromHost" type and just make `resolvedTsFileName` and `resolvedJsFileName` optional properties
(but still automatically infer one of them to supply if the host supplied neither)
* Remove type inference for spread types
* Update inference test for spread types
* Make spread assignability and apparent type stricter
Assignability now does not allow properties to the left of a type
parameter.
Apparent type now only returns the apparent type of the right-most
spread member.
* Update tests w/spread assignability+apparent type
* Moved AMD/CJS/UMD transform to end
* Spread no longer distributes intersections
* Update spread w/intersection tests
* Move System module transform to end.
* Update baseline
* Revert baseline change due to stale output
* Resolve all-object intersections inside spreads
This means that getSpreadType will return an object type, even when
spreading two intersections, as long as those intersections contain
nothing but object types themselves.
* Update and improve spread intersection tests
* Simplify expression in resolveObjectIntersection
* Update baselines with new index signature rules
* Move n-ary spread handling into separate function.
To be moved to callers in the next step.
* Move multiple-spread handling out of getSpreadType
* Clean up and reorder getSpreadType body
* Respond to PR comments
* Error for call/construct signatures in spread type
1. Simplify the error reporting code to handle all kinds of signatures.
2. Remove index signature handling code when creating a spread type
since it's an error anyway.
* Update baselines with new spread type index errors
* Explain writeSpreadType a little better
* Add more commentary to getSpreadType
* Initial implementation of 'keyof T' type operator
* Introduce PropertyNameType
* Move most of resolveModuleNameForLsHost to lsHost
* Simplify isImplicitGlob test
* Initial implementation of 'T[K]' property access types
* add a fallback logic for older versions of node that don't support 'homedir' (#11845)
* add a fallback logic for older versions of node that don't support 'homedir'
* try os.homedir first
* For JavaScript files, we report semantic errors for using TypeScript-only constructs from within a JavaScript file as syntactic errors.
* Don't require `resolvedTsFileName` and `resolvedJsFileName`, just `resolvedFileName` and `extension`. Also, change search order to do all TS searching before searching for JS.
* Fix#10108 (Completion suggestion for object literal with getter) (#11808)
* Fix#10108 (Completion suggestion for object literal with getter)
* completions for setter
* Move helper functions to core (fix build)
* Support parametric property access expressions + some renaming
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives (#11872)
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives
* pass proper value for current directory when compiling .d.ts files
* Fix bug: Return a resolution diagnostic for a `.jsx` import if `--allowJs` is turned off
* Remove a comment about a parameter that no longer exists
* Fix bug: We want to test for existence of the enum value, not whether it's non-zero
* Fix: test for presence, not absence
* Allow untyped imports
* Simplify for loops in fourslash.ts
* Rename to zipWith
* Change diagnostic message
* Make `extension` property of `ResolvedModule` optional; introduce `ResolvedModuleFull` interface for when the extension is provided.
* Consider index signatures in type produced by 'keyof T'
* Respond to PR comments
* Refactor getIndexedAccessType to be reusable from checkIndexedAccess
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Revert "Merge pull request #11354 from Microsoft/map4"
This reverts commit adfdae0, reversing
changes made to aad663c.
* Rename Experimental transform to ESNext
1. Spread/rest are no longer experimental.
2. We need a place to put stage 3 ES features.
* Changes from CR feedback
* disable CoS for inferred projects (#11909)
* Updating test due to CR changes. The order of the diagnostic messages has changed due to concatenation changes
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* Rename TransformFlags.Experimental -> ESNext
* enable non-ts extensions in inferred projects by default
* update CFG to properly handle do statements
* do not inline async IIFEs in control flow graph
* Minor fixes
* cache type for empty type literal (#11934)
cache type for empty type literal
* Improved error messages for invalid assignments to identifiers
* Accept new baselines
* Improved error messages for invalid assignments to properties
* Accept new baselines
* Improve more error messages
* Accept new baselines
* Fix realPathMap in test harness: Must be used in `directoryExists`
* Add helper function
* Update generated files (#11963)
* Move eitherIsNotLiteral check into switch and === checks
This improves error messages
* Forbid augmentation of untyped module (#11962)
* Forbid augmentation of untyped module
* Just use `undefined` for untyped modules
* Unify checking of indexed access expressions and indexed access types
* Accept new baselines
* Accept additional baselines
* Make `cachingInServerLSHost` tests work with `runtests-browser`
* Get literal type only once
* Update baselines
* Add missed test update
* Improve unification by moving more logic to getIndexedAccessType
* Add test cases to report errors for decorators in js file
* Report all the js file errors and skip only the nodes that are not allowed in js
Fixes#11800
* Fix 'keyof any' to produce 'string | number'
* Fix#11396: Make error message referene `Promise` explicitly (#11982)
* Simplify the checking for async function return type
* Fix#11396: Make error message referene `Promise` explicitly
* Minor fixes
* Adding tests
* Test case for property used in destructuring variable declaration
* Mark property referenced in the destructuring as referenced
Fixes#11324
* Spread types handle nested index [access] types
Nested index [access] types are treated as assignable to themselves only,
just like type parameters.
* Test index [access] types inside spread types
* module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program (#11999)
module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program
* Parse, bind and check rest elements
* Downlevel emit of rest elements
* Add rest tests
* Update baselines
* Remove spread types, leaving spread syntax/emit
Spreads are still typed, but cannot be created from a non-object type.
Tests still need to be updated.
* Fix lint
* Lock tslint version to 4.0.0-dev.0, because 4.0.0-dev.1 complains about unnecessary semicolons following properties
* Remove spread type tests from spread tests
* Spread handles index signatures from singleton spreads
I broke it when simplifying the logic earlier.
* Correct assignability for keyof types and type parameters
* Update tests
* Accept new baselines
* Update objectRestAssignment test and baselines
* Fix linting errors
* Update objectRestAssignment test
Missed previously, just got the baselines
* Improve readability of ES next destructuring emit
* Ensure transformFlags are correct before visiting a node.
* Port #12027, #11980 and #11932 to master (#12037)
* add test for the fix for overwrite emitting error
* cr feedback
* Address PR comments
1. Remove extra line in __rest shim.
2. Improve __rest vs __assign check for destructuring assignment.
* Move convertForOf to factory for esnext and es2015
Saves a lot of duplicated code
* Update improved baselines
* Move transformFunctionBody to factory
It is shared by es2015 and esNext transformers.
This commit just adds a convertObjectRest flag to be passed on to
flattenDestructuring functions, as well as adding necessary parameters
to use the code outside a transformer.
* Spread any types to any
* add missing bind calls to properly set parent on token nodes (#12057)
* Cache generic signature instantiations
* Accept new baselines
* Properly instantiate aliasTypeArguments
* Add regression test
* Revert incorrect logic from #11392
* Accept new baselines
* Rename SpreadElementExpression -> SpreadAssignment
and SpreadExpression (formerly SpreadElementExpression) -> SpreadElement
* Add SpreadAssignment to visitors
1. visitNode
2. reduceNode
3. emit
This fixes an emit bug for setters.
* Add --target esnext
Currently, this disables the rest and spread transforms. This will
change as proposals enter and leave stage 3.
* Add --target esnext tests and update baselines
* Revert unneeded change and comments per PR
* Rename variable in checkSwitchStatement per PR
* Do not emit __rest for --target esnext
* Add `realpath` implementation for lshost
* Create spread property types eagerly
This avoids the need for a synthetic symbol and later code called from
getTypeOfSymbol.
* Set spread type symbols in checkObjectLiteral
Instead of getSpreadType.
Also clean up special-case handling inside getSpreadType to be more
readable.
* Ports #12051 and #12032 into master (#12090)
* use local registry to check if typings package exist (#12014)
use local registry to check if typings package exist
* enable sending telemetry events to tsserver client (#12035)
enable sending telemetry events
* Address more PR comments
* return empty file watcher in case if target directory does not exist (#12091)
* return empty file watcher in case if target directory does not exist
* linter
* property handle missing config files in external projects (#12094)
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Port fix for #12069 (#12095)
* reduce set of files being watched, increase polling interval (#12054) (#12092)
* Update authors for release-2.1
* Include declaration file emit
* use createHash from ServerHost instead of explicit require (#12043)
* use createHash from ServerHost instead of explicit require
* added missing method in ServerHost stub
* (signature help) type parameter lists are never variadic (#12112)
* Handle abstract and const modifiers
* Downlevel array destructuring to ES6 in object rest
Previously array destructuring inside an object destructuring with an
object rest would downlevel the array destructuring to ES5. This breaks
if the code that targets ES2015 is using iterators instead of arrays
since iterators don't support [0] or .slice that the ES5 emit uses.
* Improve nested destructuring test for ESNext emit
Now with object destructuring inside array destructuring inside object
destructuring! Each with their own array/object rest!
Also updates baselines.
* Add support for taking in jsxFactory option and report errors for invalid combinations
* Treat `| undefined` like optionality in spread type
* Add strictNullChecks test for object spread
* Verify that jsxFactory is either identifier or qualified name
* Resolve first identifier of the jsxFactory as part of type check
* When emitting use jsx factory entity expression if provided
* Transpile unit test case
* Enabled test case for source map
* Add test cases for when jsxFactory cannot be resolved
* Parse the jsxFactory again in the checker instead of using cached value in the program
* Adds error message for incompatible assignment of identically named type
Fixes issue #12050
* Updated condition for more readability
* Report errors for import helpers missing __rest
* Correctly check spread assignments in strict mode
Previously it crashed in the binder.
* Test error for import helpers with no __rest
* synthesize complete import declaration for tslib (#12151)
* Add ES2017 string padding (#12152)
* add es2017.string.d.ts for String.prototype.{padStart,padEnd}
* append es2017.string.d.ts into es2017.d.ts
* add es2017.string into commandLineParser
* append es2017.string into error message for unit tests of commandLineParser
* append es2017.string into Gulpfile
* append es2017.string into Jakefile
* Exclude js files in non-configured projects compile-on-save emitting (#12118)
* Exclude js files in non-configured projects CoS emitting
* remove unnecessary method
* Merge release-2.1 into master (#12157)
* Update LKG
* Update version
* Update LKG
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* Update LKG
* Fix emit inferred type which is a generic type-alias both fully and partially fill type parameters
* Add tests and baselines
* Skip trying to use alias if there is target type
* Update baselines
* Add diagnostics to remind adding tsconfig file for certain external project (#11932)
* Add diagnostics for certain external project
* Show tsconfig suggestion
* fix lint error
* Address pr
* fix comment
* Update error message
* Flag for not overwrite js files by default without generating errors (#11980)
* WIP
* Properly naming things
* refactor
* apply the option to all files and check out options
* Fix typo
* Update LKG
* lockLinter
* use local registry to check if typings package exist (#12014) (#12032)
use local registry to check if typings package exist
* Add test for #11980 (#12027)
* add test for the fix for overwrite emitting error
* cr feedback
* enable sending telemetry events to tsserver client (#12034) (#12051)
enable sending telemetry events
* Update LKG
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Update LKG
* Update version
* Update LKG
* Do not emit "use strict" when targeting es6 or higher or module kind is es2015 and the file is external module
* Add tests and baselines
* [Release 2.1] fix11754 global augmentation (#12133)
* Exclude global augmentation from module resolution logic
* Address PR: check using string literal instead of NodeFlags.globalAugmentation
* Remove comment
@ghostghost mentioned this pull request Dec 7, 2016
@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
This pull request was closed.
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@yuit@mhegazy@rbuckton@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Use native maps when they're available - #11354

Merged
18 commits merged into
masterfrom
map4
Oct 27, 2016
Merged

Use native maps when they're available#11354
18 commits merged into
masterfrom
map4

Conversation

@ghost

@ghostDeleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown

The summary is that using native maps, the compiler works 5% faster and uses 5% less memory. Using shims, the performance is surprisingly less than 5% worse.

I was able to achieve good baseline performance by disabling Windows Defender in my work directory and using "High Performance" in Control Panel -> Hardware and Sound -> Power Options. There is much less variance this time around.

Benchmark numbers

This is from using our internal ts-perf tool.

map4

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.72s (± 1.10%)-0.07s (- 4.08%)1.70s1.74s
Bind Time0.69s (± 4.74%)0.52s (± 3.50%)-0.17s (- 24.86%)0.50s0.54s
Check Time3.37s (± 1.66%)2.91s (± 3.16%)-0.46s (- 13.69%)2.78s2.98s
Emit Time5.01s (± 4.73%)4.87s (± 1.35%)-0.14s (- 2.77%)4.79s4.94s
Total Time10.87s (± 2.34%)10.02s (± 1.18%)-0.84s (- 7.77%)9.86s10.12s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)356,928k (± 0.01%)-22,996k (- 6.05%)356,890k356,956k
Parse Time2.40s (± 0.75%)2.32s (± 2.13%)-0.08s (- 3.37%)2.28s2.39s
Bind Time0.92s (± 1.79%)0.71s (± 1.84%)-0.21s (- 22.52%)0.70s0.73s
Check Time4.26s (± 1.36%)3.84s (± 6.33%)-0.42s (- 9.94%)3.66s4.18s
Emit Time1.87s (± 2.44%)1.82s (± 3.16%)-0.05s (- 2.80%)1.77s1.89s
Total Time9.46s (± 1.19%)8.69s (± 3.96%)-0.77s (- 8.12%)8.42s9.16s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)190,504k (± 0.01%)-11,467k (- 5.68%)190,474k190,538k
Parse Time2.30s (± 0.89%)2.20s (± 2.07%)-0.09s (- 4.09%)2.17s2.27s
Bind Time0.72s (± 0.99%)0.57s (± 4.73%)-0.15s (- 21.33%)0.55s0.61s
Check Time3.48s (± 1.73%)3.27s (± 4.68%)-0.21s (- 6.08%)3.08s3.38s
Emit Time1.91s (± 3.15%)1.78s (± 8.00%)-0.13s (- 6.94%)1.65s1.94s
Total Time8.41s (± 0.61%)7.82s (± 1.68%)-0.59s (- 7.03%)7.71s7.99s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.15s (± 1.31%)-0.07s (- 6.06%)1.13s1.16s
Bind Time0.56s (± 2.96%)0.54s (± 4.08%)-0.02s (- 3.13%)0.52s0.57s
Check Time2.81s (± 1.48%)2.46s (± 1.85%)-0.35s (- 12.34%)2.43s2.53s
Emit Time3.11s (± 0.85%)3.19s (± 0.91%)+0.07s (+ 2.33%)3.15s3.22s
Total Time7.70s (± 0.84%)7.34s (± 1.14%)-0.37s (- 4.78%)7.28s7.46s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)309,449k (± 0.02%)-18,556k (- 5.66%)309,386k309,516k
Parse Time1.50s (± 1.02%)1.44s (± 0.88%)-0.07s (- 4.32%)1.42s1.45s
Bind Time0.73s (± 0.73%)0.58s (± 1.65%)-0.14s (- 19.89%)0.57s0.59s
Check Time3.89s (± 0.65%)3.56s (± 4.42%)-0.32s (- 8.27%)3.42s3.74s
Emit Time1.54s (± 0.91%)1.57s (± 4.86%)+0.03s (+ 2.25%)1.51s1.67s
Total Time7.65s (± 0.65%)7.16s (± 3.13%)-0.50s (- 6.48%)6.96s7.42s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)165,316k (± 0.01%)-9,433k (- 5.40%)165,292k165,344k
Parse Time1.41s (± 1.63%)1.33s (± 0.77%)-0.08s (- 5.36%)1.33s1.35s
Bind Time0.62s (± 5.95%)0.50s (± 3.40%)-0.12s (- 19.68%)0.48s0.52s
Check Time2.98s (± 0.64%)2.75s (± 0.96%)-0.23s (- 7.73%)2.71s2.77s
Emit Time1.35s (± 0.83%)1.35s (± 1.29%)+0.01s (+ 0.45%)1.33s1.37s
Total Time6.36s (± 1.07%)5.94s (± 0.82%)-0.42s (- 6.60%)5.88s5.98s

map4 with usingNativeMaps = false and usingNativeSets = false

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.80s (± 1.47%)+0.01s (+ 0.73%)1.77s1.82s
Bind Time0.69s (± 4.74%)0.71s (± 13.45%)+0.02s (+ 3.18%)0.66s0.86s
Check Time3.37s (± 1.66%)3.43s (± 3.44%)+0.06s (+ 1.68%)3.29s3.57s
Emit Time5.01s (± 4.73%)5.04s (± 4.80%)+0.03s (+ 0.66%)4.93s5.42s
Total Time10.87s (± 2.34%)10.98s (± 1.85%)+0.12s (+ 1.09%)10.83s11.29s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)383,279k (± 0.01%)+3,355k (+ 0.88%)383,241k383,338k
Parse Time2.40s (± 0.75%)2.39s (± 2.42%)-0.01s (- 0.29%)2.33s2.44s
Bind Time0.92s (± 1.79%)0.90s (± 4.74%)-0.02s (- 2.55%)0.86s0.96s
Check Time4.26s (± 1.36%)4.29s (± 0.29%)+0.03s (+ 0.66%)4.28s4.31s
Emit Time1.87s (± 2.44%)1.88s (± 1.90%)+0.01s (+ 0.51%)1.85s1.92s
Total Time9.46s (± 1.19%)9.47s (± 0.86%)+0.01s (+ 0.11%)9.36s9.54s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)203,972k (± 0.01%)+2,001k (+ 0.99%)203,951k203,991k
Parse Time2.30s (± 0.89%)2.29s (± 0.76%)-0.01s (- 0.52%)2.27s2.31s
Bind Time0.72s (± 0.99%)0.68s (± 1.41%)-0.04s (- 5.87%)0.67s0.69s
Check Time3.48s (± 1.73%)3.83s (± 1.77%)+0.35s (+ 10.19%)3.78s3.92s
Emit Time1.91s (± 3.15%)1.62s (± 3.72%)-0.29s (- 15.12%)1.58s1.71s
Total Time8.41s (± 0.61%)8.42s (± 1.66%)+0.01s (+ 0.12%)8.32s8.63s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.22s (± 5.54%)-0.01s (- 0.49%)1.17s1.28s
Bind Time0.56s (± 2.96%)0.58s (± 5.13%)+0.02s (+ 4.38%)0.57s0.63s
Check Time2.81s (± 1.48%)2.84s (± 3.00%)+0.03s (+ 1.03%)2.77s2.95s
Emit Time3.11s (± 0.85%)3.16s (± 1.84%)+0.05s (+ 1.56%)3.08s3.21s
Total Time7.70s (± 0.84%)7.81s (± 2.01%)+0.10s (+ 1.32%)7.60s7.94s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)329,980k (± 0.02%)+1,975k (+ 0.60%)329,913k330,079k
Parse Time1.50s (± 1.02%)1.49s (± 0.69%)-0.02s (- 1.13%)1.47s1.49s
Bind Time0.73s (± 0.73%)0.71s (± 3.11%)-0.01s (- 2.00%)0.68s0.73s
Check Time3.89s (± 0.65%)4.04s (± 1.24%)+0.15s (+ 3.87%)3.96s4.06s
Emit Time1.54s (± 0.91%)1.64s (± 0.63%)+0.10s (+ 6.55%)1.63s1.65s
Total Time7.65s (± 0.65%)7.87s (± 0.76%)+0.21s (+ 2.80%)7.79s7.92s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)175,835k (± 0.01%)+1,086k (+ 0.62%)175,822k175,855k
Parse Time1.41s (± 1.63%)1.39s (± 0.74%)-0.02s (- 1.10%)1.39s1.41s
Bind Time0.62s (± 5.95%)0.57s (± 3.30%)-0.05s (- 8.48%)0.56s0.59s
Check Time2.98s (± 0.64%)2.99s (± 1.14%)+0.02s (+ 0.60%)2.96s3.04s
Emit Time1.35s (± 0.83%)1.38s (± 4.53%)+0.03s (+ 2.52%)1.33s1.45s
Total Time6.36s (± 1.07%)6.34s (± 1.32%)-0.02s (- 0.25%)6.25s6.43s

Heap snapshot numbers

The memory usage tended to be about the same up until the beforeEmit event, AKA after checking.

Master had 365,935 KB total, map4 had 343,774 KB (94% as much), and map4 with shims had 368,978 KB (100% as much as master, 106% as much as map4).

(I added an event heapAfterBind to test the effects of that; map4 used 97% as much memory as master, meaning the real memory savings are during checking.)

For map4, the chrome heap snaprhot viewer shows Maps as accounting for 2% of all objects, with a shallow size equal to their retained size at 1%. However, this is misleading because most of them are mere 32KB wrapper objects which have internal _keys and _values (or table in some cases), which is what really takes up space. I wish there were a way we could include the size of those.

VSCode numbers

I also ran a simple test on the VSCode repo.

master

tsc -p src --noEmit --diagnostics (Run with 2.1.0-dev.20161005)

KindAmountSamples
Memory used737211 K736716, 733971, 743103, 742334, 729932
I/O read0.17 s0.27, 0.12, 0.20, 0.14, 0.14
Parse time5.22 s5.21, 5.18, 5.22, 5.22, 5.29
Bind time1.74 s1.77, 1.72, 1.74, 1.72, 1.75
Check time8.57 s8.69, 8.48, 8.54, 8.50, 8.63
Total time15.54 s15.67, 15.38, 15.51, 15.45, 15.67

map4

node ../TypeScript/built/local/tsc.js -p src --noEmit --diagnostics

KindRelativeAmountSamples
Memory used94%690972 K691500, 690621, 691097, 690872, 690772
I/O read:100%0.17 s0.16, 0.18, 0.20, 0.14, 0.16
Parse time96%5.02 s5.03, 4.95, 4.99, 4.96, 5.18
Bind time:83%1.44 s1.42, 1.40, 1.44, 1.42, 1.53
Check time97%8.34 s8.32, 8.27, 8.38, 8.42, 8.33
Total time95%14.81 s14.78, 14.62, 14.81, 14.80, 15.05

map4 with shims

Same command as for map4, after rebuilding with usingNativeMaps = false and usingNativeSets = false.

KindRelativeAmountSamples
Memory used101%744718 K745408, 744639, 744845, 745511, 743185
I/O read106%0.18 s0.22, 0.19, 0.20, 0.14, 0.17
Parse time99%5.19 s5.28, 5.18, 5.20, 5.17, 5.13
Bind time98%1.71 s1.72, 1.69, 1.70, 1.73, 1.72
Check time101%8.68 s8.58, 8.72, 8.68, 8.72, 8.73
Total time100%15.59 s15.59, 15.59, 15.58, 15.62, 15.57

@ghost

Deleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown
Author

Here is a performance test for doing the same map lookup once vs twice.

constBenchmark=require("benchmark")constcrypto=require("crypto")constN=10000constwords=[]for(leti=0;i<N;i++)words[i]=crypto.randomBytes(8).toString('hex')functioncreateMap(){constm=newMap()for(leti=0;i<N;i+=2)m.set(words[i],i)returnm}functioncreateObject(){consto=Object.create(null)o["__"]=undefineddeleteo["__"]for(leti=0;i<N;i+=2)o[words[i]]=ireturno}letcorrectSum=0for(leti=0;i<N;i+=2)correctSum+=iconstsuite=newBenchmark.Suitesuite.add("map has-then-get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++)if(map.has(words[i]))sum+=map.get(words[i])if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map just get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++){constx=map.get(words[i])if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object has-then-get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++)if(words[i]ino)sum+=o[words[i]]if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object just get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++){constx=o[words[i]]if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map double get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){sum+=map.get(words[i])sum+=map.get(words[i])}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("map single get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){constgot=map.get(words[i])sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("object double get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){sum+=o[words[i]]sum+=o[words[i]]}if(sum!==correctSum*2)thrownewError()returnsum})suite.add("object single get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){constgot=o[words[i]]sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.on("complete",function(){this.forEach(({name, stats})=>{console.log(`${name}: ${stats.mean*1000}ms`)})})suite.on("error",err=>{throwerr.target.error})suite.run()
map has-then-get: 1.0212332328457447ms
map just get: 0.911712559080547ms
object has-then-get: 1.9529671271167457ms
object just get: 1.9624182600334454ms
map double get: 0.7383946305889607ms
map single get: 0.651791347503374ms
object double get: 1.411747356033454ms
object single get: 1.3791293993025284ms

Looks like removing uses of has is useful for maps but not for objects. Removing double get is always good.

@ghostghost mentioned this pull request Oct 4, 2016
@ghost
ghost force-pushed the map4 branch 2 times, most recently from 1f080a8 to 6fc4eadCompareOctober 5, 2016 14:58
@ghost

Copy link
Copy Markdown
Author

This would be a breaking change. We have publicly exported maps because we have export type SymbolTable = Map<string, Symbol>;, which is the type of several public properties of Symbol.

Comment threadJakefile.js Outdated
}

var compilerSources = [
"dataStructures.ts",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be tempted to call this collections.ts, since we already have a types.ts and this is more specific.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of moving our array utilities to collections.ts?

Comment threadsrc/compiler/dataStructures.ts Outdated
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

/** Extra Map methods that may not be available, so we must provide fallbacks. */
interface FullyFeaturedMap<K, V> extends Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe call this ES6Map?

@ghostghost mentioned this pull request Oct 7, 2016
@yuit

Copy link
Copy Markdown
Contributor

Andy (Andrewkraft) (@Andy-MS) looks good for my end 👍 though it is a big change so I think it may be good idea to have Mohamed Hegazy (@mhegazy)Vladimir Matveev (@vladima)Nathan Shively-Sanders (@sandersn)Ron Buckton (@rbuckton) to check as well

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider merging the shims for NumberMap and StringMap.

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for stylistic consistency do not use classes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you share the numbers after removing classes?

@ghostDeleted user (ghost)Oct 12, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It ends up taking 20% longer. 🤕
Here are the measurements for running map4 with closure shims, with "Delta" relative to map4 with class shims.

Monaco - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used203,967k (± 0.01%)224,241k (± 0.01%)+20,274k (+ 9.94%)224,220k224,263k
Parse Time2.27s (± 0.39%)2.39s (± 3.65%)+0.12s (+ 5.30%)2.32s2.51s
Bind Time0.68s (± 1.17%)0.83s (± 1.52%)+0.15s (+ 21.41%)0.81s0.84s
Check Time3.86s (± 2.12%)4.72s (± 3.44%)+0.86s (+ 22.15%)4.55s4.89s
Emit Time1.62s (± 2.07%)2.30s (± 14.05%)+0.68s (+ 41.80%)2.04s2.72s
Total Time8.43s (± 1.26%)10.23s (± 3.36%)+1.80s (+ 21.34%)9.78s10.47s
TFS - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used175,828k (± 0.01%)188,541k (± 0.01%)+12,713k (+ 7.23%)188,529k188,551k
Parse Time1.40s (± 0.75%)1.51s (± 4.24%)+0.11s (+ 7.80%)1.46s1.60s
Bind Time0.57s (± 1.02%)0.68s (± 2.26%)+0.12s (+ 20.63%)0.67s0.70s
Check Time3.00s (± 0.53%)3.60s (± 3.55%)+0.60s (+ 19.88%)3.41s3.69s
Emit Time1.37s (± 1.09%)1.71s (± 5.74%)+0.34s (+ 25.18%)1.66s1.86s
Total Time6.33s (± 0.28%)7.50s (± 2.73%)+1.16s (+ 18.38%)7.24s7.71s

Here's the code I tested with (with equivalents for NumberMap and StringSet):

exportconstcreateStringMap: <T>(pairs?: [string,T][])=>Map<string,T>=usingNativeMaps
? <T>(pairs?: [string,T][])=>newMap(pairs)
: <T>(pairs?: [string,T][])=>{letdata=createDictionaryModeObject<T>();if(pairs){for(const[key,value]ofpairs){data[key]=value;}}return{clear(): void{data=createDictionaryModeObject<T>();},delete(key: string): void{deletedata[key];},get(key: string): T{returndata[key];},has(key: string): boolean{// tslint:disable-next-line:no-in-operatorreturnkeyindata;},set(key: string,value: T): void{data[key]=value;},forEach(action: (value: T,key: string)=>void): void{for(constkeyindata){action(data[key],key);}}}}

I bet this is allocating a different closure for each method, wheras a class just allocates space for data and shares a single prototype among all instances.

Comment threadsrc/compiler/collections.ts Outdated
// Map utilities
namespace ts {
/** Create a map containing a single entry key -> value. */
export function createMapWithEntry<T>(key: string, value: T): Map<string, T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider inlining this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or using the Map constructor optional parameter

Comment threadsrc/compiler/collections.ts Outdated
}

// Map utilities
namespace ts {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be marked internal. and consider using one closure for all of them

Comment threadsrc/compiler/program.ts Outdated

// If output has not been changed, and the file has no external modification
if (fingerprint.byteOrderMark === writeByteOrderMark &&
if (fingerprint !== undefined && fingerprint.byteOrderMark === writeByteOrderMark &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just if (figureprint

@mhegazy

Copy link
Copy Markdown
Contributor

Can you also share the perf numbers once it is in.

@mhegazy

Copy link
Copy Markdown
Contributor

Ron Buckton (@rbuckton) any more comments?

@rbucktonRon Buckton (rbuckton) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few non-blocking review comments, but this looks fine to me.

Comment threadsrc/compiler/collections.ts Outdated
declare const Map: { new<K, V>(pairs?: [K, V][]): Map<K, V> } | undefined;
const usingNativeMaps = typeof Map !== "undefined";
// tslint:disable-next-line:no-in-operator
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term "fully-featured" is a bit ambiguous. Maybe usingES6NativeMaps?

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using an object.
* `pairs` is an optional list of entries to add to the new map.
*/
export const StringMap: { new<T>(pairs?: [string, T][]): Map<string, T>; } = usingNativeMaps ? Map : ShimMap;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love for us to be able to just call this Map instead of StringMap or NumberMap, but its a bit messy to avoid colliding with the global Map

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or stick with createMap<K extends string | number, V>() and createSet<T extends string | number>()

Comment threadsrc/compiler/collections.ts Outdated
* Creates a sorted array of keys.
* Sorts keys according to the iteration order they would have if they were in an object, instead of from a Map.
* This is so that tests run consistently whether or not we have a Map shim in place.
* The difference between Map iteration order and V8 object insertion order is that V8 moves natrual-number-like keys to the front.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"natural"

Comment threadsrc/compiler/collections.ts Outdated
}

delete(value: string) {
delete this.data[value];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Sets return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
}

delete(key: K): void {
delete this.data[key as string];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Maps return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
However, `forEach` will iterate over strings because values are stringified before being put in the map.
*/

constructor(pairs?: [K, V][]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-ES6 native maps don't support constructor arguments.

delete(key: K): void {
delete this.data[key as string];
delete(key: K): boolean {
const had = this.has(key);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this. Just do return delete this.data[key as string].

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deletealways returns true in strict mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. That's unfortunate...and odd.

delete(value: string) {
delete this.data[value];
delete(value: string): boolean {
const had = this.has(value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, you can just do return delete this.data[value] since a delete expression returns boolean

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard

@ghost
ghost merged commit adfdae0 into masterOct 27, 2016
@ghost
ghost deleted the map4 branch October 27, 2016 20:27
@ghost

Copy link
Copy Markdown
Author

Will do a final performance comparison tomorrow.

ghost pushed a commit that referenced this pull request Oct 27, 2016
This reverts commit adfdae0, reversing
changes made to aad663c.
ghost pushed a commit that referenced this pull request Oct 27, 2016
Revert "Merge pull request #11354 from Microsoft/map4"
Mohamed Hegazy (mhegazy) added a commit that referenced this pull request Nov 10, 2016
* Use a single ShimMap class, and indicate that iteration always yields string keys (which it did before too)
* Remove emacs-added newline at end of baseline
* Remove space at end of line in baseline
* Add numeric indexer to strings and remove lint
* Update baselines with spread string's numeric indexers
* Reset baseline line number to the locally incorrect value
* Remove trailing newline from baseline again
* Respond to PR comments
* Refactor getTypeFromTypeLiteral, from PR comments
* Fix lint
* Use same literal comparison rules for switch/===
switch was missing the rule for converting literal types to the literal
base type if needed.
* Add switch comparability test and update baselines
* Push eitherIsNotLiteral check into isTypeEqualityComparableTo
Since all callers need this check -- it's how equality is supposed to
work everywhere.
* Update baselines
There are more literal types in error messages because error reporting
no longer has the advantage of calls to getBaseLiteralType
* Adds ES5 to ES3 transformer for reserved words
* Minor cleanup
* Cleaned up emit of enum declaration
* Return both ts and js results from module resolution, and don't have moduleNameResolver responsible for omitting files based on compiler options
* Instead of getResolutionOrDiagnostic, use getResolutionDiagnostic and avoid using resolution.resolvedFileName if the diagnostic is defined.
* Remove "ResolvedModuleFromHost" type and just make `resolvedTsFileName` and `resolvedJsFileName` optional properties
(but still automatically infer one of them to supply if the host supplied neither)
* Remove type inference for spread types
* Update inference test for spread types
* Make spread assignability and apparent type stricter
Assignability now does not allow properties to the left of a type
parameter.
Apparent type now only returns the apparent type of the right-most
spread member.
* Update tests w/spread assignability+apparent type
* Moved AMD/CJS/UMD transform to end
* Spread no longer distributes intersections
* Update spread w/intersection tests
* Move System module transform to end.
* Update baseline
* Revert baseline change due to stale output
* Resolve all-object intersections inside spreads
This means that getSpreadType will return an object type, even when
spreading two intersections, as long as those intersections contain
nothing but object types themselves.
* Update and improve spread intersection tests
* Simplify expression in resolveObjectIntersection
* Update baselines with new index signature rules
* Move n-ary spread handling into separate function.
To be moved to callers in the next step.
* Move multiple-spread handling out of getSpreadType
* Clean up and reorder getSpreadType body
* Respond to PR comments
* Error for call/construct signatures in spread type
1. Simplify the error reporting code to handle all kinds of signatures.
2. Remove index signature handling code when creating a spread type
since it's an error anyway.
* Update baselines with new spread type index errors
* Explain writeSpreadType a little better
* Add more commentary to getSpreadType
* Initial implementation of 'keyof T' type operator
* Introduce PropertyNameType
* Move most of resolveModuleNameForLsHost to lsHost
* Simplify isImplicitGlob test
* Initial implementation of 'T[K]' property access types
* add a fallback logic for older versions of node that don't support 'homedir' (#11845)
* add a fallback logic for older versions of node that don't support 'homedir'
* try os.homedir first
* For JavaScript files, we report semantic errors for using TypeScript-only constructs from within a JavaScript file as syntactic errors.
* Don't require `resolvedTsFileName` and `resolvedJsFileName`, just `resolvedFileName` and `extension`. Also, change search order to do all TS searching before searching for JS.
* Fix#10108 (Completion suggestion for object literal with getter) (#11808)
* Fix#10108 (Completion suggestion for object literal with getter)
* completions for setter
* Move helper functions to core (fix build)
* Support parametric property access expressions + some renaming
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives (#11872)
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives
* pass proper value for current directory when compiling .d.ts files
* Fix bug: Return a resolution diagnostic for a `.jsx` import if `--allowJs` is turned off
* Remove a comment about a parameter that no longer exists
* Fix bug: We want to test for existence of the enum value, not whether it's non-zero
* Fix: test for presence, not absence
* Allow untyped imports
* Simplify for loops in fourslash.ts
* Rename to zipWith
* Change diagnostic message
* Make `extension` property of `ResolvedModule` optional; introduce `ResolvedModuleFull` interface for when the extension is provided.
* Consider index signatures in type produced by 'keyof T'
* Respond to PR comments
* Refactor getIndexedAccessType to be reusable from checkIndexedAccess
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Revert "Merge pull request #11354 from Microsoft/map4"
This reverts commit adfdae0, reversing
changes made to aad663c.
* Rename Experimental transform to ESNext
1. Spread/rest are no longer experimental.
2. We need a place to put stage 3 ES features.
* Changes from CR feedback
* disable CoS for inferred projects (#11909)
* Updating test due to CR changes. The order of the diagnostic messages has changed due to concatenation changes
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* Rename TransformFlags.Experimental -> ESNext
* enable non-ts extensions in inferred projects by default
* update CFG to properly handle do statements
* do not inline async IIFEs in control flow graph
* Minor fixes
* cache type for empty type literal (#11934)
cache type for empty type literal
* Improved error messages for invalid assignments to identifiers
* Accept new baselines
* Improved error messages for invalid assignments to properties
* Accept new baselines
* Improve more error messages
* Accept new baselines
* Fix realPathMap in test harness: Must be used in `directoryExists`
* Add helper function
* Update generated files (#11963)
* Move eitherIsNotLiteral check into switch and === checks
This improves error messages
* Forbid augmentation of untyped module (#11962)
* Forbid augmentation of untyped module
* Just use `undefined` for untyped modules
* Unify checking of indexed access expressions and indexed access types
* Accept new baselines
* Accept additional baselines
* Make `cachingInServerLSHost` tests work with `runtests-browser`
* Get literal type only once
* Update baselines
* Add missed test update
* Improve unification by moving more logic to getIndexedAccessType
* Add test cases to report errors for decorators in js file
* Report all the js file errors and skip only the nodes that are not allowed in js
Fixes#11800
* Fix 'keyof any' to produce 'string | number'
* Fix#11396: Make error message referene `Promise` explicitly (#11982)
* Simplify the checking for async function return type
* Fix#11396: Make error message referene `Promise` explicitly
* Minor fixes
* Adding tests
* Test case for property used in destructuring variable declaration
* Mark property referenced in the destructuring as referenced
Fixes#11324
* Spread types handle nested index [access] types
Nested index [access] types are treated as assignable to themselves only,
just like type parameters.
* Test index [access] types inside spread types
* module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program (#11999)
module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program
* Parse, bind and check rest elements
* Downlevel emit of rest elements
* Add rest tests
* Update baselines
* Remove spread types, leaving spread syntax/emit
Spreads are still typed, but cannot be created from a non-object type.
Tests still need to be updated.
* Fix lint
* Lock tslint version to 4.0.0-dev.0, because 4.0.0-dev.1 complains about unnecessary semicolons following properties
* Remove spread type tests from spread tests
* Spread handles index signatures from singleton spreads
I broke it when simplifying the logic earlier.
* Correct assignability for keyof types and type parameters
* Update tests
* Accept new baselines
* Update objectRestAssignment test and baselines
* Fix linting errors
* Update objectRestAssignment test
Missed previously, just got the baselines
* Improve readability of ES next destructuring emit
* Ensure transformFlags are correct before visiting a node.
* Port #12027, #11980 and #11932 to master (#12037)
* add test for the fix for overwrite emitting error
* cr feedback
* Address PR comments
1. Remove extra line in __rest shim.
2. Improve __rest vs __assign check for destructuring assignment.
* Move convertForOf to factory for esnext and es2015
Saves a lot of duplicated code
* Update improved baselines
* Move transformFunctionBody to factory
It is shared by es2015 and esNext transformers.
This commit just adds a convertObjectRest flag to be passed on to
flattenDestructuring functions, as well as adding necessary parameters
to use the code outside a transformer.
* Spread any types to any
* add missing bind calls to properly set parent on token nodes (#12057)
* Cache generic signature instantiations
* Accept new baselines
* Properly instantiate aliasTypeArguments
* Add regression test
* Revert incorrect logic from #11392
* Accept new baselines
* Rename SpreadElementExpression -> SpreadAssignment
and SpreadExpression (formerly SpreadElementExpression) -> SpreadElement
* Add SpreadAssignment to visitors
1. visitNode
2. reduceNode
3. emit
This fixes an emit bug for setters.
* Add --target esnext
Currently, this disables the rest and spread transforms. This will
change as proposals enter and leave stage 3.
* Add --target esnext tests and update baselines
* Revert unneeded change and comments per PR
* Rename variable in checkSwitchStatement per PR
* Do not emit __rest for --target esnext
* Add `realpath` implementation for lshost
* Create spread property types eagerly
This avoids the need for a synthetic symbol and later code called from
getTypeOfSymbol.
* Set spread type symbols in checkObjectLiteral
Instead of getSpreadType.
Also clean up special-case handling inside getSpreadType to be more
readable.
* Ports #12051 and #12032 into master (#12090)
* use local registry to check if typings package exist (#12014)
use local registry to check if typings package exist
* enable sending telemetry events to tsserver client (#12035)
enable sending telemetry events
* Address more PR comments
* return empty file watcher in case if target directory does not exist (#12091)
* return empty file watcher in case if target directory does not exist
* linter
* property handle missing config files in external projects (#12094)
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Port fix for #12069 (#12095)
* reduce set of files being watched, increase polling interval (#12054) (#12092)
* Update authors for release-2.1
* Include declaration file emit
* use createHash from ServerHost instead of explicit require (#12043)
* use createHash from ServerHost instead of explicit require
* added missing method in ServerHost stub
* (signature help) type parameter lists are never variadic (#12112)
* Handle abstract and const modifiers
* Downlevel array destructuring to ES6 in object rest
Previously array destructuring inside an object destructuring with an
object rest would downlevel the array destructuring to ES5. This breaks
if the code that targets ES2015 is using iterators instead of arrays
since iterators don't support [0] or .slice that the ES5 emit uses.
* Improve nested destructuring test for ESNext emit
Now with object destructuring inside array destructuring inside object
destructuring! Each with their own array/object rest!
Also updates baselines.
* Add support for taking in jsxFactory option and report errors for invalid combinations
* Treat `| undefined` like optionality in spread type
* Add strictNullChecks test for object spread
* Verify that jsxFactory is either identifier or qualified name
* Resolve first identifier of the jsxFactory as part of type check
* When emitting use jsx factory entity expression if provided
* Transpile unit test case
* Enabled test case for source map
* Add test cases for when jsxFactory cannot be resolved
* Parse the jsxFactory again in the checker instead of using cached value in the program
* Adds error message for incompatible assignment of identically named type
Fixes issue #12050
* Updated condition for more readability
* Report errors for import helpers missing __rest
* Correctly check spread assignments in strict mode
Previously it crashed in the binder.
* Test error for import helpers with no __rest
* synthesize complete import declaration for tslib (#12151)
* Add ES2017 string padding (#12152)
* add es2017.string.d.ts for String.prototype.{padStart,padEnd}
* append es2017.string.d.ts into es2017.d.ts
* add es2017.string into commandLineParser
* append es2017.string into error message for unit tests of commandLineParser
* append es2017.string into Gulpfile
* append es2017.string into Jakefile
* Exclude js files in non-configured projects compile-on-save emitting (#12118)
* Exclude js files in non-configured projects CoS emitting
* remove unnecessary method
* Merge release-2.1 into master (#12157)
* Update LKG
* Update version
* Update LKG
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* Update LKG
* Fix emit inferred type which is a generic type-alias both fully and partially fill type parameters
* Add tests and baselines
* Skip trying to use alias if there is target type
* Update baselines
* Add diagnostics to remind adding tsconfig file for certain external project (#11932)
* Add diagnostics for certain external project
* Show tsconfig suggestion
* fix lint error
* Address pr
* fix comment
* Update error message
* Flag for not overwrite js files by default without generating errors (#11980)
* WIP
* Properly naming things
* refactor
* apply the option to all files and check out options
* Fix typo
* Update LKG
* lockLinter
* use local registry to check if typings package exist (#12014) (#12032)
use local registry to check if typings package exist
* Add test for #11980 (#12027)
* add test for the fix for overwrite emitting error
* cr feedback
* enable sending telemetry events to tsserver client (#12034) (#12051)
enable sending telemetry events
* Update LKG
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Update LKG
* Update version
* Update LKG
* Do not emit "use strict" when targeting es6 or higher or module kind is es2015 and the file is external module
* Add tests and baselines
* [Release 2.1] fix11754 global augmentation (#12133)
* Exclude global augmentation from module resolution logic
* Address PR: check using string literal instead of NodeFlags.globalAugmentation
* Remove comment
@ghostghost mentioned this pull request Dec 7, 2016
@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
This pull request was closed.
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@yuit@mhegazy@rbuckton@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Use native maps when they're available - #11354

Merged
18 commits merged into
masterfrom
map4
Oct 27, 2016
Merged

Use native maps when they're available#11354
18 commits merged into
masterfrom
map4

Conversation

@ghost

@ghostDeleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown

The summary is that using native maps, the compiler works 5% faster and uses 5% less memory. Using shims, the performance is surprisingly less than 5% worse.

I was able to achieve good baseline performance by disabling Windows Defender in my work directory and using "High Performance" in Control Panel -> Hardware and Sound -> Power Options. There is much less variance this time around.

Benchmark numbers

This is from using our internal ts-perf tool.

map4

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.72s (± 1.10%)-0.07s (- 4.08%)1.70s1.74s
Bind Time0.69s (± 4.74%)0.52s (± 3.50%)-0.17s (- 24.86%)0.50s0.54s
Check Time3.37s (± 1.66%)2.91s (± 3.16%)-0.46s (- 13.69%)2.78s2.98s
Emit Time5.01s (± 4.73%)4.87s (± 1.35%)-0.14s (- 2.77%)4.79s4.94s
Total Time10.87s (± 2.34%)10.02s (± 1.18%)-0.84s (- 7.77%)9.86s10.12s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)356,928k (± 0.01%)-22,996k (- 6.05%)356,890k356,956k
Parse Time2.40s (± 0.75%)2.32s (± 2.13%)-0.08s (- 3.37%)2.28s2.39s
Bind Time0.92s (± 1.79%)0.71s (± 1.84%)-0.21s (- 22.52%)0.70s0.73s
Check Time4.26s (± 1.36%)3.84s (± 6.33%)-0.42s (- 9.94%)3.66s4.18s
Emit Time1.87s (± 2.44%)1.82s (± 3.16%)-0.05s (- 2.80%)1.77s1.89s
Total Time9.46s (± 1.19%)8.69s (± 3.96%)-0.77s (- 8.12%)8.42s9.16s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)190,504k (± 0.01%)-11,467k (- 5.68%)190,474k190,538k
Parse Time2.30s (± 0.89%)2.20s (± 2.07%)-0.09s (- 4.09%)2.17s2.27s
Bind Time0.72s (± 0.99%)0.57s (± 4.73%)-0.15s (- 21.33%)0.55s0.61s
Check Time3.48s (± 1.73%)3.27s (± 4.68%)-0.21s (- 6.08%)3.08s3.38s
Emit Time1.91s (± 3.15%)1.78s (± 8.00%)-0.13s (- 6.94%)1.65s1.94s
Total Time8.41s (± 0.61%)7.82s (± 1.68%)-0.59s (- 7.03%)7.71s7.99s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.15s (± 1.31%)-0.07s (- 6.06%)1.13s1.16s
Bind Time0.56s (± 2.96%)0.54s (± 4.08%)-0.02s (- 3.13%)0.52s0.57s
Check Time2.81s (± 1.48%)2.46s (± 1.85%)-0.35s (- 12.34%)2.43s2.53s
Emit Time3.11s (± 0.85%)3.19s (± 0.91%)+0.07s (+ 2.33%)3.15s3.22s
Total Time7.70s (± 0.84%)7.34s (± 1.14%)-0.37s (- 4.78%)7.28s7.46s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)309,449k (± 0.02%)-18,556k (- 5.66%)309,386k309,516k
Parse Time1.50s (± 1.02%)1.44s (± 0.88%)-0.07s (- 4.32%)1.42s1.45s
Bind Time0.73s (± 0.73%)0.58s (± 1.65%)-0.14s (- 19.89%)0.57s0.59s
Check Time3.89s (± 0.65%)3.56s (± 4.42%)-0.32s (- 8.27%)3.42s3.74s
Emit Time1.54s (± 0.91%)1.57s (± 4.86%)+0.03s (+ 2.25%)1.51s1.67s
Total Time7.65s (± 0.65%)7.16s (± 3.13%)-0.50s (- 6.48%)6.96s7.42s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)165,316k (± 0.01%)-9,433k (- 5.40%)165,292k165,344k
Parse Time1.41s (± 1.63%)1.33s (± 0.77%)-0.08s (- 5.36%)1.33s1.35s
Bind Time0.62s (± 5.95%)0.50s (± 3.40%)-0.12s (- 19.68%)0.48s0.52s
Check Time2.98s (± 0.64%)2.75s (± 0.96%)-0.23s (- 7.73%)2.71s2.77s
Emit Time1.35s (± 0.83%)1.35s (± 1.29%)+0.01s (+ 0.45%)1.33s1.37s
Total Time6.36s (± 1.07%)5.94s (± 0.82%)-0.42s (- 6.60%)5.88s5.98s

map4 with usingNativeMaps = false and usingNativeSets = false

Monaco

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.79s (± 0.95%)1.80s (± 1.47%)+0.01s (+ 0.73%)1.77s1.82s
Bind Time0.69s (± 4.74%)0.71s (± 13.45%)+0.02s (+ 3.18%)0.66s0.86s
Check Time3.37s (± 1.66%)3.43s (± 3.44%)+0.06s (+ 1.68%)3.29s3.57s
Emit Time5.01s (± 4.73%)5.04s (± 4.80%)+0.03s (+ 0.66%)4.93s5.42s
Total Time10.87s (± 2.34%)10.98s (± 1.85%)+0.12s (+ 1.09%)10.83s11.29s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used379,924k (± 0.00%)383,279k (± 0.01%)+3,355k (+ 0.88%)383,241k383,338k
Parse Time2.40s (± 0.75%)2.39s (± 2.42%)-0.01s (- 0.29%)2.33s2.44s
Bind Time0.92s (± 1.79%)0.90s (± 4.74%)-0.02s (- 2.55%)0.86s0.96s
Check Time4.26s (± 1.36%)4.29s (± 0.29%)+0.03s (+ 0.66%)4.28s4.31s
Emit Time1.87s (± 2.44%)1.88s (± 1.90%)+0.01s (+ 0.51%)1.85s1.92s
Total Time9.46s (± 1.19%)9.47s (± 0.86%)+0.01s (+ 0.11%)9.36s9.54s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used201,971k (± 0.00%)203,972k (± 0.01%)+2,001k (+ 0.99%)203,951k203,991k
Parse Time2.30s (± 0.89%)2.29s (± 0.76%)-0.01s (- 0.52%)2.27s2.31s
Bind Time0.72s (± 0.99%)0.68s (± 1.41%)-0.04s (- 5.87%)0.67s0.69s
Check Time3.48s (± 1.73%)3.83s (± 1.77%)+0.35s (+ 10.19%)3.78s3.92s
Emit Time1.91s (± 3.15%)1.62s (± 3.72%)-0.29s (- 15.12%)1.58s1.71s
Total Time8.41s (± 0.61%)8.42s (± 1.66%)+0.01s (+ 0.12%)8.32s8.63s

TFS

tsc (x86)
ProjectBaselineCurrentDeltaBestWorst
Parse Time1.22s (± 2.62%)1.22s (± 5.54%)-0.01s (- 0.49%)1.17s1.28s
Bind Time0.56s (± 2.96%)0.58s (± 5.13%)+0.02s (+ 4.38%)0.57s0.63s
Check Time2.81s (± 1.48%)2.84s (± 3.00%)+0.03s (+ 1.03%)2.77s2.95s
Emit Time3.11s (± 0.85%)3.16s (± 1.84%)+0.05s (+ 1.56%)3.08s3.21s
Total Time7.70s (± 0.84%)7.81s (± 2.01%)+0.10s (+ 1.32%)7.60s7.94s
node (v6.7.0, x64)
ProjectBaselineCurrentDeltaBestWorst
Memory used328,005k (± 0.00%)329,980k (± 0.02%)+1,975k (+ 0.60%)329,913k330,079k
Parse Time1.50s (± 1.02%)1.49s (± 0.69%)-0.02s (- 1.13%)1.47s1.49s
Bind Time0.73s (± 0.73%)0.71s (± 3.11%)-0.01s (- 2.00%)0.68s0.73s
Check Time3.89s (± 0.65%)4.04s (± 1.24%)+0.15s (+ 3.87%)3.96s4.06s
Emit Time1.54s (± 0.91%)1.64s (± 0.63%)+0.10s (+ 6.55%)1.63s1.65s
Total Time7.65s (± 0.65%)7.87s (± 0.76%)+0.21s (+ 2.80%)7.79s7.92s
node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used174,749k (± 0.00%)175,835k (± 0.01%)+1,086k (+ 0.62%)175,822k175,855k
Parse Time1.41s (± 1.63%)1.39s (± 0.74%)-0.02s (- 1.10%)1.39s1.41s
Bind Time0.62s (± 5.95%)0.57s (± 3.30%)-0.05s (- 8.48%)0.56s0.59s
Check Time2.98s (± 0.64%)2.99s (± 1.14%)+0.02s (+ 0.60%)2.96s3.04s
Emit Time1.35s (± 0.83%)1.38s (± 4.53%)+0.03s (+ 2.52%)1.33s1.45s
Total Time6.36s (± 1.07%)6.34s (± 1.32%)-0.02s (- 0.25%)6.25s6.43s

Heap snapshot numbers

The memory usage tended to be about the same up until the beforeEmit event, AKA after checking.

Master had 365,935 KB total, map4 had 343,774 KB (94% as much), and map4 with shims had 368,978 KB (100% as much as master, 106% as much as map4).

(I added an event heapAfterBind to test the effects of that; map4 used 97% as much memory as master, meaning the real memory savings are during checking.)

For map4, the chrome heap snaprhot viewer shows Maps as accounting for 2% of all objects, with a shallow size equal to their retained size at 1%. However, this is misleading because most of them are mere 32KB wrapper objects which have internal _keys and _values (or table in some cases), which is what really takes up space. I wish there were a way we could include the size of those.

VSCode numbers

I also ran a simple test on the VSCode repo.

master

tsc -p src --noEmit --diagnostics (Run with 2.1.0-dev.20161005)

KindAmountSamples
Memory used737211 K736716, 733971, 743103, 742334, 729932
I/O read0.17 s0.27, 0.12, 0.20, 0.14, 0.14
Parse time5.22 s5.21, 5.18, 5.22, 5.22, 5.29
Bind time1.74 s1.77, 1.72, 1.74, 1.72, 1.75
Check time8.57 s8.69, 8.48, 8.54, 8.50, 8.63
Total time15.54 s15.67, 15.38, 15.51, 15.45, 15.67

map4

node ../TypeScript/built/local/tsc.js -p src --noEmit --diagnostics

KindRelativeAmountSamples
Memory used94%690972 K691500, 690621, 691097, 690872, 690772
I/O read:100%0.17 s0.16, 0.18, 0.20, 0.14, 0.16
Parse time96%5.02 s5.03, 4.95, 4.99, 4.96, 5.18
Bind time:83%1.44 s1.42, 1.40, 1.44, 1.42, 1.53
Check time97%8.34 s8.32, 8.27, 8.38, 8.42, 8.33
Total time95%14.81 s14.78, 14.62, 14.81, 14.80, 15.05

map4 with shims

Same command as for map4, after rebuilding with usingNativeMaps = false and usingNativeSets = false.

KindRelativeAmountSamples
Memory used101%744718 K745408, 744639, 744845, 745511, 743185
I/O read106%0.18 s0.22, 0.19, 0.20, 0.14, 0.17
Parse time99%5.19 s5.28, 5.18, 5.20, 5.17, 5.13
Bind time98%1.71 s1.72, 1.69, 1.70, 1.73, 1.72
Check time101%8.68 s8.58, 8.72, 8.68, 8.72, 8.73
Total time100%15.59 s15.59, 15.59, 15.58, 15.62, 15.57

@ghost

Deleted user (ghost) commented Oct 4, 2016

Copy link
Copy Markdown
Author

Here is a performance test for doing the same map lookup once vs twice.

constBenchmark=require("benchmark")constcrypto=require("crypto")constN=10000constwords=[]for(leti=0;i<N;i++)words[i]=crypto.randomBytes(8).toString('hex')functioncreateMap(){constm=newMap()for(leti=0;i<N;i+=2)m.set(words[i],i)returnm}functioncreateObject(){consto=Object.create(null)o["__"]=undefineddeleteo["__"]for(leti=0;i<N;i+=2)o[words[i]]=ireturno}letcorrectSum=0for(leti=0;i<N;i+=2)correctSum+=iconstsuite=newBenchmark.Suitesuite.add("map has-then-get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++)if(map.has(words[i]))sum+=map.get(words[i])if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map just get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i++){constx=map.get(words[i])if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object has-then-get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++)if(words[i]ino)sum+=o[words[i]]if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("object just get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i++){constx=o[words[i]]if(x!==undefined)sum+=x}if(sum!==correctSum)thrownewError(sum)returnsum})suite.add("map double get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){sum+=map.get(words[i])sum+=map.get(words[i])}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("map single get",()=>{constmap=createMap()letsum=0for(leti=0;i<N;i+=2){constgot=map.get(words[i])sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.add("object double get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){sum+=o[words[i]]sum+=o[words[i]]}if(sum!==correctSum*2)thrownewError()returnsum})suite.add("object single get",()=>{consto=createObject()letsum=0for(leti=0;i<N;i+=2){constgot=o[words[i]]sum+=gotsum+=got}if(sum!==correctSum*2)thrownewError(sum)returnsum})suite.on("complete",function(){this.forEach(({name, stats})=>{console.log(`${name}: ${stats.mean*1000}ms`)})})suite.on("error",err=>{throwerr.target.error})suite.run()
map has-then-get: 1.0212332328457447ms
map just get: 0.911712559080547ms
object has-then-get: 1.9529671271167457ms
object just get: 1.9624182600334454ms
map double get: 0.7383946305889607ms
map single get: 0.651791347503374ms
object double get: 1.411747356033454ms
object single get: 1.3791293993025284ms

Looks like removing uses of has is useful for maps but not for objects. Removing double get is always good.

@ghostghost mentioned this pull request Oct 4, 2016
@ghost
ghost force-pushed the map4 branch 2 times, most recently from 1f080a8 to 6fc4eadCompareOctober 5, 2016 14:58
@ghost

Copy link
Copy Markdown
Author

This would be a breaking change. We have publicly exported maps because we have export type SymbolTable = Map<string, Symbol>;, which is the type of several public properties of Symbol.

Comment threadJakefile.js Outdated
}

var compilerSources = [
"dataStructures.ts",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be tempted to call this collections.ts, since we already have a types.ts and this is more specific.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of moving our array utilities to collections.ts?

Comment threadsrc/compiler/dataStructures.ts Outdated
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

/** Extra Map methods that may not be available, so we must provide fallbacks. */
interface FullyFeaturedMap<K, V> extends Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe call this ES6Map?

@ghostghost mentioned this pull request Oct 7, 2016
@yuit

Copy link
Copy Markdown
Contributor

Andy (Andrewkraft) (@Andy-MS) looks good for my end 👍 though it is a big change so I think it may be good idea to have Mohamed Hegazy (@mhegazy)Vladimir Matveev (@vladima)Nathan Shively-Sanders (@sandersn)Ron Buckton (@rbuckton) to check as well

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider merging the shims for NumberMap and StringMap.

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using a sparse array.
* This is generic over the key type because it is usually an enum.
*/
export const NumberMap: NumberMapConstructor = usingNativeMaps ? Map : class ShimNumberMap<K extends number, V> implements Map<K, V> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for stylistic consistency do not use classes.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you share the numbers after removing classes?

@ghostDeleted user (ghost)Oct 12, 2016

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It ends up taking 20% longer. 🤕
Here are the measurements for running map4 with closure shims, with "Delta" relative to map4 with class shims.

Monaco - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used203,967k (± 0.01%)224,241k (± 0.01%)+20,274k (+ 9.94%)224,220k224,263k
Parse Time2.27s (± 0.39%)2.39s (± 3.65%)+0.12s (+ 5.30%)2.32s2.51s
Bind Time0.68s (± 1.17%)0.83s (± 1.52%)+0.15s (+ 21.41%)0.81s0.84s
Check Time3.86s (± 2.12%)4.72s (± 3.44%)+0.86s (+ 22.15%)4.55s4.89s
Emit Time1.62s (± 2.07%)2.30s (± 14.05%)+0.68s (+ 41.80%)2.04s2.72s
Total Time8.43s (± 1.26%)10.23s (± 3.36%)+1.80s (+ 21.34%)9.78s10.47s
TFS - node (v6.7.0, x86)
ProjectBaselineCurrentDeltaBestWorst
Memory used175,828k (± 0.01%)188,541k (± 0.01%)+12,713k (+ 7.23%)188,529k188,551k
Parse Time1.40s (± 0.75%)1.51s (± 4.24%)+0.11s (+ 7.80%)1.46s1.60s
Bind Time0.57s (± 1.02%)0.68s (± 2.26%)+0.12s (+ 20.63%)0.67s0.70s
Check Time3.00s (± 0.53%)3.60s (± 3.55%)+0.60s (+ 19.88%)3.41s3.69s
Emit Time1.37s (± 1.09%)1.71s (± 5.74%)+0.34s (+ 25.18%)1.66s1.86s
Total Time6.33s (± 0.28%)7.50s (± 2.73%)+1.16s (+ 18.38%)7.24s7.71s

Here's the code I tested with (with equivalents for NumberMap and StringSet):

exportconstcreateStringMap: <T>(pairs?: [string,T][])=>Map<string,T>=usingNativeMaps
? <T>(pairs?: [string,T][])=>newMap(pairs)
: <T>(pairs?: [string,T][])=>{letdata=createDictionaryModeObject<T>();if(pairs){for(const[key,value]ofpairs){data[key]=value;}}return{clear(): void{data=createDictionaryModeObject<T>();},delete(key: string): void{deletedata[key];},get(key: string): T{returndata[key];},has(key: string): boolean{// tslint:disable-next-line:no-in-operatorreturnkeyindata;},set(key: string,value: T): void{data[key]=value;},forEach(action: (value: T,key: string)=>void): void{for(constkeyindata){action(data[key],key);}}}}

I bet this is allocating a different closure for each method, wheras a class just allocates space for data and shares a single prototype among all instances.

Comment threadsrc/compiler/collections.ts Outdated
// Map utilities
namespace ts {
/** Create a map containing a single entry key -> value. */
export function createMapWithEntry<T>(key: string, value: T): Map<string, T> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider inlining this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or using the Map constructor optional parameter

Comment threadsrc/compiler/collections.ts Outdated
}

// Map utilities
namespace ts {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be marked internal. and consider using one closure for all of them

Comment threadsrc/compiler/program.ts Outdated

// If output has not been changed, and the file has no external modification
if (fingerprint.byteOrderMark === writeByteOrderMark &&
if (fingerprint !== undefined && fingerprint.byteOrderMark === writeByteOrderMark &&

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just if (figureprint

@mhegazy

Copy link
Copy Markdown
Contributor

Can you also share the perf numbers once it is in.

@mhegazy

Copy link
Copy Markdown
Contributor

Ron Buckton (@rbuckton) any more comments?

@rbucktonRon Buckton (rbuckton) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few non-blocking review comments, but this looks fine to me.

Comment threadsrc/compiler/collections.ts Outdated
declare const Map: { new<K, V>(pairs?: [K, V][]): Map<K, V> } | undefined;
const usingNativeMaps = typeof Map !== "undefined";
// tslint:disable-next-line:no-in-operator
const fullyFeaturedMaps = usingNativeMaps && "keys" in Map.prototype && "values" in Map.prototype && "entries" in Map.prototype;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term "fully-featured" is a bit ambiguous. Maybe usingES6NativeMaps?

Comment threadsrc/compiler/collections.ts Outdated
* In runtimes without Maps, this is implemented using an object.
* `pairs` is an optional list of entries to add to the new map.
*/
export const StringMap: { new<T>(pairs?: [string, T][]): Map<string, T>; } = usingNativeMaps ? Map : ShimMap;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love for us to be able to just call this Map instead of StringMap or NumberMap, but its a bit messy to avoid colliding with the global Map

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or stick with createMap<K extends string | number, V>() and createSet<T extends string | number>()

Comment threadsrc/compiler/collections.ts Outdated
* Creates a sorted array of keys.
* Sorts keys according to the iteration order they would have if they were in an object, instead of from a Map.
* This is so that tests run consistently whether or not we have a Map shim in place.
* The difference between Map iteration order and V8 object insertion order is that V8 moves natrual-number-like keys to the front.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"natural"

Comment threadsrc/compiler/collections.ts Outdated
}

delete(value: string) {
delete this.data[value];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Sets return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
}

delete(key: K): void {
delete this.data[key as string];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Native Maps return boolean for delete.

Comment threadsrc/compiler/collections.ts Outdated
However, `forEach` will iterate over strings because values are stringified before being put in the map.
*/

constructor(pairs?: [K, V][]) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-ES6 native maps don't support constructor arguments.

delete(key: K): void {
delete this.data[key as string];
delete(key: K): boolean {
const had = this.has(key);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this. Just do return delete this.data[key as string].

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deletealways returns true in strict mode.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. That's unfortunate...and odd.

delete(value: string) {
delete this.data[value];
delete(value: string): boolean {
const had = this.has(value);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, you can just do return delete this.data[value] since a delete expression returns boolean

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disregard

@ghost
ghost merged commit adfdae0 into masterOct 27, 2016
@ghost
ghost deleted the map4 branch October 27, 2016 20:27
@ghost

Copy link
Copy Markdown
Author

Will do a final performance comparison tomorrow.

ghost pushed a commit that referenced this pull request Oct 27, 2016
This reverts commit adfdae0, reversing
changes made to aad663c.
ghost pushed a commit that referenced this pull request Oct 27, 2016
Revert "Merge pull request #11354 from Microsoft/map4"
Mohamed Hegazy (mhegazy) added a commit that referenced this pull request Nov 10, 2016
* Use a single ShimMap class, and indicate that iteration always yields string keys (which it did before too)
* Remove emacs-added newline at end of baseline
* Remove space at end of line in baseline
* Add numeric indexer to strings and remove lint
* Update baselines with spread string's numeric indexers
* Reset baseline line number to the locally incorrect value
* Remove trailing newline from baseline again
* Respond to PR comments
* Refactor getTypeFromTypeLiteral, from PR comments
* Fix lint
* Use same literal comparison rules for switch/===
switch was missing the rule for converting literal types to the literal
base type if needed.
* Add switch comparability test and update baselines
* Push eitherIsNotLiteral check into isTypeEqualityComparableTo
Since all callers need this check -- it's how equality is supposed to
work everywhere.
* Update baselines
There are more literal types in error messages because error reporting
no longer has the advantage of calls to getBaseLiteralType
* Adds ES5 to ES3 transformer for reserved words
* Minor cleanup
* Cleaned up emit of enum declaration
* Return both ts and js results from module resolution, and don't have moduleNameResolver responsible for omitting files based on compiler options
* Instead of getResolutionOrDiagnostic, use getResolutionDiagnostic and avoid using resolution.resolvedFileName if the diagnostic is defined.
* Remove "ResolvedModuleFromHost" type and just make `resolvedTsFileName` and `resolvedJsFileName` optional properties
(but still automatically infer one of them to supply if the host supplied neither)
* Remove type inference for spread types
* Update inference test for spread types
* Make spread assignability and apparent type stricter
Assignability now does not allow properties to the left of a type
parameter.
Apparent type now only returns the apparent type of the right-most
spread member.
* Update tests w/spread assignability+apparent type
* Moved AMD/CJS/UMD transform to end
* Spread no longer distributes intersections
* Update spread w/intersection tests
* Move System module transform to end.
* Update baseline
* Revert baseline change due to stale output
* Resolve all-object intersections inside spreads
This means that getSpreadType will return an object type, even when
spreading two intersections, as long as those intersections contain
nothing but object types themselves.
* Update and improve spread intersection tests
* Simplify expression in resolveObjectIntersection
* Update baselines with new index signature rules
* Move n-ary spread handling into separate function.
To be moved to callers in the next step.
* Move multiple-spread handling out of getSpreadType
* Clean up and reorder getSpreadType body
* Respond to PR comments
* Error for call/construct signatures in spread type
1. Simplify the error reporting code to handle all kinds of signatures.
2. Remove index signature handling code when creating a spread type
since it's an error anyway.
* Update baselines with new spread type index errors
* Explain writeSpreadType a little better
* Add more commentary to getSpreadType
* Initial implementation of 'keyof T' type operator
* Introduce PropertyNameType
* Move most of resolveModuleNameForLsHost to lsHost
* Simplify isImplicitGlob test
* Initial implementation of 'T[K]' property access types
* add a fallback logic for older versions of node that don't support 'homedir' (#11845)
* add a fallback logic for older versions of node that don't support 'homedir'
* try os.homedir first
* For JavaScript files, we report semantic errors for using TypeScript-only constructs from within a JavaScript file as syntactic errors.
* Don't require `resolvedTsFileName` and `resolvedJsFileName`, just `resolvedFileName` and `extension`. Also, change search order to do all TS searching before searching for JS.
* Fix#10108 (Completion suggestion for object literal with getter) (#11808)
* Fix#10108 (Completion suggestion for object literal with getter)
* completions for setter
* Move helper functions to core (fix build)
* Support parametric property access expressions + some renaming
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives (#11872)
* only emit /// types reference for a symbol in d.ts file if all declarations of a symbol come from type reference directives
* pass proper value for current directory when compiling .d.ts files
* Fix bug: Return a resolution diagnostic for a `.jsx` import if `--allowJs` is turned off
* Remove a comment about a parameter that no longer exists
* Fix bug: We want to test for existence of the enum value, not whether it's non-zero
* Fix: test for presence, not absence
* Allow untyped imports
* Simplify for loops in fourslash.ts
* Rename to zipWith
* Change diagnostic message
* Make `extension` property of `ResolvedModule` optional; introduce `ResolvedModuleFull` interface for when the extension is provided.
* Consider index signatures in type produced by 'keyof T'
* Respond to PR comments
* Refactor getIndexedAccessType to be reusable from checkIndexedAccess
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Revert "Merge pull request #11354 from Microsoft/map4"
This reverts commit adfdae0, reversing
changes made to aad663c.
* Rename Experimental transform to ESNext
1. Spread/rest are no longer experimental.
2. We need a place to put stage 3 ES features.
* Changes from CR feedback
* disable CoS for inferred projects (#11909)
* Updating test due to CR changes. The order of the diagnostic messages has changed due to concatenation changes
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* Rename TransformFlags.Experimental -> ESNext
* enable non-ts extensions in inferred projects by default
* update CFG to properly handle do statements
* do not inline async IIFEs in control flow graph
* Minor fixes
* cache type for empty type literal (#11934)
cache type for empty type literal
* Improved error messages for invalid assignments to identifiers
* Accept new baselines
* Improved error messages for invalid assignments to properties
* Accept new baselines
* Improve more error messages
* Accept new baselines
* Fix realPathMap in test harness: Must be used in `directoryExists`
* Add helper function
* Update generated files (#11963)
* Move eitherIsNotLiteral check into switch and === checks
This improves error messages
* Forbid augmentation of untyped module (#11962)
* Forbid augmentation of untyped module
* Just use `undefined` for untyped modules
* Unify checking of indexed access expressions and indexed access types
* Accept new baselines
* Accept additional baselines
* Make `cachingInServerLSHost` tests work with `runtests-browser`
* Get literal type only once
* Update baselines
* Add missed test update
* Improve unification by moving more logic to getIndexedAccessType
* Add test cases to report errors for decorators in js file
* Report all the js file errors and skip only the nodes that are not allowed in js
Fixes#11800
* Fix 'keyof any' to produce 'string | number'
* Fix#11396: Make error message referene `Promise` explicitly (#11982)
* Simplify the checking for async function return type
* Fix#11396: Make error message referene `Promise` explicitly
* Minor fixes
* Adding tests
* Test case for property used in destructuring variable declaration
* Mark property referenced in the destructuring as referenced
Fixes#11324
* Spread types handle nested index [access] types
Nested index [access] types are treated as assignable to themselves only,
just like type parameters.
* Test index [access] types inside spread types
* module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program (#11999)
module resolution: prefer locally defined ambient modules, reuse resolutions to ambient modules from the old program
* Parse, bind and check rest elements
* Downlevel emit of rest elements
* Add rest tests
* Update baselines
* Remove spread types, leaving spread syntax/emit
Spreads are still typed, but cannot be created from a non-object type.
Tests still need to be updated.
* Fix lint
* Lock tslint version to 4.0.0-dev.0, because 4.0.0-dev.1 complains about unnecessary semicolons following properties
* Remove spread type tests from spread tests
* Spread handles index signatures from singleton spreads
I broke it when simplifying the logic earlier.
* Correct assignability for keyof types and type parameters
* Update tests
* Accept new baselines
* Update objectRestAssignment test and baselines
* Fix linting errors
* Update objectRestAssignment test
Missed previously, just got the baselines
* Improve readability of ES next destructuring emit
* Ensure transformFlags are correct before visiting a node.
* Port #12027, #11980 and #11932 to master (#12037)
* add test for the fix for overwrite emitting error
* cr feedback
* Address PR comments
1. Remove extra line in __rest shim.
2. Improve __rest vs __assign check for destructuring assignment.
* Move convertForOf to factory for esnext and es2015
Saves a lot of duplicated code
* Update improved baselines
* Move transformFunctionBody to factory
It is shared by es2015 and esNext transformers.
This commit just adds a convertObjectRest flag to be passed on to
flattenDestructuring functions, as well as adding necessary parameters
to use the code outside a transformer.
* Spread any types to any
* add missing bind calls to properly set parent on token nodes (#12057)
* Cache generic signature instantiations
* Accept new baselines
* Properly instantiate aliasTypeArguments
* Add regression test
* Revert incorrect logic from #11392
* Accept new baselines
* Rename SpreadElementExpression -> SpreadAssignment
and SpreadExpression (formerly SpreadElementExpression) -> SpreadElement
* Add SpreadAssignment to visitors
1. visitNode
2. reduceNode
3. emit
This fixes an emit bug for setters.
* Add --target esnext
Currently, this disables the rest and spread transforms. This will
change as proposals enter and leave stage 3.
* Add --target esnext tests and update baselines
* Revert unneeded change and comments per PR
* Rename variable in checkSwitchStatement per PR
* Do not emit __rest for --target esnext
* Add `realpath` implementation for lshost
* Create spread property types eagerly
This avoids the need for a synthetic symbol and later code called from
getTypeOfSymbol.
* Set spread type symbols in checkObjectLiteral
Instead of getSpreadType.
Also clean up special-case handling inside getSpreadType to be more
readable.
* Ports #12051 and #12032 into master (#12090)
* use local registry to check if typings package exist (#12014)
use local registry to check if typings package exist
* enable sending telemetry events to tsserver client (#12035)
enable sending telemetry events
* Address more PR comments
* return empty file watcher in case if target directory does not exist (#12091)
* return empty file watcher in case if target directory does not exist
* linter
* property handle missing config files in external projects (#12094)
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Port fix for #12069 (#12095)
* reduce set of files being watched, increase polling interval (#12054) (#12092)
* Update authors for release-2.1
* Include declaration file emit
* use createHash from ServerHost instead of explicit require (#12043)
* use createHash from ServerHost instead of explicit require
* added missing method in ServerHost stub
* (signature help) type parameter lists are never variadic (#12112)
* Handle abstract and const modifiers
* Downlevel array destructuring to ES6 in object rest
Previously array destructuring inside an object destructuring with an
object rest would downlevel the array destructuring to ES5. This breaks
if the code that targets ES2015 is using iterators instead of arrays
since iterators don't support [0] or .slice that the ES5 emit uses.
* Improve nested destructuring test for ESNext emit
Now with object destructuring inside array destructuring inside object
destructuring! Each with their own array/object rest!
Also updates baselines.
* Add support for taking in jsxFactory option and report errors for invalid combinations
* Treat `| undefined` like optionality in spread type
* Add strictNullChecks test for object spread
* Verify that jsxFactory is either identifier or qualified name
* Resolve first identifier of the jsxFactory as part of type check
* When emitting use jsx factory entity expression if provided
* Transpile unit test case
* Enabled test case for source map
* Add test cases for when jsxFactory cannot be resolved
* Parse the jsxFactory again in the checker instead of using cached value in the program
* Adds error message for incompatible assignment of identically named type
Fixes issue #12050
* Updated condition for more readability
* Report errors for import helpers missing __rest
* Correctly check spread assignments in strict mode
Previously it crashed in the binder.
* Test error for import helpers with no __rest
* synthesize complete import declaration for tslib (#12151)
* Add ES2017 string padding (#12152)
* add es2017.string.d.ts for String.prototype.{padStart,padEnd}
* append es2017.string.d.ts into es2017.d.ts
* add es2017.string into commandLineParser
* append es2017.string into error message for unit tests of commandLineParser
* append es2017.string into Gulpfile
* append es2017.string into Jakefile
* Exclude js files in non-configured projects compile-on-save emitting (#12118)
* Exclude js files in non-configured projects CoS emitting
* remove unnecessary method
* Merge release-2.1 into master (#12157)
* Update LKG
* Update version
* Update LKG
* Skip overloads with too-short function parameters
If the parameter of an overload is a function and the argument is also a
function, skip the overload if the parameter has fewer arguments than
the argument does. That overload cannot possibly apply, and should not
participate in, for example, contextual typing.
Example:
```ts
interface I {
(a: number): void;
(b: string, c): void;
}
declare function f(i: I): void;
f((x, y) => {});
```
This code now skips the first overload instead of considering.
This was a longstanding bug but was only uncovered now that more
functions expressions are context sensitive.
* Test skip overloads w/too-short function params
1. Update changed baseline.
2. Add a new test with baseline.
* Minor style improvements
* Ignore optionality when skipping overloads
* Do not use contextual signatures with too few parameters
* isAritySmaller runs later: getNonGenericSignature
* rewrite void-returning statements in constructors that capture result of super call (#11868)
* rewrite void-returning statements in constructors that capture result of super call
* linter
* Update LKG
* Fix emit inferred type which is a generic type-alias both fully and partially fill type parameters
* Add tests and baselines
* Skip trying to use alias if there is target type
* Update baselines
* Add diagnostics to remind adding tsconfig file for certain external project (#11932)
* Add diagnostics for certain external project
* Show tsconfig suggestion
* fix lint error
* Address pr
* fix comment
* Update error message
* Flag for not overwrite js files by default without generating errors (#11980)
* WIP
* Properly naming things
* refactor
* apply the option to all files and check out options
* Fix typo
* Update LKG
* lockLinter
* use local registry to check if typings package exist (#12014) (#12032)
use local registry to check if typings package exist
* Add test for #11980 (#12027)
* add test for the fix for overwrite emitting error
* cr feedback
* enable sending telemetry events to tsserver client (#12034) (#12051)
enable sending telemetry events
* Update LKG
* Reuse subtree transform flags for incrementally parsed nodes (#12088)
* Update LKG
* Update version
* Update LKG
* Do not emit "use strict" when targeting es6 or higher or module kind is es2015 and the file is external module
* Add tests and baselines
* [Release 2.1] fix11754 global augmentation (#12133)
* Exclude global augmentation from module resolution logic
* Address PR: check using string literal instead of NodeFlags.globalAugmentation
* Remove comment
@ghostghost mentioned this pull request Dec 7, 2016
@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
This pull request was closed.
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@yuit@mhegazy@rbuckton@msftclas