Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/objects.cc

Issue 223533002: Don't overwrite transition array map while iterating over the transition tree. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 7224 matching lines...) Expand 10 before | Expand all | Expand 10 after
7235 7235
7236 7236
7237 void Map::RemoveFromCodeCache(Name* name, Code* code, int index) { 7237 void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
7238 // No GC is supposed to happen between a call to IndexInCodeCache and 7238 // No GC is supposed to happen between a call to IndexInCodeCache and
7239 // RemoveFromCodeCache so the code cache must be there. 7239 // RemoveFromCodeCache so the code cache must be there.
7240 ASSERT(!code_cache()->IsFixedArray()); 7240 ASSERT(!code_cache()->IsFixedArray());
7241 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index); 7241 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
7242 } 7242 }
7243 7243
7244 7244
7245 // An iterator over all map transitions in an descriptor array, reusing the map 7245 // An iterator over all map transitions in an descriptor array, reusing the
7246 // field of the contens array while it is running. 7246 // constructor field of the map while it is running. Negative values in
7247 // the constructor field indicate an active map transition iteration. The
7248 // original constructor is restored after iterating over all entries.
7247 class IntrusiveMapTransitionIterator { 7249 class IntrusiveMapTransitionIterator {
7248 public: 7250 public:
7249 explicit IntrusiveMapTransitionIterator(TransitionArray* transition_array) 7251 IntrusiveMapTransitionIterator(
7250 : transition_array_(transition_array) { } 7252 Map* map, TransitionArray* transition_array, Object* constructor)
7253 : map_(map),
7254 transition_array_(transition_array),
7255 constructor_(constructor) { }
7251 7256
7252 void Start() { 7257 void StartIfNotStarted() {
7253 ASSERT(!IsIterating()); 7258 ASSERT(!(*IteratorField())->IsSmi() || IsIterating());
7254 *TransitionArrayHeader() = Smi::FromInt(0); 7259 if (!(*IteratorField())->IsSmi()) {
7260 ASSERT(*IteratorField() == constructor_);
7261 *IteratorField() = Smi::FromInt(-1);
7262 }
7255 } 7263 }
7256 7264
7257 bool IsIterating() { 7265 bool IsIterating() {
7258 return (*TransitionArrayHeader())->IsSmi(); 7266 return (*IteratorField())->IsSmi() &&
7267 Smi::cast(*IteratorField())->value() < 0;
7259 } 7268 }
7260 7269
7261 Map* Next() { 7270 Map* Next() {
7262 ASSERT(IsIterating()); 7271 ASSERT(IsIterating());
7263 int index = Smi::cast(*TransitionArrayHeader())->value(); 7272 int value = Smi::cast(*IteratorField())->value();
7273 int index = -value - 1;
7264 int number_of_transitions = transition_array_->number_of_transitions(); 7274 int number_of_transitions = transition_array_->number_of_transitions();
7265 while (index < number_of_transitions) { 7275 while (index < number_of_transitions) {
7266 *TransitionArrayHeader() = Smi::FromInt(index + 1); 7276 *IteratorField() = Smi::FromInt(value - 1);
7267 return transition_array_->GetTarget(index); 7277 return transition_array_->GetTarget(index);
7268 } 7278 }
7269 7279
7270 *TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map(); 7280 *IteratorField() = constructor_;
7271 return NULL; 7281 return NULL;
7272 } 7282 }
7273 7283
7274 private: 7284 private:
7275 Object** TransitionArrayHeader() { 7285 Object** IteratorField() {
7276 return HeapObject::RawField(transition_array_, TransitionArray::kMapOffset); 7286 return HeapObject::RawField(map_, Map::kConstructorOffset);
7277 } 7287 }
7278 7288
7289 Map* map_;
7279 TransitionArray* transition_array_; 7290 TransitionArray* transition_array_;
7291 Object* constructor_;
7280 }; 7292 };
7281 7293
7282 7294
7283 // An iterator over all prototype transitions, reusing the map field of the 7295 // An iterator over all prototype transitions, reusing the constructor field
7284 // underlying array while it is running. 7296 // of the map while it is running. Positive values in the constructor field
7297 // indicate an active prototype transition iteration. The original constructor
7298 // is restored after iterating over all entries.
7285 class IntrusivePrototypeTransitionIterator { 7299 class IntrusivePrototypeTransitionIterator {
7286 public: 7300 public:
7287 explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans) 7301 IntrusivePrototypeTransitionIterator(
7288 : proto_trans_(proto_trans) { } 7302 Map* map, HeapObject* proto_trans, Object* constructor)
7303 : map_(map), proto_trans_(proto_trans), constructor_(constructor) { }
7289 7304
7290 void Start() { 7305 void StartIfNotStarted() {
7291 ASSERT(!IsIterating()); 7306 if (!(*IteratorField())->IsSmi()) {
7292 *Header() = Smi::FromInt(0); 7307 ASSERT(*IteratorField() == constructor_);
7308 *IteratorField() = Smi::FromInt(0);
7309 }
7293 } 7310 }
7294 7311
7295 bool IsIterating() { 7312 bool IsIterating() {
7296 return (*Header())->IsSmi(); 7313 return (*IteratorField())->IsSmi() &&
7314 Smi::cast(*IteratorField())->value() >= 0;
7297 } 7315 }
7298 7316
7299 Map* Next() { 7317 Map* Next() {
7300 ASSERT(IsIterating()); 7318 ASSERT(IsIterating());
7301 int transitionNumber = Smi::cast(*Header())->value(); 7319 int transitionNumber = Smi::cast(*IteratorField())->value();
7302 if (transitionNumber < NumberOfTransitions()) { 7320 if (transitionNumber < NumberOfTransitions()) {
7303 *Header() = Smi::FromInt(transitionNumber + 1); 7321 *IteratorField() = Smi::FromInt(transitionNumber + 1);
7304 return GetTransition(transitionNumber); 7322 return GetTransition(transitionNumber);
7305 } 7323 }
7306 *Header() = proto_trans_->GetHeap()->fixed_array_map(); 7324 *IteratorField() = constructor_;
7307 return NULL; 7325 return NULL;
7308 } 7326 }
7309 7327
7310 private: 7328 private:
7311 Object** Header() { 7329 Object** IteratorField() {
7312 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset); 7330 return HeapObject::RawField(map_, Map::kConstructorOffset);
7313 } 7331 }
7314 7332
7315 int NumberOfTransitions() { 7333 int NumberOfTransitions() {
7316 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_); 7334 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7317 Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset); 7335 Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
7318 return Smi::cast(num)->value(); 7336 return Smi::cast(num)->value();
7319 } 7337 }
7320 7338
7321 Map* GetTransition(int transitionNumber) { 7339 Map* GetTransition(int transitionNumber) {
7322 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_); 7340 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7323 return Map::cast(proto_trans->get(IndexFor(transitionNumber))); 7341 return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
7324 } 7342 }
7325 7343
7326 int IndexFor(int transitionNumber) { 7344 int IndexFor(int transitionNumber) {
7327 return Map::kProtoTransitionHeaderSize + 7345 return Map::kProtoTransitionHeaderSize +
7328 Map::kProtoTransitionMapOffset + 7346 Map::kProtoTransitionMapOffset +
7329 transitionNumber * Map::kProtoTransitionElementsPerEntry; 7347 transitionNumber * Map::kProtoTransitionElementsPerEntry;
7330 } 7348 }
7331 7349
7350 Map* map_;
7332 HeapObject* proto_trans_; 7351 HeapObject* proto_trans_;
7352 Object* constructor_;
7333 }; 7353 };
7334 7354
7335 7355
7336 // To traverse the transition tree iteratively, we have to store two kinds of 7356 // To traverse the transition tree iteratively, we have to store two kinds of
7337 // information in a map: The parent map in the traversal and which children of a 7357 // information in a map: The parent map in the traversal and which children of a
7338 // node have already been visited. To do this without additional memory, we 7358 // node have already been visited. To do this without additional memory, we
7339 // temporarily reuse two maps with known values: 7359 // temporarily reuse two fields with known values:
7340 // 7360 //
7341 // (1) The map of the map temporarily holds the parent, and is restored to the 7361 // (1) The map of the map temporarily holds the parent, and is restored to the
7342 // meta map afterwards. 7362 // meta map afterwards.
7343 // 7363 //
7344 // (2) The info which children have already been visited depends on which part 7364 // (2) The info which children have already been visited depends on which part
7345 // of the map we currently iterate: 7365 // of the map we currently iterate. We use the constructor field of the
7366 // map to store the current index. We can do that because the constructor
7367 // is the same for all involved maps.
7346 // 7368 //
7347 // (a) If we currently follow normal map transitions, we temporarily store 7369 // (a) If we currently follow normal map transitions, we temporarily store
7348 // the current index in the map of the FixedArray of the desciptor 7370 // the current index in the constructor field, and restore it to the
7349 // array's contents, and restore it to the fixed array map afterwards. 7371 // original constructor afterwards. Note that a single descriptor can
7350 // Note that a single descriptor can have 0, 1, or 2 transitions. 7372 // have 0, 1, or 2 transitions.
7351 // 7373 //
7352 // (b) If we currently follow prototype transitions, we temporarily store 7374 // (b) If we currently follow prototype transitions, we temporarily store
7353 // the current index in the map of the FixedArray holding the prototype 7375 // the current index in the constructor field, and restore it to the
7354 // transitions, and restore it to the fixed array map afterwards. 7376 // original constructor afterwards.
7355 // 7377 //
7356 // Note that the child iterator is just a concatenation of two iterators: One 7378 // Note that the child iterator is just a concatenation of two iterators: One
7357 // iterating over map transitions and one iterating over prototype transisitons. 7379 // iterating over map transitions and one iterating over prototype transisitons.
7358 class TraversableMap : public Map { 7380 class TraversableMap : public Map {
7359 public: 7381 public:
7360 // Record the parent in the traversal within this map. Note that this destroys 7382 // Record the parent in the traversal within this map. Note that this destroys
7361 // this map's map! 7383 // this map's map!
7362 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); } 7384 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
7363 7385
7364 // Reset the current map's map, returning the parent previously stored in it. 7386 // Reset the current map's map, returning the parent previously stored in it.
7365 TraversableMap* GetAndResetParent() { 7387 TraversableMap* GetAndResetParent() {
7366 TraversableMap* old_parent = static_cast<TraversableMap*>(map()); 7388 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
7367 set_map_no_write_barrier(GetHeap()->meta_map()); 7389 set_map_no_write_barrier(GetHeap()->meta_map());
7368 return old_parent; 7390 return old_parent;
7369 } 7391 }
7370 7392
7371 // Start iterating over this map's children, possibly destroying a FixedArray 7393 // If we have an unvisited child map, return that one and advance. If we have
7372 // map (see explanation above). 7394 // none, return NULL and restore the overwritten constructor field.
7373 void ChildIteratorStart() { 7395 TraversableMap* ChildIteratorNext(Object* constructor) {
7374 if (HasTransitionArray()) { 7396 if (!HasTransitionArray()) return NULL;
7375 if (HasPrototypeTransitions()) {
7376 IntrusivePrototypeTransitionIterator(GetPrototypeTransitions()).Start();
7377 }
7378 7397
7379 IntrusiveMapTransitionIterator(transitions()).Start(); 7398 TransitionArray* transition_array = transitions();
7380 }
7381 }
7382
7383 // If we have an unvisited child map, return that one and advance. If we have
7384 // none, return NULL and reset any destroyed FixedArray maps.
7385 TraversableMap* ChildIteratorNext() {
7386 TransitionArray* transition_array = unchecked_transition_array();
7387 if (!transition_array->map()->IsSmi() &&
7388 !transition_array->IsTransitionArray()) {
7389 return NULL;
7390 }
7391
7392 if (transition_array->HasPrototypeTransitions()) { 7399 if (transition_array->HasPrototypeTransitions()) {
7393 HeapObject* proto_transitions = 7400 HeapObject* proto_transitions =
7394 transition_array->UncheckedPrototypeTransitions(); 7401 transition_array->GetPrototypeTransitions();
7395 IntrusivePrototypeTransitionIterator proto_iterator(proto_transitions); 7402 IntrusivePrototypeTransitionIterator proto_iterator(this,
7403 proto_transitions,
7404 constructor);
7405 proto_iterator.StartIfNotStarted();
7396 if (proto_iterator.IsIterating()) { 7406 if (proto_iterator.IsIterating()) {
7397 Map* next = proto_iterator.Next(); 7407 Map* next = proto_iterator.Next();
7398 if (next != NULL) return static_cast<TraversableMap*>(next); 7408 if (next != NULL) return static_cast<TraversableMap*>(next);
7399 } 7409 }
7400 } 7410 }
7401 7411
7402 IntrusiveMapTransitionIterator transition_iterator(transition_array); 7412 IntrusiveMapTransitionIterator transition_iterator(this,
7413 transition_array,
7414 constructor);
7415 transition_iterator.StartIfNotStarted();
7403 if (transition_iterator.IsIterating()) { 7416 if (transition_iterator.IsIterating()) {
7404 Map* next = transition_iterator.Next(); 7417 Map* next = transition_iterator.Next();
7405 if (next != NULL) return static_cast<TraversableMap*>(next); 7418 if (next != NULL) return static_cast<TraversableMap*>(next);
7406 } 7419 }
7407 7420
7408 return NULL; 7421 return NULL;
7409 } 7422 }
7410 }; 7423 };
7411 7424
7412 7425
7413 // Traverse the transition tree in postorder without using the C++ stack by 7426 // Traverse the transition tree in postorder without using the C++ stack by
7414 // doing pointer reversal. 7427 // doing pointer reversal.
7415 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { 7428 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
7429 // Make sure that we do not allocate in the callback.
7430 DisallowHeapAllocation no_allocation;
7431
7416 TraversableMap* current = static_cast<TraversableMap*>(this); 7432 TraversableMap* current = static_cast<TraversableMap*>(this);
7417 current->ChildIteratorStart(); 7433 // Get the root constructor here to restore it later when finished iterating
7434 // over maps.
7435 Object* root_constructor = constructor();
7418 while (true) { 7436 while (true) {
7419 TraversableMap* child = current->ChildIteratorNext(); 7437 TraversableMap* child = current->ChildIteratorNext(root_constructor);
7420 if (child != NULL) { 7438 if (child != NULL) {
7421 child->ChildIteratorStart();
7422 child->SetParent(current); 7439 child->SetParent(current);
7423 current = child; 7440 current = child;
7424 } else { 7441 } else {
7425 TraversableMap* parent = current->GetAndResetParent(); 7442 TraversableMap* parent = current->GetAndResetParent();
7426 callback(current, data); 7443 callback(current, data);
7427 if (current == this) break; 7444 if (current == this) break;
7428 current = parent; 7445 current = parent;
7429 } 7446 }
7430 } 7447 }
7431 } 7448 }
(...skipping 9047 matching lines...) Expand 10 before | Expand all | Expand 10 after
16479 #define ERROR_MESSAGES_TEXTS(C, T) T, 16496 #define ERROR_MESSAGES_TEXTS(C, T) T,
16480 static const char* error_messages_[] = { 16497 static const char* error_messages_[] = {
16481 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) 16498 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS)
16482 }; 16499 };
16483 #undef ERROR_MESSAGES_TEXTS 16500 #undef ERROR_MESSAGES_TEXTS
16484 return error_messages_[reason]; 16501 return error_messages_[reason];
16485 } 16502 }
16486 16503
16487 16504
16488 } } // namespace v8::internal 16505 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698