@@ -8,6 +8,16 @@ import EmptyObject from './empty_object';
88import { lookupDescriptor } from './utils' ;
99import symbol from './symbol' ;
1010
11+ let metaCounters = window . _metaCounters = {
12+ peekCalls : 0 ,
13+ peekParentCalls : 0 ,
14+ peekPrototypeWalks : 0 ,
15+ setCalls : 0 ,
16+ deleteCalls : 0 ,
17+ metaCalls : 0 ,
18+ metaInstantiated : 0
19+ } ;
20+
1121/**
1222@module ember-metal
1323*/
@@ -55,7 +65,8 @@ if (isEnabled('ember-glimmer-detect-backtracking-rerender') ||
5565let memberNames = Object . keys ( members ) ;
5666const META_FIELD = '__ember_meta__' ;
5767
58- function Meta ( obj , parentMeta ) {
68+ export function Meta ( obj , parentMeta ) {
69+ metaCounters . metaInstantiated ++ ;
5970 this . _cache = undefined ;
6071 this . _weak = undefined ;
6172 this . _watching = undefined ;
@@ -354,63 +365,120 @@ if (isEnabled('mandatory-setter')) {
354365 } ;
355366}
356367
368+ const HAS_NATIVE_WEAKMAP = ( function ( ) {
369+ // detect if `WeakMap` is even present
370+ let hasWeakMap = typeof WeakMap === 'function' ;
371+ if ( ! hasWeakMap ) { return false ; }
372+
373+ let instance = new WeakMap ( ) ;
374+ // use `Object`'s `.toString` directly to prevent us from detecting
375+ // polyfills as native weakmaps
376+ return Object . prototype . toString . call ( instance ) === '[object WeakMap]' ;
377+ } ) ( ) ;
378+
379+ let setMeta , peekMeta , meta , deleteMeta ;
380+
357381// choose the one appropriate for given platform
358- let setMeta = function ( obj , meta ) {
359- // if `null` already, just set it to the new value
360- // otherwise define property first
361- if ( obj [ META_FIELD ] !== null ) {
362- if ( obj . __defineNonEnumerable ) {
363- obj . __defineNonEnumerable ( EMBER_META_PROPERTY ) ;
364- } else {
365- Object . defineProperty ( obj , META_FIELD , META_DESC ) ;
366- }
367- }
382+ if ( HAS_NATIVE_WEAKMAP ) {
383+ let getPrototypeOf = Object . getPrototypeOf ;
384+ let metaStore = new WeakMap ( ) ;
368385
369- obj [ META_FIELD ] = meta ;
370- } ;
386+ setMeta = function WeakMap_setMeta ( obj , meta ) {
387+ metaCounters . setCalls ++ ;
388+ metaStore . set ( obj , meta ) ;
389+ } ;
371390
372- /**
373- Retrieves the meta hash for an object. If `writable` is true ensures the
374- hash is writable for this object as well.
375-
376- The meta object contains information about computed property descriptors as
377- well as any watched properties and other information. You generally will
378- not access this information directly but instead work with higher level
379- methods that manipulate this hash indirectly.
380-
381- @method meta
382- @for Ember
383- @private
384-
385- @param {Object } obj The object to retrieve meta for
386- @param {Boolean } [writable=true] Pass `false` if you do not intend to modify
387- the meta hash, allowing the method to avoid making an unnecessary copy.
388- @return {Object } the meta hash for an object
389- */
390- export function meta ( obj ) {
391- let maybeMeta = peekMeta ( obj ) ;
392- let parent ;
391+ peekMeta = function WeakMap_peekMeta ( obj ) {
392+ metaCounters . peekCalls ++ ;
393+ return metaStore . get ( obj ) ;
394+ } ;
393395
394- // remove this code, in-favor of explicit parent
395- if ( maybeMeta ) {
396- if ( maybeMeta . source === obj ) {
396+ deleteMeta = function WeakMap_deleteMeta ( obj ) {
397+ metaCounters . deleteCalls ++ ;
398+
399+ // set value to `null` so that we can detect
400+ // a deleted meta in peekMeta later
401+ metaStore . set ( obj , null ) ;
402+ } ;
403+
404+ /**
405+ Retrieves the meta hash for an object. If `writable` is true ensures the
406+ hash is writable for this object as well.
407+
408+ The meta object contains information about computed property descriptors as
409+ well as any watched properties and other information. You generally will
410+ not access this information directly but instead work with higher level
411+ methods that manipulate this hash indirectly.
412+
413+ @method meta
414+ @for Ember
415+ @private
416+
417+ @param {Object } obj The object to retrieve meta for
418+ @param {Boolean } [writable=true] Pass `false` if you do not intend to modify
419+ the meta hash, allowing the method to avoid making an unnecessary copy.
420+ @return {Object } the meta hash for an object
421+ */
422+ meta = function WeakMap_meta ( obj ) {
423+ metaCounters . metaCalls ++ ;
424+ let maybeMeta = peekMeta ( obj ) ;
425+
426+ if ( maybeMeta ) {
397427 return maybeMeta ;
398428 }
399- parent = maybeMeta ;
400- }
401429
402- let newMeta = new Meta ( obj , parent ) ;
403- setMeta ( obj , newMeta ) ;
404- return newMeta ;
405- }
430+ let newMeta = new Meta ( obj , peekMeta ( getPrototypeOf ( obj ) ) ) ;
431+ setMeta ( obj , newMeta ) ;
432+ return newMeta ;
433+ } ;
434+ } else {
435+ setMeta = function Fallback_setMeta ( obj , meta ) {
436+ // if `null` already, just set it to the new value
437+ // otherwise define property first
438+ if ( obj [ META_FIELD ] !== null ) {
439+ if ( obj . __defineNonEnumerable ) {
440+ obj . __defineNonEnumerable ( EMBER_META_PROPERTY ) ;
441+ } else {
442+ Object . defineProperty ( obj , META_FIELD , META_DESC ) ;
443+ }
444+ }
406445
407- export function peekMeta ( obj ) {
408- return obj [ META_FIELD ] ;
409- }
446+ obj [ META_FIELD ] = meta ;
447+ } ;
410448
411- export function deleteMeta ( obj ) {
412- if ( typeof obj [ META_FIELD ] !== 'object' ) {
413- return ;
414- }
415- obj [ META_FIELD ] = null ;
449+ peekMeta = function Fallback_peekMeta ( obj ) {
450+ return obj [ META_FIELD ] ;
451+ } ;
452+
453+ deleteMeta = function Fallback_deleteMeta ( obj ) {
454+ if ( typeof obj [ META_FIELD ] !== 'object' ) {
455+ return ;
456+ }
457+ obj [ META_FIELD ] = null ;
458+ } ;
459+
460+ meta = function Fallback_meta ( obj ) {
461+ metaCounters . metaCalls ++ ;
462+ let maybeMeta = peekMeta ( obj ) ;
463+ let parent ;
464+
465+ // remove this code, in-favor of explicit parent
466+ if ( maybeMeta ) {
467+ if ( maybeMeta . source === obj ) {
468+ return maybeMeta ;
469+ }
470+ parent = maybeMeta ;
471+ }
472+
473+ let newMeta = new Meta ( obj , parent ) ;
474+ setMeta ( obj , newMeta ) ;
475+ return newMeta ;
476+ } ;
416477}
478+
479+ export {
480+ peekMeta ,
481+ setMeta ,
482+ deleteMeta ,
483+ meta
484+ } ;
0 commit comments