| Index: src/v8natives.js
|
| ===================================================================
|
| --- src/v8natives.js (revision 3785)
|
| +++ src/v8natives.js (working copy)
|
| @@ -307,7 +307,7 @@
|
|
|
| // ES5 8.10.4
|
| function FromPropertyDescriptor(desc) {
|
| - if(IS_UNDEFINED(desc)) return desc;
|
| + if (IS_UNDEFINED(desc)) return desc;
|
| var obj = new $Object();
|
| if (IsDataDescriptor(desc)) {
|
| obj.value = desc.getValue();
|
| @@ -333,7 +333,6 @@
|
| desc.setEnumerable(ToBoolean(obj.enumerable));
|
| }
|
|
|
| -
|
| if ("configurable" in obj) {
|
| desc.setConfigurable(ToBoolean(obj.configurable));
|
| }
|
| @@ -377,7 +376,9 @@
|
| this.writable_ = false;
|
| this.hasWritable_ = false;
|
| this.enumerable_ = false;
|
| + this.hasEnumerable_ = false;
|
| this.configurable_ = false;
|
| + this.hasConfigurable_ = false;
|
| this.get_ = void 0;
|
| this.hasGetter_ = false;
|
| this.set_ = void 0;
|
| @@ -396,8 +397,14 @@
|
| }
|
|
|
|
|
| +PropertyDescriptor.prototype.hasValue = function() {
|
| + return this.hasValue_;
|
| +}
|
| +
|
| +
|
| PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
|
| this.enumerable_ = enumerable;
|
| + this.hasEnumerable_ = true;
|
| }
|
|
|
|
|
| @@ -406,6 +413,11 @@
|
| }
|
|
|
|
|
| +PropertyDescriptor.prototype.hasEnumerable = function() {
|
| + return this.hasEnumerable_;
|
| +}
|
| +
|
| +
|
| PropertyDescriptor.prototype.setWritable = function(writable) {
|
| this.writable_ = writable;
|
| this.hasWritable_ = true;
|
| @@ -419,9 +431,15 @@
|
|
|
| PropertyDescriptor.prototype.setConfigurable = function(configurable) {
|
| this.configurable_ = configurable;
|
| + this.hasConfigurable_ = true;
|
| }
|
|
|
|
|
| +PropertyDescriptor.prototype.hasConfigurable = function() {
|
| + return this.hasConfigurable_;
|
| +}
|
| +
|
| +
|
| PropertyDescriptor.prototype.isConfigurable = function() {
|
| return this.configurable_;
|
| }
|
| @@ -438,6 +456,11 @@
|
| }
|
|
|
|
|
| +PropertyDescriptor.prototype.hasGetter = function() {
|
| + return this.hasGetter_;
|
| +}
|
| +
|
| +
|
| PropertyDescriptor.prototype.setSet = function(set) {
|
| this.set_ = set;
|
| this.hasSetter_ = true;
|
| @@ -449,6 +472,12 @@
|
| }
|
|
|
|
|
| +PropertyDescriptor.prototype.hasSetter = function() {
|
| + return this.hasSetter_;
|
| +}
|
| +
|
| +
|
| +
|
| // ES5 section 8.12.1.
|
| function GetOwnProperty(obj, p) {
|
| var desc = new PropertyDescriptor();
|
| @@ -458,8 +487,7 @@
|
| // obj is an accessor [true, Get, Set, Enumerable, Configurable]
|
| var props = %GetOwnProperty(ToObject(obj), ToString(p));
|
|
|
| - if (IS_UNDEFINED(props))
|
| - return void 0;
|
| + if (IS_UNDEFINED(props)) return void 0;
|
|
|
| // This is an accessor
|
| if (props[0]) {
|
| @@ -476,17 +504,90 @@
|
| }
|
|
|
|
|
| -// ES5 8.12.9. This version cannot cope with the property p already
|
| -// being present on obj.
|
| +// ES5 section 8.12.2.
|
| +function GetProperty(obj, p) {
|
| + var prop = GetOwnProperty(obj);
|
| + if (!IS_UNDEFINED(prop)) return prop;
|
| + var proto = obj.__proto__;
|
| + if (IS_NULL(proto)) return void 0;
|
| + return GetProperty(proto, p);
|
| +}
|
| +
|
| +
|
| +// ES5 section 8.12.6
|
| +function HasProperty(obj, p) {
|
| + var desc = GetProperty(obj, p);
|
| + return IS_UNDEFINED(desc) ? false : true;
|
| +}
|
| +
|
| +
|
| +// ES5 8.12.9.
|
| function DefineOwnProperty(obj, p, desc, should_throw) {
|
| - var flag = desc.isEnumerable() ? 0 : DONT_ENUM;
|
| - if (IsDataDescriptor(desc)) {
|
| - flag |= desc.isWritable() ? 0 : (DONT_DELETE | READ_ONLY);
|
| - %SetProperty(obj, p, desc.getValue(), flag);
|
| + var current = GetOwnProperty(obj, p);
|
| + var extensible = %IsExtensible(ToObject(obj));
|
| +
|
| + // Error handling according to spec.
|
| + // Step 3
|
| + if (IS_UNDEFINED(current) && !extensible)
|
| + throw MakeTypeError("define_disallowed", ["defineProperty"]);
|
| +
|
| + if (!IS_UNDEFINED(current) && !current.isConfigurable()) {
|
| + // Step 7
|
| + if (desc.isConfigurable() || desc.isEnumerable() != current.isEnumerable())
|
| + throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
|
| + // Step 9
|
| + if (IsDataDescriptor(current) != IsDataDescriptor(desc))
|
| + throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
|
| + // Step 10
|
| + if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
|
| + if (!current.isWritable() && desc.isWritable())
|
| + throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
|
| + if (!current.isWritable() && desc.hasValue() &&
|
| + !SameValue(desc.getValue(), current.getValue())) {
|
| + throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
|
| + }
|
| + }
|
| + // Step 11
|
| + if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
|
| + if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())){
|
| + throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
|
| + }
|
| + if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet()))
|
| + throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
|
| + }
|
| + }
|
| +
|
| + // Send flags - enumerable and configurable are common - writable is
|
| + // only send to the data descriptor.
|
| + // Take special care if enumerable and configurable is not defined on
|
| + // desc (we need to preserve the existing values from current).
|
| + var flag = NONE;
|
| + if (desc.hasEnumerable()) {
|
| + flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
|
| + } else if (!IS_UNDEFINED(current)) {
|
| + flag |= current.isEnumerable() ? 0 : DONT_ENUM;
|
| } else {
|
| - if (IS_FUNCTION(desc.getGet())) %DefineAccessor(obj, p, GETTER, desc.getGet(), flag);
|
| - if (IS_FUNCTION(desc.getSet())) %DefineAccessor(obj, p, SETTER, desc.getSet(), flag);
|
| + flag |= DONT_ENUM;
|
| }
|
| +
|
| + if (desc.hasConfigurable()) {
|
| + flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
|
| + } else if (!IS_UNDEFINED(current)) {
|
| + flag |= current.isConfigurable() ? 0 : DONT_DELETE;
|
| + } else
|
| + flag |= DONT_DELETE;
|
| +
|
| + if (IsDataDescriptor(desc) || IsGenericDescriptor(desc)) {
|
| + flag |= desc.isWritable() ? 0 : READ_ONLY;
|
| + %DefineOrRedefineDataProperty(obj, p, desc.getValue(), flag);
|
| + } else {
|
| + if (desc.hasGetter() && IS_FUNCTION(desc.getGet())) {
|
| + %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);
|
| + }
|
| + if (desc.hasSetter() && IS_FUNCTION(desc.getSet())) {
|
| + %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag);
|
| + }
|
| + }
|
| return true;
|
| }
|
|
|
| @@ -558,10 +659,21 @@
|
| }
|
|
|
|
|
| -// ES5 section 15.2.3.7. This version cannot cope with the properies already
|
| -// being present on obj. Therefore it is not exposed as
|
| -// Object.defineProperties yet.
|
| +// ES5 section 15.2.3.6.
|
| +function ObjectDefineProperty(obj, p, attributes) {
|
| + if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
|
| + throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
|
| + var name = ToString(p);
|
| + var desc = ToPropertyDescriptor(attributes);
|
| + DefineOwnProperty(obj, name, desc, true);
|
| + return obj;
|
| +}
|
| +
|
| +
|
| +// ES5 section 15.2.3.7.
|
| function ObjectDefineProperties(obj, properties) {
|
| + if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
|
| + throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
|
| var props = ToObject(properties);
|
| var key_values = [];
|
| for (var key in props) {
|
| @@ -611,6 +723,8 @@
|
| InstallFunctions($Object, DONT_ENUM, $Array(
|
| "keys", ObjectKeys,
|
| "create", ObjectCreate,
|
| + "defineProperty", ObjectDefineProperty,
|
| + "defineProperties", ObjectDefineProperties,
|
| "getPrototypeOf", ObjectGetPrototypeOf,
|
| "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
|
| "getOwnPropertyNames", ObjectGetOwnPropertyNames
|
|
|