JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec, JSObject*, JSValue, const ArgList& args) { if (!args.at(0).isObject()) return throwError(exec, TypeError, "Requested property descriptor of a value that is not an object."); UString propertyName = args.at(1).toString(exec); if (exec->hadException()) return jsNull(); JSObject* object = asObject(args.at(0)); PropertyDescriptor descriptor; if (!object->getOwnPropertyDescriptor(exec, Identifier(exec, propertyName), descriptor)) return jsUndefined(); if (exec->hadException()) return jsUndefined(); JSObject* description = constructEmptyObject(exec); if (!descriptor.isAccessorDescriptor()) { description->putDirect(exec->propertyNames().value, descriptor.value() ? descriptor.value() : jsUndefined(), 0); description->putDirect(exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0); } else { description->putDirect(exec->propertyNames().get, descriptor.getter() ? descriptor.getter() : jsUndefined(), 0); description->putDirect(exec->propertyNames().set, descriptor.setter() ? descriptor.setter() : jsUndefined(), 0); } description->putDirect(exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0); description->putDirect(exec->propertyNames().configurable, jsBoolean(descriptor.configurable()), 0); return description; }
EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec) { // 1. If Type(O) is not Object throw a TypeError exception. JSValue obj = exec->argument(0); if (!obj.isObject()) return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.isFrozen can only be called on Objects."))); JSObject* object = asObject(obj); if (isJSFinalObject(object)) return JSValue::encode(jsBoolean(object->isFrozen(exec->vm()))); // 2. For each named own property name P of O, PropertyNameArray properties(exec); object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties); PropertyNameArray::const_iterator end = properties.end(); for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) { // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. PropertyDescriptor desc; if (!object->getOwnPropertyDescriptor(exec, *iter, desc)) continue; // b. If IsDataDescriptor(desc) is true then // i. If desc.[[Writable]] is true, return false. c. If desc.[[Configurable]] is true, then return false. if ((desc.isDataDescriptor() && desc.writable()) || desc.configurable()) return JSValue::encode(jsBoolean(false)); } // 3. If the [[Extensible]] internal property of O is false, then return true. // 4. Otherwise, return false. return JSValue::encode(jsBoolean(!object->isExtensible())); }
EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec) { if (!exec->argument(0).isObject()) return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested property descriptor of a value that is not an object."))); String propertyName = exec->argument(1).toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsNull()); JSObject* object = asObject(exec->argument(0)); PropertyDescriptor descriptor; if (!object->getOwnPropertyDescriptor(exec, Identifier(exec, propertyName), descriptor)) return JSValue::encode(jsUndefined()); if (exec->hadException()) return JSValue::encode(jsUndefined()); JSObject* description = constructEmptyObject(exec); if (!descriptor.isAccessorDescriptor()) { description->putDirect(exec->vm(), exec->propertyNames().value, descriptor.value() ? descriptor.value() : jsUndefined(), 0); description->putDirect(exec->vm(), exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0); } else { ASSERT(descriptor.getter()); ASSERT(descriptor.setter()); description->putDirect(exec->vm(), exec->propertyNames().get, descriptor.getter(), 0); description->putDirect(exec->vm(), exec->propertyNames().set, descriptor.setter(), 0); } description->putDirect(exec->vm(), exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0); description->putDirect(exec->vm(), exec->propertyNames().configurable, jsBoolean(descriptor.configurable()), 0); return JSValue::encode(description); }
EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec) { JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); Identifier propertyName = exec->argument(0).toString(exec)->toIdentifier(exec); PropertyDescriptor descriptor; bool enumerable = thisObject->getOwnPropertyDescriptor(exec, propertyName, descriptor) && descriptor.enumerable(); return JSValue::encode(jsBoolean(enumerable)); }
bool JSObject::getPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) { JSObject* object = this; while (true) { if (object->getOwnPropertyDescriptor(exec, propertyName, descriptor)) return true; JSValue prototype = object->prototype(); if (!prototype.isObject()) return false; object = asObject(prototype); } }
EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec) { auto propertyName = exec->argument(0).toPropertyKey(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); PropertyDescriptor descriptor; bool enumerable = thisObject->getOwnPropertyDescriptor(exec, propertyName, descriptor) && descriptor.enumerable(); return JSValue::encode(jsBoolean(enumerable)); }
EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec) { // 1. If Type(O) is not Object throw a TypeError exception. JSValue obj = exec->argument(0); if (!obj.isObject()) return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.freeze can only be called on Objects."))); JSObject* object = asObject(obj); if (isJSFinalObject(object) && !hasIndexedProperties(object->indexingType())) { object->freeze(exec->vm()); return JSValue::encode(obj); } // 2. For each named own property name P of O, PropertyNameArray properties(exec); object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties); PropertyNameArray::const_iterator end = properties.end(); for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) { // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. PropertyDescriptor desc; if (!object->getOwnPropertyDescriptor(exec, *iter, desc)) continue; // b. If IsDataDescriptor(desc) is true, then // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false. if (desc.isDataDescriptor()) desc.setWritable(false); // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false. desc.setConfigurable(false); // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments. object->methodTable(exec->vm())->defineOwnProperty(object, exec, *iter, desc, true); if (exec->hadException()) return JSValue::encode(obj); } // 3. Set the [[Extensible]] internal property of O to false. object->preventExtensions(exec->vm()); // 4. Return O. return JSValue::encode(obj); }