X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/81345200c95645a1b0d2635520f96ad55dfde63f..40a37d088818fc2fbeba2ef850dbcaaf294befbf:/inspector/InjectedScriptSource.js?ds=sidebyside diff --git a/inspector/InjectedScriptSource.js b/inspector/InjectedScriptSource.js index db331cf..a7a1e5c 100644 --- a/inspector/InjectedScriptSource.js +++ b/inspector/InjectedScriptSource.js @@ -216,12 +216,7 @@ InjectedScript.prototype = { return result; }, - /** - * @param {string} objectId - * @param {boolean} ownProperties - * @return {Array.|boolean} - */ - getProperties: function(objectId, ownProperties) + getProperties: function(objectId, ownProperties, ownAndGetterProperties) { var parsedObjectId = this._parseObjectId(objectId); var object = this._objectForId(parsedObjectId); @@ -229,7 +224,8 @@ InjectedScript.prototype = { if (!this._isDefined(object)) return false; - var descriptors = this._propertyDescriptors(object, ownProperties); + + var descriptors = this._propertyDescriptors(object, ownProperties, ownAndGetterProperties); // Go over properties, wrap object values. for (var i = 0; i < descriptors.length; ++i) { @@ -245,6 +241,7 @@ InjectedScript.prototype = { if (!("enumerable" in descriptor)) descriptor.enumerable = false; } + return descriptors; }, @@ -317,70 +314,6 @@ InjectedScript.prototype = { delete this._idToObjectGroupName[id]; }, - /** - * @param {Object} object - * @param {boolean} ownProperties - * @return {Array.} - */ - _propertyDescriptors: function(object, ownProperties) - { - var descriptors = []; - var nameProcessed = {}; - nameProcessed["__proto__"] = null; - for (var o = object; this._isDefined(o); o = o.__proto__) { - var names = Object.getOwnPropertyNames(/** @type {!Object} */ (o)); - for (var i = 0; i < names.length; ++i) { - var name = names[i]; - if (nameProcessed[name]) - continue; - - try { - nameProcessed[name] = true; - var descriptor = Object.getOwnPropertyDescriptor(/** @type {!Object} */ (object), name); - if (!descriptor) { - // Not all bindings provide proper descriptors. Fall back to the writable, configurable property. - try { - descriptor = { name: name, value: object[name], writable: false, configurable: false, enumerable: false}; - if (o === object) - descriptor.isOwn = true; - descriptors.push(descriptor); - } catch (e) { - // Silent catch. - } - continue; - } - if (descriptor.hasOwnProperty("get") && descriptor.hasOwnProperty("set") && !descriptor.get && !descriptor.set) { - // Not all bindings provide proper descriptors. Fall back to the writable, configurable property. - try { - descriptor = { name: name, value: object[name], writable: false, configurable: false, enumerable: false}; - if (o === object) - descriptor.isOwn = true; - descriptors.push(descriptor); - } catch (e) { - // Silent catch. - } - continue; - } - } catch (e) { - var descriptor = {}; - descriptor.value = e; - descriptor.wasThrown = true; - } - - descriptor.name = name; - if (o === object) - descriptor.isOwn = true; - descriptors.push(descriptor); - } - if (ownProperties) { - if (object.__proto__) - descriptors.push({ name: "__proto__", value: object.__proto__, writable: true, configurable: true, enumerable: false, isOwn: true}); - break; - } - } - return descriptors; - }, - /** * @param {string} expression * @param {string} objectGroup @@ -679,6 +612,108 @@ InjectedScript.prototype = { return module; }, + _propertyDescriptors: function(object, ownProperties, ownAndGetterProperties) + { + // Modes: + // - ownProperties - only own properties and __proto__ + // - ownAndGetterProperties - own properties, __proto__, and getters in the prototype chain + // - neither - get all properties in the prototype chain, exclude __proto__ + + var descriptors = []; + var nameProcessed = {}; + nameProcessed["__proto__"] = null; + + function createFakeValueDescriptor(name, descriptor, isOwnProperty) + { + try { + return {name: name, value: object[name], writable: descriptor.writable || false, configurable: descriptor.configurable || false, enumerable: descriptor.enumerable || false}; + } catch (e) { + var errorDescriptor = {name: name, value: e, wasThrown: true}; + if (isOwnProperty) + errorDescriptor.isOwn = true; + return errorDescriptor; + } + } + + function processDescriptor(descriptor, isOwnProperty, possibleNativeBindingGetter) + { + // Own properties only. + if (ownProperties) { + if (isOwnProperty) + descriptors.push(descriptor); + return; + } + + // Own and getter properties. + if (ownAndGetterProperties) { + if (isOwnProperty) { + // Own property, include the descriptor as is. + descriptors.push(descriptor); + } else if (descriptor.hasOwnProperty("get") && descriptor.get) { + // Getter property in the prototype chain. Create a fake value descriptor. + descriptors.push(createFakeValueDescriptor(descriptor.name, descriptor, isOwnProperty)); + } else if (possibleNativeBindingGetter) { + // Possible getter property in the prototype chain. + descriptors.push(descriptor); + } + return; + } + + // All properties. + descriptors.push(descriptor); + } + + function processPropertyNames(o, names, isOwnProperty) + { + for (var i = 0; i < names.length; ++i) { + var name = names[i]; + if (nameProcessed[name] || name === "__proto__") + continue; + + nameProcessed[name] = true; + + var descriptor = Object.getOwnPropertyDescriptor(o, name); + if (!descriptor) { + // FIXME: Bad descriptor. Can we get here? + // Fall back to very restrictive settings. + var fakeDescriptor = createFakeValueDescriptor(name, {writable: false, configurable: false, enumerable: false}, isOwnProperty); + processDescriptor(fakeDescriptor, isOwnProperty); + continue; + } + + if (descriptor.hasOwnProperty("get") && descriptor.hasOwnProperty("set") && !descriptor.get && !descriptor.set) { + // FIXME: Web Inspector: Native Bindings Descriptors are Incomplete + // Developers may create such a descriptors, so we should be resilient: + // var x = {}; Object.defineProperty(x, "p", {get:undefined}); Object.getOwnPropertyDescriptor(x, "p") + var fakeDescriptor = createFakeValueDescriptor(name, descriptor, isOwnProperty); + processDescriptor(fakeDescriptor, isOwnProperty, true); + continue; + } + + descriptor.name = name; + if (isOwnProperty) + descriptor.isOwn = true; + processDescriptor(descriptor, isOwnProperty); + } + } + + // Iterate prototype chain. + for (var o = object; this._isDefined(o); o = o.__proto__) { + var isOwnProperty = o === object; + processPropertyNames(o, Object.getOwnPropertyNames(o), isOwnProperty); + if (ownProperties) + break; + } + + // Include __proto__ at the end. + try { + if (object.__proto__) + descriptors.push({name: "__proto__", value: object.__proto__, writable: true, configurable: true, enumerable: false, isOwn: true}); + } catch (e) {} + + return descriptors; + }, + /** * @param {*} object * @return {boolean}