From: arv Date: Thu, 19 Feb 2015 16:15:25 +0000 (-0800) Subject: Super store X-Git-Tag: upstream/4.7.83~4286 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0cffc08b667a067089c7eecffea3e8021ab2ff57;p=platform%2Fupstream%2Fv8.git Super store When the property is not found on the [[HomeObject]] prototype chain then we should do a [[DefineOwnProperty]] on the instance. BUG=v8:3330 LOG=N Review URL: https://codereview.chromium.org/934463003 Cr-Commit-Position: refs/heads/master@{#26754} --- diff --git a/src/objects.cc b/src/objects.cc index 5d210bd..0eda491 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -291,7 +291,7 @@ MaybeHandle Object::GetPropertyWithAccessor(Handle receiver, if (structure->IsAccessorInfo()) { Handle info = Handle::cast(structure); if (!info->IsCompatibleReceiver(*receiver)) { - Handle args[2] = { name, receiver }; + Handle args[] = {name, receiver}; THROW_NEW_ERROR(isolate, NewTypeError("incompatible_method_receiver", HandleVector(args, arraysize(args))), @@ -356,7 +356,7 @@ MaybeHandle Object::SetPropertyWithAccessor( // api style callbacks ExecutableAccessorInfo* info = ExecutableAccessorInfo::cast(*structure); if (!info->IsCompatibleReceiver(*receiver)) { - Handle args[2] = { name, receiver }; + Handle args[] = {name, receiver}; THROW_NEW_ERROR(isolate, NewTypeError("incompatible_method_receiver", HandleVector(args, arraysize(args))), @@ -383,10 +383,11 @@ MaybeHandle Object::SetPropertyWithAccessor( receiver, Handle::cast(setter), value); } else { if (is_sloppy(language_mode)) return value; - Handle args[2] = { name, holder }; - THROW_NEW_ERROR( - isolate, NewTypeError("no_setter_in_callback", HandleVector(args, 2)), - Object); + Handle args[] = {name, holder}; + THROW_NEW_ERROR(isolate, + NewTypeError("no_setter_in_callback", + HandleVector(args, arraysize(args))), + Object); } } @@ -753,13 +754,12 @@ MaybeHandle Object::SetElementWithReceiver( Handle target = Handle::cast(receiver); ElementsAccessor* accessor = target->GetElementsAccessor(); PropertyAttributes attrs = accessor->GetAttributes(target, index); - if ((attrs & READ_ONLY) != 0) { - return WriteToReadOnlyElement(isolate, receiver, index, value, - language_mode); + if (attrs == ABSENT) { + return JSObject::SetElement(target, index, value, NONE, language_mode, + false); } - PropertyAttributes new_attrs = attrs != ABSENT ? attrs : NONE; - return JSObject::SetElement(target, index, value, new_attrs, language_mode, - false); + return JSObject::SetElement(target, index, value, attrs, language_mode, false, + DEFINE_PROPERTY); } @@ -3047,15 +3047,17 @@ MaybeHandle Object::SetProperty(Handle object, } -MaybeHandle Object::SetProperty(LookupIterator* it, - Handle value, - LanguageMode language_mode, - StoreFromKeyed store_mode, - StorePropertyMode data_store_mode) { +MaybeHandle Object::SetPropertyInternal(LookupIterator* it, + Handle value, + LanguageMode language_mode, + StoreFromKeyed store_mode, + bool* found) { // Make sure that the top context does not change when doing callbacks or // interceptor calls. AssertNoContextChange ncc(it->isolate()); + *found = true; + bool done = false; for (; it->IsFound(); it->Next()) { switch (it->state()) { @@ -3135,32 +3137,102 @@ MaybeHandle Object::SetProperty(LookupIterator* it, // the property did not exist yet on the global object itself, we have to // throw a reference error in strict mode. if (it->GetReceiver()->IsJSGlobalObject() && is_strict(language_mode)) { - Handle args[1] = {it->name()}; - THROW_NEW_ERROR(it->isolate(), - NewReferenceError("not_defined", HandleVector(args, 1)), - Object); + Handle args[] = {it->name()}; + THROW_NEW_ERROR( + it->isolate(), + NewReferenceError("not_defined", HandleVector(args, arraysize(args))), + Object); } - if (data_store_mode == SUPER_PROPERTY) { - LookupIterator own_lookup(it->GetReceiver(), it->name(), - LookupIterator::OWN); + *found = false; + return MaybeHandle(); +} - return JSObject::SetProperty(&own_lookup, value, language_mode, store_mode, - NORMAL_PROPERTY); - } +MaybeHandle Object::SetProperty(LookupIterator* it, + Handle value, + LanguageMode language_mode, + StoreFromKeyed store_mode) { + bool found = false; + MaybeHandle result = + SetPropertyInternal(it, value, language_mode, store_mode, &found); + if (found) return result; return AddDataProperty(it, value, NONE, language_mode, store_mode); } +MaybeHandle Object::SetSuperProperty(LookupIterator* it, + Handle value, + LanguageMode language_mode, + StoreFromKeyed store_mode) { + bool found = false; + MaybeHandle result = + SetPropertyInternal(it, value, language_mode, store_mode, &found); + if (found) return result; + + LookupIterator own_lookup(it->GetReceiver(), it->name(), LookupIterator::OWN); + + switch (own_lookup.state()) { + case LookupIterator::NOT_FOUND: + return JSObject::AddDataProperty(&own_lookup, value, NONE, language_mode, + store_mode); + + case LookupIterator::DATA: { + PropertyDetails details = own_lookup.property_details(); + if (details.IsConfigurable() || !details.IsReadOnly()) { + return JSObject::SetOwnPropertyIgnoreAttributes( + Handle::cast(it->GetReceiver()), it->name(), value, + details.attributes()); + } + return WriteToReadOnlyProperty(&own_lookup, value, language_mode); + } + + case LookupIterator::ACCESSOR: { + PropertyDetails details = own_lookup.property_details(); + if (details.IsConfigurable()) { + return JSObject::SetOwnPropertyIgnoreAttributes( + Handle::cast(it->GetReceiver()), it->name(), value, + details.attributes()); + } + + return RedefineNonconfigurableProperty(it->isolate(), it->name(), value, + language_mode); + } + + case LookupIterator::TRANSITION: + UNREACHABLE(); + break; + + case LookupIterator::INTERCEPTOR: + case LookupIterator::JSPROXY: + case LookupIterator::ACCESS_CHECK: { + bool found = false; + MaybeHandle result = SetPropertyInternal( + &own_lookup, value, language_mode, store_mode, &found); + if (found) return result; + return SetDataProperty(&own_lookup, value); + } + } + + UNREACHABLE(); + return MaybeHandle(); +} + + MaybeHandle Object::WriteToReadOnlyProperty( LookupIterator* it, Handle value, LanguageMode language_mode) { - if (is_sloppy(language_mode)) return value; + return WriteToReadOnlyProperty(it->isolate(), it->GetReceiver(), it->name(), + value, language_mode); +} - Handle args[] = {it->name(), it->GetReceiver()}; - THROW_NEW_ERROR(it->isolate(), - NewTypeError("strict_read_only_property", - HandleVector(args, arraysize(args))), + +MaybeHandle Object::WriteToReadOnlyProperty( + Isolate* isolate, Handle receiver, Handle name, + Handle value, LanguageMode language_mode) { + if (is_sloppy(language_mode)) return value; + Handle args[] = {name, receiver}; + THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property", + HandleVector(args, arraysize(args))), Object); } @@ -3170,11 +3242,18 @@ MaybeHandle Object::WriteToReadOnlyElement(Isolate* isolate, uint32_t index, Handle value, LanguageMode language_mode) { - if (is_sloppy(language_mode)) return value; + return WriteToReadOnlyProperty(isolate, receiver, + isolate->factory()->NewNumberFromUint(index), + value, language_mode); +} - Handle args[] = {isolate->factory()->NewNumberFromUint(index), - receiver}; - THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property", + +MaybeHandle Object::RedefineNonconfigurableProperty( + Isolate* isolate, Handle name, Handle value, + LanguageMode language_mode) { + if (is_sloppy(language_mode)) return value; + Handle args[] = {name}; + THROW_NEW_ERROR(isolate, NewTypeError("redefine_disallowed", HandleVector(args, arraysize(args))), Object); } @@ -3243,7 +3322,7 @@ MaybeHandle Object::AddDataProperty(LookupIterator* it, if (it->state() != LookupIterator::TRANSITION) { if (is_sloppy(language_mode)) return value; - Handle args[1] = {it->name()}; + Handle args[] = {it->name()}; THROW_NEW_ERROR(it->isolate(), NewTypeError("object_not_extensible", HandleVector(args, arraysize(args))), @@ -3789,11 +3868,8 @@ MaybeHandle JSProxy::SetPropertyViaPrototypesWithHandler( DCHECK(writable->IsBoolean()); *done = writable->IsFalse(); if (!*done) return isolate->factory()->the_hole_value(); - if (is_sloppy(language_mode)) return value; - Handle args[] = { name, receiver }; - THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property", - HandleVector(args, arraysize(args))), - Object); + return WriteToReadOnlyProperty(isolate, receiver, name, value, + language_mode); } // We have an AccessorDescriptor. @@ -5152,9 +5228,10 @@ MaybeHandle JSObject::DeleteElement(Handle object, if (is_strict(language_mode)) { // Deleting a non-configurable property in strict mode. Handle name = factory->NewNumberFromUint(index); - Handle args[2] = { name, object }; - THROW_NEW_ERROR(isolate, NewTypeError("strict_delete_property", - HandleVector(args, 2)), + Handle args[] = {name, object}; + THROW_NEW_ERROR(isolate, + NewTypeError("strict_delete_property", + HandleVector(args, arraysize(args))), Object); } return factory->false_value(); @@ -5285,7 +5362,7 @@ MaybeHandle JSObject::DeleteProperty(Handle object, if (!it.IsConfigurable()) { // Fail if the property is not configurable. if (is_strict(language_mode)) { - Handle args[2] = {name, object}; + Handle args[] = {name, object}; THROW_NEW_ERROR(it.isolate(), NewTypeError("strict_delete_property", HandleVector(args, arraysize(args))), @@ -12660,10 +12737,11 @@ MaybeHandle JSObject::SetElementWithCallback( } else { if (is_sloppy(language_mode)) return value; Handle key(isolate->factory()->NewNumberFromUint(index)); - Handle args[2] = { key, holder }; - THROW_NEW_ERROR( - isolate, NewTypeError("no_setter_in_callback", HandleVector(args, 2)), - Object); + Handle args[] = {key, holder}; + THROW_NEW_ERROR(isolate, + NewTypeError("no_setter_in_callback", + HandleVector(args, arraysize(args))), + Object); } } @@ -12850,25 +12928,30 @@ MaybeHandle JSObject::SetDictionaryElement( if (details.type() == ACCESSOR_CONSTANT && set_mode == SET_PROPERTY) { return SetElementWithCallback(object, element, index, value, object, language_mode); + } else if (set_mode == DEFINE_PROPERTY && !details.IsConfigurable() && + details.kind() == kAccessor) { + return RedefineNonconfigurableProperty( + isolate, isolate->factory()->NewNumberFromUint(index), + isolate->factory()->undefined_value(), language_mode); + + } else if ((set_mode == DEFINE_PROPERTY && !details.IsConfigurable() && + details.IsReadOnly()) || + (set_mode == SET_PROPERTY && details.IsReadOnly() && + !element->IsTheHole())) { + // If a value has not been initialized we allow writing to it even if it + // is read-only (a declared const that has not been initialized). + return WriteToReadOnlyProperty( + isolate, object, isolate->factory()->NewNumberFromUint(index), + isolate->factory()->undefined_value(), language_mode); } else { + DCHECK(details.IsConfigurable() || !details.IsReadOnly() || + element->IsTheHole()); dictionary->UpdateMaxNumberKey(index); - // If a value has not been initialized we allow writing to it even if it - // is read-only (a declared const that has not been initialized). If a - // value is being defined we skip attribute checks completely. if (set_mode == DEFINE_PROPERTY) { details = PropertyDetails(attributes, DATA, details.dictionary_index()); dictionary->DetailsAtPut(entry, details); - } else if (details.IsReadOnly() && !element->IsTheHole()) { - if (is_sloppy(language_mode)) { - return isolate->factory()->undefined_value(); - } else { - Handle number = isolate->factory()->NewNumberFromUint(index); - Handle args[2] = { number, object }; - THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property", - HandleVector(args, 2)), - Object); - } } + // Elements of the arguments object in slow mode might be slow aliases. if (is_arguments && element->IsAliasedArgumentsEntry()) { Handle entry = @@ -12900,9 +12983,10 @@ MaybeHandle JSObject::SetDictionaryElement( } else { Handle number = isolate->factory()->NewNumberFromUint(index); Handle name = isolate->factory()->NumberToString(number); - Handle args[1] = { name }; - THROW_NEW_ERROR(isolate, NewTypeError("object_not_extensible", - HandleVector(args, 1)), + Handle args[] = {name}; + THROW_NEW_ERROR(isolate, + NewTypeError("object_not_extensible", + HandleVector(args, arraysize(args))), Object); } } @@ -13602,7 +13686,7 @@ bool JSArray::WouldChangeReadOnlyLength(Handle array, MaybeHandle JSArray::ReadOnlyLengthError(Handle array) { Isolate* isolate = array->GetIsolate(); Handle length = isolate->factory()->length_string(); - Handle args[2] = { length, array }; + Handle args[] = {length, array}; THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property", HandleVector(args, arraysize(args))), Object); diff --git a/src/objects.h b/src/objects.h index 5aceb10..d4af4a6 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1017,8 +1017,6 @@ class Object { CERTAINLY_NOT_STORE_FROM_KEYED }; - enum StorePropertyMode { NORMAL_PROPERTY, SUPER_PROPERTY }; - INLINE(bool IsFixedArrayBase() const); INLINE(bool IsExternal() const); INLINE(bool IsAccessorInfo() const); @@ -1128,13 +1126,23 @@ class Object { MUST_USE_RESULT static MaybeHandle SetProperty( LookupIterator* it, Handle value, LanguageMode language_mode, - StoreFromKeyed store_mode, - StorePropertyMode data_store_mode = NORMAL_PROPERTY); + StoreFromKeyed store_mode); + + MUST_USE_RESULT static MaybeHandle SetSuperProperty( + LookupIterator* it, Handle value, LanguageMode language_mode, + StoreFromKeyed store_mode); + MUST_USE_RESULT static MaybeHandle WriteToReadOnlyProperty( LookupIterator* it, Handle value, LanguageMode language_mode); + MUST_USE_RESULT static MaybeHandle WriteToReadOnlyProperty( + Isolate* isolate, Handle reciever, Handle name, + Handle value, LanguageMode language_mode); MUST_USE_RESULT static MaybeHandle WriteToReadOnlyElement( Isolate* isolate, Handle receiver, uint32_t index, Handle value, LanguageMode language_mode); + MUST_USE_RESULT static MaybeHandle RedefineNonconfigurableProperty( + Isolate* isolate, Handle name, Handle value, + LanguageMode language_mode); MUST_USE_RESULT static MaybeHandle SetDataProperty( LookupIterator* it, Handle value); MUST_USE_RESULT static MaybeHandle AddDataProperty( @@ -1254,6 +1262,11 @@ class Object { // Return the map of the root of object's prototype chain. Map* GetRootMap(Isolate* isolate); + // Helper for SetProperty and SetSuperProperty. + MUST_USE_RESULT static MaybeHandle SetPropertyInternal( + LookupIterator* it, Handle value, LanguageMode language_mode, + StoreFromKeyed store_mode, bool* found); + DISALLOW_IMPLICIT_CONSTRUCTORS(Object); }; diff --git a/src/runtime/runtime-classes.cc b/src/runtime/runtime-classes.cc index 266f4d9..1be0341 100644 --- a/src/runtime/runtime-classes.cc +++ b/src/runtime/runtime-classes.cc @@ -311,9 +311,8 @@ static Object* StoreToSuper(Isolate* isolate, Handle home_object, Handle result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, - Object::SetProperty(&it, value, language_mode, - Object::CERTAINLY_NOT_STORE_FROM_KEYED, - Object::SUPER_PROPERTY)); + Object::SetSuperProperty(&it, value, language_mode, + Object::CERTAINLY_NOT_STORE_FROM_KEYED)); return *result; } diff --git a/test/mjsunit/harmony/super.js b/test/mjsunit/harmony/super.js index d529642..988cef2 100644 --- a/test/mjsunit/harmony/super.js +++ b/test/mjsunit/harmony/super.js @@ -595,7 +595,7 @@ setCalled = 0; getCalled = 0; assertEquals('object', typeof this); - assertTrue(this instanceof Number) + assertInstanceof(this, Number) assertEquals(42, this.valueOf()); assertEquals(1, super.x); assertEquals(1, getCalled); @@ -635,7 +635,7 @@ try { super.newProperty = 15; } catch (e) { ex = e; } - assertTrue(ex instanceof TypeError); + assertInstanceof(ex, TypeError); } } @@ -654,7 +654,7 @@ super.toString(); } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); + assertInstanceof(ex, TypeError); } }; @@ -689,7 +689,7 @@ setCalled = 0; getCalled = 0; assertEquals('object', typeof this); - assertTrue(this instanceof Number) + assertInstanceof(this, Number) assertEquals(42, this.valueOf()); assertEquals(1, super[x]); assertEquals(1, getCalled); @@ -729,7 +729,7 @@ try { super[newProperty] = 15; } catch (e) { ex = e; } - assertTrue(ex instanceof TypeError); + assertInstanceof(ex,TypeError); } }; @@ -748,7 +748,7 @@ super[toString](); } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); + assertInstanceof(ex, TypeError); } }; DerivedFromString.prototype.f.call(42); @@ -784,7 +784,7 @@ setCalled = 0; getCalled = 0; assertEquals('object', typeof this); - assertTrue(this instanceof Number) + assertInstanceof(this, Number) assertEquals(42, this.valueOf()); assertEquals(1, super[x]); assertEquals(1, getCalled); @@ -824,7 +824,7 @@ try { super[newProperty] = 15; } catch (e) { ex = e; } - assertTrue(ex instanceof TypeError); + assertInstanceof(ex, TypeError); } }; @@ -849,13 +849,13 @@ try { super[5] = 'q'; } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); + assertInstanceof(ex, TypeError); ex = null; try { super[1024] = 'q'; } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); + assertInstanceof(ex, TypeError); } }; @@ -963,8 +963,7 @@ }()); -(function TestSetterCreatingOwnProperties() { - var setterCalled; +(function TestSetterCreatingOwnPropertiesReconfigurable() { function Base() {} function Derived() {} Derived.prototype = { @@ -972,44 +971,172 @@ mSloppy() { assertEquals(42, this.ownReadOnly); super.ownReadOnly = 55; - assertEquals(42, this.ownReadOnly); + assertEquals(55, this.ownReadOnly); + var descr = Object.getOwnPropertyDescriptor(this, 'ownReadOnly'); + assertEquals(55, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertFalse(descr.writable); + assertFalse(Base.prototype.hasOwnProperty('ownReadOnly')); assertEquals(15, this.ownReadonlyAccessor); - super.ownReadonlyAccessor = 55; + super.ownReadonlyAccessor = 25; + assertEquals(25, this.ownReadonlyAccessor); + var descr = Object.getOwnPropertyDescriptor(this, 'ownReadonlyAccessor'); + assertEquals(25, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertTrue(descr.writable); + assertFalse(Base.prototype.hasOwnProperty('ownReadonlyAccessor')); + + super.ownSetter = 35; + assertEquals(35, this.ownSetter); + var descr = Object.getOwnPropertyDescriptor(this, 'ownSetter'); + assertEquals(35, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertTrue(descr.writable); + assertFalse(Base.prototype.hasOwnProperty('ownSetter')); + }, + mStrict() { + 'use strict'; + assertEquals(42, this.ownReadOnly); + super.ownReadOnly = 55; + assertEquals(55, this.ownReadOnly); + var descr = Object.getOwnPropertyDescriptor(this, 'ownReadOnly'); + assertEquals(55, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertFalse(descr.writable); + assertFalse(Base.prototype.hasOwnProperty('ownReadOnly')); + assertEquals(15, this.ownReadonlyAccessor); + super.ownReadonlyAccessor = 25; + assertEquals(25, this.ownReadonlyAccessor); + var descr = Object.getOwnPropertyDescriptor(this, 'ownReadonlyAccessor'); + assertEquals(25, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertTrue(descr.writable); + assertFalse(Base.prototype.hasOwnProperty('ownReadonlyAccessor')); + + super.ownSetter = 35; + assertEquals(35, this.ownSetter); + var descr = Object.getOwnPropertyDescriptor(this, 'ownSetter'); + assertEquals(35, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertTrue(descr.writable); + assertFalse(Base.prototype.hasOwnProperty('ownSetter')); + }, + }; + + var d = new Derived(); + Object.defineProperty(d, 'ownReadOnly', { + value: 42, + writable: false, + configurable: true + }); + Object.defineProperty(d, 'ownSetter', { + set: function() { assertUnreachable(); }, + configurable: true + }); + Object.defineProperty(d, 'ownReadonlyAccessor', { + get: function() { return 15; }, + configurable: true + }); - setterCalled = 0; - super.ownSetter = 42; - assertEquals(1, setterCalled); + d.mSloppy(); + + var d = new Derived(); + Object.defineProperty(d, 'ownReadOnly', { + value: 42, + writable: false, + configurable: true + }); + Object.defineProperty(d, 'ownSetter', { + set: function() { assertUnreachable(); }, + configurable: true + }); + Object.defineProperty(d, 'ownReadonlyAccessor', { + get: function() { return 15; }, + configurable: true + }); + d.mStrict(); +}()); + + +(function TestSetterCreatingOwnPropertiesNonConfigurable() { + function Base() {} + function Derived() {} + Derived.prototype = { + __proto__: Base.prototype, + mSloppy() { + assertEquals(42, this.ownReadOnly); + super.ownReadOnly = 55; + assertEquals(42, this.ownReadOnly); + var descr = Object.getOwnPropertyDescriptor(this, 'ownReadOnly'); + assertEquals(42, descr.value); + assertFalse(descr.configurable); + assertFalse(descr.enumerable); + assertFalse(descr.writable); + assertFalse(Base.prototype.hasOwnProperty('ownReadOnly')); + + assertEquals(15, this.ownReadonlyAccessor); + super.ownReadonlyAccessor = 25; + assertEquals(15, this.ownReadonlyAccessor); + var descr = Object.getOwnPropertyDescriptor(this, 'ownReadonlyAccessor'); + assertFalse(descr.configurable); + assertFalse(descr.enumerable); + assertFalse(Base.prototype.hasOwnProperty('ownReadonlyAccessor')); + + super.ownSetter = 35; + var descr = Object.getOwnPropertyDescriptor(this, 'ownSetter'); + assertFalse(descr.configurable); + assertFalse(descr.enumerable); + assertFalse(Base.prototype.hasOwnProperty('ownSetter')); }, mStrict() { 'use strict'; - assertEquals(42, this.ownReadOnly); var ex; + assertEquals(42, this.ownReadOnly); try { super.ownReadOnly = 55; - } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); + } catch (e) { + ex = e; + } + assertInstanceof(ex, TypeError); + assertEquals( + "Cannot assign to read only property 'ownReadOnly' of #", + ex.message); assertEquals(42, this.ownReadOnly); - assertEquals(15, this.ownReadonlyAccessor); ex = null; + assertEquals(15, this.ownReadonlyAccessor); try { - super.ownReadonlyAccessor = 55; - } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); + super.ownReadonlyAccessor = 25; + } catch (e) { + ex = e; + } + assertInstanceof(ex, TypeError); + assertEquals('Cannot redefine property: ownReadonlyAccessor', ex.message); assertEquals(15, this.ownReadonlyAccessor); - setterCalled = 0; - super.ownSetter = 42; - assertEquals(1, setterCalled); + ex = null; + try { + super.ownSetter = 35; + } catch (e) { + ex = e; + } + assertInstanceof(ex, TypeError); + assertEquals('Cannot redefine property: ownSetter', ex.message); } }; var d = new Derived(); Object.defineProperty(d, 'ownReadOnly', { value : 42, writable : false }); Object.defineProperty(d, 'ownSetter', - { set : function() { setterCalled++; } }); + { set : function() { assertUnreachable(); } }); Object.defineProperty(d, 'ownReadonlyAccessor', { get : function() { return 15; }}); d.mSloppy(); @@ -1076,11 +1203,8 @@ }()); -(function TestKeyedSetterCreatingOwnProperties() { - var ownReadOnly = 'ownReadOnly'; - var ownReadonlyAccessor = 'ownReadonlyAccessor'; - var ownSetter = 'ownSetter'; - var setterCalled; +function TestKeyedSetterCreatingOwnPropertiesReconfigurable(ownReadOnly, + ownReadonlyAccessor, ownSetter) { function Base() {} function Derived() {} Derived.prototype = { @@ -1088,56 +1212,107 @@ mSloppy() { assertEquals(42, this[ownReadOnly]); super[ownReadOnly] = 55; - assertEquals(42, this[ownReadOnly]); + assertEquals(55, this[ownReadOnly]); + var descr = Object.getOwnPropertyDescriptor(this, ownReadOnly); + assertEquals(55, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertFalse(descr.writable); + assertFalse(Base.prototype.hasOwnProperty(ownReadOnly)); assertEquals(15, this[ownReadonlyAccessor]); - super[ownReadonlyAccessor] = 55; - assertEquals(15, this[ownReadonlyAccessor]); - - setterCalled = 0; - super[ownSetter] = 42; - assertEquals(1, setterCalled); + super[ownReadonlyAccessor] = 25; + assertEquals(25, this[ownReadonlyAccessor]); + var descr = Object.getOwnPropertyDescriptor(this, ownReadonlyAccessor); + assertEquals(25, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertTrue(descr.writable); + assertFalse(Base.prototype.hasOwnProperty(ownReadonlyAccessor)); + + super[ownSetter] = 35; + assertEquals(35, this[ownSetter]); + var descr = Object.getOwnPropertyDescriptor(this, ownSetter); + assertEquals(35, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertTrue(descr.writable); + assertFalse(Base.prototype.hasOwnProperty(ownSetter)); }, mStrict() { 'use strict'; assertEquals(42, this[ownReadOnly]); - var ex; - try { - super[ownReadOnly] = 55; - } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); - assertEquals(42, this[ownReadOnly]); + super[ownReadOnly] = 55; + assertEquals(55, this[ownReadOnly]); + var descr = Object.getOwnPropertyDescriptor(this, ownReadOnly); + assertEquals(55, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertFalse(descr.writable); + assertFalse(Base.prototype.hasOwnProperty(ownReadOnly)); assertEquals(15, this[ownReadonlyAccessor]); - ex = null; - try { - super[ownReadonlyAccessor] = 55; - } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); - assertEquals(15, this[ownReadonlyAccessor]); - - setterCalled = 0; - super[ownSetter] = 42; - assertEquals(1, setterCalled); - } + super[ownReadonlyAccessor] = 25; + assertEquals(25, this[ownReadonlyAccessor]); + var descr = Object.getOwnPropertyDescriptor(this, ownReadonlyAccessor); + assertEquals(25, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertTrue(descr.writable); + assertFalse(Base.prototype.hasOwnProperty(ownReadonlyAccessor)); + + super[ownSetter] = 35; + assertEquals(35, this[ownSetter]); + var descr = Object.getOwnPropertyDescriptor(this, ownSetter); + assertEquals(35, descr.value); + assertTrue(descr.configurable); + assertFalse(descr.enumerable); + assertTrue(descr.writable); + assertFalse(Base.prototype.hasOwnProperty(ownSetter)); + }, }; var d = new Derived(); - Object.defineProperty(d, 'ownReadOnly', { value : 42, writable : false }); - Object.defineProperty(d, 'ownSetter', - { set : function() { setterCalled++; } }); - Object.defineProperty(d, 'ownReadonlyAccessor', - { get : function() { return 15; }}); + Object.defineProperty(d, ownReadOnly, { + value: 42, + writable: false, + configurable: true + }); + Object.defineProperty(d, ownSetter, { + set: function() { assertUnreachable(); }, + configurable: true + }); + Object.defineProperty(d, ownReadonlyAccessor, { + get: function() { return 15; }, + configurable: true + }); + d.mSloppy(); + + var d = new Derived(); + Object.defineProperty(d, ownReadOnly, { + value: 42, + writable: false, + configurable: true + }); + Object.defineProperty(d, ownSetter, { + set: function() { assertUnreachable(); }, + configurable: true + }); + Object.defineProperty(d, ownReadonlyAccessor, { + get: function() { return 15; }, + configurable: true + }); d.mStrict(); -}()); +} +TestKeyedSetterCreatingOwnPropertiesReconfigurable('ownReadOnly', + 'ownReadonlyAccessor', + 'ownSetter'); +TestKeyedSetterCreatingOwnPropertiesReconfigurable(42, 43, 44); -(function TestKeyedNumericSetterCreatingOwnProperties() { - var ownReadOnly = 42; - var ownReadonlyAccessor = 43; - var ownSetter = 44; - var setterCalled; +function TestKeyedSetterCreatingOwnPropertiesNonConfigurable( + ownReadOnly, ownReadonlyAccessor, ownSetter) { function Base() {} function Derived() {} Derived.prototype = { @@ -1146,48 +1321,78 @@ assertEquals(42, this[ownReadOnly]); super[ownReadOnly] = 55; assertEquals(42, this[ownReadOnly]); + var descr = Object.getOwnPropertyDescriptor(this, ownReadOnly); + assertEquals(42, descr.value); + assertFalse(descr.configurable); + assertFalse(descr.enumerable); + assertFalse(descr.writable); + assertFalse(Base.prototype.hasOwnProperty(ownReadOnly)); assertEquals(15, this[ownReadonlyAccessor]); - super[ownReadonlyAccessor] = 55; + super[ownReadonlyAccessor] = 25; assertEquals(15, this[ownReadonlyAccessor]); - - setterCalled = 0; - super[ownSetter] = 42; - assertEquals(1, setterCalled); + var descr = Object.getOwnPropertyDescriptor(this, ownReadonlyAccessor); + assertFalse(descr.configurable); + assertFalse(descr.enumerable); + assertFalse(Base.prototype.hasOwnProperty(ownReadonlyAccessor)); + + super[ownSetter] = 35; + var descr = Object.getOwnPropertyDescriptor(this, ownSetter); + assertFalse(descr.configurable); + assertFalse(descr.enumerable); + assertFalse(Base.prototype.hasOwnProperty(ownSetter)); }, mStrict() { 'use strict'; - assertEquals(42, this[ownReadOnly]); var ex; + assertEquals(42, this[ownReadOnly]); try { super[ownReadOnly] = 55; - } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); + } catch (e) { + ex = e; + } + assertInstanceof(ex, TypeError); + assertEquals( + "Cannot assign to read only property '" + ownReadOnly + + "' of #", + ex.message); assertEquals(42, this[ownReadOnly]); - assertEquals(15, this[ownReadonlyAccessor]); ex = null; + assertEquals(15, this[ownReadonlyAccessor]); try { - super[ownReadonlyAccessor] = 55; - } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); + super[ownReadonlyAccessor] = 25; + } catch (e) { + ex = e; + } + assertInstanceof(ex, TypeError); + assertEquals('Cannot redefine property: ' + ownReadonlyAccessor, + ex.message); assertEquals(15, this[ownReadonlyAccessor]); - setterCalled = 0; - super[ownSetter] = 42; - assertEquals(1, setterCalled); + ex = null; + try { + super[ownSetter] = 35; + } catch (e) { + ex = e; + } + assertInstanceof(ex, TypeError); + assertEquals('Cannot redefine property: ' + ownSetter, ex.message); } - } + }; var d = new Derived(); Object.defineProperty(d, ownReadOnly, { value : 42, writable : false }); Object.defineProperty(d, ownSetter, - { set : function() { setterCalled++; } }); + { set : function() { assertUnreachable(); } }); Object.defineProperty(d, ownReadonlyAccessor, { get : function() { return 15; }}); d.mSloppy(); d.mStrict(); -}()); +} +TestKeyedSetterCreatingOwnPropertiesNonConfigurable('ownReadOnly', + 'ownReadonlyAccessor', 'ownSetter'); +TestKeyedSetterCreatingOwnPropertiesNonConfigurable(42, 43, 44); (function TestSetterNoProtoWalk() { @@ -1684,7 +1889,7 @@ assertEquals(27, this.x); var ex = null; try { super.x = 10; } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); + assertInstanceof(ex, TypeError); assertEquals(27, super.x); assertEquals(27, this.x); } @@ -1716,7 +1921,7 @@ assertEquals(27, this[x]); var ex = null; try { super[x] = 10; } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); + assertInstanceof(ex, TypeError); assertEquals(27, super[x]); assertEquals(27, this[x]); } @@ -1748,7 +1953,7 @@ assertEquals(27, this[x]); var ex = null; try { super[x] = 10; } catch(e) { ex = e; } - assertTrue(ex instanceof TypeError); + assertInstanceof(ex, TypeError); assertEquals(27, super[x]); assertEquals(27, this[x]); } @@ -1845,7 +2050,7 @@ var f = new F(42); // TODO(dslomov,arv): Fix this. BUG=v8:3886. - assertTrue(f instanceof Number); + assertInstanceof(f, Number); }()); (function TestSuperCallErrorCases() {