xpcom/glue/nsDeque.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsDeque.h"
     7 #include "nsISupportsImpl.h"
     8 #include <string.h>
     9 #ifdef DEBUG_rickg
    10 #include <stdio.h>
    11 #endif
    13 /**
    14  * 07/02/2001  09:17p 509,104 clangref.pdf from openwatcom's site
    15  * Watcom C Language Reference Edition 11.0c
    16  * page 118 of 297
    17  *
    18  * The % symbol yields the remainder from the division of the first operand
    19  * by the second operand. The operands of % must have integral type.
    20  *
    21  * When both operands of % are positive, the result is a positive value
    22  * smaller than the second operand. When one or both operands is negative,
    23  * whether the result is positive or negative is implementation-defined.
    24  *
    25  */
    26 /* Ok, so first of all, C is underspecified. joy.
    27  * The following functions do not provide a correct implementation of modulus
    28  * They provide functionality for x>-y.
    29  * There are risks of 2*y being greater than max int, which is part of the
    30  * reason no multiplication is used and other operations are avoided.
    31  *
    32  * modasgn
    33  * @param x variable
    34  * @param y expression
    35  * approximately equivalent to x %= y
    36  *
    37  * modulus
    38  * @param x expression
    39  * @param y expression
    40  * approximately equivalent to x % y
    41  */
    42 #define modasgn(x,y) if (x<0) x+=y; x%=y
    43 #define modulus(x,y) ((x<0)?(x+y)%(y):(x)%(y))
    45 /**
    46  * Standard constructor
    47  * @param deallocator, called by Erase and ~nsDeque
    48  */
    49 nsDeque::nsDeque(nsDequeFunctor* aDeallocator) {
    50   MOZ_COUNT_CTOR(nsDeque);
    51   mDeallocator=aDeallocator;
    52   mOrigin=mSize=0;
    53   mData=mBuffer; // don't allocate space until you must
    54   mCapacity=sizeof(mBuffer)/sizeof(mBuffer[0]);
    55   memset(mData, 0, mCapacity*sizeof(mBuffer[0]));
    56 }
    58 /**
    59  * Destructor
    60  */
    61 nsDeque::~nsDeque() {
    62   MOZ_COUNT_DTOR(nsDeque);
    64 #ifdef DEBUG_rickg
    65   char buffer[30];
    66   printf("Capacity: %i\n", mCapacity);
    68   static int mCaps[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    69   switch(mCapacity) {
    70     case 4:     mCaps[0]++; break;
    71     case 8:     mCaps[1]++; break;
    72     case 16:    mCaps[2]++; break;
    73     case 32:    mCaps[3]++; break;
    74     case 64:    mCaps[4]++; break;
    75     case 128:   mCaps[5]++; break;
    76     case 256:   mCaps[6]++; break;
    77     case 512:   mCaps[7]++; break;
    78     case 1024:  mCaps[8]++; break;
    79     case 2048:  mCaps[9]++; break;
    80     case 4096:  mCaps[10]++; break;
    81     default:
    82       break;
    83   }
    84 #endif
    86   Erase();
    87   if (mData && (mData!=mBuffer)) {
    88     free(mData);
    89   }
    90   mData=0;
    91   SetDeallocator(0);
    92 }
    94 size_t nsDeque::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
    95   size_t size = 0;
    96   if (mData != mBuffer) {
    97     size += aMallocSizeOf(mData);
    98   }
   100   if (mDeallocator) {
   101     size += aMallocSizeOf(mDeallocator);
   102   }
   104   return size;
   105 }
   107 size_t nsDeque::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
   108   return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
   109 }
   111 /**
   112  * Set the functor to be called by Erase()
   113  * The deque owns the functor.
   114  *
   115  * @param   aDeallocator functor object for use by Erase()
   116  */
   117 void nsDeque::SetDeallocator(nsDequeFunctor* aDeallocator){
   118   delete mDeallocator;
   119   mDeallocator=aDeallocator;
   120 }
   122 /**
   123  * Remove all items from container without destroying them.
   124  */
   125 void nsDeque::Empty() {
   126   if (mSize && mData) {
   127     memset(mData, 0, mCapacity*sizeof(mData));
   128   }
   129   mSize=0;
   130   mOrigin=0;
   131 }
   133 /**
   134  * Remove and delete all items from container
   135  */
   136 void nsDeque::Erase() {
   137   if (mDeallocator && mSize) {
   138     ForEach(*mDeallocator);
   139   }
   140   Empty();
   141 }
   143 /**
   144  * This method quadruples the size of the deque
   145  * Elements in the deque are resequenced so that elements
   146  * in the deque are stored sequentially
   147  *
   148  * @return  whether growing succeeded
   149  */
   150 bool nsDeque::GrowCapacity() {
   151   int32_t theNewSize=mCapacity<<2;
   152   NS_ASSERTION(theNewSize>mCapacity, "Overflow");
   153   if (theNewSize<=mCapacity)
   154     return false;
   155   void** temp=(void**)malloc(theNewSize * sizeof(void*));
   156   if (!temp)
   157     return false;
   159   //Here's the interesting part: You can't just move the elements
   160   //directly (in situ) from the old buffer to the new one.
   161   //Since capacity has changed, the old origin doesn't make
   162   //sense anymore. It's better to resequence the elements now.
   164   memcpy(temp, mData + mOrigin, sizeof(void*) * (mCapacity - mOrigin));
   165   memcpy(temp + (mCapacity - mOrigin), mData, sizeof(void*) * mOrigin);
   167   if (mData != mBuffer) {
   168     free(mData);
   169   }
   171   mCapacity=theNewSize;
   172   mOrigin=0; //now realign the origin...
   173   mData=temp;
   175   return true;
   176 }
   178 /**
   179  * This method adds an item to the end of the deque.
   180  * This operation has the potential to cause the
   181  * underlying buffer to resize.
   182  *
   183  * @param   aItem: new item to be added to deque
   184  */
   185 bool nsDeque::Push(void* aItem, const fallible_t&) {
   186   if (mSize==mCapacity && !GrowCapacity()) {
   187     return false;
   188   }
   189   mData[modulus(mOrigin + mSize, mCapacity)]=aItem;
   190   mSize++;
   191   return true;
   192 }
   194 /**
   195  * This method adds an item to the front of the deque.
   196  * This operation has the potential to cause the
   197  * underlying buffer to resize.
   198  *
   199  * --Commments for GrowCapacity() case
   200  * We've grown and shifted which means that the old
   201  * final element in the deque is now the first element
   202  * in the deque.  This is temporary.
   203  * We haven't inserted the new element at the front.
   204  *
   205  * To continue with the idea of having the front at zero
   206  * after a grow, we move the old final item (which through
   207  * the voodoo of mOrigin-- is now the first) to its final
   208  * position which is conveniently the old length.
   209  *
   210  * Note that this case only happens when the deque is full.
   211  * [And that pieces of this magic only work if the deque is full.]
   212  * picture:
   213  *   [ABCDEFGH] @[mOrigin:3]:D.
   214  * Task: PushFront("Z")
   215  * shift mOrigin so, @[mOrigin:2]:C
   216  * stretch and rearrange: (mOrigin:0)
   217  *   [CDEFGHAB ________ ________ ________]
   218  * copy: (The second C is currently out of bounds)
   219  *   [CDEFGHAB C_______ ________ ________]
   220  * later we will insert Z:
   221  *   [ZDEFGHAB C_______ ________ ________]
   222  * and increment size: 9. (C is no longer out of bounds)
   223  * --
   224  * @param   aItem: new item to be added to deque
   225  */
   226 bool nsDeque::PushFront(void* aItem, const fallible_t&) {
   227   mOrigin--;
   228   modasgn(mOrigin,mCapacity);
   229   if (mSize==mCapacity) {
   230     if (!GrowCapacity()) {
   231       return false;
   232     }
   233     /* Comments explaining this are above*/
   234     mData[mSize]=mData[mOrigin];
   235   }
   236   mData[mOrigin]=aItem;
   237   mSize++;
   238   return true;
   239 }
   241 /**
   242  * Remove and return the last item in the container.
   243  *
   244  * @return  ptr to last item in container
   245  */
   246 void* nsDeque::Pop() {
   247   void* result=0;
   248   if (mSize>0) {
   249     --mSize;
   250     int32_t offset=modulus(mSize + mOrigin, mCapacity);
   251     result=mData[offset];
   252     mData[offset]=0;
   253     if (!mSize) {
   254       mOrigin=0;
   255     }
   256   }
   257   return result;
   258 }
   260 /**
   261  * This method gets called you want to remove and return
   262  * the first member in the container.
   263  *
   264  * @return  last item in container
   265  */
   266 void* nsDeque::PopFront() {
   267   void* result=0;
   268   if (mSize>0) {
   269     NS_ASSERTION(mOrigin < mCapacity, "Error: Bad origin");
   270     result=mData[mOrigin];
   271     mData[mOrigin++]=0;     //zero it out for debugging purposes.
   272     mSize--;
   273     // Cycle around if we pop off the end
   274     // and reset origin if when we pop the last element
   275     if (mCapacity==mOrigin || !mSize) {
   276       mOrigin=0;
   277     }
   278   }
   279   return result;
   280 }
   282 /**
   283  * This method gets called you want to peek at the bottom
   284  * member without removing it.
   285  *
   286  * @return  last item in container
   287  */
   288 void* nsDeque::Peek() {
   289   void* result=0;
   290   if (mSize>0) {
   291     result = mData[modulus(mSize - 1 + mOrigin, mCapacity)];
   292   }
   293   return result;
   294 } 
   296 /**
   297  * This method gets called you want to peek at the topmost
   298  * member without removing it.
   299  *
   300  * @return  last item in container
   301  */
   302 void* nsDeque::PeekFront() {
   303   void* result=0;
   304   if (mSize>0) {
   305     result=mData[mOrigin];
   306   }
   307   return result;
   308 }
   310 /**
   311  * Call this to retrieve the ith element from this container.
   312  * Keep in mind that accessing the underlying elements is
   313  * done in a relative fashion. Object 0 is not necessarily
   314  * the first element (the first element is at mOrigin).
   315  *
   316  * @param   aIndex : 0 relative offset of item you want
   317  * @return  void* or null
   318  */
   319 void* nsDeque::ObjectAt(int32_t aIndex) const {
   320   void* result=0;
   321   if ((aIndex>=0) && (aIndex<mSize)) {
   322     result=mData[modulus(mOrigin + aIndex, mCapacity)];
   323   }
   324   return result;
   325 }
   327 void* nsDeque::RemoveObjectAt(int32_t aIndex) {
   328   if ((aIndex<0) || (aIndex>=mSize)) {
   329     return 0;
   330   }
   331   void* result=mData[modulus(mOrigin + aIndex, mCapacity)];
   333   // "Shuffle down" all elements in the array by 1, overwritting the element
   334   // being removed.
   335   for (int32_t i=aIndex; i<mSize; i++) {
   336     mData[modulus(mOrigin + i, mCapacity)] = mData[modulus(mOrigin + i + 1, mCapacity)];
   337   }
   338   mSize--;
   340   return result;
   341 }
   343 /**
   344  * Create and return an iterator pointing to
   345  * the beginning of the queue. Note that this
   346  * takes the circular buffer semantics into account.
   347  *
   348  * @return  new deque iterator, init'ed to 1st item
   349  */
   350 nsDequeIterator nsDeque::Begin() const{
   351   return nsDequeIterator(*this, 0);
   352 }
   354 /**
   355  * Create and return an iterator pointing to
   356  * the last item in the deque.
   357  * Note that this takes the circular buffer semantics
   358  * into account.
   359  *
   360  * @return  new deque iterator, init'ed to the last item
   361  */
   362 nsDequeIterator nsDeque::End() const{
   363   return nsDequeIterator(*this, mSize - 1);
   364 }
   366 void* nsDeque::Last() const {
   367   return End().GetCurrent();
   368 }
   370 /**
   371  * Call this method when you want to iterate all the
   372  * members of the container, passing a functor along
   373  * to call your code.
   374  *
   375  * @param   aFunctor object to call for each member
   376  * @return  *this
   377  */
   378 void nsDeque::ForEach(nsDequeFunctor& aFunctor) const{
   379   for (int32_t i=0; i<mSize; i++) {
   380     aFunctor(ObjectAt(i));
   381   }
   382 }
   384 /**
   385  * Call this method when you want to iterate all the
   386  * members of the container, calling the functor you 
   387  * passed with each member. This process will interrupt
   388  * if your function returns non 0 to this method.
   389  *
   390  * @param   aFunctor object to call for each member
   391  * @return  first nonzero result of aFunctor or 0.
   392  */
   393 const void* nsDeque::FirstThat(nsDequeFunctor& aFunctor) const{
   394   for (int32_t i=0; i<mSize; i++) {
   395     void* obj=aFunctor(ObjectAt(i));
   396     if (obj) {
   397       return obj;
   398     }
   399   }
   400   return 0;
   401 }
   403 /******************************************************
   404  * Here comes the nsDequeIterator class...
   405  ******************************************************/
   407 /**
   408  * DequeIterator is an object that knows how to iterate (forward and backward)
   409  * through a Deque. Normally, you don't need to do this, but there are some special
   410  * cases where it is pretty handy, so here you go.
   411  *
   412  * This is a standard dequeiterator constructor
   413  *
   414  * @param   aQueue is the deque object to be iterated
   415  * @param   aIndex is the starting position for your iteration
   416  */
   417 nsDequeIterator::nsDequeIterator(const nsDeque& aQueue, int aIndex)
   418 : mIndex(aIndex),
   419   mDeque(aQueue)
   420 {
   421 }
   423 /**
   424  * Create a copy of a DequeIterator
   425  *
   426  * @param   aCopy is another iterator to copy from
   427  */
   428 nsDequeIterator::nsDequeIterator(const nsDequeIterator& aCopy)
   429 : mIndex(aCopy.mIndex),
   430   mDeque(aCopy.mDeque)
   431 {
   432 }
   434 /**
   435  * Moves iterator to first element in deque
   436  * @return  *this
   437  */
   438 nsDequeIterator& nsDequeIterator::First(){
   439   mIndex=0;
   440   return *this;
   441 }
   443 /**
   444  * Standard assignment operator for dequeiterator
   445  *
   446  * @param   aCopy is an iterator to be copied from
   447  * @return  *this
   448  */
   449 nsDequeIterator& nsDequeIterator::operator=(const nsDequeIterator& aCopy) {
   450   NS_ASSERTION(&mDeque==&aCopy.mDeque,"you can't change the deque that an interator is iterating over, sorry.");
   451   mIndex=aCopy.mIndex;
   452   return *this;
   453 }
   455 /**
   456  * preform ! operation against to iterators to test for equivalence
   457  * (or lack thereof)!
   458  *
   459  * @param   aIter is the object to be compared to
   460  * @return  TRUE if NOT equal.
   461  */
   462 bool nsDequeIterator::operator!=(nsDequeIterator& aIter) {
   463   return bool(!this->operator==(aIter));
   464 }
   466 /**
   467  * Compare two iterators for increasing order.
   468  *
   469  * @param   aIter is the other iterator to be compared to
   470  * @return  TRUE if this object points to an element before
   471  *          the element pointed to by aIter.
   472  *          FALSE if this and aIter are not iterating over the same deque.
   473  */
   474 bool nsDequeIterator::operator<(nsDequeIterator& aIter) {
   475   return bool(((mIndex<aIter.mIndex) && (&mDeque==&aIter.mDeque)));
   476 }
   478 /**
   479  * Compare two iterators for equivalence.
   480  *
   481  * @param   aIter is the other iterator to be compared to
   482  * @return  TRUE if EQUAL
   483  */
   484 bool nsDequeIterator::operator==(nsDequeIterator& aIter) {
   485   return bool(((mIndex==aIter.mIndex) && (&mDeque==&aIter.mDeque)));
   486 }
   488 /**
   489  * Compare two iterators for non strict decreasing order.
   490  *
   491  * @param   aIter is the other iterator to be compared to
   492  * @return  TRUE if this object points to the same element, or
   493  *          an element after the element pointed to by aIter.
   494  *          FALSE if this and aIter are not iterating over the same deque.
   495  */
   496 bool nsDequeIterator::operator>=(nsDequeIterator& aIter) {
   497   return bool(((mIndex>=aIter.mIndex) && (&mDeque==&aIter.mDeque)));
   498 }
   500 /**
   501  * Pre-increment operator
   502  *
   503  * @return  object at post-incremented index
   504  */
   505 void* nsDequeIterator::operator++() {
   506   NS_ASSERTION(mIndex<mDeque.mSize,
   507     "You have reached the end of the Internet."\
   508     "You have seen everything there is to see. Please go back. Now."
   509   );
   510 #ifndef TIMELESS_LIGHTWEIGHT
   511   if (mIndex>=mDeque.mSize) return 0;
   512 #endif
   513   return mDeque.ObjectAt(++mIndex);
   514 }
   516 /**
   517  * Post-increment operator
   518  *
   519  * @param   param is ignored
   520  * @return  object at pre-incremented index
   521  */
   522 void* nsDequeIterator::operator++(int) {
   523   NS_ASSERTION(mIndex<=mDeque.mSize,
   524     "You have already reached the end of the Internet."\
   525     "You have seen everything there is to see. Please go back. Now."
   526   );
   527 #ifndef TIMELESS_LIGHTWEIGHT
   528   if (mIndex>mDeque.mSize) return 0;
   529 #endif
   530   return mDeque.ObjectAt(mIndex++);
   531 }
   533 /**
   534  * Pre-decrement operator
   535  *
   536  * @return  object at pre-decremented index
   537  */
   538 void* nsDequeIterator::operator--() {
   539   NS_ASSERTION(mIndex>=0,
   540     "You have reached the beginning of the Internet."\
   541     "You have seen everything there is to see. Please go forward. Now."
   542   );
   543 #ifndef TIMELESS_LIGHTWEIGHT
   544   if (mIndex<0) return 0;
   545 #endif
   546   return mDeque.ObjectAt(--mIndex);
   547 }
   549 /**
   550  * Post-decrement operator
   551  *
   552  * @param   param is ignored
   553  * @return  object at post-decremented index
   554  */
   555 void* nsDequeIterator::operator--(int) {
   556   NS_ASSERTION(mIndex>=0,
   557     "You have already reached the beginning of the Internet."\
   558     "You have seen everything there is to see. Please go forward. Now."
   559   );
   560 #ifndef TIMELESS_LIGHTWEIGHT
   561   if (mIndex<0) return 0;
   562 #endif
   563   return mDeque.ObjectAt(mIndex--);
   564 }
   566 /**
   567  * Dereference operator
   568  * Note that the iterator floats, so you don't need to do:
   569  * <code>++iter; aDeque.PopFront();</code>
   570  * Unless you actually want your iterator to jump 2 spaces.
   571  *
   572  * Picture: [1 2I 3 4]
   573  * PopFront()
   574  * Picture: [2 3I 4]
   575  * Note that I still happily points to object at the second index
   576  *
   577  * @return  object at ith index
   578  */
   579 void* nsDequeIterator::GetCurrent() {
   580   NS_ASSERTION(mIndex<mDeque.mSize&&mIndex>=0,"Current is out of bounds");
   581 #ifndef TIMELESS_LIGHTWEIGHT
   582   if (mIndex>=mDeque.mSize||mIndex<0) return 0;
   583 #endif
   584   return mDeque.ObjectAt(mIndex);
   585 }
   587 /**
   588  * Call this method when you want to iterate all the
   589  * members of the container, passing a functor along
   590  * to call your code.
   591  *
   592  * @param   aFunctor object to call for each member
   593  * @return  *this
   594  */
   595 void nsDequeIterator::ForEach(nsDequeFunctor& aFunctor) const{
   596   mDeque.ForEach(aFunctor);
   597 }
   599 /**
   600  * Call this method when you want to iterate all the
   601  * members of the container, calling the functor you 
   602  * passed with each member. This process will interrupt
   603  * if your function returns non 0 to this method.
   604  *
   605  * @param   aFunctor object to call for each member
   606  * @return  first nonzero result of aFunctor or 0.
   607  */
   608 const void* nsDequeIterator::FirstThat(nsDequeFunctor& aFunctor) const{
   609   return mDeque.FirstThat(aFunctor);
   610 }

mercurial