void LLScriptHeapRunTime::coalesce(S32 address1, S32 address2) { // we need to bump the base offset by the second block's S32 toffset = address1; S32 offset1 = bytestream2integer(mBuffer, toffset); offset1 += bytestream2integer(mBuffer, address2); integer2bytestream(mBuffer, address1, offset1); }
LLScriptHeapEntry::LLScriptHeapEntry(U8 *entry) : mEntry(entry) { S32 offset = 0; mNext = bytestream2integer(entry, offset); mRefCount = bytestream2integer(entry, offset); mType = *(entry + offset); mData = entry + offset; mListOffset = offset; }
LLScriptLibData *lsa_get_list_ptr(U8 *buffer, S32 &offset, BOOL b_dec_ref) { if (get_register(buffer, LREG_FR)) return (new LLScriptLibData); S32 orig_offset = offset; // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization // and function clean up of ref counts isn't based on scope (a mistake, I know) offset += get_register(buffer, LREG_HR) - 1; if ( (offset < get_register(buffer, LREG_HR)) ||(offset >= get_register(buffer, LREG_HP))) { set_fault(buffer, LSRF_BOUND_CHECK_ERROR); return (new LLScriptLibData); } LLScriptAllocEntry entry; bytestream2alloc_entry(entry, buffer, offset); if (!entry.mType) { set_fault(buffer, LSRF_HEAP_ERROR); return NULL; } LLScriptLibData base, *tip = &base; if (entry.mType != LST_LIST) { return NULL; } else { // get length of list S32 i, length = bytestream2integer(buffer, offset); for (i = 0; i < length; i++) { S32 address = bytestream2integer(buffer, offset); tip->mListp = lsa_get_data(buffer, address, FALSE); tip = tip->mListp; } } if (b_dec_ref) { lsa_decrease_ref_count(buffer, orig_offset); } tip = base.mListp; base.mListp = NULL; return tip; }
void LLScriptHeapRunTime::increaseRefCount(S32 address) { if (!mBuffer) return; if (!address) { // unused temp string entry return; } // get current reference count S32 toffset = address + 4; S32 count = bytestream2integer(mBuffer, toffset); count++; if (mbPrint) printf("0x%X inc ref count %d\n", address - mHeapRegister, count); // see which type it is U8 type = *(mBuffer + toffset); if (type == LSCRIPTTypeByte[LST_STRING]) { toffset = address + 4; integer2bytestream(mBuffer, toffset, count); } // TO DO: put list stuff here! else { set_fault(mBuffer, LSRF_HEAP_ERROR); } }
void LLScriptHeapRunTime::decreaseRefCount(S32 address) { if (!mBuffer) return; if (!address) { // unused temp string entry return; } // get offset S32 toffset = address; // read past offset (rely on function side effect) bytestream2integer(mBuffer, toffset); // get current reference count S32 count = bytestream2integer(mBuffer, toffset); // see which type it is U8 type = *(mBuffer + toffset); if (type == LSCRIPTTypeByte[LST_STRING]) { count--; if (mbPrint) printf("0x%X dec ref count %d\n", address - mHeapRegister, count); toffset = address + 4; integer2bytestream(mBuffer, toffset, count); if (!count) { // we can blow this one away removeData(address); } } // TO DO: put list stuff here! else { set_fault(mBuffer, LSRF_HEAP_ERROR); } }
void lsa_decrease_ref_count(U8 *buffer, S32 offset) { if (get_register(buffer, LREG_FR)) return; // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization // and function clean up of ref counts isn't based on scope (a mistake, I know) offset += get_register(buffer, LREG_HR) - 1; if ( (offset < get_register(buffer, LREG_HR)) ||(offset >= get_register(buffer, LREG_HP))) { set_fault(buffer, LSRF_BOUND_CHECK_ERROR); return; } S32 orig_offset = offset; LLScriptAllocEntry entry; bytestream2alloc_entry(entry, buffer, offset); entry.mReferenceCount--; if (entry.mReferenceCount < 0) { entry.mReferenceCount = 0; set_fault(buffer, LSRF_HEAP_ERROR); } else if (!entry.mReferenceCount) { if (entry.mType == LST_LIST) { S32 i, num = bytestream2integer(buffer, offset); for (i = 0; i < num; i++) { S32 list_offset = bytestream2integer(buffer, offset); lsa_decrease_ref_count(buffer, list_offset); } } entry.mType = LST_NULL; } alloc_entry2bytestream(buffer, orig_offset, entry); }
LLScriptLSOParse::LLScriptLSOParse(FILE *fp) { U8 sizearray[4]; S32 filesize; S32 pos = 0; fread(&sizearray, 1, 4, fp); filesize = bytestream2integer(sizearray, pos); mRawData = new U8[filesize]; fseek(fp, 0, SEEK_SET); fread(mRawData, 1, filesize, fp); initOpCodePrinting(); }
void LLScriptHeapRunTime::split(S32 address1, S32 size) { S32 toffset = address1; S32 oldoffset = bytestream2integer(mBuffer, toffset); // add new offset and zero out reference count and block used S32 newoffset = oldoffset - size; S32 newblockpos = address1 + size; // set new offset integer2bytestream(mBuffer, newblockpos, newoffset); // zero out reference count integer2bytestream(mBuffer, newblockpos, 0); // mark as empty *(mBuffer + newblockpos) = 0; // now, change the offset of the original block integer2bytestream(mBuffer, address1, size + HEAP_BLOCK_HEADER_SIZE); }
LLScriptLSOParse::LLScriptLSOParse(LLFILE *fp) { U8 sizearray[4]; S32 filesize; S32 pos = 0; if (fread(&sizearray, 1, 4, fp) != 4) { llwarns << "Short read" << llendl; filesize = 0; } else { filesize = bytestream2integer(sizearray, pos); } mRawData = new U8[filesize]; fseek(fp, 0, SEEK_SET); if (fread(mRawData, 1, filesize, fp) != filesize) { llwarns << "Short read" << llendl; } initOpCodePrinting(); }
void lsa_fprint_heap(U8 *buffer, LLFILE *fp) { S32 offset = get_register(buffer, LREG_HR); S32 readoffset; S32 ivalue; F32 fpvalue; LLVector3 vvalue; LLQuaternion qvalue; char string[4096]; /*Flawfinder: ignore*/ LLScriptAllocEntry entry; bytestream2alloc_entry(entry, buffer, offset); while (offset + entry.mSize < MAX_HEAP_SIZE) { fprintf(fp, "[0x%X] ", offset); fprintf(fp, "%s ", LSCRIPTTypeNames[entry.mType]); fprintf(fp, "Ref Count: %d ", entry.mReferenceCount); fprintf(fp, "Size: %d = ", entry.mSize); readoffset = offset; switch(entry.mType) { case LST_INTEGER: ivalue = bytestream2integer(buffer, readoffset); fprintf(fp, "%d\n", ivalue); break; case LST_FLOATINGPOINT: fpvalue = bytestream2float(buffer, readoffset); fprintf(fp, "%f\n", fpvalue); break; case LST_STRING: bytestream2char(string, buffer, readoffset, sizeof(string)); fprintf(fp, "%s\n", string); break; case LST_KEY: bytestream2char(string, buffer, readoffset, sizeof(string)); fprintf(fp, "%s\n", string); break; case LST_VECTOR: bytestream2vector(vvalue, buffer, readoffset); fprintf(fp, "< %f, %f, %f >\n", vvalue.mV[VX], vvalue.mV[VY], vvalue.mV[VZ]); break; case LST_QUATERNION: bytestream2quaternion(qvalue, buffer, readoffset); fprintf(fp, "< %f, %f, %f, %f >\n", qvalue.mQ[VX], qvalue.mQ[VY], qvalue.mQ[VZ], qvalue.mQ[VS]); break; case LST_LIST: ivalue = bytestream2integer(buffer, readoffset); fprintf(fp, "%d\n", ivalue); break; default: fprintf(fp, "\n"); break; } offset += entry.mSize; bytestream2alloc_entry(entry, buffer, offset); } fprintf(fp, "[0x%X] ", offset); fprintf(fp, "%s ", LSCRIPTTypeNames[entry.mType]); fprintf(fp, "Ref Count: %d ", entry.mReferenceCount); fprintf(fp, "Size: %d", entry.mSize); fprintf(fp, "\n"); }
LLScriptLibData *lsa_get_data(U8 *buffer, S32 &offset, BOOL b_dec_ref) { if (get_register(buffer, LREG_FR)) return (new LLScriptLibData); S32 orig_offset = offset; // this bit of nastiness is to get around that code paths to local variables can result in lack of initialization // and function clean up of ref counts isn't based on scope (a mistake, I know) offset += get_register(buffer, LREG_HR) - 1; if ( (offset < get_register(buffer, LREG_HR)) ||(offset >= get_register(buffer, LREG_HP))) { set_fault(buffer, LSRF_BOUND_CHECK_ERROR); return (new LLScriptLibData); } LLScriptAllocEntry entry; bytestream2alloc_entry(entry, buffer, offset); LLScriptLibData *retval = new LLScriptLibData; if (!entry.mType) { set_fault(buffer, LSRF_HEAP_ERROR); return retval; } retval->mType = (LSCRIPTType)entry.mType; if (entry.mType != LST_LIST) { switch(entry.mType) { case LST_INTEGER: retval->mInteger = bytestream2integer(buffer, offset); break; case LST_FLOATINGPOINT: retval->mFP = bytestream2float(buffer, offset); break; case LST_KEY: bytestream2char(gLSAStringRead, buffer, offset, sizeof(gLSAStringRead)); // global sring buffer? for real? :( retval->mKey = new char[strlen(gLSAStringRead) + 1]; /*Flawfinder: ignore*/ strcpy(retval->mKey, gLSAStringRead); /*Flawfinder: ignore*/ break; case LST_STRING: bytestream2char(gLSAStringRead, buffer, offset, sizeof(gLSAStringRead)); retval->mString = new char[strlen(gLSAStringRead) + 1]; /*Flawfinder: ignore*/ strcpy(retval->mString, gLSAStringRead); /*Flawfinder: ignore*/ break; case LST_VECTOR: bytestream2vector(retval->mVec, buffer, offset); break; case LST_QUATERNION: bytestream2quaternion(retval->mQuat, buffer, offset); break; default: break; } } else { // get length of list S32 i, length = bytestream2integer(buffer, offset); LLScriptLibData *tip = retval; for (i = 0; i < length; i++) { S32 address = bytestream2integer(buffer, offset); tip->mListp = lsa_get_data(buffer, address, FALSE); tip = tip->mListp; } } if (retval->checkForMultipleLists()) { set_fault(buffer, LSRF_NESTING_LISTS); } if (b_dec_ref) { lsa_decrease_ref_count(buffer, orig_offset); } return retval; }
S32 LLScriptHeapRunTime::findOpenBlock(S32 size) { S32 offset; S32 toffset; U8 blocktype; while(1) { if (mCurrentPosition + size >= mStackPointer) { set_fault(mBuffer, LSRF_STACK_HEAP_COLLISION); mCurrentPosition = 0; } toffset = mCurrentPosition; offset = bytestream2integer(mBuffer, toffset); if (!offset) { // we've reached the end of Heap, return this location if we'll fit // do we need to coalesce with last empty space? if (mLastEmpty) { // ok, that everything from mLastEmpty to us is empty, so we don't need a block // zero out the last empty's offset and return it mCurrentPosition = mLastEmpty; integer2bytestream(mBuffer, mLastEmpty, 0); mLastEmpty = 0; } // now, zero out next offset to prevent "trouble" offset = mCurrentPosition + size; integer2bytestream(mBuffer, offset, 0); // set HP to appropriate value set_register(mBuffer, LREG_HP, mCurrentPosition + size); return size; } // ok, is this slot empty? toffset += LSCRIPTDataSize[LST_INTEGER]; blocktype = *(mBuffer + toffset++); if (!blocktype) { // Empty block, do we need to coalesce? if (mLastEmpty) { coalesce(mLastEmpty, mCurrentPosition); mCurrentPosition = mLastEmpty; toffset = mCurrentPosition; offset = bytestream2integer(mBuffer, toffset); } // do we fit in this block? if (offset >= size) { // do we need to split the block? (only split if splitting will leave > HEAP_BLOCK_SPLIT_THRESHOLD bytes of free space) if (offset - HEAP_BLOCK_SPLIT_THRESHOLD >= size) { split(mCurrentPosition, size); return size; } else return offset; } } // nothing found, keep looking mCurrentPosition += offset; } // fake return to prevent warnings mCurrentPosition = 0; return 0; }
void LLScriptHeapRunTime::removeData(S32 address) { if (!mBuffer) return; S32 toffset = address; // read past offset (relying on function side effect bytestream2integer(mBuffer, toffset); // make sure that reference count is 0 integer2bytestream(mBuffer, toffset, 0); // show the block as empty *(mBuffer + toffset) = 0; // now, clean up the heap S32 clean = mHeapRegister; S32 tclean; S32 clean_offset; S32 nclean; S32 tnclean; S32 next_offset; U8 type; U8 ntype; for(;;) { tclean = clean; clean_offset = bytestream2integer(mBuffer, tclean); // is this block, empty? tclean += LSCRIPTDataSize[LST_INTEGER]; type = *(mBuffer + tclean); if (!clean_offset) { if (!type) { // we're done! if our block is empty, we can pull in the HP and zero out our offset set_register(mBuffer, LREG_HP, clean); } return; } if (!type) { // if we're empty, try to coalesce with the next one nclean = clean + clean_offset; tnclean = nclean; next_offset = bytestream2integer(mBuffer, tnclean); tnclean += LSCRIPTDataSize[LST_INTEGER]; ntype = *(mBuffer + tnclean); if (!next_offset) { // we're done! if our block is empty, we can pull in the HP and zero out our offset tclean = clean; integer2bytestream(mBuffer, tclean, 0); set_register(mBuffer, LREG_HP, clean); return; } if (!ntype) { // hooray! we can coalesce tclean = clean; integer2bytestream(mBuffer, tclean, clean_offset + next_offset); // don't skip forward so that we can keep coalescing on next pass through the loop } else { clean += clean_offset; } } else { // if not, move on to the next block clean += clean_offset; } } }