From b89a7ee8b956c96a1dcee995ea840feddc5d4b27 Mon Sep 17 00:00:00 2001 From: Pierre Frisch Date: Thu, 22 Dec 2011 07:25:50 -0800 Subject: First commit of Ninja to ninja-internal Signed-off-by: Valerio Virgillito --- node_modules/montage/core/shim/weak-map.js | 454 +++++++++++++++++++++++++++++ 1 file changed, 454 insertions(+) create mode 100755 node_modules/montage/core/shim/weak-map.js (limited to 'node_modules/montage/core/shim/weak-map.js') diff --git a/node_modules/montage/core/shim/weak-map.js b/node_modules/montage/core/shim/weak-map.js new file mode 100755 index 00000000..ae99a60c --- /dev/null +++ b/node_modules/montage/core/shim/weak-map.js @@ -0,0 +1,454 @@ +/* + This file contains proprietary software owned by Motorola Mobility, Inc.
+ No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+ (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ +/* + Derived from http://code.google.com/p/es-lab/source/browse/trunk/src/ses/WeakMap.js + Added the export + Removed the check for ses +// Copyright (C) 2011 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + */ + +/** + * @fileoverview Install a leaky WeakMap emulation on platforms that + * don't provide a built-in one. + * + *

Assumes that an ES5 platform where, if {@code WeakMap} is + * already present, then it conforms to the anticipated ES6 + * specification. To run this file on an ES5 or almost ES5 + * implementation where the {@code WeakMap} specification does not + * quite conform, run repairES5.js first. + * + * @author Mark S. Miller + * @requires ses + * @overrides WeakMap + */ + +/** + @module montage/core/shim/weak-map +*/ + + /** + * This {@code WeakMap} emulation is observably equivalent to the + * ES-Harmony WeakMap, but with leakier garbage collection properties. + * + * As with true WeakMaps, in this emulation, a key does not + * retain maps indexed by that key and (crucially) a map does not + * retain the keys it indexes. A map by itself also does not retain + * the values associated with that map. + * +

However, the values associated with a key in some map are + * retained so long as that key is retained and those associations are + * not overridden. For example, when used to support membranes, all + * values exported from a given membrane will live for the lifetime + * they would have had in the absence of an interposed membrane. Even + * when the membrane is revoked, all objects that would have been + * reachable in the absence of revocation will still be reachable, as + * far as the GC can tell, even though they will no longer be relevant + * to ongoing computation. + * + *

The API implemented here is approximately the API as implemented + * in FF6.0a1 and agreed to by MarkM, Andreas Gal, and Dave Herman, + * rather than the offially approved proposal page. TODO(erights): + * upgrade the ecmascript WeakMap proposal page to explain this API + * change and present to EcmaScript committee for their approval. + * +

The first difference between the emulation here and that in + * FF6.0a1 is the presence of non enumerable {@code get___, has___, + * set___, and delete___} methods on WeakMap instances to represent + * what would be the hidden internal properties of a primitive + * implementation. Whereas the FF6.0a1 WeakMap.prototype methods + * require their {@code this} to be a genuine WeakMap instance (i.e., + * an object of {@code [[Class]]} "WeakMap}), since there is nothing + * unforgeable about the pseudo-internal method names used here, + * nothing prevents these emulated prototype methods from being + * applied to non-WeakMaps with pseudo-internal methods of the same + * names. + * + *

Another difference is that our emulated {@code + * WeakMap.prototype} is not itself a WeakMap. A problem with the + * current FF6.0a1 API is that WeakMap.prototype is itself a WeakMap + * providing ambient mutability and an ambient communications + * channel. Thus, if a WeakMap is already present and has this + * problem, repairES5.js wraps it in a safe wrappper in order to + * prevent access to this channel. (See + * PATCH_MUTABLE_FROZEN_WEAKMAP_PROTO in repairES5.js). + @class module:montage/core/shim/weak-map.WeakMap + */ + +var WeakMap; + +/** + * If this is a full secureable ES5 platform and the ES-Harmony {@code WeakMap} is + * absent, install an approximate emulation. + * + *

If this is almost a secureable ES5 platform, then WeakMap.js + * should be run after repairES5.js. + * + *

See {@code WeakMap} for documentation of the garbage collection + * properties of this WeakMap emulation. + */ +(function() { + "use strict"; + +// if (typeof ses !== 'undefined' && ses.ok && !ses.ok()) { +// // already too broken, so give up +// return; +// } + + if (typeof WeakMap === 'function') { + // assumed fine, so we're done. + return; + } + + var hop = Object.prototype.hasOwnProperty; + var gopn = Object.getOwnPropertyNames; + var defProp = Object.defineProperty; + + /** + * Holds the orginal static properties of the Object constructor, + * after repairES5 fixes these if necessary to be a more complete + * secureable ES5 environment, but before installing the following + * WeakMap emulation overrides and before any untrusted code runs. + */ + var originalProps = {}; + gopn(Object).forEach(function(name) { + originalProps[name] = Object[name]; + }); + + /** + * Security depends on HIDDEN_NAME being both unguessable and + * undiscoverable by untrusted code. + * + *

Given the known weaknesses of Math.random() on existing + * browsers, it does not generate unguessability we can be confident + * of. TODO(erights): Detect crypto.getRandomValues and if there, + * use it instead. + * + *

It is the monkey patching logic in this file that is intended + * to ensure undiscoverability. The basic idea is that there are + * three fundamental means of discovering properties of an object: + * The for/in loop, Object.keys(), and Object.getOwnPropertyNames(), + * as well as some proposed ES6 extensions that appear on our + * whitelist. The first two only discover enumerable properties, and + * we only use HIDDEN_NAME to name a non-enumerable property, so the + * only remaining threat should be getOwnPropertyNames and some + * proposed ES6 extensions that appear on our whitelist. We monkey + * patch them to remove HIDDEN_NAME from the list of properties they + * returns. + */ + var HIDDEN_NAME = 'ident:' + Math.random() + '___'; + + /** + * Monkey patch getOwnPropertyNames to avoid revealing the + * HIDDEN_NAME. + * + *

The ES5.1 spec requires each name to appear only once, but as + * of this writing, this requirement is controversial for ES6, so we + * made this code robust against this case. If the resulting extra + * search turns out to be expensive, we can probably relax this once + * ES6 is adequately supported on all major browsers, iff no browser + * versions we support at that time have relaxed this constraint + * without providing built-in ES6 WeakMaps. + */ + + defProp(Object, 'getOwnPropertyNames', { + value: function fakeGetOwnPropertyNames(obj) { + var result = gopn(obj); + var i = 0; + while ((i = result.indexOf(HIDDEN_NAME, i)) >= 0) { + result.splice(i, 1); + } + return result; + } + }); + + /** + getPropertyNames is not in ES5 but it is proposed for ES6 and
+ does appear in our whitelist, so we need to clean it too. + */ + + + if ('getPropertyNames' in Object) { + defProp(Object, 'getPropertyNames', { + value: function fakeGetPropertyNames(obj) { + var result = originalProps.getPropertyNames(obj); + var i = 0; + while ((i = result.indexOf(HIDDEN_NAME, i)) >= 0) { + result.splice(i, 1); + } + return result; + } + }); + } + + /** + *

To treat objects as identity-keys with reasonable efficiency + * on ES5 by itself (i.e., without any object-keyed collections), we + * need to add a hidden property to such key objects when we + * can. This raises several issues: + *

+ * We do so by + * + * Unfortunately, because of same-origin iframes, we cannot reliably + * add this hidden property before an object becomes + * non-extensible. Instead, if we encounter a non-extensible object + * without a hidden record that we can detect (whether or not it has + * a hidden record stored under a name secret to us), then we just + * use the key object itself to represent its identity in a brute + * force leaky map stored in the weak map, losing all the advantages + * of weakness for these. + */ + function getHiddenRecord(key) { + if (key !== Object(key)) { + throw new TypeError('Not an object: ' + key); + } + var hiddenRecord = key[HIDDEN_NAME]; + if (hiddenRecord && hiddenRecord.key === key) { return hiddenRecord; } + if (!originalProps.isExtensible(key)) { + // Weak map must brute force, as explained in doc-comment above. + return void 0; + } + var gets = []; + var vals = []; + hiddenRecord = { + key: key, // self pointer for quick own check above. + gets: gets, // get___ methods identifying weak maps + vals: vals // values associated with this key in each + // corresponding weak map. + }; + defProp(key, HIDDEN_NAME, { + value: hiddenRecord, + writable: false, + enumerable: false, + configurable: false + }); + return hiddenRecord; + } + + + /** + * Monkey patch operations that would make their argument + * non-extensible. + * + *

The monkey patched versions throw a TypeError if their + * argument is not an object, so it should only be done to functions + * that should throw a TypeError anyway if their argument is not an + * object. + */ + (function(){ + var oldFreeze = Object.freeze; + defProp(Object, 'freeze', { + value: function identifyingFreeze(obj) { + getHiddenRecord(obj); + return oldFreeze(obj); + } + }); + var oldSeal = Object.seal; + defProp(Object, 'seal', { + value: function identifyingSeal(obj) { + getHiddenRecord(obj); + return oldSeal(obj); + } + }); + var oldPreventExtensions = Object.preventExtensions; + defProp(Object, 'preventExtensions', { + value: function identifyingPreventExtensions(obj) { + getHiddenRecord(obj); + return oldPreventExtensions(obj); + } + }); + })(); + + + function constFunc(func) { + Object.freeze(func.prototype); + return Object.freeze(func); + } + + WeakMap = function() { + var keys = []; // brute force for prematurely non-extensible keys. + var vals = []; // brute force for corresponding values. + + function get___(key, opt_default) { + var hr = getHiddenRecord(key); + var i, vs; + if (hr) { + i = hr.gets.indexOf(get___); + vs = hr.vals; + } else { + i = keys.indexOf(key); + vs = vals; + } + return (i >= 0) ? vs[i] : opt_default; + } + + function has___(key) { + var hr = getHiddenRecord(key); + var i; + if (hr) { + i = hr.gets.indexOf(get___); + } else { + i = keys.indexOf(key); + } + return i >= 0; + } + + function set___(key, value) { + var hr = getHiddenRecord(key); + var i; + if (hr) { + i = hr.gets.indexOf(get___); + if (i >= 0) { + hr.vals[i] = value; + } else { + hr.gets.push(get___); + hr.vals.push(value); + } + } else { + i = keys.indexOf(key); + if (i >= 0) { + vals[i] = value; + } else { + keys.push(key); + vals.push(value); + } + } + } + + function delete___(key) { + var hr = getHiddenRecord(key); + var i; + if (hr) { + i = hr.gets.indexOf(get___); + if (i >= 0) { + hr.gets.splice(i, 1); + hr.vals.splice(i, 1); + } + } else { + i = keys.indexOf(key); + if (i >= 0) { + keys.splice(i, 1); + vals.splice(i, 1); + } + } + return true; + } + + return Object.create(WeakMap.prototype, { + get___: { value: constFunc(get___) }, + has___: { value: constFunc(has___) }, + set___: { value: constFunc(set___) }, + delete___: { value: constFunc(delete___) } + }); + }; + + WeakMap.prototype = Object.create(Object.prototype, /** @lends module:montage/core/shim/weak-map.WeakMap# */ { + + +/** + * Returns the value most recently associated with key, or + * opt_default if none. + * @function + * @param {object} key + * @param {object} opt_default + */ + get: { + value: function get(key, opt_default) { + return this.get___(key, opt_default); + }, + writable: true, + configurable: true + }, + +/** + * Returns true if there is a value associated with the specified key in the WeakMap, otherwise returns false + * @function + * @param {object} key + */ + has: { + value: function has(key) { + return this.has___(key); + }, + writable: true, + configurable: true + }, + +/** + * Associate value with key in this WeakMap, overwriting any + * previous association if present. + * @function + * @param {object} key + * @param {object} value + */ + set: { + value: function set(key, value) { + this.set___(key, value); + }, + writable: true, + configurable: true + }, + +/** + * Remove any association for key in this WeakMap, returning + * whether there was one. + * @function + * @param {object} key + * + * FIXME

Note that the boolean return here does not work like the + * delete operator. The operator returns + * whether the deletion succeeds at bringing about a state in + * which the deleted property is absent. The delete + * operator therefore returns true if the property was already + * absent, whereas this {@link delete} method returns false if + * the association was already absent. + */ + 'delete': { + value: function remove(key) { + return this.delete___(key); + }, + writable: true, + configurable: true + } + }); + +})(); + +exports.WeakMap = WeakMap; -- cgit v1.2.3