Bugfix: A TransitionArray can disappear during copy.

During handlification of TransitionArray code, an error was introduced
in TransitionArray::CopyInsert because after creating a copy of a
TransitionArray, it may be that the array disappears during GC
because it is modified during the marking of the owning map.

R=verwaest@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20654 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mvstanton@chromium.org 2014-04-10 13:06:52 +00:00
parent f4cce54313
commit 8aa93f2443
4 changed files with 47 additions and 43 deletions

View File

@ -2375,7 +2375,7 @@ bool Map::InstancesNeedRewriting(Map* target,
Handle<TransitionArray> Map::SetElementsTransitionMap(
Handle<Map> map, Handle<Map> transitioned_map) {
Handle<TransitionArray> transitions = Map::AddTransition(
Handle<TransitionArray> transitions = TransitionArray::CopyInsert(
map,
map->GetIsolate()->factory()->elements_transition_symbol(),
transitioned_map,
@ -2505,18 +2505,6 @@ void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
}
Handle<TransitionArray> Map::AddTransition(Handle<Map> map,
Handle<Name> key,
Handle<Map> target,
SimpleTransitionFlag flag) {
if (map->HasTransitionArray()) {
return TransitionArray::CopyInsert(map, key, target);
}
return TransitionArray::NewWith(
flag, key, target, handle(map->GetBackPointer(), map->GetIsolate()));
}
void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object,
int modify_index,
Representation new_representation,
@ -6875,7 +6863,7 @@ Handle<Map> Map::ShareDescriptor(Handle<Map> map,
Handle<Map> result = Map::CopyDropDescriptors(map);
Handle<Name> name = descriptor->GetKey();
Handle<TransitionArray> transitions =
Map::AddTransition(map, name, result, SIMPLE_TRANSITION);
TransitionArray::CopyInsert(map, name, result, SIMPLE_TRANSITION);
// Ensure there's space for the new descriptor in the shared descriptor array.
if (descriptors->NumberOfSlackDescriptors() == 0) {
@ -6924,7 +6912,7 @@ Handle<Map> Map::CopyReplaceDescriptors(Handle<Map> map,
result->InitializeDescriptors(*descriptors);
if (flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()) {
Handle<TransitionArray> transitions = Map::AddTransition(
Handle<TransitionArray> transitions = TransitionArray::CopyInsert(
map, name, result, simple_flag);
map->set_transitions(*transitions);
result->SetBackPointer(*map);
@ -6960,8 +6948,8 @@ Handle<Map> Map::CopyInstallDescriptors(Handle<Map> map,
result->set_owns_descriptors(false);
Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
Handle<TransitionArray> transitions = Map::AddTransition(map, name, result,
SIMPLE_TRANSITION);
Handle<TransitionArray> transitions = TransitionArray::CopyInsert(
map, name, result, SIMPLE_TRANSITION);
map->set_transitions(*transitions);
result->SetBackPointer(*map);
@ -7032,9 +7020,8 @@ Handle<Map> Map::CopyForObserved(Handle<Map> map) {
new_map = Map::Copy(map);
}
Handle<TransitionArray> transitions =
Map::AddTransition(map, isolate->factory()->observed_symbol(), new_map,
FULL_TRANSITION);
Handle<TransitionArray> transitions = TransitionArray::CopyInsert(
map, isolate->factory()->observed_symbol(), new_map, FULL_TRANSITION);
map->set_transitions(*transitions);

View File

@ -6191,10 +6191,6 @@ class Map: public HeapObject {
inline int SearchTransition(Name* name);
inline FixedArrayBase* GetInitialElements();
static Handle<TransitionArray> AddTransition(Handle<Map> map,
Handle<Name> key,
Handle<Map> target,
SimpleTransitionFlag flag);
DECL_ACCESSORS(transitions, TransitionArray)
inline void ClearTransitions(Heap* heap,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);

View File

@ -80,20 +80,20 @@ static bool InsertionPointFound(Name* key1, Name* key2) {
}
Handle<TransitionArray> TransitionArray::NewWith(SimpleTransitionFlag flag,
Handle<Name> key,
Handle<TransitionArray> TransitionArray::NewWith(Handle<Map> map,
Handle<Name> name,
Handle<Map> target,
Handle<Object> back_pointer) {
SimpleTransitionFlag flag) {
Handle<TransitionArray> result;
Factory* factory = key->GetIsolate()->factory();
Factory* factory = name->GetIsolate()->factory();
if (flag == SIMPLE_TRANSITION) {
result = factory->NewSimpleTransitionArray(target);
} else {
result = factory->NewTransitionArray(1);
result->NoIncrementalWriteBarrierSet(0, *key, *target);
result->NoIncrementalWriteBarrierSet(0, *name, *target);
}
result->set_back_pointer_storage(*back_pointer);
result->set_back_pointer_storage(map->GetBackPointer());
return result;
}
@ -116,9 +116,11 @@ MaybeObject* TransitionArray::ExtendToFullTransitionArray() {
Handle<TransitionArray> TransitionArray::CopyInsert(Handle<Map> map,
Handle<Name> name,
Handle<Map> target) {
ASSERT(map->HasTransitionArray());
Handle<TransitionArray> result;
Handle<Map> target,
SimpleTransitionFlag flag) {
if (!map->HasTransitionArray()) {
return TransitionArray::NewWith(map, name, target, flag);
}
int number_of_transitions = map->transitions()->number_of_transitions();
int new_size = number_of_transitions;
@ -126,12 +128,29 @@ Handle<TransitionArray> TransitionArray::CopyInsert(Handle<Map> map,
int insertion_index = map->transitions()->Search(*name);
if (insertion_index == kNotFound) ++new_size;
result = map->GetIsolate()->factory()->NewTransitionArray(new_size);
Handle<TransitionArray> result =
map->GetIsolate()->factory()->NewTransitionArray(new_size);
// The map's transition array may have grown smaller during the allocation
// above as it was weakly traversed. Trim the result copy if needed, and
// recompute variables.
// The map's transition array may have disappeared or grown smaller during
// the allocation above as it was weakly traversed. Trim the result copy if
// needed, and recompute variables.
DisallowHeapAllocation no_gc;
if (!map->HasTransitionArray()) {
if (flag == SIMPLE_TRANSITION) {
ASSERT(result->length() >= kSimpleTransitionSize);
result->Shrink(kSimpleTransitionSize);
result->set(kSimpleTransitionTarget, *target);
} else {
ASSERT(result->length() >= ToKeyIndex(1));
result->Shrink(ToKeyIndex(1));
result->set(kPrototypeTransitionsIndex, Smi::FromInt(0));
result->NoIncrementalWriteBarrierSet(0, *name, *target);
}
result->set_back_pointer_storage(map->GetBackPointer());
return result;
}
TransitionArray* array = map->transitions();
if (array->number_of_transitions() != number_of_transitions) {
ASSERT(array->number_of_transitions() < number_of_transitions);
@ -142,7 +161,7 @@ Handle<TransitionArray> TransitionArray::CopyInsert(Handle<Map> map,
insertion_index = array->Search(*name);
if (insertion_index == kNotFound) ++new_size;
result->Shrink(new_size);
result->Shrink(ToKeyIndex(new_size));
}
if (array->HasPrototypeTransitions()) {

View File

@ -96,19 +96,21 @@ class TransitionArray: public FixedArray {
inline int number_of_entries() { return number_of_transitions(); }
// Allocate a new transition array with a single entry.
static Handle<TransitionArray> NewWith(SimpleTransitionFlag flag,
Handle<Name> key,
static Handle<TransitionArray> NewWith(Handle<Map> map,
Handle<Name> name,
Handle<Map> target,
Handle<Object> back_pointer);
SimpleTransitionFlag flag);
MUST_USE_RESULT MaybeObject* ExtendToFullTransitionArray();
// Copy the transition array, inserting a new transition.
// Create a transition array, copying from the owning map if it already has
// one, otherwise creating a new one according to flag.
// TODO(verwaest): This should not cause an existing transition to be
// overwritten.
static Handle<TransitionArray> CopyInsert(Handle<Map> map,
Handle<Name> name,
Handle<Map> target);
Handle<Map> target,
SimpleTransitionFlag flag);
// Copy a single transition from the origin array.
inline void NoIncrementalWriteBarrierCopyFrom(TransitionArray* origin,