Object.oberve: assertions to narrow down flaky crashes with array length mutation.

R=mstarzinger@chromium.org
BUG=v8:2409

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13221 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
rossberg@chromium.org 2012-12-14 14:19:18 +00:00
parent 1aed997ad6
commit 1080d2aade
5 changed files with 39 additions and 22 deletions

View File

@ -311,6 +311,9 @@ void Map::MapVerify() {
SLOW_ASSERT(transitions()->IsSortedNoDuplicates());
SLOW_ASSERT(transitions()->IsConsistentWithBackPointers(this));
}
ASSERT(!is_observed() || instance_type() < FIRST_JS_OBJECT_TYPE ||
instance_type() > LAST_JS_OBJECT_TYPE ||
has_slow_elements_kind() || has_external_array_elements());
}

View File

@ -1416,23 +1416,29 @@ void JSObject::initialize_elements() {
MaybeObject* JSObject::ResetElements() {
Object* obj;
if (map()->is_observed()) {
// Maintain invariant that observed elements are always in dictionary mode.
SeededNumberDictionary* dictionary;
MaybeObject* maybe = SeededNumberDictionary::Allocate(0);
if (!maybe->To(&dictionary)) return maybe;
if (map() == GetHeap()->non_strict_arguments_elements_map()) {
FixedArray::cast(elements())->set(1, dictionary);
} else {
set_elements(dictionary);
}
return this;
}
ElementsKind elements_kind = GetInitialFastElementsKind();
if (!FLAG_smi_only_arrays) {
elements_kind = FastSmiToObjectElementsKind(elements_kind);
}
MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
elements_kind);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
set_map(Map::cast(obj));
MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), elements_kind);
Map* map;
if (!maybe->To(&map)) return maybe;
set_map(map);
initialize_elements();
if (FLAG_harmony_observation && map()->is_observed()) {
// Maintain invariant that observed elements are always in dictionary mode.
// For this to work on arrays, we have to make sure to reset length first.
if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(0));
maybe_obj = NormalizeElements();
if (maybe_obj->IsFailure()) return maybe_obj;
}
return this;
}
@ -3362,6 +3368,9 @@ bool Map::owns_descriptors() {
void Map::set_is_observed(bool is_observed) {
ASSERT(instance_type() < FIRST_JS_OBJECT_TYPE ||
instance_type() > LAST_JS_OBJECT_TYPE ||
has_slow_elements_kind() || has_external_array_elements());
set_bit_field3(IsObserved::update(bit_field3(), is_observed));
}

View File

@ -4764,6 +4764,10 @@ class Map: public HeapObject {
inline void set_elements_kind(ElementsKind elements_kind) {
ASSERT(elements_kind < kElementsKindCount);
ASSERT(kElementsKindCount <= (1 << kElementsKindBitCount));
ASSERT(!is_observed() ||
elements_kind == DICTIONARY_ELEMENTS ||
elements_kind == NON_STRICT_ARGUMENTS_ELEMENTS ||
IsExternalArrayElementsKind(elements_kind));
set_bit_field2((bit_field2() & ~kElementsKindMask) |
(elements_kind << kElementsKindShift));
ASSERT(this->elements_kind() == elements_kind);

View File

@ -4376,6 +4376,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
Handle<Object> object = args.at<Object>(0);
if (object->IsJSObject()) {
Handle<JSObject> js_object(Handle<JSObject>::cast(object));
ASSERT(!js_object->map()->is_observed());
ElementsKind new_kind = js_object->HasFastHoleyElements()
? FAST_HOLEY_DOUBLE_ELEMENTS
: FAST_DOUBLE_ELEMENTS;
@ -4392,6 +4393,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
Handle<Object> object = args.at<Object>(0);
if (object->IsJSObject()) {
Handle<JSObject> js_object(Handle<JSObject>::cast(object));
ASSERT(!js_object->map()->is_observed());
ElementsKind new_kind = js_object->HasFastHoleyElements()
? FAST_HOLEY_ELEMENTS
: FAST_ELEMENTS;
@ -13487,19 +13489,21 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetIsObserved) {
ASSERT(proto->IsJSGlobalObject());
obj = JSReceiver::cast(proto);
}
ASSERT(!(obj->map()->is_observed() && obj->IsJSObject() &&
JSObject::cast(obj)->HasFastElements()));
if (obj->map()->is_observed() != is_observed) {
if (is_observed && obj->IsJSObject() &&
!JSObject::cast(obj)->HasExternalArrayElements()) {
// Go to dictionary mode, so that we don't skip map checks.
MaybeObject* maybe = JSObject::cast(obj)->NormalizeElements();
if (maybe->IsFailure()) return maybe;
ASSERT(!JSObject::cast(obj)->HasFastElements());
}
MaybeObject* maybe = obj->map()->Copy();
Map* map;
if (!maybe->To(&map)) return maybe;
map->set_is_observed(is_observed);
obj->set_map(map);
if (is_observed && obj->IsJSObject() &&
!JSObject::cast(obj)->HasExternalArrayElements()) {
// Go to dictionary mode, so that we don't skip map checks.
maybe = JSObject::cast(obj)->NormalizeElements();
if (maybe->IsFailure()) return maybe;
ASSERT(!JSObject::cast(obj)->HasFastElements());
}
}
return isolate->heap()->undefined_value();
}

View File

@ -943,11 +943,8 @@ function TestFastElementsLength(polymorphic, optimize, oldSize, newSize) {
}
}
// TODO(rossberg): Still flaky on buildbots, disable for now...
/*
for (var b1 = 0; b1 < 2; ++b1)
for (var b2 = 0; b2 < 2; ++b2)
for (var n1 = 0; n1 < 3; ++n1)
for (var n2 = 0; n2 < 3; ++n2)
TestFastElementsLength(b1 != 0, b2 != 0, 20*n1, 20*n2);
*/