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

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 explicit IntrusiveMapTransitionIterator(
Michael Starzinger 2014/04/03 13:07:37 nit: Doesn't need to be "explicit" any longer.
Hannes Payer (out of office) 2014/04/03 20:01:35 Done.
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 *IteratorField() = Smi::FromInt(-1);
Michael Starzinger 2014/04/03 13:07:37 Can we ASSERT(*IteratorField() == constructor_) he
Hannes Payer (out of office) 2014/04/03 20:01:35 Done.
7261 }
7255 } 7262 }
7256 7263
7257 bool IsIterating() { 7264 bool IsIterating() {
7258 return (*TransitionArrayHeader())->IsSmi(); 7265 return (*IteratorField())->IsSmi() &&
7266 Smi::cast(*IteratorField())->value() < 0;
7259 } 7267 }
7260 7268
7261 Map* Next() { 7269 Map* Next() {
7262 ASSERT(IsIterating()); 7270 ASSERT(IsIterating());
7263 int index = Smi::cast(*TransitionArrayHeader())->value(); 7271 int value = Smi::cast(*IteratorField())->value();
7272 int index = (value * -1) - 1;
Michael Starzinger 2014/04/03 13:07:37 nit: Would "-value - 1" be easier to read?
Hannes Payer (out of office) 2014/04/03 20:01:35 Done.
7264 int number_of_transitions = transition_array_->number_of_transitions(); 7273 int number_of_transitions = transition_array_->number_of_transitions();
7265 while (index < number_of_transitions) { 7274 while (index < number_of_transitions) {
7266 *TransitionArrayHeader() = Smi::FromInt(index + 1); 7275 *IteratorField() = Smi::FromInt(value - 1);
7267 return transition_array_->GetTarget(index); 7276 return transition_array_->GetTarget(index);
7268 } 7277 }
7269 7278
7270 *TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map(); 7279 *IteratorField() = constructor_;
7271 return NULL; 7280 return NULL;
7272 } 7281 }
7273 7282
7274 private: 7283 private:
7275 Object** TransitionArrayHeader() { 7284 Object** IteratorField() {
7276 return HeapObject::RawField(transition_array_, TransitionArray::kMapOffset); 7285 return HeapObject::RawField(map_, Map::kConstructorOffset);
7277 } 7286 }
7278 7287
7288 Map* map_;
7279 TransitionArray* transition_array_; 7289 TransitionArray* transition_array_;
7290 Object* constructor_;
7280 }; 7291 };
7281 7292
7282 7293
7283 // An iterator over all prototype transitions, reusing the map field of the 7294 // An iterator over all prototype transitions, reusing the constructor field
7284 // underlying array while it is running. 7295 // of map while it is running. Positive values in the constructor field
Michael Starzinger 2014/04/03 13:07:37 nit: s/of map/of the map/
Hannes Payer (out of office) 2014/04/03 20:01:35 Done.
7296 // indicate an active prototype transition iteration. The original constructor
7297 // is restored after iterating over all entries.
7285 class IntrusivePrototypeTransitionIterator { 7298 class IntrusivePrototypeTransitionIterator {
7286 public: 7299 public:
7287 explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans) 7300 explicit IntrusivePrototypeTransitionIterator(
Michael Starzinger 2014/04/03 13:07:37 nit: Doesn't need to be "explicit" any longer.
Hannes Payer (out of office) 2014/04/03 20:01:35 Done.
7288 : proto_trans_(proto_trans) { } 7301 Map* map, HeapObject* proto_trans, Object* constructor)
7302 : map_(map), proto_trans_(proto_trans), constructor_(constructor) { }
7289 7303
7290 void Start() { 7304 void Start() {
7291 ASSERT(!IsIterating()); 7305 ASSERT(!IsIterating());
7292 *Header() = Smi::FromInt(0); 7306 *IteratorField() = Smi::FromInt(0);
Michael Starzinger 2014/04/03 13:07:37 Can we ASSERT(*IteratorField() == constructor_) he
Hannes Payer (out of office) 2014/04/03 20:01:35 Done.
7293 } 7307 }
7294 7308
7295 bool IsIterating() { 7309 bool IsIterating() {
7296 return (*Header())->IsSmi(); 7310 return (*IteratorField())->IsSmi() &&
7311 Smi::cast(*IteratorField())->value() >= 0;
7297 } 7312 }
7298 7313
7299 Map* Next() { 7314 Map* Next() {
7300 ASSERT(IsIterating()); 7315 ASSERT(IsIterating());
7301 int transitionNumber = Smi::cast(*Header())->value(); 7316 int transitionNumber = Smi::cast(*IteratorField())->value();
7302 if (transitionNumber < NumberOfTransitions()) { 7317 if (transitionNumber < NumberOfTransitions()) {
7303 *Header() = Smi::FromInt(transitionNumber + 1); 7318 *IteratorField() = Smi::FromInt(transitionNumber + 1);
7304 return GetTransition(transitionNumber); 7319 return GetTransition(transitionNumber);
7305 } 7320 }
7306 *Header() = proto_trans_->GetHeap()->fixed_array_map(); 7321 *IteratorField() = constructor_;
7307 return NULL; 7322 return NULL;
7308 } 7323 }
7309 7324
7310 private: 7325 private:
7311 Object** Header() { 7326 Object** IteratorField() {
7312 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset); 7327 return HeapObject::RawField(map_, Map::kConstructorOffset);
7313 } 7328 }
7314 7329
7315 int NumberOfTransitions() { 7330 int NumberOfTransitions() {
7316 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_); 7331 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7317 Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset); 7332 Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
7318 return Smi::cast(num)->value(); 7333 return Smi::cast(num)->value();
7319 } 7334 }
7320 7335
7321 Map* GetTransition(int transitionNumber) { 7336 Map* GetTransition(int transitionNumber) {
7322 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_); 7337 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7323 return Map::cast(proto_trans->get(IndexFor(transitionNumber))); 7338 return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
7324 } 7339 }
7325 7340
7326 int IndexFor(int transitionNumber) { 7341 int IndexFor(int transitionNumber) {
7327 return Map::kProtoTransitionHeaderSize + 7342 return Map::kProtoTransitionHeaderSize +
7328 Map::kProtoTransitionMapOffset + 7343 Map::kProtoTransitionMapOffset +
7329 transitionNumber * Map::kProtoTransitionElementsPerEntry; 7344 transitionNumber * Map::kProtoTransitionElementsPerEntry;
7330 } 7345 }
7331 7346
7347 Map* map_;
7332 HeapObject* proto_trans_; 7348 HeapObject* proto_trans_;
7349 Object* constructor_;
7333 }; 7350 };
7334 7351
7335 7352
7336 // To traverse the transition tree iteratively, we have to store two kinds of 7353 // 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 7354 // 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 7355 // node have already been visited. To do this without additional memory, we
7339 // temporarily reuse two maps with known values: 7356 // temporarily reuse two fields with known values:
7340 // 7357 //
7341 // (1) The map of the map temporarily holds the parent, and is restored to the 7358 // (1) The map of the map temporarily holds the parent, and is restored to the
7342 // meta map afterwards. 7359 // meta map afterwards.
7343 // 7360 //
7344 // (2) The info which children have already been visited depends on which part 7361 // (2) The info which children have already been visited depends on which part
7345 // of the map we currently iterate: 7362 // of the map we currently iterate. We use the constructor field of the
7363 // map to store the current index. We can do that because the constructor
7364 // is the same for all involved maps.
7346 // 7365 //
7347 // (a) If we currently follow normal map transitions, we temporarily store 7366 // (a) If we currently follow normal map transitions, we temporarily store
7348 // the current index in the map of the FixedArray of the desciptor 7367 // 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. 7368 // original constructor afterwards. Note that a single descriptor can
7350 // Note that a single descriptor can have 0, 1, or 2 transitions. 7369 // have 0, 1, or 2 transitions.
7351 // 7370 //
7352 // (b) If we currently follow prototype transitions, we temporarily store 7371 // (b) If we currently follow prototype transitions, we temporarily store
7353 // the current index in the map of the FixedArray holding the prototype 7372 // the current index in the constructor field, and restore it to the
7354 // transitions, and restore it to the fixed array map afterwards. 7373 // original constructor afterwards.
7355 // 7374 //
7356 // Note that the child iterator is just a concatenation of two iterators: One 7375 // Note that the child iterator is just a concatenation of two iterators: One
7357 // iterating over map transitions and one iterating over prototype transisitons. 7376 // iterating over map transitions and one iterating over prototype transisitons.
7358 class TraversableMap : public Map { 7377 class TraversableMap : public Map {
7359 public: 7378 public:
7360 // Record the parent in the traversal within this map. Note that this destroys 7379 // Record the parent in the traversal within this map. Note that this destroys
7361 // this map's map! 7380 // this map's map!
7362 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); } 7381 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
7363 7382
7364 // Reset the current map's map, returning the parent previously stored in it. 7383 // Reset the current map's map, returning the parent previously stored in it.
7365 TraversableMap* GetAndResetParent() { 7384 TraversableMap* GetAndResetParent() {
7366 TraversableMap* old_parent = static_cast<TraversableMap*>(map()); 7385 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
7367 set_map_no_write_barrier(GetHeap()->meta_map()); 7386 set_map_no_write_barrier(GetHeap()->meta_map());
7368 return old_parent; 7387 return old_parent;
7369 } 7388 }
7370 7389
7371 // Start iterating over this map's children, possibly destroying a FixedArray 7390 // Start iterating over this map's children, possibly overwritting the
7372 // map (see explanation above). 7391 // constructor field of the map.
7373 void ChildIteratorStart() { 7392 void ChildIteratorStart(Object* constructor) {
Michael Starzinger 2014/04/03 13:07:37 It might make it more uniform to to get rid of the
Hannes Payer (out of office) 2014/04/03 20:01:35 Done. That is an awesome comment, thanks! Note tha
7374 if (HasTransitionArray()) { 7393 if (HasTransitionArray()) {
7375 if (HasPrototypeTransitions()) { 7394 if (HasPrototypeTransitions()) {
7376 IntrusivePrototypeTransitionIterator(GetPrototypeTransitions()).Start(); 7395 // We start the iterator for prototype transitions here. The map
7396 // transition iterator is started in ChildIteratorNext, after finishing
7397 // the prototype transitions (if such exist).
7398 IntrusivePrototypeTransitionIterator(this,
7399 GetPrototypeTransitions(),
7400 constructor).Start();
7377 } 7401 }
7378
7379 IntrusiveMapTransitionIterator(transitions()).Start();
7380 } 7402 }
7381 } 7403 }
7382 7404
7383 // If we have an unvisited child map, return that one and advance. If we have 7405 // 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. 7406 // none, return NULL and restore the overwritten constructor field.
7385 TraversableMap* ChildIteratorNext() { 7407 TraversableMap* ChildIteratorNext(Object* constructor) {
7386 TransitionArray* transition_array = unchecked_transition_array(); 7408 if (!HasTransitionArray()) return NULL;
7387 if (!transition_array->map()->IsSmi() &&
7388 !transition_array->IsTransitionArray()) {
7389 return NULL;
7390 }
7391 7409
7410 TransitionArray* transition_array = transitions();
7392 if (transition_array->HasPrototypeTransitions()) { 7411 if (transition_array->HasPrototypeTransitions()) {
7393 HeapObject* proto_transitions = 7412 HeapObject* proto_transitions =
7394 transition_array->UncheckedPrototypeTransitions(); 7413 transition_array->GetPrototypeTransitions();
7395 IntrusivePrototypeTransitionIterator proto_iterator(proto_transitions); 7414 IntrusivePrototypeTransitionIterator proto_iterator(this,
7415 proto_transitions,
7416 constructor);
7396 if (proto_iterator.IsIterating()) { 7417 if (proto_iterator.IsIterating()) {
7397 Map* next = proto_iterator.Next(); 7418 Map* next = proto_iterator.Next();
7398 if (next != NULL) return static_cast<TraversableMap*>(next); 7419 if (next != NULL) return static_cast<TraversableMap*>(next);
7399 } 7420 }
7400 } 7421 }
7401 7422
7402 IntrusiveMapTransitionIterator transition_iterator(transition_array); 7423 IntrusiveMapTransitionIterator transition_iterator(this,
7424 transition_array,
7425 constructor);
7426 transition_iterator.StartIfNotStarted();
7403 if (transition_iterator.IsIterating()) { 7427 if (transition_iterator.IsIterating()) {
7404 Map* next = transition_iterator.Next(); 7428 Map* next = transition_iterator.Next();
7405 if (next != NULL) return static_cast<TraversableMap*>(next); 7429 if (next != NULL) return static_cast<TraversableMap*>(next);
7406 } 7430 }
7407 7431
7408 return NULL; 7432 return NULL;
7409 } 7433 }
7410 }; 7434 };
7411 7435
7412 7436
7413 // Traverse the transition tree in postorder without using the C++ stack by 7437 // Traverse the transition tree in postorder without using the C++ stack by
7414 // doing pointer reversal. 7438 // doing pointer reversal.
7415 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) { 7439 void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
7416 TraversableMap* current = static_cast<TraversableMap*>(this); 7440 TraversableMap* current = static_cast<TraversableMap*>(this);
7417 current->ChildIteratorStart(); 7441 // Get the root constructor here to restore it later when finished iterating
7442 // over maps.
7443 Object* root_constructor = constructor();
7444 current->ChildIteratorStart(root_constructor);
7418 while (true) { 7445 while (true) {
7419 TraversableMap* child = current->ChildIteratorNext(); 7446 TraversableMap* child = current->ChildIteratorNext(root_constructor);
7420 if (child != NULL) { 7447 if (child != NULL) {
7421 child->ChildIteratorStart(); 7448 child->ChildIteratorStart(root_constructor);
7422 child->SetParent(current); 7449 child->SetParent(current);
7423 current = child; 7450 current = child;
7424 } else { 7451 } else {
7425 TraversableMap* parent = current->GetAndResetParent(); 7452 TraversableMap* parent = current->GetAndResetParent();
7426 callback(current, data); 7453 callback(current, data);
7427 if (current == this) break; 7454 if (current == this) break;
7428 current = parent; 7455 current = parent;
7429 } 7456 }
7430 } 7457 }
7431 } 7458 }
(...skipping 9047 matching lines...) Expand 10 before | Expand all | Expand 10 after
16479 #define ERROR_MESSAGES_TEXTS(C, T) T, 16506 #define ERROR_MESSAGES_TEXTS(C, T) T,
16480 static const char* error_messages_[] = { 16507 static const char* error_messages_[] = {
16481 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS) 16508 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS)
16482 }; 16509 };
16483 #undef ERROR_MESSAGES_TEXTS 16510 #undef ERROR_MESSAGES_TEXTS
16484 return error_messages_[reason]; 16511 return error_messages_[reason];
16485 } 16512 }
16486 16513
16487 16514
16488 } } // namespace v8::internal 16515 } } // 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