lscript_heapruntime.cpp

Go to the documentation of this file.
00001 
00032 #if 0
00033 
00034 #include "linden_common.h"
00035 
00036 #include "lscript_heapruntime.h"
00037 #include "lscript_execute.h"
00038 
00039 
00040 /*
00041         String Heap Format
00042         Byte            Description
00043         0x0 - 0xnn      Single byte string including null terminator
00044 
00045         List Heap Format
00046         Byte            Description
00047         0x0                     Next Entry Type
00048                                         0: End of list
00049                                         1: Integer
00050                                         2: Floating point
00051                                         3: String
00052                                         4: Vector
00053                                         5: Quaternion
00054                                         6: List
00055         0x1 - 0x4       Integer, Floating Point, String Address, List Address
00056         or      
00057         0x1 - 0xd       Vector
00058         or      
00059         0x1 - 0x11      Quaternion
00060         . . .   
00061 
00062         Heap Block Format
00063         Byte            Description
00064         0x0 - 0x3       Offset to Next Block
00065         0x4 - 0x7       Object Reference Count
00066         0x8             Block Type
00067                                         0: Empty
00068                                         3: String
00069                                         6: List
00070         0x9 - 0xM       Object Data
00071 
00072         Heap Management
00073 
00074         Adding Data
00075 
00076         1)      Set last empty spot to zero.
00077         2)      Go to start of the heap (HR).
00078         3)      Get next 4 bytes of offset.
00079         4)      If zero, we've reached the end of used memory.  If empty spot is zero go to step 9.  Otherwise set base offset to 0 and go to step 9.
00080         5)      Skip 4 bytes.
00081         6)      Get next 1 byte of entry type.
00082         7)      If zero, this spot is empty.  If empty spot is zero, set empty spot to this address and go to step 9.  Otherwise, coalesce with last empty spot and then go to step 9.
00083         8)      Skip forward by offset and go to step 3.
00084         9)      If the spot is empty, check to see if the size needed == offset - 9.
00085         10)      If it does, let's drop our data into this spot.  Set reference count to 1.  Set entry type appropriately and copy the data in.  
00086         11)      If size needed < offset - 9 then we can stick in data and add in an empty block.
00087         12)      Otherwise, we need to keep looking.  Go to step 3.
00088 
00089         Increasing reference counts
00090                 
00091         Decreasing reference counts
00092         1)      Set entry type to 0.
00093         2)      If offset is non-zero and the next entry is empty, coalesce.  Go to step 2.
00094 
00095         What increases reference count:
00096                 Initial creation sets reference count to 1.
00097                 Storing the reference increases reference count by 1.
00098                 Pushing the reference increases reference count by 1.
00099                 Duplicating the reference increases reference count by 1.
00100 
00101         What decreases the reference count:
00102                 Popping the reference decreases reference count by 1.
00103  */
00104 
00105 
00106 LLScriptHeapRunTime::LLScriptHeapRunTime()
00107 : mLastEmpty(0), mBuffer(NULL), mCurrentPosition(0), mStackPointer(0), mHeapRegister(0), mbPrint(FALSE)
00108 {
00109 }
00110 
00111 LLScriptHeapRunTime::~LLScriptHeapRunTime()
00112 {
00113 }
00114 
00115 S32 LLScriptHeapRunTime::addData(char *string)
00116 {
00117         if (!mBuffer)
00118                 return 0;
00119 
00120         S32 size = strlen(string) + 1;
00121         S32 block_offset = findOpenBlock(size + HEAP_BLOCK_HEADER_SIZE);
00122 
00123         if (mCurrentPosition)
00124         {
00125                 S32 offset = mCurrentPosition;
00126                 if (offset + block_offset + HEAP_BLOCK_HEADER_SIZE + LSCRIPTDataSize[LST_INTEGER] >= mStackPointer)
00127                 {
00128                         set_fault(mBuffer, LSRF_STACK_HEAP_COLLISION);
00129                         return 0;
00130                 }
00131                 // cool, we've found a spot!
00132                 // set offset
00133                 integer2bytestream(mBuffer, offset, block_offset);
00134                 // set reference count
00135                 integer2bytestream(mBuffer, offset, 1);
00136                 // set type
00137                 *(mBuffer + offset++) = LSCRIPTTypeByte[LST_STRING];
00138                 // plug in data
00139                 char2bytestream(mBuffer, offset, string);
00140                 if (mbPrint)
00141                         printf("0x%X created ref count %d\n", mCurrentPosition - mHeapRegister, 1);
00142 
00143                 // now, zero out next offset to prevent "trouble"
00144         //      offset = mCurrentPosition + size + HEAP_BLOCK_HEADER_SIZE;
00145         //      integer2bytestream(mBuffer, offset, 0);
00146         }
00147         return mCurrentPosition;
00148 }
00149 
00150 S32 LLScriptHeapRunTime::addData(U8 *list)
00151 {
00152         if (!mBuffer)
00153                 return 0;
00154         return 0;
00155 }
00156 
00157 S32 LLScriptHeapRunTime::catStrings(S32 address1, S32 address2)
00158 {
00159         if (!mBuffer)
00160                 return 0;
00161 
00162         S32 dataaddress1 = address1 + 2*LSCRIPTDataSize[LST_INTEGER] + 1;
00163         S32 dataaddress2 = address2 + 2*LSCRIPTDataSize[LST_INTEGER] + 1;
00164 
00165         S32 toffset1 = dataaddress1;
00166         safe_heap_bytestream_count_char(mBuffer, toffset1);
00167 
00168         S32 toffset2 = dataaddress2;
00169         safe_heap_bytestream_count_char(mBuffer, toffset2);
00170 
00171         // calculate new string size
00172         S32 size1 = toffset1 - dataaddress1;
00173         S32 size2 = toffset2 - dataaddress2;
00174         S32 newbuffer = size1 + size2 - 1;
00175 
00176         char *temp = new char[newbuffer];
00177 
00178         // get the strings
00179         bytestream2char(temp, mBuffer, dataaddress1);
00180         bytestream2char(temp + size1 - 1, mBuffer, dataaddress2);
00181 
00182         decreaseRefCount(address1);
00183         decreaseRefCount(address2);
00184 
00185         S32 retaddress = addData(temp);
00186 
00187         return retaddress;
00188 }
00189 
00190 S32 LLScriptHeapRunTime::cmpStrings(S32 address1, S32 address2)
00191 {
00192         if (!mBuffer)
00193                 return 0;
00194 
00195         S32 dataaddress1 = address1 + 2*LSCRIPTDataSize[LST_INTEGER] + 1;
00196         S32 dataaddress2 = address2 + 2*LSCRIPTDataSize[LST_INTEGER] + 1;
00197 
00198         S32 toffset1 = dataaddress1;
00199         safe_heap_bytestream_count_char(mBuffer, toffset1);
00200 
00201         S32 toffset2 = dataaddress2;
00202         safe_heap_bytestream_count_char(mBuffer, toffset2);
00203 
00204         // calculate new string size
00205         S32 size1 = toffset1 - dataaddress1;
00206         S32 size2 = toffset2 - dataaddress2;
00207 
00208         if (size1 != size2)
00209         {
00210                 return llmin(size1, size2);
00211         }
00212         else
00213         {
00214                 return strncmp((char *)(mBuffer + dataaddress1), (char *)(mBuffer + dataaddress2), size1);
00215         }
00216 }
00217 
00218 void LLScriptHeapRunTime::removeData(S32 address)
00219 {
00220         if (!mBuffer)
00221                 return;
00222 
00223         S32 toffset = address;
00224         // read past offset (relying on function side effect
00225         bytestream2integer(mBuffer, toffset);
00226 
00227         // make sure that reference count is 0
00228         integer2bytestream(mBuffer, toffset, 0);
00229         // show the block as empty
00230         *(mBuffer + toffset) = 0;
00231 
00232         // now, clean up the heap
00233         S32 clean = mHeapRegister;
00234         S32 tclean;
00235         S32 clean_offset;
00236 
00237         S32 nclean;
00238         S32 tnclean;
00239         S32 next_offset;
00240 
00241         U8  type;
00242         U8  ntype;
00243 
00244         for(;;)
00245         {
00246                 tclean = clean;
00247                 clean_offset = bytestream2integer(mBuffer, tclean);
00248                 // is this block, empty?
00249                 tclean += LSCRIPTDataSize[LST_INTEGER];
00250                 type = *(mBuffer + tclean);
00251                 
00252                 if (!clean_offset)
00253                 {
00254                         if (!type)
00255                         {
00256                                 // we're done! if our block is empty, we can pull in the HP and zero out our offset
00257                                 set_register(mBuffer, LREG_HP, clean);
00258                         }
00259                         return;
00260                 }
00261 
00262 
00263                 if (!type)
00264                 {
00265                         // if we're empty, try to coalesce with the next one
00266                         nclean = clean + clean_offset;
00267                         tnclean = nclean;
00268                         next_offset = bytestream2integer(mBuffer, tnclean);
00269                         tnclean += LSCRIPTDataSize[LST_INTEGER];
00270                         ntype = *(mBuffer + tnclean);
00271 
00272                         if (!next_offset)
00273                         {
00274                                 // we're done! if our block is empty, we can pull in the HP and zero out our offset
00275                                 tclean = clean;
00276                                 integer2bytestream(mBuffer, tclean, 0);
00277                                 set_register(mBuffer, LREG_HP, clean);
00278                                 return;
00279                         }
00280 
00281                         if (!ntype)
00282                         {
00283                                 // hooray!  we can coalesce
00284                                 tclean = clean;
00285                                 integer2bytestream(mBuffer, tclean, clean_offset + next_offset);
00286                                 // don't skip forward so that we can keep coalescing on next pass through the loop
00287                         }
00288                         else
00289                         {
00290                                 clean += clean_offset;
00291                         }
00292                 }
00293                 else
00294                 {
00295                         // if not, move on to the next block
00296                         clean += clean_offset;
00297                 }
00298         }
00299 }       
00300 
00301 void LLScriptHeapRunTime::coalesce(S32 address1, S32 address2)
00302 {
00303         // we need to bump the base offset by the second block's
00304         S32 toffset = address1;
00305         S32 offset1 = bytestream2integer(mBuffer, toffset);
00306         offset1 += bytestream2integer(mBuffer, address2);
00307 
00308         integer2bytestream(mBuffer, address1, offset1);
00309 }
00310 
00311 void LLScriptHeapRunTime::split(S32 address1, S32 size)
00312 {
00313         S32 toffset = address1;
00314         S32 oldoffset = bytestream2integer(mBuffer, toffset);
00315 
00316         // add new offset and zero out reference count and block used
00317         S32 newoffset = oldoffset - size;
00318         S32 newblockpos = address1 + size;
00319 
00320         // set new offset
00321         integer2bytestream(mBuffer, newblockpos, newoffset);
00322         // zero out reference count
00323         integer2bytestream(mBuffer, newblockpos, 0);
00324         // mark as empty
00325         *(mBuffer + newblockpos) = 0;
00326 
00327         // now, change the offset of the original block
00328         integer2bytestream(mBuffer, address1, size + HEAP_BLOCK_HEADER_SIZE);
00329 }
00330 
00331 /* 
00332 
00333         For reference count changes, strings are easy.  For lists, we'll need to go through the lists reducing
00334         the reference counts for any included strings and lists
00335 
00336  */
00337 
00338 void LLScriptHeapRunTime::increaseRefCount(S32 address)
00339 {
00340         if (!mBuffer)
00341                 return;
00342 
00343         if (!address)
00344         {
00345                 // unused temp string entry
00346                 return;
00347         }
00348 
00349         // get current reference count
00350         S32 toffset = address + 4;
00351         S32 count = bytestream2integer(mBuffer, toffset);
00352 
00353         count++;
00354 
00355         if (mbPrint)
00356                 printf("0x%X inc ref count %d\n", address - mHeapRegister, count);
00357 
00358         // see which type it is
00359         U8 type = *(mBuffer + toffset);
00360 
00361         if (type == LSCRIPTTypeByte[LST_STRING])
00362         {
00363                 toffset = address + 4;
00364                 integer2bytestream(mBuffer, toffset, count);
00365         }
00366         // TO DO: put list stuff here!
00367         else
00368         {
00369                 set_fault(mBuffer, LSRF_HEAP_ERROR);
00370         }
00371 }
00372 
00373 void LLScriptHeapRunTime::decreaseRefCount(S32 address)
00374 {
00375         if (!mBuffer)
00376                 return;
00377 
00378         if (!address)
00379         {
00380                 // unused temp string entry
00381                 return;
00382         }
00383 
00384         // get offset
00385         S32 toffset = address;
00386         // read past offset (rely on function side effect)
00387         bytestream2integer(mBuffer, toffset);
00388 
00389         // get current reference count
00390         S32 count = bytestream2integer(mBuffer, toffset);
00391 
00392         // see which type it is
00393         U8 type = *(mBuffer + toffset);
00394 
00395         if (type == LSCRIPTTypeByte[LST_STRING])
00396         {
00397                 count--;
00398 
00399                 if (mbPrint)
00400                         printf("0x%X dec ref count %d\n", address - mHeapRegister, count);
00401 
00402                 toffset = address + 4;
00403                 integer2bytestream(mBuffer, toffset, count);
00404                 if (!count)
00405                 {
00406                         // we can blow this one away
00407                         removeData(address);
00408                 }
00409         }
00410         // TO DO: put list stuff here!
00411         else
00412         {
00413                 set_fault(mBuffer, LSRF_HEAP_ERROR);
00414         }
00415 }
00416 
00417 // if we're going to assign a variable, we need to decrement the reference count of what we were pointing at (if anything)
00418 void LLScriptHeapRunTime::releaseLocal(S32 address)
00419 {
00420         S32 hr = get_register(mBuffer, LREG_HR);
00421         address = lscript_local_get(mBuffer, address);
00422         if (  (address >= hr)
00423                 &&(address < hr + get_register(mBuffer, LREG_HP)))
00424         {
00425                 decreaseRefCount(address);
00426         }
00427 }
00428 
00429 void LLScriptHeapRunTime::releaseGlobal(S32 address)
00430 {
00431         // NOTA BENE: Global strings are referenced relative to the HR while local strings aren't
00432         S32 hr = get_register(mBuffer, LREG_HR);
00433         address = lscript_global_get(mBuffer, address) + hr;
00434         if (  (address >= hr)
00435                 &&(address <  hr + get_register(mBuffer, LREG_HP)))
00436         {
00437                 decreaseRefCount(address);
00438         }
00439 }
00440 
00441 
00442 // we know the following function has "unreachable code"
00443 // don't remind us every friggin' time we compile. . . 
00444 
00445 #if defined(_MSC_VER)
00446 # pragma warning(disable: 4702) // unreachable code
00447 #endif
00448 
00449 S32 LLScriptHeapRunTime::findOpenBlock(S32 size)
00450 {
00451         S32 offset;
00452         S32 toffset;
00453         U8 blocktype;
00454 
00455         while(1)
00456         {
00457                 if (mCurrentPosition + size >= mStackPointer)
00458                 {
00459                         set_fault(mBuffer, LSRF_STACK_HEAP_COLLISION);
00460                         mCurrentPosition = 0;
00461                 }
00462 
00463                 toffset = mCurrentPosition;
00464                 offset = bytestream2integer(mBuffer, toffset);
00465                 if (!offset)
00466                 {
00467                         // we've reached the end of Heap, return this location if we'll fit
00468                         // do we need to coalesce with last empty space?
00469                         if (mLastEmpty)
00470                         {
00471                                 // ok, that everything from mLastEmpty to us is empty, so we don't need a block
00472                                 // zero out the last empty's offset and return it
00473                                 mCurrentPosition = mLastEmpty;
00474                                 integer2bytestream(mBuffer, mLastEmpty, 0);
00475                                 mLastEmpty = 0;
00476                         }
00477                         // now, zero out next offset to prevent "trouble"
00478                         offset = mCurrentPosition + size;
00479                         integer2bytestream(mBuffer, offset, 0);
00480 
00481                         // set HP to appropriate value
00482                         set_register(mBuffer, LREG_HP, mCurrentPosition + size);
00483                         return size;
00484                 }
00485 
00486                 // ok, is this slot empty?
00487                 toffset += LSCRIPTDataSize[LST_INTEGER];
00488 
00489                 blocktype = *(mBuffer + toffset++);
00490 
00491                 if (!blocktype)
00492                 {
00493                         // Empty block, do we need to coalesce?
00494                         if (mLastEmpty)
00495                         {
00496                                 coalesce(mLastEmpty, mCurrentPosition);
00497                                 mCurrentPosition = mLastEmpty;
00498                                 toffset = mCurrentPosition;
00499                                 offset = bytestream2integer(mBuffer, toffset);
00500                         }
00501 
00502                         // do we fit in this block?
00503                         if (offset >= size)
00504                         {
00505                                 // do we need to split the block? (only split if splitting will leave > HEAP_BLOCK_SPLIT_THRESHOLD bytes of free space)
00506                                 if (offset - HEAP_BLOCK_SPLIT_THRESHOLD >= size)
00507                                 {
00508                                         split(mCurrentPosition, size);
00509                                         return size;
00510                                 }
00511                                 else
00512                                         return offset;
00513                         }
00514                 }
00515                 // nothing found, keep looking
00516                 mCurrentPosition += offset;
00517         }
00518         // fake return to prevent warnings
00519         mCurrentPosition = 0;
00520         return 0;
00521 }
00522 
00523 LLScriptHeapRunTime     gRunTime;
00524 #endif

Generated on Thu Jul 1 06:09:51 2010 for Second Life Viewer by  doxygen 1.4.7