Handle<Object> value,
PropertyAttributes attributes) {
SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
- if (attributes != NONE) dictionary->set_requires_slow_elements();
+ if (attributes != NONE) object->RequireSlowElements(dictionary);
dictionary->ValueAtPut(entry, *value);
PropertyDetails details = dictionary->DetailsAt(entry);
details = PropertyDetails(attributes, DATA, details.dictionary_index(),
Handle<SeededNumberDictionary> new_dictionary =
SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
details);
- if (attributes != NONE) new_dictionary->set_requires_slow_elements();
+ if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
if (dictionary.is_identical_to(new_dictionary)) return;
object->set_elements(*new_dictionary);
}
Handle<SeededNumberDictionary> new_dictionary =
SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
details);
- if (attributes != NONE) new_dictionary->set_requires_slow_elements();
+ if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
if (*dictionary != *new_dictionary) {
FixedArray::cast(object->elements())->set(1, *new_dictionary);
}
SeededNumberDictionary::cast(parameter_map->get(1)));
arguments = SeededNumberDictionary::AddNumberEntry(arguments, entry,
value, details);
+ // If the attributes were NONE, we would have called set rather than
+ // reconfigure.
+ DCHECK_NE(NONE, attributes);
+ object->RequireSlowElements(*arguments);
parameter_map->set(1, *arguments);
} else {
Handle<FixedArrayBase> arguments(
PropertyCellType::kMutable);
if (IsElement()) {
- // TODO(verwaest): Remove this hack once we have a quick way to check the
- // prototype chain in element setters.
// TODO(verwaest): Move code into the element accessor.
- bool was_dictionary = receiver->HasDictionaryElements();
Handle<SeededNumberDictionary> dictionary =
JSObject::NormalizeElements(receiver);
- was_dictionary = was_dictionary && dictionary->requires_slow_elements();
dictionary = SeededNumberDictionary::Set(dictionary, index_, pair, details);
- dictionary->set_requires_slow_elements();
+ receiver->RequireSlowElements(*dictionary);
if (receiver->HasSlowArgumentsElements()) {
FixedArray* parameter_map = FixedArray::cast(receiver->elements());
FixedArray::cast(receiver->elements())->set(1, *dictionary);
} else {
receiver->set_elements(*dictionary);
- if (!was_dictionary) heap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
}
} else {
PropertyNormalizationMode mode = receiver->map()->is_prototype_map()
}
+void JSObject::RequireSlowElements(SeededNumberDictionary* dictionary) {
+ if (dictionary->requires_slow_elements()) return;
+ dictionary->set_requires_slow_elements();
+ // TODO(verwaest): Remove this hack.
+ if (map()->is_prototype_map()) {
+ GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
+ }
+}
+
+
Handle<SeededNumberDictionary> JSObject::NormalizeElements(
Handle<JSObject> object) {
DCHECK(!object->HasExternalArrayElements() &&
DCHECK(object->HasDictionaryElements() || object->HasSlowArgumentsElements());
// Make sure that we never go back to fast case.
- dictionary->set_requires_slow_elements();
+ object->RequireSlowElements(*dictionary);
// Do a map transition, other objects with this map may still
// be extensible.
if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
SeededNumberDictionary* dictionary = object->element_dictionary();
// Make sure we never go back to the fast case
- dictionary->set_requires_slow_elements();
+ object->RequireSlowElements(dictionary);
if (attrs != NONE) {
ApplyAttributesToDictionary(dictionary, attrs);
}
if (iter.GetCurrent()->IsJSProxy()) return true;
// String wrappers have non-configurable, non-writable elements.
if (iter.GetCurrent()->IsStringWrapper()) return true;
+ JSObject* current = JSObject::cast(iter.GetCurrent());
- if (IsDictionaryElementsKind(
- JSObject::cast(iter.GetCurrent())->map()->elements_kind())) {
+ if (current->HasDictionaryElements() &&
+ current->element_dictionary()->requires_slow_elements()) {
return true;
}
+
+ if (current->HasSlowArgumentsElements()) {
+ FixedArray* parameter_map = FixedArray::cast(current->elements());
+ Object* arguments = parameter_map->get(1);
+ if (SeededNumberDictionary::cast(arguments)->requires_slow_elements()) {
+ return true;
+ }
+ }
}
return false;
// Check if this index is high enough that we should require slow
// elements.
if (key > kRequiresSlowElementsLimit) {
+ // TODO(verwaest): Remove this hack.
+ GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
set_requires_slow_elements();
return;
}
--- /dev/null
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function f(a, b, c, d) { return arguments; }
+
+// Ensure non-configurable argument elements stay non-configurable.
+(function () {
+ var args = f(1);
+ Object.defineProperty(args, "0", {value: 10, configurable: false});
+ assertFalse(Object.getOwnPropertyDescriptor(args, "0").configurable);
+ for (var i = 0; i < 10; i++) {
+ args[i] = 1;
+ }
+ assertFalse(Object.getOwnPropertyDescriptor(args, "0").configurable);
+})();
+
+// Ensure read-only properties on the prototype chain cause TypeError.
+
+// Newly added.
+(function () {
+ var o = [];
+ var proto = {};
+ var index = 3;
+ function store(o, i, v) { "use strict"; o[i] = v; };
+ o.__proto__ = proto;
+ for (var i = 0; i < index; i++) {
+ store(o, i, 0);
+ }
+ Object.defineProperty(proto, index, {value: 100, writable: false});
+ assertThrows(function() { store(o, index, 0); });
+ assertEquals(100, o[index]);
+})();
+
+// Reconfigured.
+(function () {
+ var o = [];
+ var proto = {3: 10000};
+ var index = 3;
+ function store(o, i, v) { "use strict"; o[i] = v; };
+ o.__proto__ = proto;
+ for (var i = 0; i < index; i++) {
+ store(o, i, 0);
+ }
+ Object.defineProperty(proto, index, {value: 100, writable: false});
+ assertThrows(function() { store(o, index, 0); });
+ assertEquals(100, o[index]);
+})();
+
+// Newly added to arguments object.
+(function () {
+ var o = [];
+ var proto = f(100);
+ var index = 3;
+ function store(o, i, v) { "use strict"; o[i] = v; };
+ o.__proto__ = proto;
+ for (var i = 0; i < index; i++) {
+ store(o, i, 0);
+ }
+ Object.defineProperty(proto, index, {value: 100, writable: false});
+ assertThrows(function() { store(o, index, 0); });
+ assertEquals(100, o[index]);
+})();
+
+// Reconfigured on to arguments object.
+(function () {
+ var o = [];
+ var proto = f(100, 200, 300, 400);
+ var index = 3;
+ function store(o, i, v) { "use strict"; o[i] = v; };
+ o.__proto__ = proto;
+ for (var i = 0; i < index; i++) {
+ store(o, i, 0);
+ }
+ Object.defineProperty(proto, index, {value: 100, writable: false});
+ assertThrows(function() { store(o, index, 0); });
+ assertEquals(100, o[index]);
+})();
+
+// Extensions prevented object.
+(function () {
+ var o = [];
+ var proto = [0, 1, 2, 3];
+ var index = 3;
+ function store(o, i, v) { "use strict"; o[i] = v; };
+ o.__proto__ = proto;
+ for (var i = 0; i < index; i++) {
+ store(o, i, 0);
+ }
+ Object.preventExtensions(proto);
+ Object.defineProperty(proto, index, {value: 100, writable: false});
+ assertThrows(function() { store(o, index, 0); });
+ assertEquals(100, o[index]);
+})();
+
+// Extensions prevented arguments object.
+(function () {
+ var o = [];
+ var proto = f(100, 200, 300, 400);
+ var index = 3;
+ function store(o, i, v) { "use strict"; o[i] = v; };
+ o.__proto__ = proto;
+ for (var i = 0; i < index; i++) {
+ store(o, i, 0);
+ }
+ Object.preventExtensions(proto);
+ Object.defineProperty(proto, index, {value: 100, writable: false});
+ assertThrows(function() { store(o, index, 0); });
+ assertEquals(100, o[index]);
+})();
+
+// Array with large index.
+(function () {
+ var o = [];
+ var proto = [];
+ var index = 3;
+ function store(o, i, v) { "use strict"; o[i] = v; };
+ o.__proto__ = proto;
+ for (var i = 0; i < index; i++) {
+ store(o, i, 0);
+ }
+ proto[1 << 30] = 1;
+ Object.defineProperty(proto, index, {value: 100, writable: false});
+ assertThrows(function() { store(o, index, 0); });
+ assertEquals(100, o[index]);
+})();
+
+// Frozen object.
+(function () {
+ var o = [];
+ var proto = [0, 1, 2, 3];
+ function store(o, i, v) { "use strict"; o[i] = v; };
+ o.__proto__ = proto;
+ for (var i = 0; i < 3; i++) {
+ store(o, i, 0);
+ }
+ Object.freeze(proto);
+ assertThrows(function() { store(o, 3, 0); });
+ assertEquals(3, o[3]);
+})();
+
+// Frozen arguments object.
+(function () {
+ var o = [];
+ var proto = f(0, 1, 2, 3);
+ function store(o, i, v) { "use strict"; o[i] = v; };
+ o.__proto__ = proto;
+ for (var i = 0; i < 3; i++) {
+ store(o, i, 0);
+ }
+ Object.freeze(proto);
+ assertThrows(function() { store(o, 3, 0); });
+ assertEquals(3, o[3]);
+})();