Skip to content

Commit 74b9c49

Browse files
authored
Merge pull request #16222 from emberjs/move-cp-cache-to-weakmap
Move computed property caches into a weak map
2 parents 6f92209 + 7f3f387 commit 74b9c49

File tree

12 files changed

+64
-89
lines changed

12 files changed

+64
-89
lines changed

packages/ember-metal/lib/alias.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
Descriptor,
77
defineProperty
88
} from './properties';
9-
import { ComputedProperty } from './computed';
9+
import { ComputedProperty, getCacheFor } from './computed';
1010
import { meta as metaFor } from './meta';
1111
import {
1212
addDependentKeys,
@@ -52,9 +52,9 @@ export class AliasedProperty extends Descriptor {
5252
get(obj, keyName) {
5353
let ret = get(obj, this.altKey);
5454
let meta = metaFor(obj);
55-
let cache = meta.writableCache();
56-
if (cache[keyName] !== CONSUMED) {
57-
cache[keyName] = CONSUMED;
55+
let cache = getCacheFor(obj);
56+
if (cache.get(keyName) !== CONSUMED) {
57+
cache.set(keyName, CONSUMED);
5858
addDependentKeys(this, obj, keyName, meta);
5959
}
6060
return ret;

packages/ember-metal/lib/chains.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { get } from './property_get';
22
import { descriptorFor, meta as metaFor, peekMeta } from './meta';
33
import { watchKey, unwatchKey } from './watch_key';
4-
import { cacheFor } from './computed';
4+
import { getCachedValueFor } from './computed';
55
import { eachProxyFor } from './each_proxy';
66

77
const FIRST_KEY = /^([^\.]+)/;
@@ -333,10 +333,7 @@ function lazyGet(obj, key) {
333333
return get(obj, key);
334334
// Otherwise attempt to get the cached value of the computed property
335335
} else {
336-
let cache = meta.readableCache();
337-
if (cache !== undefined) {
338-
return cacheFor.get(cache, key);
339-
}
336+
return getCachedValueFor(obj, key);
340337
}
341338
}
342339

packages/ember-metal/lib/computed.js

Lines changed: 32 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { inspect } from 'ember-utils';
22
import { assert, warn, Error as EmberError } from 'ember-debug';
33
import { set } from './property_set';
4-
import { meta as metaFor, peekMeta, UNDEFINED } from './meta';
4+
import { meta as metaFor, peekMeta } from './meta';
55
import expandProperties from './expand_properties';
66
import {
77
Descriptor,
@@ -317,9 +317,8 @@ ComputedPropertyPrototype.didChange = function(obj, keyName) {
317317
return;
318318
}
319319

320-
let cache = meta.readableCache();
321-
if (cache !== undefined && cache[keyName] !== undefined) {
322-
cache[keyName] = undefined;
320+
let cache = peekCacheFor(obj);
321+
if (cache !== undefined && cache.delete(keyName)) {
323322
removeDependentKeys(this, obj, keyName, meta);
324323
}
325324
};
@@ -329,20 +328,17 @@ ComputedPropertyPrototype.get = function(obj, keyName) {
329328
return this._getter.call(obj, keyName);
330329
}
331330

332-
let meta = metaFor(obj);
333-
let cache = meta.writableCache();
331+
let cache = getCacheFor(obj);
334332

335-
let result = cache[keyName];
336-
if (result === UNDEFINED) {
337-
return undefined;
338-
} else if (result !== undefined) {
339-
return result;
333+
if (cache.has(keyName)) {
334+
return cache.get(keyName);
340335
}
341336

342337
let ret = this._getter.call(obj, keyName);
343338

344-
cache[keyName] = ret === undefined ? UNDEFINED : ret;
339+
cache.set(keyName, ret);
345340

341+
let meta = metaFor(obj);
346342
let chainWatchers = meta.readableChainWatchers();
347343
if (chainWatchers !== undefined) {
348344
chainWatchers.revalidate(keyName);
@@ -373,7 +369,7 @@ ComputedPropertyPrototype._throwReadOnlyError = function computedPropertyThrowRe
373369
};
374370

375371
ComputedPropertyPrototype.clobberSet = function computedPropertyClobberSet(obj, keyName, value) {
376-
let cachedValue = cacheFor(obj, keyName);
372+
let cachedValue = getCachedValueFor(obj, keyName);
377373
defineProperty(obj, keyName, null, cachedValue);
378374
set(obj, keyName, value);
379375
return value;
@@ -395,15 +391,9 @@ ComputedPropertyPrototype.setWithSuspend = function computedPropertySetWithSuspe
395391

396392
ComputedPropertyPrototype._set = function computedPropertySet(obj, keyName, value) {
397393
let meta = metaFor(obj);
398-
let cache = meta.writableCache();
399-
400-
let val = cache[keyName];
401-
let hadCachedValue = val !== undefined;
402-
403-
let cachedValue;
404-
if (hadCachedValue && val !== UNDEFINED) {
405-
cachedValue = val;
406-
}
394+
let cache = getCacheFor(obj);
395+
let hadCachedValue = cache.has(keyName);
396+
let cachedValue = cache.get(keyName);
407397

408398
let ret = this._setter.call(obj, keyName, value, cachedValue);
409399

@@ -416,7 +406,7 @@ ComputedPropertyPrototype._set = function computedPropertySet(obj, keyName, valu
416406
addDependentKeys(this, obj, keyName, meta);
417407
}
418408

419-
cache[keyName] = ret === undefined ? UNDEFINED : ret;
409+
cache.set(keyName, ret);
420410

421411
notifyPropertyChange(obj, keyName, meta);
422412

@@ -428,10 +418,9 @@ ComputedPropertyPrototype.teardown = function(obj, keyName, meta) {
428418
if (this._volatile) {
429419
return;
430420
}
431-
let cache = meta.readableCache();
432-
if (cache !== undefined && cache[keyName] !== undefined) {
421+
let cache = peekCacheFor(obj);
422+
if (cache !== undefined && cache.delete(keyName)) {
433423
removeDependentKeys(this, obj, keyName, meta);
434-
cache[keyName] = undefined;
435424
}
436425
};
437426

@@ -535,6 +524,8 @@ export default function computed(...args) {
535524
return cp;
536525
}
537526

527+
const COMPUTED_PROPERTY_CACHED_VALUES = new WeakMap();
528+
538529
/**
539530
Returns the cached value for a property, if one exists.
540531
This can be useful for peeking at the value of a computed
@@ -550,39 +541,27 @@ export default function computed(...args) {
550541
@return {Object} the cached value
551542
@public
552543
*/
553-
function cacheFor(obj, key) {
554-
let meta = peekMeta(obj);
555-
let cache = meta !== undefined ? meta.source === obj && meta.readableCache() : undefined;
556-
let ret = cache !== undefined ? cache[key] : undefined;
557-
558-
if (ret === UNDEFINED) {
559-
return undefined;
544+
export function getCacheFor(obj) {
545+
let cache = COMPUTED_PROPERTY_CACHED_VALUES.get(obj);
546+
if (cache === undefined) {
547+
cache = new Map();
548+
COMPUTED_PROPERTY_CACHED_VALUES.set(obj, cache);
560549
}
561-
return ret;
550+
return cache;
562551
}
563552

564-
cacheFor.set = function(cache, key, value) {
565-
if (value === undefined) {
566-
cache[key] = UNDEFINED;
567-
} else {
568-
cache[key] = value;
553+
export function getCachedValueFor(obj, key) {
554+
let cache = COMPUTED_PROPERTY_CACHED_VALUES.get(obj);
555+
if (cache !== undefined) {
556+
return cache.get(key);
569557
}
570-
};
571-
572-
cacheFor.get = function(cache, key) {
573-
let ret = cache[key];
574-
if (ret === UNDEFINED) {
575-
return undefined;
576-
}
577-
return ret;
578-
};
558+
}
579559

580-
cacheFor.remove = function(cache, key) {
581-
cache[key] = undefined;
582-
};
560+
export function peekCacheFor(obj) {
561+
return COMPUTED_PROPERTY_CACHED_VALUES.get(obj);
562+
}
583563

584564
export {
585565
ComputedProperty,
586-
computed,
587-
cacheFor
566+
computed
588567
};

packages/ember-metal/lib/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
export { default } from './core'; // reexports
33
export {
44
default as computed,
5-
cacheFor,
5+
getCacheFor,
6+
getCachedValueFor,
7+
peekCacheFor,
68
ComputedProperty
79
} from './computed';
810
export { default as alias } from './alias';

packages/ember-metal/lib/meta.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ export class Meta {
4545
counters.metaInstantiated++;
4646
}
4747

48-
this._cache = undefined;
49-
5048
if (EMBER_METAL_ES5_GETTERS) {
5149
this._descriptors = undefined;
5250
}
@@ -266,9 +264,6 @@ export class Meta {
266264
}
267265
}
268266

269-
writableCache() { return this._getOrCreateOwnMap('_cache'); }
270-
readableCache() { return this._cache; }
271-
272267
writableTags() { return this._getOrCreateOwnMap('_tags'); }
273268
readableTags() { return this._tags; }
274269

packages/ember-metal/lib/properties.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { HAS_NATIVE_PROXY } from 'ember-utils';
77
import { descriptorFor, meta as metaFor, peekMeta, DESCRIPTOR, UNDEFINED } from './meta';
88
import { overrideChains } from './property_events';
99
import { DESCRIPTOR_TRAP, EMBER_METAL_ES5_GETTERS, MANDATORY_SETTER } from 'ember/features';
10+
import { peekCacheFor } from './computed';
1011
// ..........................................................
1112
// DESCRIPTOR
1213
//
@@ -338,9 +339,9 @@ export function _hasCachedComputedProperties() {
338339

339340
function didDefineComputedProperty(constructor) {
340341
if (hasCachedComputedProperties === false) { return; }
341-
let cache = metaFor(constructor).readableCache();
342342

343-
if (cache && cache._computedProperties !== undefined) {
344-
cache._computedProperties = undefined;
343+
let cache = peekCacheFor(constructor);
344+
if (cache !== undefined) {
345+
cache.delete('_computedProperties');
345346
}
346347
}

packages/ember-metal/tests/computed_test.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { testBoth } from 'internal-test-helpers';
44
import {
55
ComputedProperty,
66
computed,
7-
cacheFor,
7+
getCachedValueFor,
88
Descriptor,
99
defineProperty,
1010
get,
@@ -316,24 +316,24 @@ testBoth('inherited property should not pick up cache', function(get, set, asser
316316
assert.equal(get(objB, 'foo'), 'bar 2', 'objB third get');
317317
});
318318

319-
testBoth('cacheFor should return the cached value', function(get, set, assert) {
320-
assert.equal(cacheFor(obj, 'foo'), undefined, 'should not yet be a cached value');
319+
testBoth('getCachedValueFor should return the cached value', function(get, set, assert) {
320+
assert.equal(getCachedValueFor(obj, 'foo'), undefined, 'should not yet be a cached value');
321321

322322
get(obj, 'foo');
323323

324-
assert.equal(cacheFor(obj, 'foo'), 'bar 1', 'should retrieve cached value');
324+
assert.equal(getCachedValueFor(obj, 'foo'), 'bar 1', 'should retrieve cached value');
325325
});
326326

327-
testBoth('cacheFor should return falsy cached values', function(get, set, assert) {
327+
testBoth('getCachedValueFor should return falsy cached values', function(get, set, assert) {
328328
defineProperty(obj, 'falsy', computed(function() {
329329
return false;
330330
}));
331331

332-
assert.equal(cacheFor(obj, 'falsy'), undefined, 'should not yet be a cached value');
332+
assert.equal(getCachedValueFor(obj, 'falsy'), undefined, 'should not yet be a cached value');
333333

334334
get(obj, 'falsy');
335335

336-
assert.equal(cacheFor(obj, 'falsy'), false, 'should retrieve cached value');
336+
assert.equal(getCachedValueFor(obj, 'falsy'), false, 'should retrieve cached value');
337337
});
338338

339339
testBoth('setting a cached computed property passes the old value as the third argument', function(get, set, assert) {

packages/ember-metal/tests/observer_test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
notifyPropertyChange,
77
defineProperty,
88
computed,
9-
cacheFor,
9+
getCachedValueFor,
1010
Mixin,
1111
mixin,
1212
observer,
@@ -484,7 +484,7 @@ testBoth('depending on a chain with a computed property', function(get, set, ass
484484
changed++;
485485
});
486486

487-
assert.equal(cacheFor(obj, 'computed'), undefined, 'addObserver should not compute CP');
487+
assert.equal(getCachedValueFor(obj, 'computed'), undefined, 'addObserver should not compute CP');
488488

489489
set(obj, 'computed.foo', 'baz');
490490

packages/ember-runtime/lib/mixins/array.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
eachProxyArrayWillChange,
2323
eachProxyArrayDidChange,
2424
beginPropertyChanges,
25-
endPropertyChanges
25+
endPropertyChanges,
26+
peekCacheFor
2627
} from 'ember-metal';
2728
import { assert, deprecate } from 'ember-debug';
2829
import Enumerable from './enumerable';
@@ -105,7 +106,7 @@ export function arrayContentDidChange(array, startIdx, removeAmt, addAmt) {
105106
sendEvent(array, '@array:change', [array, startIdx, removeAmt, addAmt]);
106107

107108
let meta = peekMeta(array);
108-
let cache = meta !== undefined ? meta.readableCache() : undefined;
109+
let cache = peekCacheFor(array);
109110
if (cache !== undefined) {
110111
let length = get(array, 'length');
111112
let addedAmount = (addAmt === -1 ? 0 : addAmt);
@@ -114,17 +115,17 @@ export function arrayContentDidChange(array, startIdx, removeAmt, addAmt) {
114115
let previousLength = length - delta;
115116

116117
let normalStartIdx = startIdx < 0 ? previousLength + startIdx : startIdx;
117-
if (cache.firstObject !== undefined && normalStartIdx === 0) {
118+
if (cache.has('firstObject') && normalStartIdx === 0) {
118119
notifyPropertyChange(array, 'firstObject', meta);
119120
}
120121

121-
if (cache.lastObject !== undefined) {
122+
if (cache.has('lastObject')) {
122123
let previousLastIndex = previousLength - 1;
123124
let lastAffectedIndex = normalStartIdx + removedAmount;
124125
if (previousLastIndex < lastAffectedIndex) {
125126
notifyPropertyChange(array, 'lastObject', meta);
126127
}
127-
}
128+
}
128129
}
129130

130131
return array;

packages/ember-runtime/lib/mixins/observable.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
endPropertyChanges,
1818
addObserver,
1919
removeObserver,
20-
cacheFor,
20+
getCachedValueFor,
2121
isNone
2222
} from 'ember-metal';
2323
import { assert } from 'ember-debug';
@@ -476,6 +476,6 @@ export default Mixin.create({
476476
@public
477477
*/
478478
cacheFor(keyName) {
479-
return cacheFor(this, keyName);
479+
return getCachedValueFor(this, keyName);
480480
},
481481
});

0 commit comments

Comments
 (0)