Revision: 24696
Author: [email protected]
Date: Fri Oct 17 13:19:45 2014 UTC
Log: Keyed stores to super with numeric keys.
[email protected], [email protected], [email protected]
BUG=v8:3330
LOG=N
Review URL: https://codereview.chromium.org/649603003
https://code.google.com/p/v8/source/detail?r=24696
Modified:
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
/branches/bleeding_edge/src/runtime/runtime-classes.cc
/branches/bleeding_edge/test/mjsunit/harmony/super.js
=======================================
--- /branches/bleeding_edge/src/objects.cc Fri Oct 17 13:01:54 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc Fri Oct 17 13:19:45 2014 UTC
@@ -800,6 +800,82 @@
return isolate->factory()->undefined_value();
}
+
+
+MaybeHandle<Object> Object::SetElementWithReceiver(
+ Isolate* isolate, Handle<Object> object, Handle<Object> receiver,
+ uint32_t index, Handle<Object> value, StrictMode strict_mode) {
+ // Iterate up the prototype chain until an element is found or the null
+ // prototype is encountered.
+ bool done = false;
+ for (PrototypeIterator iter(isolate, object,
+ object->IsJSProxy() || object->IsJSObject()
+ ? PrototypeIterator::START_AT_RECEIVER
+ : PrototypeIterator::START_AT_PROTOTYPE);
+ !iter.IsAtEnd() && !done; iter.Advance()) {
+ if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
+ // TODO(dslomov): implement.
+ isolate->ThrowIllegalOperation();
+ return MaybeHandle<Object>();
+ }
+
+ Handle<JSObject> js_object =
+ Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+
+ // Check access rights if needed.
+ if (js_object->IsAccessCheckNeeded()) {
+ if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_SET)) {
+ isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_SET);
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ return isolate->factory()->undefined_value();
+ }
+ }
+
+ if (js_object->HasIndexedInterceptor()) {
+ Maybe<PropertyAttributes> from_interceptor =
+ JSObject::GetElementAttributeFromInterceptor(js_object, receiver,
+ index);
+ if (!from_interceptor.has_value) return MaybeHandle<Object>();
+ if ((from_interceptor.value & READ_ONLY) != 0) {
+ return WriteToReadOnlyElement(isolate, receiver, index, value,
+ strict_mode);
+ }
+ done = from_interceptor.value != ABSENT;
+ }
+
+ if (!done &&
+ js_object->elements() != isolate->heap()->empty_fixed_array()) {
+ ElementsAccessor* accessor = js_object->GetElementsAccessor();
+ PropertyAttributes attrs =
+ accessor->GetAttributes(receiver, js_object, index);
+ if ((attrs & READ_ONLY) != 0) {
+ return WriteToReadOnlyElement(isolate, receiver, index, value,
+ strict_mode);
+ }
+ Handle<AccessorPair> accessor_pair;
+ if (accessor->GetAccessorPair(receiver, js_object, index)
+ .ToHandle(&accessor_pair)) {
+ return JSObject::SetElementWithCallback(receiver, accessor_pair,
index,
+ value, js_object,
strict_mode);
+ } else {
+ done = attrs != ABSENT;
+ }
+ }
+ }
+
+ if (!receiver->IsJSObject()) {
+ return WriteToReadOnlyElement(isolate, receiver, index, value,
strict_mode);
+ }
+ Handle<JSObject> target = Handle<JSObject>::cast(receiver);
+ ElementsAccessor* accessor = target->GetElementsAccessor();
+ PropertyAttributes attrs = accessor->GetAttributes(receiver, target,
index);
+ if ((attrs & READ_ONLY) != 0) {
+ return WriteToReadOnlyElement(isolate, receiver, index, value,
strict_mode);
+ }
+ PropertyAttributes new_attrs = attrs != ABSENT ? attrs : NONE;
+ return JSObject::SetElement(target, index, value, new_attrs, strict_mode,
+ false);
+}
Map* Object::GetRootMap(Isolate* isolate) {
@@ -2930,6 +3006,21 @@
HandleVector(args, arraysize(args))),
Object);
}
+
+
+MaybeHandle<Object> Object::WriteToReadOnlyElement(Isolate* isolate,
+ Handle<Object> receiver,
+ uint32_t index,
+ Handle<Object> value,
+ StrictMode strict_mode)
{
+ if (strict_mode != STRICT) return value;
+
+ Handle<Object> args[] = {isolate->factory()->NewNumberFromUint(index),
+ receiver};
+ THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
+ HandleVector(args,
arraysize(args))),
+ Object);
+}
MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
@@ -4075,6 +4166,21 @@
// callbacks or interceptor calls.
AssertNoContextChange ncc(isolate);
+ Maybe<PropertyAttributes> from_interceptor =
+ GetElementAttributeFromInterceptor(object, receiver, index);
+ if (!from_interceptor.has_value) return Maybe<PropertyAttributes>();
+ if (from_interceptor.value != ABSENT) return
maybe(from_interceptor.value);
+
+ return GetElementAttributeWithoutInterceptor(object, receiver, index,
+ check_prototype);
+}
+
+
+Maybe<PropertyAttributes> JSObject::GetElementAttributeFromInterceptor(
+ Handle<JSObject> object, Handle<Object> receiver, uint32_t index) {
+ Isolate* isolate = object->GetIsolate();
+ AssertNoContextChange ncc(isolate);
+
Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
PropertyCallbackArguments args(
isolate, interceptor->data(), *receiver, *object);
@@ -4095,9 +4201,8 @@
v8::Handle<v8::Value> result = args.Call(getter, index);
if (!result.IsEmpty()) return maybe(NONE);
}
-
- return GetElementAttributeWithoutInterceptor(
- object, receiver, index, check_prototype);
+ RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate,
Maybe<PropertyAttributes>());
+ return maybe(ABSENT);
}
@@ -11867,13 +11972,10 @@
}
-MaybeHandle<Object> JSObject::SetElementWithCallback(Handle<JSObject>
object,
- Handle<Object>
structure,
- uint32_t index,
- Handle<Object> value,
- Handle<JSObject>
holder,
- StrictMode
strict_mode) {
- Isolate* isolate = object->GetIsolate();
+MaybeHandle<Object> JSObject::SetElementWithCallback(
+ Handle<Object> object, Handle<Object> structure, uint32_t index,
+ Handle<Object> value, Handle<JSObject> holder, StrictMode strict_mode)
{
+ Isolate* isolate = holder->GetIsolate();
// We should never get here to initialize a const with the hole
// value since a const declaration would conflict with the setter.
@@ -11889,7 +11991,7 @@
if (call_fun == NULL) return value;
Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Handle<String> key(isolate->factory()->NumberToString(number));
- LOG(isolate, ApiNamedPropertyAccess("store", *object, *key));
+ LOG(isolate, ApiNamedPropertyAccess("store", *holder, *key));
PropertyCallbackArguments
args(isolate, data->data(), *object, *holder);
args.Call(call_fun,
=======================================
--- /branches/bleeding_edge/src/objects.h Thu Oct 16 13:19:36 2014 UTC
+++ /branches/bleeding_edge/src/objects.h Fri Oct 17 13:19:45 2014 UTC
@@ -1131,6 +1131,9 @@
StorePropertyMode data_store_mode = NORMAL_PROPERTY);
MUST_USE_RESULT static MaybeHandle<Object> WriteToReadOnlyProperty(
LookupIterator* it, Handle<Object> value, StrictMode strict_mode);
+ MUST_USE_RESULT static MaybeHandle<Object> WriteToReadOnlyElement(
+ Isolate* isolate, Handle<Object> receiver, uint32_t index,
+ Handle<Object> value, StrictMode strict_mode);
MUST_USE_RESULT static MaybeHandle<Object> SetDataProperty(
LookupIterator* it, Handle<Object> value);
MUST_USE_RESULT static MaybeHandle<Object> AddDataProperty(
@@ -1176,6 +1179,10 @@
Handle<Object> receiver,
uint32_t index);
+ MUST_USE_RESULT static MaybeHandle<Object> SetElementWithReceiver(
+ Isolate* isolate, Handle<Object> object, Handle<Object> receiver,
+ uint32_t index, Handle<Object> value, StrictMode strict_mode);
+
static inline Handle<Object> GetPrototypeSkipHiddenPrototypes(
Isolate* isolate, Handle<Object> receiver);
@@ -1927,8 +1934,7 @@
// These methods do not perform access checks!
MUST_USE_RESULT static MaybeHandle<AccessorPair>
GetOwnElementAccessorPair(
- Handle<JSObject> object,
- uint32_t index);
+ Handle<JSObject> object, uint32_t index);
MUST_USE_RESULT static MaybeHandle<Object> SetFastElement(
Handle<JSObject> object,
@@ -2253,18 +2259,30 @@
GetElementAttributeWithInterceptor(Handle<JSObject> object,
Handle<JSReceiver> receiver,
uint32_t index, bool
continue_search);
+
+ // Queries indexed interceptor on an object for property attributes.
+ //
+ // We determine property attributes as follows:
+ // - if interceptor has a query callback, then the property attributes
are
+ // the result of query callback for index.
+ // - otherwise if interceptor has a getter callback and it returns
+ // non-empty value on index, then the property attributes is NONE
+ // (property is present, and it is enumerable, configurable, writable)
+ // - otherwise there are no property attributes that can be inferred for
+ // interceptor, and this function returns ABSENT.
+ MUST_USE_RESULT static Maybe<PropertyAttributes>
+ GetElementAttributeFromInterceptor(Handle<JSObject> object,
+ Handle<Object> receiver,
+ uint32_t index);
+
MUST_USE_RESULT static Maybe<PropertyAttributes>
GetElementAttributeWithoutInterceptor(Handle<JSObject> object,
Handle<JSReceiver> receiver,
uint32_t index,
bool continue_search);
MUST_USE_RESULT static MaybeHandle<Object> SetElementWithCallback(
- Handle<JSObject> object,
- Handle<Object> structure,
- uint32_t index,
- Handle<Object> value,
- Handle<JSObject> holder,
- StrictMode strict_mode);
+ Handle<Object> object, Handle<Object> structure, uint32_t index,
+ Handle<Object> value, Handle<JSObject> holder, StrictMode
strict_mode);
MUST_USE_RESULT static MaybeHandle<Object> SetElementWithInterceptor(
Handle<JSObject> object,
uint32_t index,
=======================================
--- /branches/bleeding_edge/src/runtime/runtime-classes.cc Fri Oct 10
10:40:29 2014 UTC
+++ /branches/bleeding_edge/src/runtime/runtime-classes.cc Fri Oct 17
13:19:45 2014 UTC
@@ -285,6 +285,30 @@
Object::SUPER_PROPERTY));
return *result;
}
+
+
+static Object* StoreElementToSuper(Isolate* isolate,
+ Handle<JSObject> home_object,
+ Handle<Object> receiver, uint32_t index,
+ Handle<Object> value,
+ StrictMode strict_mode) {
+ if (home_object->IsAccessCheckNeeded() &&
+ !isolate->MayIndexedAccess(home_object, index, v8::ACCESS_SET)) {
+ isolate->ReportFailedAccessCheck(home_object, v8::ACCESS_SET);
+ RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
+ }
+
+ PrototypeIterator iter(isolate, home_object);
+ Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
+ if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
+
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+ isolate, result,
+ Object::SetElementWithReceiver(isolate, proto, receiver, index,
value,
+ strict_mode));
+ return *result;
+}
RUNTIME_FUNCTION(Runtime_StoreToSuper_Strict) {
@@ -314,13 +338,18 @@
static Object* StoreKeyedToSuper(Isolate* isolate, Handle<JSObject>
home_object,
Handle<Object> receiver, Handle<Object>
key,
Handle<Object> value, StrictMode
strict_mode) {
+ uint32_t index;
+
+ if (key->ToArrayIndex(&index)) {
+ return StoreElementToSuper(isolate, home_object, receiver, index,
value,
+ strict_mode);
+ }
Handle<Name> name;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
Runtime::ToName(isolate, key));
- uint32_t index;
if (name->AsArrayIndex(&index)) {
- // TODO(dslomov): Implement.
- return ThrowUnsupportedSuper(isolate);
+ return StoreElementToSuper(isolate, home_object, receiver, index,
value,
+ strict_mode);
}
return StoreToSuper(isolate, home_object, receiver, name, value,
strict_mode);
}
=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/super.js Fri Oct 17
09:16:03 2014 UTC
+++ /branches/bleeding_edge/test/mjsunit/harmony/super.js Fri Oct 17
13:19:45 2014 UTC
@@ -321,6 +321,74 @@
}());
+(function TestSetterNumericKeyed() {
+ var x = 42;
+ function Base() {}
+ Base.prototype = {
+ constructor: Base,
+ _x: 'base'
+ };
+
+ Object.defineProperty(Base.prototype, x,
+ { get: function() { return this._x; },
+ set: function(v) { this._x = v; }
+ });
+
+ function Derived() {}
+ Derived.__proto__ = Base;
+ Derived.prototype = {
+ __proto__: Base.prototype,
+ constructor: Derived,
+ _x: 'derived'
+ };
+ Derived.prototype.testSetter = function() {
+ assertEquals('foobar', super[x] = 'foobar');
+ assertEquals('foobarabc', super[x] += 'abc');
+ }.toMethod(Derived.prototype);
+ var d = new Derived();
+ d.testSetter();
+ assertEquals('base', Base.prototype._x);
+ assertEquals('foobarabc', d._x);
+ d._x = '';
+ Derived.prototype.testSetterStrict = function() {
+ 'use strict';
+ assertEquals('foobar', super[x] = 'foobar');
+ assertEquals('foobarabc', super[x] += 'abc');
+ }.toMethod(Derived.prototype);
+ d.testSetterStrict();
+ assertEquals('base', Base.prototype._x);
+ assertEquals('foobarabc', d._x);
+
+
+ Derived.prototype.testSetterWithToString = function() {
+ var toStringCalled;
+ var o = { toString: function() {
+ toStringCalled++;
+ return x;
+ } };
+
+ toStringCalled = 0;
+ super[o] = 'set';
+ assertEquals(1, toStringCalled);
+ assertEquals('set', this._x);
+
+ var eToThrow = new Error();
+ var oThrowsInToString = { toString: function() {
+ throw eToThrow;
+ } };
+
+ var ex = null;
+ try {
+ super[oThrowsInToString] = 'xyz';
+ } catch(e) { ex = e }
+ assertEquals(eToThrow, ex);
+ assertEquals('set', this._x);
+ }.toMethod(Derived.prototype);
+ d = new Derived();
+ d.testSetterWithToString();
+}());
+
+
(function TestSetterKeyed() {
var x = 'x';
function Base() {}
@@ -389,19 +457,11 @@
return "1";
} };
- ex = null;
- try {
- super[oReturnsNumericString] = 'abc';
- } catch(e) { ex = e }
- assertTrue(ex instanceof ReferenceError);
+ assertEquals('abc', super[oReturnsNumericString] = 'abc');
assertEquals('set', this._x);
- ex = null;
- try {
- super[1] = 10; // Indexed properties unsupported yet.
- } catch (e) { ex = e; }
- assertTrue(ex instanceof ReferenceError);
+ assertEquals(10, super[1] = 10);
}.toMethod(Derived.prototype);
d = new Derived();
d.testSetterWithToString();
@@ -446,6 +506,31 @@
constructor: Derived,
};
+ Derived.prototype.testSetter = function() {
+ assertEquals('x from Base', super[x]);
+ super[x] = 'data property';
+ assertEquals('x from Base', super[x]);
+ assertEquals('data property', this[x]);
+ }.toMethod(Derived.prototype);
+
+ new Derived().testSetter();
+}());
+
+
+(function TestKeyedNumericSetterDataProperties() {
+ var x = 42;
+ function Base() {}
+ Base.prototype = {
+ constructor: Base,
+ 42: 'x from Base'
+ };
+
+ function Derived() {}
+ Derived.prototype = {
+ __proto__: Base.prototype,
+ constructor: Derived,
+ };
+
Derived.prototype.testSetter = function() {
assertEquals('x from Base', super[x]);
super[x] = 'data property';
@@ -639,6 +724,122 @@
f.toMethod(DerivedFromString.prototype).call(42);
}());
+
+(function TestNumericKeyedAccessorsOnPrimitives() {
+ var x = 42;
+ var newProperty = 43;
+ var getCalled = 0;
+ var setCalled = 0;
+ function Base() {}
+ Base.prototype = {
+ constructor: Base,
+ };
+
+ Object.defineProperty(Base.prototype, x, {
+ get: function() {
+ getCalled++;
+ return 1;
+ },
+ set: function(v) {
+ setCalled++;
+ return v;
+ }
+ });
+
+ function Derived() {}
+ Derived.prototype = {
+ __proto__: Base.prototype,
+ constructor: Derived,
+ };
+ Derived.prototype.testSetter = function() {
+ setCalled = 0;
+ getCalled = 0;
+ assertEquals('object', typeof this);
+ assertTrue(this instanceof Number)
+ assertEquals(42, this.valueOf());
+ assertEquals(1, super[x]);
+ assertEquals(1, getCalled);
+ assertEquals(0, setCalled);
+
+ assertEquals(5, super[x] = 5);
+ assertEquals(1, getCalled);
+ assertEquals(1, setCalled);
+
+ assertEquals(6, super[x] += 5);
+ assertEquals(2, getCalled);
+ assertEquals(2, setCalled);
+
+ super[newProperty] = 15;
+ assertEquals(15, this[newProperty]);
+ assertEquals(undefined, super[newProperty]);
+ }.toMethod(Derived.prototype);
+
+ Derived.prototype.testSetterStrict = function() {
+ 'use strict';
+ getCalled = 0;
+ setCalled = 0;
+ assertTrue(42 === this);
+
+ assertEquals(1, super[x]);
+ assertEquals(1, getCalled);
+ assertEquals(0, setCalled);
+
+ assertEquals(5, super[x] = 5);
+ assertEquals(1, getCalled);
+ assertEquals(1, setCalled);
+
+ assertEquals(6, super[x] += 5);
+ assertEquals(2, getCalled);
+ assertEquals(2, setCalled);
+
+ var ex;
+ try {
+ super[newProperty] = 15;
+ } catch (e) { ex = e; }
+ assertTrue(ex instanceof TypeError);
+ }.toMethod(Derived.prototype);
+
+ Derived.prototype.testSetter.call(42);
+ Derived.prototype.testSetterStrict.call(42);
+}());
+
+
+(function TestKeyedNumericSetterOnExotics() {
+ function Base() {}
+ function Derived() {}
+ Derived.prototype = { __proto__: Base.prototype };
+
+ Derived.prototype.callSetterOnArray = function() {
+ super[42] = 1;
+ }.toMethod(Derived.prototype);
+
+ Derived.prototype.callStrictSetterOnString = function() {
+ 'use strict';
+ assertEquals('string', typeof this);
+ assertTrue('abcdef' === this);
+ var ex = null;
+ try {
+ super[5] = 'q';
+ } catch(e) { ex = e; }
+ assertTrue(ex instanceof TypeError);
+
+ ex = null;
+ try {
+ super[1024] = 'q';
+ } catch(e) { ex = e; }
+ assertTrue(ex instanceof TypeError);
+ }.toMethod(Derived.prototype);
+
+ var x = [];
+ assertEquals(0, x.length);
+ Derived.prototype.callSetterOnArray.call(x);
+ assertEquals(43, x.length);
+ assertEquals(1, x[42]);
+
+ var s = 'abcdef';
+ Derived.prototype.callStrictSetterOnString.call(s)
+}());
+
(function TestSetterUndefinedProperties() {
function Base() {}
@@ -699,6 +900,36 @@
}());
+(function TestKeyedNumericSetterUndefinedProperties() {
+ var x = 42;
+ function Base() {}
+ function Derived() {}
+ Derived.prototype = { __proto__ : Base.prototype };
+ Derived.prototype.mSloppy = function () {
+ assertEquals(undefined, super[x]);
+ assertEquals(undefined, this[x]);
+ super[x] = 10;
+ assertEquals(10, this[x]);
+ assertEquals(undefined, super[x]);
+ }.toMethod(Derived.prototype);
+
+ Derived.prototype.mStrict = function () {
+ 'use strict';
+ assertEquals(undefined, super[x]);
+ assertEquals(undefined, this[x]);
+ super[x] = 10;
+ assertEquals(10, this[x]);
+ assertEquals(undefined, super[x]);
+ }.toMethod(Derived.prototype);
+ var d = new Derived();
+ d.mSloppy();
+ assertEquals(10, d[x]);
+ var d1 = new Derived();
+ d1.mStrict();
+ assertEquals(10, d[x]);
+}());
+
+
(function TestSetterCreatingOwnProperties() {
function Base() {}
function Derived() {}
@@ -869,6 +1100,63 @@
d.mStrict();
}());
+
+(function TestKeyedNumericSetterCreatingOwnProperties() {
+ var ownReadOnly = 42;
+ var ownReadonlyAccessor = 43;
+ var ownSetter = 44;
+ function Base() {}
+ function Derived() {}
+ Derived.prototype = { __proto__ : Base.prototype };
+ var setterCalled;
+
+ Derived.prototype.mSloppy = function() {
+ assertEquals(42, this[ownReadOnly]);
+ super[ownReadOnly] = 55;
+ assertEquals(42, this[ownReadOnly]);
+
+ assertEquals(15, this[ownReadonlyAccessor]);
+ super[ownReadonlyAccessor] = 55;
+ assertEquals(15, this[ownReadonlyAccessor]);
+
+ setterCalled = 0;
+ super[ownSetter] = 42;
+ assertEquals(1, setterCalled);
+ }.toMethod(Derived.prototype);
+
+ Derived.prototype.mStrict = function() {
+ 'use strict';
+ assertEquals(42, this[ownReadOnly]);
+ var ex;
+ try {
+ super[ownReadOnly] = 55;
+ } catch(e) { ex = e; }
+ assertTrue(ex instanceof TypeError);
+ assertEquals(42, this[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);
+ }.toMethod(Derived.prototype);
+
+ 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; }});
+ d.mSloppy();
+ d.mStrict();
+}());
+
(function TestSetterNoProtoWalk() {
function Base() {}
@@ -949,6 +1237,77 @@
set x(v) { setCalled++; }
};
+ Derived.prototype.mSloppy = function() {
+ setCalled = 0;
+ getCalled = 0;
+ assertEquals(42, this[x]);
+ assertEquals(1, getCalled);
+ assertEquals(0, setCalled);
+
+ getCalled = 0;
+ setCalled = 0;
+ this[x] = 43;
+ assertEquals(0, getCalled);
+ assertEquals(1, setCalled);
+
+ getCalled = 0;
+ setCalled = 0;
+ super[x] = 15;
+ assertEquals(0, setCalled);
+ assertEquals(0, getCalled);
+
+ assertEquals(15, this[x]);
+ assertEquals(0, getCalled);
+ assertEquals(0, setCalled);
+
+ }.toMethod(Derived.prototype);
+
+ Derived.prototype.mStrict = function() {
+ 'use strict';
+ setCalled = 0;
+ getCalled = 0;
+ assertEquals(42, this[x]);
+ assertEquals(1, getCalled);
+ assertEquals(0, setCalled);
+
+ getCalled = 0;
+ setCalled = 0;
+ this[x] = 43;
+ assertEquals(0, getCalled);
+ assertEquals(1, setCalled);
+
+ getCalled = 0;
+ setCalled = 0;
+ super[x] = 15;
+ assertEquals(0, setCalled);
+ assertEquals(0, getCalled);
+
+ assertEquals(15, this[x]);
+ assertEquals(0, getCalled);
+ assertEquals(0, setCalled);
+
+ }.toMethod(Derived.prototype);
+
+ new Derived().mSloppy();
+ new Derived().mStrict();
+}());
+
+
+(function TestKeyedNumericSetterNoProtoWalk() {
+ var x = 42;
+ function Base() {}
+ function Derived() {}
+ var getCalled;
+ var setCalled;
+ Derived.prototype = {
+ __proto__ : Base.prototype,
+ };
+
+ Object.defineProperty(Derived.prototype, x, {
+ get: function() { getCalled++; return 42; },
+ set: function(v) { setCalled++; }
+ });
+
Derived.prototype.mSloppy = function() {
setCalled = 0;
getCalled = 0;
@@ -1053,17 +1412,19 @@
var nonEnumNonConfig = 'nonEnumNonConfig';
function Base() {}
function Derived() {}
+
+ Derived.prototype = { __proto__: Base.prototype };
Derived.prototype.mStrict = function (){
'use strict';
super[nonEnumConfig] = 5;
- var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig');
+ var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
assertEquals(5, d1.value);
assertTrue(d1.configurable);
assertFalse(d1.enumerable);
super[nonEnumNonConfig] = 5;
- var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig');
+ var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
assertEquals(5, d1.value);
assertFalse(d1.configurable);
assertFalse(d1.enumerable);
@@ -1071,27 +1432,74 @@
Derived.prototype.mSloppy = function (){
super[nonEnumConfig] = 42;
- var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumConfig');
+ var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
assertEquals(42, d1.value);
assertTrue(d1.configurable);
assertFalse(d1.enumerable);
super[nonEnumNonConfig] = 42;
- var d1 = Object.getOwnPropertyDescriptor(this, 'nonEnumNonConfig');
+ var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
assertEquals(42, d1.value);
assertFalse(d1.configurable);
assertFalse(d1.enumerable);
}.toMethod(Derived.prototype);
var d = new Derived();
- Object.defineProperty(d, 'nonEnumConfig',
+ Object.defineProperty(d, nonEnumConfig,
{ value : 0, enumerable : false, configurable : true, writable :
true });
- Object.defineProperty(d, 'nonEnumNonConfig',
+ Object.defineProperty(d, nonEnumNonConfig,
{ value : 0, enumerable : false, configurable : false, writable :
true });
d.mStrict();
d.mSloppy();
}());
+
+(function TestKeyedNumericSetterDoesNotReconfigure() {
+ var nonEnumConfig = 42;
+ var nonEnumNonConfig = 43;
+ function Base() {}
+ function Derived() {}
+
+ Derived.prototype = { __proto__: Base.prototype };
+
+ Derived.prototype.mStrict = function (){
+ 'use strict';
+ super[nonEnumConfig] = 5;
+ var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
+ assertEquals(5, d1.value);
+ assertTrue(d1.configurable);
+ assertFalse(d1.enumerable);
+
+ super[nonEnumNonConfig] = 5;
+ var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
+ assertEquals(5, d1.value);
+ assertFalse(d1.configurable);
+ assertFalse(d1.enumerable);
+ }.toMethod(Derived.prototype);
+
+ Derived.prototype.mSloppy = function (){
+ super[nonEnumConfig] = 42;
+ var d1 = Object.getOwnPropertyDescriptor(this, nonEnumConfig);
+ assertEquals(42, d1.value);
+ assertTrue(d1.configurable);
+ assertFalse(d1.enumerable);
+
+ super[nonEnumNonConfig] = 42;
+ var d1 = Object.getOwnPropertyDescriptor(this, nonEnumNonConfig);
+ assertEquals(42, d1.value);
+ assertFalse(d1.configurable);
+ assertFalse(d1.enumerable);
+ }.toMethod(Derived.prototype);
+
+ var d = new Derived();
+ Object.defineProperty(d, nonEnumConfig,
+ { value : 0, enumerable : false, configurable : true, writable :
true });
+ Object.defineProperty(d, nonEnumNonConfig,
+ { value : 0, enumerable : false, configurable : false, writable :
true });
+ d.mStrict();
+ d.mSloppy();
+}());
+
(function TestCountOperations() {
function Base() {}
@@ -1190,6 +1598,143 @@
}());
+(function TestKeyedNumericCountOperations() {
+ var x = 42;
+ function Base() {}
+ Base.prototype = {
+ constructor: Base,
+ _x: 1
+ };
+
+ Object.defineProperty(Base.prototype, x, {
+ get: function() { return this._x; },
+ set: function(v) { this._x = v;; }
+ });
+
+ function Derived() {}
+ Derived.__proto__ = Base;
+ Derived.prototype = {
+ __proto__: Base.prototype,
+ constructor: Derived,
+ _x: 2
+ };
+
+ Derived.prototype.testCounts = function() {
+ assertEquals(2, this._x);
+ assertEquals(2, super[x]);
+ super[x]++;
+ assertEquals(3, super[x]);
+ ++super[x];
+ assertEquals(4, super[x]);
+ assertEquals(4, super[x]++);
+ assertEquals(5, super[x]);
+ assertEquals(6, ++super[x]);
+ assertEquals(6, super[x]);
+ assertEquals(6, this._x);
+
+ super[x]--;
+ assertEquals(5, super[x]);
+ --super[x];
+ assertEquals(4, super[x]);
+ assertEquals(4, super[x]--);
+ assertEquals(3, super[x]);
+ assertEquals(2, --super[x]);
+ assertEquals(2, super[x]);
+ assertEquals(2, this._x);
+ }.toMethod(Derived.prototype);
+ new Derived().testCounts();
+}());
+
+
+(function TestSetterSuperNonWritable() {
+ function Base() {}
+ Object.defineProperty(Base.prototype, 'x', { value : 27, writable: false
});
+ function Derived() {}
+
+ Derived.prototype = { __proto__: Base.prototype, constructor: Derived };
+
+ Derived.prototype.mSloppy = function() {
+ assertEquals(27, super.x);
+ assertEquals(27, this.x);
+ super.x = 10;
+ assertEquals(27, super.x);
+ assertEquals(27, this.x);
+ }.toMethod(Derived.prototype);
+ Derived.prototype.mStrict = function() {
+ 'use strict';
+ assertEquals(27, super.x);
+ assertEquals(27, this.x);
+ var ex = null;
+ try { super.x = 10; } catch(e) { ex = e; }
+ assertTrue(ex instanceof TypeError);
+ assertEquals(27, super.x);
+ assertEquals(27, this.x);
+ }.toMethod(Derived.prototype);
+ new Derived().mSloppy();
+ new Derived().mStrict();
+}());
+
+
+(function TestSetterKeyedSuperNonWritable() {
+ var x = 'xyz';
+ function Base() {}
+ Object.defineProperty(Base.prototype, x, { value : 27, writable: false
});
+ function Derived() {}
+
+ Derived.prototype = { __proto__: Base.prototype, constructor: Derived };
+
+ Derived.prototype.mSloppy = function() {
+ assertEquals(27, super[x]);
+ assertEquals(27, this[x]);
+ super[x] = 10;
+ assertEquals(27, super[x]);
+ assertEquals(27, this[x]);
+ }.toMethod(Derived.prototype);
+ Derived.prototype.mStrict = function() {
+ 'use strict';
+ assertEquals(27, super[x]);
+ assertEquals(27, this[x]);
+ var ex = null;
+ try { super[x] = 10; } catch(e) { ex = e; }
+ assertTrue(ex instanceof TypeError);
+ assertEquals(27, super[x]);
+ assertEquals(27, this[x]);
+ }.toMethod(Derived.prototype);
+ new Derived().mSloppy();
+ new Derived().mStrict();
+}());
+
+
+(function TestSetterKeyedNumericSuperNonWritable() {
+ var x = 42;
+ function Base() {}
+ Object.defineProperty(Base.prototype, x, { value : 27, writable: false
});
+ function Derived() {}
+
+ Derived.prototype = { __proto__: Base.prototype, constructor: Derived };
+
+ Derived.prototype.mSloppy = function() {
+ assertEquals(27, super[x]);
+ assertEquals(27, this[x]);
+ super[x] = 10;
+ assertEquals(27, super[x]);
+ assertEquals(27, this[x]);
+ }.toMethod(Derived.prototype);
+ Derived.prototype.mStrict = function() {
+ 'use strict';
+ assertEquals(27, super[x]);
+ assertEquals(27, this[x]);
+ var ex = null;
+ try { super[x] = 10; } catch(e) { ex = e; }
+ assertTrue(ex instanceof TypeError);
+ assertEquals(27, super[x]);
+ assertEquals(27, this[x]);
+ }.toMethod(Derived.prototype);
+ new Derived().mSloppy();
+ new Derived().mStrict();
+}());
+
+
(function TestSuperCall() {
function Subclass(base, constructor) {
var homeObject = {
@@ -1284,10 +1829,3 @@
// Filed https://bugs.ecmascript.org/show_bug.cgi?id=3282
assertThrows(function() { new T(); }, TypeError);
}());
-
-
-(function TestUnsupportedCases() {
- function f(x) { super[x] = 5; }
- var o = {};
- assertThrows(function(){f.toMethod(o)(15);}, ReferenceError);
-}());
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.