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

Side by Side Diff: Source/wtf/Vector.h

Issue 189543014: Ensure proper finalization of garbage-collected types. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: rebase and sign error in Vector Created 6 years, 9 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 | « Source/wtf/HashTable.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * 3 *
4 * This library is free software; you can redistribute it and/or 4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public 5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either 6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version. 7 * version 2 of the License, or (at your option) any later version.
8 * 8 *
9 * This library is distributed in the hope that it will be useful, 9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 , m_capacity(0) 306 , m_capacity(0)
307 { 307 {
308 } 308 }
309 309
310 VectorBufferBase(T* buffer, size_t capacity) 310 VectorBufferBase(T* buffer, size_t capacity)
311 : m_buffer(buffer) 311 : m_buffer(buffer)
312 , m_capacity(capacity) 312 , m_capacity(capacity)
313 { 313 {
314 } 314 }
315 315
316 ~VectorBufferBase()
317 {
318 }
319
320 T* m_buffer; 316 T* m_buffer;
321 unsigned m_capacity; 317 unsigned m_capacity;
322 unsigned m_size; 318 unsigned m_size;
323 }; 319 };
324 320
325 template<typename T, size_t inlineCapacity, typename Allocator = DefaultAllo cator> 321 template<typename T, size_t inlineCapacity, typename Allocator = DefaultAllo cator>
326 class VectorBuffer; 322 class VectorBuffer;
327 323
328 template<typename T, typename Allocator> 324 template<typename T, typename Allocator>
329 class VectorBuffer<T, 0, Allocator> : private VectorBufferBase<T, Allocator> { 325 class VectorBuffer<T, 0, Allocator> : private VectorBufferBase<T, Allocator> {
330 private: 326 private:
331 typedef VectorBufferBase<T, Allocator> Base; 327 typedef VectorBufferBase<T, Allocator> Base;
332 public: 328 public:
333 VectorBuffer() 329 VectorBuffer()
334 { 330 {
335 } 331 }
336 332
337 VectorBuffer(size_t capacity) 333 VectorBuffer(size_t capacity)
338 { 334 {
339 // Calling malloc(0) might take a lock and may actually do an 335 // Calling malloc(0) might take a lock and may actually do an
340 // allocation on some systems. 336 // allocation on some systems.
341 if (capacity) 337 if (capacity)
342 allocateBuffer(capacity); 338 allocateBuffer(capacity);
343 } 339 }
344 340
345 ~VectorBuffer()
346 {
347 }
348
349 void destruct() 341 void destruct()
350 { 342 {
351 deallocateBuffer(m_buffer); 343 deallocateBuffer(m_buffer);
352 m_buffer = 0; 344 m_buffer = 0;
353 } 345 }
354 346
355 void deallocateBuffer(T* bufferToDeallocate) 347 void deallocateBuffer(T* bufferToDeallocate)
356 { 348 {
357 Allocator::backingFree(bufferToDeallocate); 349 Allocator::backingFree(bufferToDeallocate);
358 } 350 }
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
400 { 392 {
401 } 393 }
402 394
403 VectorBuffer(size_t capacity) 395 VectorBuffer(size_t capacity)
404 : Base(inlineBuffer(), inlineCapacity) 396 : Base(inlineBuffer(), inlineCapacity)
405 { 397 {
406 if (capacity > inlineCapacity) 398 if (capacity > inlineCapacity)
407 Base::allocateBuffer(capacity); 399 Base::allocateBuffer(capacity);
408 } 400 }
409 401
410 ~VectorBuffer()
411 {
412 }
413
414 void destruct() 402 void destruct()
415 { 403 {
416 deallocateBuffer(m_buffer); 404 deallocateBuffer(m_buffer);
417 m_buffer = 0; 405 m_buffer = 0;
418 } 406 }
419 407
420 NEVER_INLINE void reallyDeallocateBuffer(T* bufferToDeallocate) 408 NEVER_INLINE void reallyDeallocateBuffer(T* bufferToDeallocate)
421 { 409 {
422 Allocator::backingFree(bufferToDeallocate); 410 Allocator::backingFree(bufferToDeallocate);
423 } 411 }
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 using Base::m_buffer; 474 using Base::m_buffer;
487 using Base::m_capacity; 475 using Base::m_capacity;
488 476
489 static const size_t m_inlineBufferSize = inlineCapacity * sizeof(T); 477 static const size_t m_inlineBufferSize = inlineCapacity * sizeof(T);
490 T* inlineBuffer() { return reinterpret_cast_ptr<T*>(m_inlineBuffer.buffe r); } 478 T* inlineBuffer() { return reinterpret_cast_ptr<T*>(m_inlineBuffer.buffe r); }
491 const T* inlineBuffer() const { return reinterpret_cast_ptr<const T*>(m_ inlineBuffer.buffer); } 479 const T* inlineBuffer() const { return reinterpret_cast_ptr<const T*>(m_ inlineBuffer.buffer); }
492 480
493 AlignedBuffer<m_inlineBufferSize, WTF_ALIGN_OF(T)> m_inlineBuffer; 481 AlignedBuffer<m_inlineBufferSize, WTF_ALIGN_OF(T)> m_inlineBuffer;
494 }; 482 };
495 483
484 template<typename T, size_t inlineCapacity, typename Allocator>
485 class Vector;
486
487 // VectorDestructorBase defines the destructor of a vector. This base is use d in order to
488 // completely avoid creating a destructor for a vector that does not need to be destructed.
489 // By doing so, the clang compiler will have correct information about wheth er or not a
490 // vector has a trivial destructor and we use that in a compiler plugin to e nsure the
491 // correctness of non-finalized garbage-collected classes and the use of Vec torTraits::needsDestruction.
492
493 // All non-GC managed vectors needs a destructor. This destructor will simpl y call finalize on the actual vector type.
494 template<typename Derived, typename Elements, bool hasInlineCapacity, bool i sGarbageCollected>
495 class VectorDestructorBase {
496 public:
497 ~VectorDestructorBase() { static_cast<Derived*>(this)->finalize(); }
498 };
499
500 // Heap-allocated vectors with no inlineCapacity never need a destructor.
501 template<typename Derived, typename Elements>
502 class VectorDestructorBase<Derived, Elements, false, true> { };
503
504 // Heap-allocator vectors with inlineCapacity need a destructor if the inlin e elements do.
505 // The use of VectorTraits<Elements>::needsDestruction is delayed until we k now that
506 // inlineCapacity is non-zero to allow classes that recursively refer to the mselves in vector
507 // members. If inlineCapacity is non-zero doing so would have undefined mean ing, so in this
508 // case we can use HeapVectorWithInlineCapacityDestructorBase to define a de structor
509 // depending on the value of VectorTraits<Elements>::needsDestruction.
510 template<typename Derived, bool elementsNeedsDestruction>
511 class HeapVectorWithInlineCapacityDestructorBase;
512
513 template<typename Derived>
514 class HeapVectorWithInlineCapacityDestructorBase<Derived, true> {
515 public:
516 ~HeapVectorWithInlineCapacityDestructorBase() { static_cast<Derived*>(th is)->finalize(); }
517 };
518
519 template<typename Derived>
520 class HeapVectorWithInlineCapacityDestructorBase<Derived, false> { };
521
522 template<typename Derived, typename Elements>
523 class VectorDestructorBase<Derived, Elements, true, true> : public HeapVecto rWithInlineCapacityDestructorBase<Derived, VectorTraits<Elements>::needsDestruct ion> { };
524
496 template<typename T, size_t inlineCapacity = 0, typename Allocator = Default Allocator> 525 template<typename T, size_t inlineCapacity = 0, typename Allocator = Default Allocator>
497 class Vector : private VectorBuffer<T, inlineCapacity, Allocator> { 526 class Vector : private VectorBuffer<T, inlineCapacity, Allocator>, public Ve ctorDestructorBase<Vector<T, inlineCapacity, Allocator>, T, (inlineCapacity > 0) , Allocator::isGarbageCollected> {
498 private: 527 private:
499 typedef VectorBuffer<T, inlineCapacity, Allocator> Base; 528 typedef VectorBuffer<T, inlineCapacity, Allocator> Base;
500 typedef VectorTypeOperations<T> TypeOperations; 529 typedef VectorTypeOperations<T> TypeOperations;
501 530
502 public: 531 public:
503 typedef T ValueType; 532 typedef T ValueType;
504 533
505 typedef T* iterator; 534 typedef T* iterator;
506 typedef const T* const_iterator; 535 typedef const T* const_iterator;
507 typedef std::reverse_iterator<iterator> reverse_iterator; 536 typedef std::reverse_iterator<iterator> reverse_iterator;
(...skipping 21 matching lines...) Expand all
529 : Base(size) 558 : Base(size)
530 { 559 {
531 m_size = size; 560 m_size = size;
532 TypeOperations::initialize(begin(), end()); 561 TypeOperations::initialize(begin(), end());
533 } 562 }
534 563
535 // Off-GC-heap vectors: Destructor should be called. 564 // Off-GC-heap vectors: Destructor should be called.
536 // On-GC-heap vectors: Destructor should be called for inline buffers 565 // On-GC-heap vectors: Destructor should be called for inline buffers
537 // (if any) but destructor shouldn't be called for vector backing since 566 // (if any) but destructor shouldn't be called for vector backing since
538 // it is managed by the traced GC heap. 567 // it is managed by the traced GC heap.
539 ~Vector() 568 void finalize()
540 { 569 {
541 if (!inlineCapacity) { 570 if (!inlineCapacity) {
542 if (LIKELY(!Base::buffer())) 571 if (LIKELY(!Base::buffer()))
543 return; 572 return;
544 } 573 }
545 if (LIKELY(m_size) && !(Allocator::isGarbageCollected && this->hasOu tOfLineBuffer())) { 574 if (LIKELY(m_size) && !(Allocator::isGarbageCollected && this->hasOu tOfLineBuffer())) {
546 TypeOperations::destruct(begin(), end()); 575 TypeOperations::destruct(begin(), end());
547 m_size = 0; // Partial protection against use-after-free. 576 m_size = 0; // Partial protection against use-after-free.
548 } 577 }
549 578
550 Base::destruct(); 579 Base::destruct();
551 } 580 }
552 581
553 void finalize()
554 {
555 this->~Vector();
556 }
557
558 void clearUnusedSlots(T* from, T* to) 582 void clearUnusedSlots(T* from, T* to)
559 { 583 {
560 VectorUnusedSlotClearer<Allocator::isGarbageCollected && (VectorTrai ts<T>::needsDestruction || ShouldBeTraced<VectorTraits<T> >::value || VectorTrai ts<T>::isWeak), T>::clear(from, to); 584 VectorUnusedSlotClearer<Allocator::isGarbageCollected && (VectorTrai ts<T>::needsDestruction || ShouldBeTraced<VectorTraits<T> >::value || VectorTrai ts<T>::isWeak), T>::clear(from, to);
561 } 585 }
562 586
563 Vector(const Vector&); 587 Vector(const Vector&);
564 template<size_t otherCapacity> 588 template<size_t otherCapacity>
565 explicit Vector(const Vector<T, otherCapacity, Allocator>&); 589 explicit Vector(const Vector<T, otherCapacity, Allocator>&);
566 590
567 Vector& operator=(const Vector&); 591 Vector& operator=(const Vector&);
(...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after
1145 } 1169 }
1146 if (this->hasOutOfLineBuffer()) 1170 if (this->hasOutOfLineBuffer())
1147 Allocator::markNoTracing(visitor, buffer()); 1171 Allocator::markNoTracing(visitor, buffer());
1148 } 1172 }
1149 1173
1150 } // namespace WTF 1174 } // namespace WTF
1151 1175
1152 using WTF::Vector; 1176 using WTF::Vector;
1153 1177
1154 #endif // WTF_Vector_h 1178 #endif // WTF_Vector_h
OLDNEW
« no previous file with comments | « Source/wtf/HashTable.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698