321 lines
8.1 KiB
C++
Executable File
321 lines
8.1 KiB
C++
Executable File
/**
|
|
* @file lscript_bytecode.cpp
|
|
* @brief classes to build actual bytecode
|
|
*
|
|
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/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;
|