Commit 047b4bfb authored by verwaest's avatar verwaest Committed by Commit bot

Fix non-standard element handling

BUG=

Review URL: https://codereview.chromium.org/1228113003

Cr-Commit-Position: refs/heads/master@{#29677}
parent a9c7712e
......@@ -950,7 +950,7 @@ class DictionaryElementsAccessor
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(),
......@@ -969,7 +969,7 @@ class DictionaryElementsAccessor
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);
}
......@@ -1614,7 +1614,7 @@ class SlowSloppyArgumentsElementsAccessor
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);
}
......@@ -1647,6 +1647,10 @@ class SlowSloppyArgumentsElementsAccessor
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(
......
......@@ -318,16 +318,12 @@ void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
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());
......@@ -338,7 +334,6 @@ void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
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()
......
......@@ -4789,6 +4789,16 @@ static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
}
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() &&
......@@ -5430,7 +5440,7 @@ MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
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.
......@@ -5603,7 +5613,7 @@ MaybeHandle<Object> JSObject::PreventExtensionsWithTransition(
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);
}
......@@ -6224,11 +6234,20 @@ bool Map::DictionaryElementsInPrototypeChainOnly() {
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;
......@@ -14663,6 +14682,8 @@ void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
// 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;
}
......
......@@ -2102,6 +2102,8 @@ class JSObject: public JSReceiver {
static Handle<SeededNumberDictionary> NormalizeElements(
Handle<JSObject> object);
void RequireSlowElements(SeededNumberDictionary* dictionary);
// Transform slow named properties to fast variants.
static void MigrateSlowToFast(Handle<JSObject> object,
int unused_property_fields, const char* reason);
......
// 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]);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment