/** * @file lscript_bytecode.cpp * @brief classes to build actual bytecode * * $LicenseInfo:firstyear=2002&license=viewergpl$ * * Copyright (c) 2002-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #include "linden_common.h" #include "lscript_bytecode.h" #include "lscript_error.h" #if defined(_MSC_VER) # pragma warning(disable: 4102) // 'yy_more' : unreferenced label # pragma warning(disable: 4702) // unreachable code #endif LLScriptJumpTable::LLScriptJumpTable() { } LLScriptJumpTable::~LLScriptJumpTable() { mLabelMap.deleteAllData(); mJumpMap.deleteAllData(); } void LLScriptJumpTable::addLabel(char *name, S32 offset) { char *temp = gScopeStringTable->addString(name); mLabelMap[temp] = new S32(offset); } void LLScriptJumpTable::addJump(char *name, S32 offset) { char *temp = gScopeStringTable->addString(name); mJumpMap[temp] = new S32(offset); } LLScriptByteCodeChunk::LLScriptByteCodeChunk(BOOL b_need_jumps) : mCodeChunk(NULL), mCurrentOffset(0), mJumpTable(NULL) { if (b_need_jumps) { mJumpTable = new LLScriptJumpTable(); } } LLScriptByteCodeChunk::~LLScriptByteCodeChunk() { delete [] mCodeChunk; delete mJumpTable; } void LLScriptByteCodeChunk::addByte(U8 byte) { if (mCodeChunk) { U8 *temp = new U8[mCurrentOffset + 1]; memcpy(temp, mCodeChunk, mCurrentOffset); /* Flawfinder: ignore */ delete [] mCodeChunk; mCodeChunk = temp; } else { mCodeChunk = new U8[1]; } *(mCodeChunk + mCurrentOffset++) = byte; } void LLScriptByteCodeChunk::addU16(U16 data) { U8 temp[2]; S32 offset = 0; u162bytestream(temp, offset, data); addBytes(temp, 2); } void LLScriptByteCodeChunk::addBytes(const U8 *bytes, S32 size) { if (mCodeChunk) { U8 *temp = new U8[mCurrentOffset + size]; memcpy(temp, mCodeChunk, mCurrentOffset); /* Flawfinder: ignore */ delete [] mCodeChunk; mCodeChunk = temp; } else { mCodeChunk = new U8[size]; } memcpy(mCodeChunk + mCurrentOffset, bytes, size);/* Flawfinder: ignore */ mCurrentOffset += size; } void LLScriptByteCodeChunk::addBytes(const char *bytes, S32 size) { if (mCodeChunk) { U8 *temp = new U8[mCurrentOffset + size]; memcpy(temp, mCodeChunk, mCurrentOffset); /*Flawfinder: ignore*/ delete [] mCodeChunk; mCodeChunk = temp; } else { mCodeChunk = new U8[size]; } memcpy(mCodeChunk + mCurrentOffset, bytes, size); /*Flawfinder: ignore*/ mCurrentOffset += size; } void LLScriptByteCodeChunk::addBytes(S32 size) { if (mCodeChunk) { U8 *temp = new U8[mCurrentOffset + size]; memcpy(temp, mCodeChunk, mCurrentOffset); /*Flawfinder: ignore*/ delete [] mCodeChunk; mCodeChunk = temp; } else { mCodeChunk = new U8[size]; } memset(mCodeChunk + mCurrentOffset, 0, size); mCurrentOffset += size; } void LLScriptByteCodeChunk::addBytesDontInc(S32 size) { if (mCodeChunk) { U8 *temp = new U8[mCurrentOffset + size]; memcpy(temp, mCodeChunk, mCurrentOffset); /*Flawfinder: ignore*/ delete [] mCodeChunk; mCodeChunk = temp; } else { mCodeChunk = new U8[size]; } memset(mCodeChunk + mCurrentOffset, 0, size); } void LLScriptByteCodeChunk::addInteger(S32 value) { U8 temp[4]; S32 offset = 0; integer2bytestream(temp, offset, value); addBytes(temp, 4); } void LLScriptByteCodeChunk::addFloat(F32 value) { U8 temp[4]; S32 offset = 0; float2bytestream(temp, offset, value); addBytes(temp, 4); } void LLScriptByteCodeChunk::addLabel(char *name) { if (mJumpTable) { mJumpTable->addLabel(name, mCurrentOffset); } } void LLScriptByteCodeChunk::addJump(char *name) { if (mJumpTable) { mJumpTable->addJump(name, mCurrentOffset); } } // format is Byte 0: jump op code Byte 1 - 4: offset // the jump position points to Byte 5, so we need to add the data at // offset - 4, offset - 3, offset - 2, and offset - 1 // offset is label - jump void LLScriptByteCodeChunk::connectJumps() { char *jump; S32 offset, jumppos; if (mJumpTable) { for (jump = mJumpTable->mJumpMap.getFirstKey(); jump; jump = mJumpTable->mJumpMap.getNextKey()) { jumppos = *mJumpTable->mJumpMap[jump]; offset = *mJumpTable->mLabelMap[jump] - jumppos; jumppos = jumppos - 4; integer2bytestream(mCodeChunk, jumppos, offset); } } } LLScriptScriptCodeChunk::LLScriptScriptCodeChunk(S32 total_size) : mTotalSize(total_size), mCompleteCode(NULL) { mRegisters = new LLScriptByteCodeChunk(FALSE); mGlobalVariables = new LLScriptByteCodeChunk(FALSE); mGlobalFunctions = new LLScriptByteCodeChunk(FALSE); mStates = new LLScriptByteCodeChunk(FALSE); mHeap = new LLScriptByteCodeChunk(FALSE); } LLScriptScriptCodeChunk::~LLScriptScriptCodeChunk() { delete mRegisters; delete mGlobalVariables; delete mGlobalFunctions; delete mStates; delete mHeap; delete [] mCompleteCode; } void LLScriptScriptCodeChunk::build(LLFILE *efp, LLFILE *bcfp) { S32 code_data_size = mRegisters->mCurrentOffset + mGlobalVariables->mCurrentOffset + mGlobalFunctions->mCurrentOffset + mStates->mCurrentOffset + mHeap->mCurrentOffset; S32 offset = 0; if (code_data_size < mTotalSize) { mCompleteCode = new U8[mTotalSize]; memset(mCompleteCode, 0, mTotalSize); memcpy(mCompleteCode, mRegisters->mCodeChunk, mRegisters->mCurrentOffset); offset += mRegisters->mCurrentOffset; set_register(mCompleteCode, LREG_IP, 0); set_register(mCompleteCode, LREG_VN, LSL2_VERSION_NUMBER); set_event_register(mCompleteCode, LREG_IE, 0, LSL2_CURRENT_MAJOR_VERSION); set_register(mCompleteCode, LREG_BP, mTotalSize - 1); set_register(mCompleteCode, LREG_SP, mTotalSize - 1); set_register(mCompleteCode, LREG_GVR, offset); memcpy(mCompleteCode + offset, mGlobalVariables->mCodeChunk, mGlobalVariables->mCurrentOffset); /*Flawfinder: ignore*/ offset += mGlobalVariables->mCurrentOffset; set_register(mCompleteCode, LREG_GFR, offset); memcpy(mCompleteCode + offset, mGlobalFunctions->mCodeChunk, mGlobalFunctions->mCurrentOffset); /*Flawfinder: ignore*/ offset += mGlobalFunctions->mCurrentOffset; set_register(mCompleteCode, LREG_SR, offset); // zero is, by definition the default state set_register(mCompleteCode, LREG_CS, 0); set_register(mCompleteCode, LREG_NS, 0); set_event_register(mCompleteCode, LREG_CE, LSCRIPTStateBitField[LSTT_STATE_ENTRY], LSL2_CURRENT_MAJOR_VERSION); S32 default_state_offset = 0; if (LSL2_CURRENT_MAJOR_VERSION == LSL2_MAJOR_VERSION_TWO) { default_state_offset = 8; } else { default_state_offset = 4; } set_event_register(mCompleteCode, LREG_ER, bytestream2u64(mStates->mCodeChunk, default_state_offset), LSL2_CURRENT_MAJOR_VERSION); memcpy(mCompleteCode + offset, mStates->mCodeChunk, mStates->mCurrentOffset); /*Flawfinder: ignore*/ offset += mStates->mCurrentOffset; set_register(mCompleteCode, LREG_HR, offset); memcpy(mCompleteCode + offset, mHeap->mCodeChunk, mHeap->mCurrentOffset); /*Flawfinder: ignore*/ offset += mHeap->mCurrentOffset; set_register(mCompleteCode, LREG_HP, offset); set_register(mCompleteCode, LREG_FR, 0); set_register(mCompleteCode, LREG_SLR, 0); set_register(mCompleteCode, LREG_ESR, 0); set_register(mCompleteCode, LREG_PR, 0); set_register(mCompleteCode, LREG_TM, mTotalSize); if (fwrite(mCompleteCode, 1, mTotalSize, bcfp) != (size_t)mTotalSize) { llwarns << "Short write" << llendl; } } else { gErrorToText.writeError(efp, 0, 0, LSERROR_ASSEMBLE_OUT_OF_MEMORY); } } LLScriptScriptCodeChunk *gScriptCodeChunk;