summaryrefslogtreecommitdiff
path: root/indra/lscript/lscript_execute/lscript_execute.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/lscript/lscript_execute/lscript_execute.cpp')
-rw-r--r--indra/lscript/lscript_execute/lscript_execute.cpp1243
1 files changed, 754 insertions, 489 deletions
diff --git a/indra/lscript/lscript_execute/lscript_execute.cpp b/indra/lscript/lscript_execute/lscript_execute.cpp
index 12b55c8ea8..d79e9f8bde 100644
--- a/indra/lscript/lscript_execute/lscript_execute.cpp
+++ b/indra/lscript/lscript_execute/lscript_execute.cpp
@@ -2,35 +2,31 @@
* @file lscript_execute.cpp
* @brief classes to execute bytecode
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* 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://secondlife.com/developers/opensource/gplv2
+ * 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.
*
- * 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://secondlife.com/developers/opensource/flossexception
+ * 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.
*
- * 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.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
+#include <algorithm>
#include <sstream>
#include "lscript_execute.h"
@@ -39,13 +35,19 @@
#include "lscript_library.h"
#include "lscript_heapruntime.h"
#include "lscript_alloc.h"
+#include "llstat.h"
+
+
+// Static
+const S32 DEFAULT_SCRIPT_TIMER_CHECK_SKIP = 4;
+S32 LLScriptExecute::sTimerCheckSkip = DEFAULT_SCRIPT_TIMER_CHECK_SKIP;
void (*binary_operations[LST_EOF][LST_EOF])(U8 *buffer, LSCRIPTOpCodesEnum opcode);
void (*unary_operations[LST_EOF])(U8 *buffer, LSCRIPTOpCodesEnum opcode);
-char* LSCRIPTRunTimeFaultStrings[LSRF_EOF] = /*Flawfinder: ignore*/
+const char* LSCRIPTRunTimeFaultStrings[LSRF_EOF] = /*Flawfinder: ignore*/
{
- "invalid", // LSRF_INVALID,
+ "Invalid", // LSRF_INVALID,
"Math Error", // LSRF_MATH,
"Stack-Heap Collision", // LSRF_STACK_HEAP_COLLISION,
"Bounds Check Error", // LSRF_BOUND_CHECK_ERROR,
@@ -55,16 +57,23 @@ char* LSCRIPTRunTimeFaultStrings[LSRF_EOF] = /*Flawfinder: ignore*/
"Hit Sandbox Limit", // LSRF_SANDBOX,
"Chat Overrun", // LSRF_CHAT_OVERRUN,
"Too Many Listens", // LSRF_TOO_MANY_LISTENS,
- "Lists may not contain lists" // LSRF_NESTING_LISTS,
+ "Lists may not contain lists", // LSRF_NESTING_LISTS,
+ "CLI Exception" // LSRF_CLI
};
-//static
-S64 LLScriptExecute::sGlobalInstructionCount = 0;
+void LLScriptExecuteLSL2::startRunning() {}
+void LLScriptExecuteLSL2::stopRunning() {}
+
+const char* URL_REQUEST_GRANTED = "URL_REQUEST_GRANTED";
+const char* URL_REQUEST_DENIED = "URL_REQUEST_DENIED";
-LLScriptExecute::LLScriptExecute(FILE *fp)
+// HTTP Requests to LSL scripts will time out after 25 seconds.
+const U64 LSL_HTTP_REQUEST_TIMEOUT_USEC = 25 * USEC_PER_SEC;
+
+LLScriptExecuteLSL2::LLScriptExecuteLSL2(LLFILE *fp)
{
U8 sizearray[4];
- S32 filesize;
+ size_t filesize;
S32 pos = 0;
if (fread(&sizearray, 1, 4, fp) != 4)
{
@@ -84,19 +93,27 @@ LLScriptExecute::LLScriptExecute(FILE *fp)
init();
}
-LLScriptExecute::LLScriptExecute(U8 *buffer)
+LLScriptExecuteLSL2::LLScriptExecuteLSL2(const U8* bytecode, U32 bytecode_size)
{
- mBuffer = buffer;
-
+ mBuffer = new U8[TOP_OF_MEMORY];
+ memset(mBuffer + bytecode_size, 0, TOP_OF_MEMORY - bytecode_size);
+ S32 src_offset = 0;
+ S32 dest_offset = 0;
+ bytestream2bytestream(mBuffer, dest_offset, bytecode, src_offset, bytecode_size);
+ mBytecodeSize = bytecode_size;
+ mBytecode = new U8[mBytecodeSize];
+ memcpy(mBytecode, bytecode, mBytecodeSize);
init();
}
-LLScriptExecute::~LLScriptExecute()
+LLScriptExecute::~LLScriptExecute() {}
+LLScriptExecuteLSL2::~LLScriptExecuteLSL2()
{
- delete [] mBuffer;
+ delete[] mBuffer;
+ delete[] mBytecode;
}
-void LLScriptExecute::init()
+void LLScriptExecuteLSL2::init()
{
S32 i, j;
@@ -270,7 +287,7 @@ void LLScriptExecute::init()
// Utility routine for when there's a boundary error parsing bytecode
-void LLScriptExecute::recordBoundaryError( const LLUUID &id )
+void LLScriptExecuteLSL2::recordBoundaryError( const LLUUID &id )
{
set_fault(mBuffer, LSRF_BOUND_CHECK_ERROR);
llwarns << "Script boundary error for ID " << id << llendl;
@@ -278,7 +295,7 @@ void LLScriptExecute::recordBoundaryError( const LLUUID &id )
// set IP to the event handler with some error checking
-void LLScriptExecute::setStateEventOpcoodeStartSafely( S32 state, LSCRIPTStateEventType event, const LLUUID &id )
+void LLScriptExecuteLSL2::setStateEventOpcoodeStartSafely( S32 state, LSCRIPTStateEventType event, const LLUUID &id )
{
S32 opcode_start = get_state_event_opcoode_start( mBuffer, state, event );
if ( opcode_start == -1 )
@@ -296,12 +313,499 @@ void LLScriptExecute::setStateEventOpcoodeStartSafely( S32 state, LSCRIPTStateEv
S32 lscript_push_variable(LLScriptLibData *data, U8 *buffer);
-U32 LLScriptExecute::run(BOOL b_print, const LLUUID &id, char **errorstr, BOOL &state_transition)
+void LLScriptExecuteLSL2::resumeEventHandler(BOOL b_print, const LLUUID &id, F32 time_slice)
+{
+ // call opcode run function pointer with buffer and IP
+ mInstructionCount++;
+ S32 value = get_register(mBuffer, LREG_IP);
+ S32 tvalue = value;
+ S32 opcode = safe_instruction_bytestream2byte(mBuffer, tvalue);
+ mExecuteFuncs[opcode](mBuffer, value, b_print, id);
+ set_ip(mBuffer, value);
+ add_register_fp(mBuffer, LREG_ESR, -0.1f);
+ // lsa_print_heap(mBuffer);
+
+ if (b_print)
+ {
+ lsa_print_heap(mBuffer);
+ printf("ip: 0x%X\n", get_register(mBuffer, LREG_IP));
+ printf("sp: 0x%X\n", get_register(mBuffer, LREG_SP));
+ printf("bp: 0x%X\n", get_register(mBuffer, LREG_BP));
+ printf("hr: 0x%X\n", get_register(mBuffer, LREG_HR));
+ printf("hp: 0x%X\n", get_register(mBuffer, LREG_HP));
+ }
+
+ // NOTE: Babbage: all mExecuteFuncs return false.
+}
+
+void LLScriptExecuteLSL2::callEventHandler(LSCRIPTStateEventType event, const LLUUID &id, F32 time_slice)
+{
+ S32 major_version = getMajorVersion();
+ // push a zero to be popped
+ lscript_push(mBuffer, 0);
+ // push sp as current bp
+ S32 sp = get_register(mBuffer, LREG_SP);
+ lscript_push(mBuffer, sp);
+
+ // Update current handler and current events registers.
+ set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version);
+ U64 current_events = get_event_register(mBuffer, LREG_CE, major_version);
+ current_events &= ~LSCRIPTStateBitField[event];
+ set_event_register(mBuffer, LREG_CE, current_events, major_version);
+
+ // now, push any additional stack space
+ U32 current_state = get_register(mBuffer, LREG_CS);
+ S32 additional_size = get_event_stack_size(mBuffer, current_state, event);
+ lscript_pusharge(mBuffer, additional_size);
+
+ // now set the bp correctly
+ sp = get_register(mBuffer, LREG_SP);
+ sp += additional_size;
+ set_bp(mBuffer, sp);
+
+ // set IP to the function
+ S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event);
+ set_ip(mBuffer, opcode_start);
+}
+
+//void callStateExitHandler()
+//{
+// // push a zero to be popped
+// lscript_push(mBuffer, 0);
+// // push sp as current bp
+// S32 sp = get_register(mBuffer, LREG_SP);
+// lscript_push(mBuffer, sp);
+//
+// // now, push any additional stack space
+// S32 additional_size = get_event_stack_size(mBuffer, current_state, LSTT_STATE_EXIT);
+// lscript_pusharge(mBuffer, additional_size);
+//
+// sp = get_register(mBuffer, LREG_SP);
+// sp += additional_size;
+// set_bp(mBuffer, sp);
+//
+// // set IP to the event handler
+// S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, LSTT_STATE_EXIT);
+// set_ip(mBuffer, opcode_start);
+//}
+//
+//void callStateEntryHandler()
+//{
+// // push a zero to be popped
+// lscript_push(mBuffer, 0);
+// // push sp as current bp
+// S32 sp = get_register(mBuffer, LREG_SP);
+// lscript_push(mBuffer, sp);
+//
+// event = return_first_event((S32)LSCRIPTStateBitField[LSTT_STATE_ENTRY]);
+// set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version);
+// current_events &= ~LSCRIPTStateBitField[event];
+// set_event_register(mBuffer, LREG_CE, current_events, major_version);
+//
+// // now, push any additional stack space
+// S32 additional_size = get_event_stack_size(mBuffer, current_state, event) - size;
+// lscript_pusharge(mBuffer, additional_size);
+//
+// // now set the bp correctly
+// sp = get_register(mBuffer, LREG_SP);
+// sp += additional_size + size;
+// set_bp(mBuffer, sp);
+// // set IP to the function
+// S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event);
+// set_ip(mBuffer, opcode_start);
+//}
+
+void LLScriptExecuteLSL2::callQueuedEventHandler(LSCRIPTStateEventType event, const LLUUID &id, F32 time_slice)
+{
+ S32 major_version = getMajorVersion();
+ LLScriptDataCollection* eventdata;
+
+ for (eventdata = mEventData.mEventDataList.getFirstData(); eventdata; eventdata = mEventData.mEventDataList.getNextData())
+ {
+ if (eventdata->mType == event)
+ {
+ // push a zero to be popped
+ lscript_push(mBuffer, 0);
+ // push sp as current bp
+ S32 sp = get_register(mBuffer, LREG_SP);
+ lscript_push(mBuffer, sp);
+
+ // Update current handler and current events registers.
+ set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version);
+ U64 current_events = get_event_register(mBuffer, LREG_CE, major_version);
+ current_events &= ~LSCRIPTStateBitField[event];
+ set_event_register(mBuffer, LREG_CE, current_events, major_version);
+
+ // push any arguments that need to be pushed onto the stack
+ // last piece of data will be type LST_NULL
+ LLScriptLibData *data = eventdata->mData;
+ U32 size = 0;
+ while (data->mType)
+ {
+ size += lscript_push_variable(data, mBuffer);
+ data++;
+ }
+ // now, push any additional stack space
+ U32 current_state = get_register(mBuffer, LREG_CS);
+ S32 additional_size = get_event_stack_size(mBuffer, current_state, event) - size;
+ lscript_pusharge(mBuffer, additional_size);
+
+ // now set the bp correctly
+ sp = get_register(mBuffer, LREG_SP);
+ sp += additional_size + size;
+ set_bp(mBuffer, sp);
+
+ // set IP to the function
+ S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event);
+ set_ip(mBuffer, opcode_start);
+
+ mEventData.mEventDataList.deleteCurrentData();
+ break;
+ }
+ }
+}
+
+void LLScriptExecuteLSL2::callNextQueuedEventHandler(U64 event_register, const LLUUID &id, F32 time_slice)
+{
+ S32 major_version = getMajorVersion();
+ LLScriptDataCollection* eventdata = mEventData.getNextEvent();
+ if (eventdata)
+ {
+ LSCRIPTStateEventType event = eventdata->mType;
+
+ // make sure that we can actually handle this one
+ if (LSCRIPTStateBitField[event] & event_register)
+ {
+ // push a zero to be popped
+ lscript_push(mBuffer, 0);
+ // push sp as current bp
+ S32 sp = get_register(mBuffer, LREG_SP);
+ lscript_push(mBuffer, sp);
+
+ // Update current handler and current events registers.
+ set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version);
+ U64 current_events = get_event_register(mBuffer, LREG_CE, major_version);
+ current_events &= ~LSCRIPTStateBitField[event];
+ set_event_register(mBuffer, LREG_CE, current_events, major_version);
+
+ // push any arguments that need to be pushed onto the stack
+ // last piece of data will be type LST_NULL
+ LLScriptLibData *data = eventdata->mData;
+ U32 size = 0;
+ while (data->mType)
+ {
+ size += lscript_push_variable(data, mBuffer);
+ data++;
+ }
+
+ // now, push any additional stack space
+ U32 current_state = get_register(mBuffer, LREG_CS);
+ S32 additional_size = get_event_stack_size(mBuffer, current_state, event) - size;
+ lscript_pusharge(mBuffer, additional_size);
+
+ // now set the bp correctly
+ sp = get_register(mBuffer, LREG_SP);
+ sp += additional_size + size;
+ set_bp(mBuffer, sp);
+
+ // set IP to the function
+ S32 opcode_start = get_state_event_opcoode_start(mBuffer, current_state, event);
+ set_ip(mBuffer, opcode_start);
+ }
+ else
+ {
+ llwarns << "Somehow got an event that we're not registered for!" << llendl;
+ }
+ delete eventdata;
+ }
+}
+
+U64 LLScriptExecuteLSL2::nextState()
+{
+ // copy NS to CS
+ S32 next_state = get_register(mBuffer, LREG_NS);
+ set_register(mBuffer, LREG_CS, next_state);
+
+ // copy new state's handled events into ER (SR + CS*4 + 4)
+ return get_handled_events(mBuffer, next_state);
+}
+
+//virtual
+void LLScriptExecuteLSL2::addEvent(LLScriptDataCollection* event)
+{
+ mEventData.addEventData(event);
+}
+
+//virtual
+void LLScriptExecuteLSL2::removeEventType(LSCRIPTStateEventType event_type)
+{
+ mEventData.removeEventType(event_type);
+}
+
+//virtual
+F32 LLScriptExecuteLSL2::getSleep() const
+{
+ return get_register_fp(mBuffer, LREG_SLR);
+}
+
+//virtual
+void LLScriptExecuteLSL2::setSleep(F32 value)
+{
+ set_register_fp(mBuffer, LREG_SLR, value);
+}
+
+//virtual
+U64 LLScriptExecuteLSL2::getCurrentHandler()
+{
+ return get_event_register(mBuffer, LREG_IE, getMajorVersion());
+}
+
+//virtual
+F32 LLScriptExecuteLSL2::getEnergy() const
+{
+ return get_register_fp(mBuffer, LREG_ESR);
+}
+
+//virtual
+void LLScriptExecuteLSL2::setEnergy(F32 value)
+{
+ set_register_fp(mBuffer, LREG_ESR, value);
+}
+
+//virtual
+U32 LLScriptExecuteLSL2::getFreeMemory()
+{
+ return get_register(mBuffer, LREG_SP) - get_register(mBuffer, LREG_HP);
+}
+
+//virtual
+S32 LLScriptExecuteLSL2::getParameter()
+{
+ return get_register(mBuffer, LREG_PR);
+}
+
+//virtual
+void LLScriptExecuteLSL2::setParameter(S32 value)
+{
+ set_register(mBuffer, LREG_PR, value);
+}
+
+
+S32 LLScriptExecuteLSL2::writeState(U8 **dest, U32 header_size, U32 footer_size)
+{
+ // data format:
+ // 4 bytes of size of Registers, Name and Description, and Global Variables
+ // Registers, Name and Description, and Global Variables data
+ // 4 bytes of size of Heap
+ // Heap data
+ // 4 bytes of stack size
+ // Stack data
+
+ S32 registers_size = get_register(mBuffer, LREG_GFR);
+
+ if (get_register(mBuffer, LREG_HP) > TOP_OF_MEMORY)
+ reset_hp_to_safe_spot(mBuffer);
+
+ S32 heap_size = get_register(mBuffer, LREG_HP) - get_register(mBuffer, LREG_HR);
+ S32 stack_size = get_register(mBuffer, LREG_TM) - get_register(mBuffer, LREG_SP);
+ S32 total_size = registers_size + LSCRIPTDataSize[LST_INTEGER] +
+ heap_size + LSCRIPTDataSize[LST_INTEGER] +
+ stack_size + LSCRIPTDataSize[LST_INTEGER];
+
+ // actually allocate data
+ delete[] *dest;
+ *dest = new U8[header_size + total_size + footer_size];
+ memset(*dest, 0, header_size + total_size + footer_size);
+ S32 dest_offset = header_size;
+ S32 src_offset = 0;
+
+ // registers
+ integer2bytestream(*dest, dest_offset, registers_size);
+
+ // llinfos << "Writing CE: " << getCurrentEvents() << llendl;
+ bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, registers_size);
+
+ // heap
+ integer2bytestream(*dest, dest_offset, heap_size);
+
+ src_offset = get_register(mBuffer, LREG_HR);
+ bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, heap_size);
+
+ // stack
+ integer2bytestream(*dest, dest_offset, stack_size);
+
+ src_offset = get_register(mBuffer, LREG_SP);
+ bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, stack_size);
+
+ return total_size;
+}
+
+S32 LLScriptExecuteLSL2::writeBytecode(U8 **dest)
+{
+ // data format:
+ // registers through top of heap
+ // Heap data
+ S32 total_size = get_register(mBuffer, LREG_HP);
+
+ // actually allocate data
+ delete [] *dest;
+ *dest = new U8[total_size];
+ S32 dest_offset = 0;
+ S32 src_offset = 0;
+
+ bytestream2bytestream(*dest, dest_offset, mBuffer, src_offset, total_size);
+
+ return total_size;
+}
+
+S32 LLScriptExecuteLSL2::readState(U8 *src)
+{
+ // first, blitz heap and stack
+ S32 hr = get_register(mBuffer, LREG_HR);
+ S32 tm = get_register(mBuffer, LREG_TM);
+ memset(mBuffer + hr, 0, tm - hr);
+
+ S32 src_offset = 0;
+ S32 dest_offset = 0;
+ S32 size;
+
+ // read register size
+ size = bytestream2integer(src, src_offset);
+
+ // copy data into register area
+ bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size);
+// llinfos << "Read CE: " << getCurrentEvents() << llendl;
+ if (get_register(mBuffer, LREG_TM) != TOP_OF_MEMORY)
+ {
+ llwarns << "Invalid state. Top of memory register does not match"
+ << " constant." << llendl;
+ reset_hp_to_safe_spot(mBuffer);
+ return -1;
+ }
+
+ // read heap size
+ size = bytestream2integer(src, src_offset);
+
+ // set dest offset
+ dest_offset = get_register(mBuffer, LREG_HR);
+
+ if (dest_offset + size > TOP_OF_MEMORY)
+ {
+ reset_hp_to_safe_spot(mBuffer);
+ return -1;
+ }
+
+ // copy data into heap area
+ bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size);
+
+ // read stack size
+ size = bytestream2integer(src, src_offset);
+
+ // set dest offset
+ dest_offset = get_register(mBuffer, LREG_SP);
+
+ if (dest_offset + size > TOP_OF_MEMORY)
+ {
+ reset_hp_to_safe_spot(mBuffer);
+ return -1;
+ }
+
+ // copy data into heap area
+ bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size);
+
+ // Return offset to first byte after read data.
+ return src_offset;
+}
+
+void LLScriptExecuteLSL2::reset()
+{
+ LLScriptExecute::reset();
+
+ const U8 *src = getBytecode();
+ S32 size = getBytecodeSize();
+
+ if (!src)
+ return;
+
+ // first, blitz heap and stack
+ S32 hr = get_register(mBuffer, LREG_HR);
+ S32 tm = get_register(mBuffer, LREG_TM);
+ memset(mBuffer + hr, 0, tm - hr);
+
+ S32 dest_offset = 0;
+ S32 src_offset = 0;
+
+ bytestream2bytestream(mBuffer, dest_offset, src, src_offset, size);
+}
+
+S32 LLScriptExecuteLSL2::getMajorVersion() const
+{
+ S32 version = getVersion();
+ S32 major_version = 0;
+ if (version == LSL2_VERSION1_END_NUMBER){
+ major_version = 1;
+ }
+ else if (version == LSL2_VERSION_NUMBER)
+ {
+ major_version = 2;
+ }
+ return major_version;
+}
+
+U32 LLScriptExecuteLSL2::getUsedMemory()
+{
+ return getBytecodeSize();
+}
+
+LLScriptExecute::LLScriptExecute() :
+ mReset(FALSE)
+{
+}
+
+void LLScriptExecute::reset()
+{
+ mReset = FALSE;
+}
+
+bool LLScriptExecute::isYieldDue() const
+{
+ if(mReset)
+ {
+ return true;
+ }
+
+ if(getSleep() > 0.f)
+ {
+ return true;
+ }
+
+ if(isFinished())
+ {
+ return true;
+ }
+
+ // State changes can occur within a single time slice,
+ // but LLScriptData's clean up is required. Yield here
+ // to allow LLScriptData to perform cleanup and then call
+ // runQuanta again.
+ if(isStateChangePending())
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Run smallest number of instructions possible:
+// a single instruction for LSL2, a segment between save tests for Mono
+void LLScriptExecute::runInstructions(BOOL b_print, const LLUUID &id,
+ const char **errorstr,
+ U32& events_processed,
+ F32 quanta)
{
// is there a fault?
// if yes, print out message and exit
- state_transition = FALSE;
- S32 value = get_register(mBuffer, LREG_VN);
+ S32 value = getVersion();
S32 major_version = 0;
if (value == LSL2_VERSION1_END_NUMBER)
{
@@ -313,323 +817,156 @@ U32 LLScriptExecute::run(BOOL b_print, const LLUUID &id, char **errorstr, BOOL &
}
else
{
- set_fault(mBuffer, LSRF_VERSION_MISMATCH);
+ setFault(LSRF_VERSION_MISMATCH);
}
- value = get_register(mBuffer, LREG_FR);
- if (value)
+ value = getFaults();
+ if (value > LSRF_INVALID && value < LSRF_EOF)
{
if (b_print)
{
printf("Error!\n");
}
*errorstr = LSCRIPTRunTimeFaultStrings[value];
- return NO_DELETE_FLAG;
+ return;
}
else
{
*errorstr = NULL;
}
- // Get IP
- // is IP nonzero?
- value = get_register(mBuffer, LREG_IP);
-
- if (value)
+ if (! isFinished())
{
- // if yes, we're in opcodes, execute the next opcode by:
- // call opcode run function pointer with buffer and IP
- mInstructionCount++;
- sGlobalInstructionCount++;
- S32 tvalue = value;
- S32 opcode = safe_instruction_bytestream2byte(mBuffer, tvalue);
- S32 b_ret_val = mExecuteFuncs[opcode](mBuffer, value, b_print, id);
- set_ip(mBuffer, value);
- add_register_fp(mBuffer, LREG_ESR, -0.1f);
- // lsa_print_heap(mBuffer);
-
- if (b_print)
- {
- lsa_print_heap(mBuffer);
- printf("ip: 0x%X\n", get_register(mBuffer, LREG_IP));
- printf("sp: 0x%X\n", get_register(mBuffer, LREG_SP));
- printf("bp: 0x%X\n", get_register(mBuffer, LREG_BP));
- printf("hr: 0x%X\n", get_register(mBuffer, LREG_HR));
- printf("hp: 0x%X\n", get_register(mBuffer, LREG_HP));
- }
- // update IP
- if (b_ret_val)
- {
- return DELETE_FLAG | CREDIT_MONEY_FLAG;
- }
- else
- {
- return NO_DELETE_FLAG;
- }
+ resumeEventHandler(b_print, id, quanta);
+ return;
}
else
{
// make sure that IE is zero
- set_event_register(mBuffer, LREG_IE, 0, major_version);
-
- // if no, we're in a state and waiting for an event
- S32 next_state = get_register(mBuffer, LREG_NS);
- S32 current_state = get_register(mBuffer, LREG_CS);
- U64 current_events = get_event_register(mBuffer, LREG_CE, major_version);
- U64 event_register = get_event_register(mBuffer, LREG_ER, major_version);
- // check NS to see if need to switch states (NS != CS)
- if (next_state != current_state)
+ setCurrentHandler(0);
+
+ // if no, we're in a state and waiting for an event
+ U64 current_events = getCurrentEvents();
+ U64 event_register = getEventHandlers();
+
+ // check NS to see if need to switch states (NS != CS)
+ if (isStateChangePending())
{
- state_transition = TRUE;
// ok, blow away any pending events
- mEventData.mEventDataList.deleteAllData();
+ deleteAllEvents();
- // if yes, check state exit flag is set
+ // if yes, check state exit flag is set
if (current_events & LSCRIPTStateBitField[LSTT_STATE_EXIT])
{
- // if yes, clear state exit flag
- set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[LSTT_STATE_EXIT], major_version);
+ // if yes, clear state exit flag
+ setCurrentHandler(LSCRIPTStateBitField[LSTT_STATE_EXIT]);
current_events &= ~LSCRIPTStateBitField[LSTT_STATE_EXIT];
- set_event_register(mBuffer, LREG_CE, current_events, major_version);
- // check state exit event handler
- // if there is a handler, call it
+ setCurrentEvents(current_events);
+
+ // check state exit event handler
+ // if there is a handler, call it
if (event_register & LSCRIPTStateBitField[LSTT_STATE_EXIT])
{
- // push a zero to be popped
- lscript_push(mBuffer, 0);
- // push sp as current bp
- S32 sp = get_register(mBuffer, LREG_SP);
- lscript_push(mBuffer, sp);
-
- // now, push any additional stack space
- S32 additional_size = get_event_stack_size(mBuffer, current_state, LSTT_STATE_EXIT);
- if ( additional_size == -1 )
- {
- recordBoundaryError( id );
- }
- else
- {
- lscript_pusharge(mBuffer, additional_size);
-
- sp = get_register(mBuffer, LREG_SP);
- sp += additional_size;
- set_bp(mBuffer, sp);
- // set IP to the event handler
- setStateEventOpcoodeStartSafely( current_state, LSTT_STATE_EXIT, id );
- }
- return NO_DELETE_FLAG;
+ ++events_processed;
+ callEventHandler(LSTT_STATE_EXIT, id, quanta);
+ return;
}
}
- // if no handler or no state exit flag switch to new state
- // set state entry flag and clear other CE flags
+
+ // if no handler or no state exit flag switch to new state
+ // set state entry flag and clear other CE flags
current_events = LSCRIPTStateBitField[LSTT_STATE_ENTRY];
- set_event_register(mBuffer, LREG_CE, current_events, major_version);
- // copy NS to CS
- set_register(mBuffer, LREG_CS, next_state);
- // copy new state's handled events into ER (SR + CS*4 + 4)
- U64 handled_events = get_handled_events(mBuffer, next_state);
- set_event_register(mBuffer, LREG_ER, handled_events, major_version);
+ setCurrentEvents(current_events);
+
+ U64 handled_events = nextState();
+ setEventHandlers(handled_events);
}
-// check to see if any current events are covered by events handled by this state (CE & ER != 0)
-// now, we want to look like we were called like a function
-// 0x0000: 00 00 00 00 (return ip)
-// 0x0004: bp (current sp)
-// 0x0008: parameters
-// push sp
-// add parameter size
-// pop bp
-// set ip
-
- S32 size = 0;
-// try to get next event from stack
+
+ // try to get next event from stack
BOOL b_done = FALSE;
LSCRIPTStateEventType event = LSTT_NULL;
- LLScriptDataCollection *eventdata;
- next_state = get_register(mBuffer, LREG_NS);
- current_state = get_register(mBuffer, LREG_CS);
- current_events = get_event_register(mBuffer, LREG_CE, major_version);
- event_register = get_event_register(mBuffer, LREG_ER, major_version);
+ current_events = getCurrentEvents();
+ event_register = getEventHandlers();
// first, check to see if state_entry or onrez are raised and handled
- if ( (current_events & LSCRIPTStateBitField[LSTT_STATE_ENTRY])
+ if ((current_events & LSCRIPTStateBitField[LSTT_STATE_ENTRY])
&&(current_events & event_register))
{
- // ok, this is easy since there isn't any data waiting, just set it
- // push a zero to be popped
- lscript_push(mBuffer, 0);
-// push sp as current bp
- S32 sp = get_register(mBuffer, LREG_SP);
- lscript_push(mBuffer, sp);
-
- event = return_first_event((S32)LSCRIPTStateBitField[LSTT_STATE_ENTRY]);
- set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version);
- current_events &= ~LSCRIPTStateBitField[event];
- set_event_register(mBuffer, LREG_CE, current_events, major_version);
-// now, push any additional stack space
- S32 additional_size = get_event_stack_size(mBuffer, current_state, event);
- if ( additional_size == -1 )
- { // b_done will be set, so we'll exit the loop at the bottom
- recordBoundaryError( id );
- }
- else
- {
- additional_size -= size;
- lscript_pusharge(mBuffer, additional_size);
-
-// now set the bp correctly
- sp = get_register(mBuffer, LREG_SP);
- sp += additional_size + size;
- set_bp(mBuffer, sp);
-// set IP to the function
- setStateEventOpcoodeStartSafely( current_state, event, id );
- }
+ ++events_processed;
+ callEventHandler(LSTT_STATE_ENTRY, id, quanta);
b_done = TRUE;
}
- else if ( (current_events & LSCRIPTStateBitField[LSTT_REZ])
- &&(current_events & event_register))
+ else if ((current_events & LSCRIPTStateBitField[LSTT_REZ])
+ &&(current_events & event_register))
{
- for (eventdata = mEventData.mEventDataList.getFirstData(); eventdata; eventdata = mEventData.mEventDataList.getNextData())
- {
- if (eventdata->mType & LSCRIPTStateBitField[LSTT_REZ])
- {
- // push a zero to be popped
- lscript_push(mBuffer, 0);
- // push sp as current bp
- S32 sp = get_register(mBuffer, LREG_SP);
- lscript_push(mBuffer, sp);
-
- set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version);
- current_events &= ~LSCRIPTStateBitField[event];
- set_event_register(mBuffer, LREG_CE, current_events, major_version);
-
- // push any arguments that need to be pushed onto the stack
- // last piece of data will be type LST_NULL
- LLScriptLibData *data = eventdata->mData;
- while (data->mType)
- {
- size += lscript_push_variable(data, mBuffer);
- data++;
- }
- // now, push any additional stack space
- S32 additional_size = get_event_stack_size(mBuffer, current_state, event);
- if ( additional_size == -1 )
- { // b_done will be set, so we'll exit the loop at the bottom
- recordBoundaryError( id );
- }
- else
- {
- additional_size -= size;
- lscript_pusharge(mBuffer, additional_size);
-
- // now set the bp correctly
- sp = get_register(mBuffer, LREG_SP);
- sp += additional_size + size;
- set_bp(mBuffer, sp);
- // set IP to the function
- setStateEventOpcoodeStartSafely( current_state, event, id );
- mEventData.mEventDataList.deleteCurrentData();
- }
- b_done = TRUE;
- break;
- }
- }
+ ++events_processed;
+ callQueuedEventHandler(LSTT_REZ, id, quanta);
+ b_done = TRUE;
}
- while (!b_done)
+ if (!b_done)
{
- eventdata = mEventData.getNextEvent();
- if (eventdata)
+ // Call handler for next queued event.
+ if(getEventCount() > 0)
{
- event = eventdata->mType;
-
- // make sure that we can actually handle this one
- if (LSCRIPTStateBitField[event] & event_register)
- {
- // push a zero to be popped
- lscript_push(mBuffer, 0);
- // push sp as current bp
- S32 sp = get_register(mBuffer, LREG_SP);
- lscript_push(mBuffer, sp);
-
- set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version);
- current_events &= ~LSCRIPTStateBitField[event];
- set_event_register(mBuffer, LREG_CE, current_events, major_version);
-
- // push any arguments that need to be pushed onto the stack
- // last piece of data will be type LST_NULL
- LLScriptLibData *data = eventdata->mData;
- while (data->mType)
- {
- size += lscript_push_variable(data, mBuffer);
- data++;
- }
- b_done = TRUE;
- // now, push any additional stack space
- S32 additional_size = get_event_stack_size(mBuffer, current_state, event);
- if ( additional_size == -1 )
- { // b_done was just set, so we'll exit the loop at the bottom
- recordBoundaryError( id );
- }
- else
- {
- additional_size -= size;
- lscript_pusharge(mBuffer, additional_size);
-
- // now set the bp correctly
- sp = get_register(mBuffer, LREG_SP);
- sp += additional_size + size;
- set_bp(mBuffer, sp);
- // set IP to the function
- setStateEventOpcoodeStartSafely( current_state, event, id );
- }
- }
- else
- {
- llwarns << "Shit, somehow got an event that we're not registered for!" << llendl;
- }
- delete eventdata;
+ ++events_processed;
+ callNextQueuedEventHandler(event_register, id, quanta);
}
else
{
-// if no data waiting, do it the old way:
+ // if no data waiting, do it the old way:
U64 handled_current = current_events & event_register;
if (handled_current)
{
- // push a zero to be popped
- lscript_push(mBuffer, 0);
- // push sp as current bp
- S32 sp = get_register(mBuffer, LREG_SP);
- lscript_push(mBuffer, sp);
-
event = return_first_event((S32)handled_current);
- set_event_register(mBuffer, LREG_IE, LSCRIPTStateBitField[event], major_version);
- current_events &= ~LSCRIPTStateBitField[event];
- set_event_register(mBuffer, LREG_CE, current_events, major_version);
- // now, push any additional stack space
- S32 additional_size = get_event_stack_size(mBuffer, current_state, event);
- if ( additional_size == -1 )
- { // b_done will be set, so we'll exit the loop at the bottom
- recordBoundaryError( id );
- }
- else
- {
- additional_size -= size;
- lscript_pusharge(mBuffer, additional_size);
-
- // now set the bp correctly
- sp = get_register(mBuffer, LREG_SP);
- sp += additional_size + size;
- set_bp(mBuffer, sp);
- // set IP to the function
- setStateEventOpcoodeStartSafely( current_state, event, id );
- }
+ ++events_processed;
+ callEventHandler(event, id, quanta);
}
- b_done = TRUE;
}
- } // while (!b_done)
- } // end of else ... in state processing code
+ b_done = TRUE;
+ }
+ }
+}
+
+// Run for a single timeslice, or until a yield or state transition is due
+F32 LLScriptExecute::runQuanta(BOOL b_print, const LLUUID &id, const char **errorstr, F32 quanta, U32& events_processed, LLTimer& timer)
+{
+ S32 timer_checks = 0;
+ F32 inloop = 0;
- return NO_DELETE_FLAG;
+ // Loop while not finished, yield not due and time remaining
+ // NOTE: Default implementation does not do adaptive timer skipping
+ // to preserve current LSL behaviour and not break scripts that rely
+ // on current execution speed.
+ while(true)
+ {
+ runInstructions(b_print, id, errorstr,
+ events_processed, quanta);
+
+ if(isYieldDue())
+ {
+ break;
+ }
+ else if(timer_checks++ >= LLScriptExecute::sTimerCheckSkip)
+ {
+ inloop = timer.getElapsedTimeF32();
+ if(inloop > quanta)
+ {
+ break;
+ }
+ timer_checks = 0;
+ }
+ }
+ if (inloop == 0.0f)
+ {
+ inloop = timer.getElapsedTimeF32();
+ }
+ return inloop;
+}
+
+F32 LLScriptExecute::runNested(BOOL b_print, const LLUUID &id, const char **errorstr, F32 quanta, U32& events_processed, LLTimer& timer)
+{
+ return LLScriptExecute::runQuanta(b_print, id, errorstr, quanta, events_processed, timer);
}
BOOL run_noop(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
@@ -2309,14 +2646,24 @@ void list_list_operation(U8 *buffer, LSCRIPTOpCodesEnum opcode)
}
}
+static U8 safe_op_index(U8 index)
+{
+ if(index >= LST_EOF)
+ {
+ // Operations on LST_NULL will always be unknown_operation.
+ index = LST_NULL;
+ }
+ return index;
+}
+
BOOL run_add(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
{
if (b_print)
printf("[0x%X]\tADD ", offset);
offset++;
U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- U8 arg1 = arg >> 4;
- U8 arg2 = arg & 0xf;
+ U8 arg1 = safe_op_index(arg >> 4);
+ U8 arg2 = safe_op_index(arg & 0xf);
if (b_print)
{
print_type(arg1);
@@ -2334,8 +2681,8 @@ BOOL run_sub(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
printf("[0x%X]\tSUB ", offset);
offset++;
U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- U8 arg1 = arg >> 4;
- U8 arg2 = arg & 0xf;
+ U8 arg1 = safe_op_index(arg >> 4);
+ U8 arg2 = safe_op_index(arg & 0xf);
if (b_print)
{
print_type(arg1);
@@ -2352,8 +2699,8 @@ BOOL run_mul(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
printf("[0x%X]\tMUL ", offset);
offset++;
U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- U8 arg1 = arg >> 4;
- U8 arg2 = arg & 0xf;
+ U8 arg1 = safe_op_index(arg >> 4);
+ U8 arg2 = safe_op_index(arg & 0xf);
if (b_print)
{
print_type(arg1);
@@ -2370,8 +2717,8 @@ BOOL run_div(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
printf("[0x%X]\tDIV ", offset);
offset++;
U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- U8 arg1 = arg >> 4;
- U8 arg2 = arg & 0xf;
+ U8 arg1 = safe_op_index(arg >> 4);
+ U8 arg2 = safe_op_index(arg & 0xf);
if (b_print)
{
print_type(arg1);
@@ -2388,8 +2735,8 @@ BOOL run_mod(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
printf("[0x%X]\tMOD ", offset);
offset++;
U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- U8 arg1 = arg >> 4;
- U8 arg2 = arg & 0xf;
+ U8 arg1 = safe_op_index(arg >> 4);
+ U8 arg2 = safe_op_index(arg & 0xf);
if (b_print)
{
print_type(arg1);
@@ -2407,8 +2754,8 @@ BOOL run_eq(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
printf("[0x%X]\tEQ ", offset);
offset++;
U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- U8 arg1 = arg >> 4;
- U8 arg2 = arg & 0xf;
+ U8 arg1 = safe_op_index(arg >> 4);
+ U8 arg2 = safe_op_index(arg & 0xf);
if (b_print)
{
print_type(arg1);
@@ -2425,8 +2772,8 @@ BOOL run_neq(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
printf("[0x%X]\tNEQ ", offset);
offset++;
U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- U8 arg1 = arg >> 4;
- U8 arg2 = arg & 0xf;
+ U8 arg1 = safe_op_index(arg >> 4);
+ U8 arg2 = safe_op_index(arg & 0xf);
if (b_print)
{
print_type(arg1);
@@ -2443,8 +2790,8 @@ BOOL run_leq(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
printf("[0x%X]\tLEQ ", offset);
offset++;
U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- U8 arg1 = arg >> 4;
- U8 arg2 = arg & 0xf;
+ U8 arg1 = safe_op_index(arg >> 4);
+ U8 arg2 = safe_op_index(arg & 0xf);
if (b_print)
{
print_type(arg1);
@@ -2461,8 +2808,8 @@ BOOL run_geq(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
printf("[0x%X]\tGEQ ", offset);
offset++;
U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- U8 arg1 = arg >> 4;
- U8 arg2 = arg & 0xf;
+ U8 arg1 = safe_op_index(arg >> 4);
+ U8 arg2 = safe_op_index(arg & 0xf);
if (b_print)
{
print_type(arg1);
@@ -2479,8 +2826,8 @@ BOOL run_less(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
printf("[0x%X]\tLESS ", offset);
offset++;
U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- U8 arg1 = arg >> 4;
- U8 arg2 = arg & 0xf;
+ U8 arg1 = safe_op_index(arg >> 4);
+ U8 arg2 = safe_op_index(arg & 0xf);
if (b_print)
{
print_type(arg1);
@@ -2497,8 +2844,8 @@ BOOL run_greater(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
printf("[0x%X]\tGREATER ", offset);
offset++;
U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- U8 arg1 = arg >> 4;
- U8 arg2 = arg & 0xf;
+ U8 arg1 = safe_op_index(arg >> 4);
+ U8 arg2 = safe_op_index(arg & 0xf);
if (b_print)
{
print_type(arg1);
@@ -2640,13 +2987,12 @@ void quaternion_operation(U8 *buffer, LSCRIPTOpCodesEnum opcode)
}
}
-
BOOL run_neg(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
{
if (b_print)
printf("[0x%X]\tNEG ", offset);
offset++;
- U8 arg = safe_instruction_bytestream2byte(buffer, offset);
+ U8 arg = safe_op_index(safe_instruction_bytestream2byte(buffer, offset));
if (b_print)
{
print_type(arg);
@@ -2972,7 +3318,7 @@ BOOL run_state(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
{
major_version = 2;
}
-
+
S32 current_state = get_register(buffer, LREG_CS);
if (state != current_state)
{
@@ -3027,46 +3373,19 @@ BOOL run_return(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
if (b_print)
printf("[0x%X]\tRETURN\n", offset);
offset++;
- S32 bp = lscript_pop_int(buffer);
+
+ // SEC-53: babbage: broken instructions may allow inbalanced pushes and
+ // pops which can cause caller BP and return IP to be corrupted, so restore
+ // SP from BP before popping caller BP and IP.
+ S32 bp = get_register(buffer, LREG_BP);
+ set_sp(buffer, bp);
+
+ bp = lscript_pop_int(buffer);
set_bp(buffer, bp);
offset = lscript_pop_int(buffer);
return FALSE;
}
-S32 axtoi(char *hexStg)
-{
- S32 n = 0; // position in string
- S32 m = 0; // position in digit[] to shift
- S32 count; // loop index
- S32 intValue = 0; // integer value of hex string
- S32 digit[9]; // hold values to convert
- while (n < 8)
- {
- if (hexStg[n]=='\0')
- break;
- if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9
- digit[n] = hexStg[n] & 0x0f; //convert to int
- else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f
- digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
- else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F
- digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
- else break;
- n++;
- }
- count = n;
- m = n - 1;
- n = 0;
- while(n < count)
- {
- // digit[n] is value of hex digit at position n
- // (m << 2) is the number of positions to shift
- // OR the bits into return value
- intValue = intValue | (digit[n] << (m << 2));
- m--; // adjust the position to set
- n++; // next digit to process
- }
- return (intValue);
-}
BOOL run_cast(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
@@ -3702,56 +4021,49 @@ BOOL run_print(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
}
-void lscript_run(char *filename, BOOL b_debug)
+void lscript_run(const std::string& filename, BOOL b_debug)
{
LLTimer timer;
- if (filename == NULL)
+
+ const char *error;
+ LLScriptExecuteLSL2 *execute = NULL;
+
+ if (filename.empty())
{
llerrs << "filename is NULL" << llendl;
// Just reporting error is likely not enough. Need
// to check how to abort or error out gracefully
// from this function. XXXTBD
}
- else
+ LLFILE* file = LLFile::fopen(filename, "r"); /* Flawfinder: ignore */
+ if(file)
{
- char *error;
- BOOL b_state;
- LLScriptExecute *execute = NULL;
-
- FILE* file = LLFile::fopen(filename, "r");
- if (file)
- {
- execute = new LLScriptExecute(file);
- // note: LLScriptExecute() closes file for us
- }
- file = LLFile::fopen(filename, "r");
- if (file)
- {
- FILE* fp = LLFile::fopen("lscript.parse", "w"); /*Flawfinder: ignore*/
- LLScriptLSOParse *parse = new LLScriptLSOParse(file);
- parse->printData(fp);
- delete parse;
- fclose(file);
- fclose(fp);
- }
- file = LLFile::fopen(filename, "r");
- if (file && execute)
- {
- timer.reset();
- while (!execute->run(b_debug, LLUUID::null, &error, b_state))
- ;
- F32 time = timer.getElapsedTimeF32();
- F32 ips = execute->mInstructionCount / time;
- llinfos << execute->mInstructionCount << " instructions in " << time << " seconds" << llendl;
- llinfos << ips/1000 << "K instructions per second" << llendl;
- printf("ip: 0x%X\n", get_register(execute->mBuffer, LREG_IP));
- printf("sp: 0x%X\n", get_register(execute->mBuffer, LREG_SP));
- printf("bp: 0x%X\n", get_register(execute->mBuffer, LREG_BP));
- printf("hr: 0x%X\n", get_register(execute->mBuffer, LREG_HR));
- printf("hp: 0x%X\n", get_register(execute->mBuffer, LREG_HP));
- delete execute;
- fclose(file);
- }
+ execute = new LLScriptExecuteLSL2(file);
+ fclose(file);
+ }
+ if (execute)
+ {
+ timer.reset();
+ F32 time_slice = 3600.0f; // 1 hr.
+ U32 events_processed = 0;
+
+ do {
+ LLTimer timer2;
+ execute->runQuanta(b_debug, LLUUID::null, &error,
+ time_slice, events_processed, timer2);
+ } while (!execute->isFinished());
+
+ F32 time = timer.getElapsedTimeF32();
+ F32 ips = execute->mInstructionCount / time;
+ llinfos << execute->mInstructionCount << " instructions in " << time << " seconds" << llendl;
+ llinfos << ips/1000 << "K instructions per second" << llendl;
+ printf("ip: 0x%X\n", get_register(execute->mBuffer, LREG_IP));
+ printf("sp: 0x%X\n", get_register(execute->mBuffer, LREG_SP));
+ printf("bp: 0x%X\n", get_register(execute->mBuffer, LREG_BP));
+ printf("hr: 0x%X\n", get_register(execute->mBuffer, LREG_HR));
+ printf("hp: 0x%X\n", get_register(execute->mBuffer, LREG_HP));
+ delete execute;
+ fclose(file);
}
}
@@ -3772,7 +4084,8 @@ void lscript_pop_variable(LLScriptLibData *data, U8 *buffer, char type)
break;
case 'k':
data->mType = LST_KEY;
-
+ data->mKey = NULL;
+
base_address = lscript_pop_int(buffer);
// 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)
@@ -3791,7 +4104,7 @@ void lscript_pop_variable(LLScriptLibData *data, U8 *buffer, char type)
}
lsa_decrease_ref_count(buffer, base_address);
}
- else
+ if (data->mKey == NULL)
{
data->mKey = new char[1];
data->mKey[0] = 0;
@@ -3799,6 +4112,7 @@ void lscript_pop_variable(LLScriptLibData *data, U8 *buffer, char type)
break;
case 's':
data->mType = LST_STRING;
+ data->mString = NULL;
base_address = lscript_pop_int(buffer);
// this bit of nastiness is to get around that code paths to local variables can result in lack of initialization
@@ -3818,7 +4132,7 @@ void lscript_pop_variable(LLScriptLibData *data, U8 *buffer, char type)
}
lsa_decrease_ref_count(buffer, base_address);
}
- else
+ if (data->mString == NULL)
{
data->mString = new char[1];
data->mString[0] = 0;
@@ -3917,19 +4231,16 @@ S32 lscript_push_variable(LLScriptLibData *data, U8 *buffer)
return 4;
}
-BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
+
+// Shared code for run_calllib() and run_calllib_two_byte()
+BOOL run_calllib_common(U8 *buffer, S32 &offset, const LLUUID &id, U16 arg)
{
- if (b_print)
- printf("[0x%X]\tCALLLIB ", offset);
- offset++;
- U8 arg = safe_instruction_bytestream2byte(buffer, offset);
- if (arg >= gScriptLibrary.mNextNumber)
+ if (arg >= gScriptLibrary.mFunctions.size())
{
set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
return FALSE;
}
- if (b_print)
- printf("%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg]->mName);
+ LLScriptLibraryFunction const & function = gScriptLibrary.mFunctions[arg];
// pull out the arguments and the return values
LLScriptLibData *arguments = NULL;
@@ -3937,14 +4248,14 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
S32 i, number;
- if (gScriptLibrary.mFunctions[arg]->mReturnType)
+ if (function.mReturnType)
{
returnvalue = new LLScriptLibData;
}
- if (gScriptLibrary.mFunctions[arg]->mArgs)
+ if (function.mArgs)
{
- number = (S32)strlen(gScriptLibrary.mFunctions[arg]->mArgs); /*Flawfinder: ignore*/
+ number = (S32)strlen(function.mArgs); //Flawfinder: ignore
arguments = new LLScriptLibData[number];
}
else
@@ -3954,24 +4265,18 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
for (i = number - 1; i >= 0; i--)
{
- lscript_pop_variable(&arguments[i], buffer, gScriptLibrary.mFunctions[arg]->mArgs[i]);
+ lscript_pop_variable(&arguments[i], buffer, function.mArgs[i]);
}
- if (b_print)
- {
- printf("%s\n", gScriptLibrary.mFunctions[arg]->mDesc);
- }
+ // Actually execute the function call
+ function.mExecFunc(returnvalue, arguments, id);
- {
- // LLFastTimer time_in_libraries1(LLFastTimer::FTM_TEMP7);
- gScriptLibrary.mFunctions[arg]->mExecFunc(returnvalue, arguments, id);
- }
- add_register_fp(buffer, LREG_ESR, -gScriptLibrary.mFunctions[arg]->mEnergyUse);
- add_register_fp(buffer, LREG_SLR, gScriptLibrary.mFunctions[arg]->mSleepTime);
+ add_register_fp(buffer, LREG_ESR, -(function.mEnergyUse));
+ add_register_fp(buffer, LREG_SLR, function.mSleepTime);
if (returnvalue)
{
- returnvalue->mType = char2type(*gScriptLibrary.mFunctions[arg]->mReturnType);
+ returnvalue->mType = char2type(*function.mReturnType);
lscript_push_return_variable(returnvalue, buffer);
}
@@ -3988,72 +4293,32 @@ BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
}
-BOOL run_calllib_two_byte(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
+BOOL run_calllib(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
{
- if (b_print)
- printf("[0x%X]\tCALLLIB ", offset);
offset++;
- U16 arg = safe_instruction_bytestream2u16(buffer, offset);
- if (arg >= gScriptLibrary.mNextNumber)
+ U16 arg = (U16) safe_instruction_bytestream2byte(buffer, offset);
+ if (b_print &&
+ arg < gScriptLibrary.mFunctions.size())
{
- set_fault(buffer, LSRF_BOUND_CHECK_ERROR);
- return FALSE;
- }
- if (b_print)
- printf("%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg]->mName);
-
- // pull out the arguments and the return values
- LLScriptLibData *arguments = NULL;
- LLScriptLibData *returnvalue = NULL;
-
- S32 i, number;
-
- if (gScriptLibrary.mFunctions[arg]->mReturnType)
- {
- returnvalue = new LLScriptLibData;
- }
-
- if (gScriptLibrary.mFunctions[arg]->mArgs)
- {
- number = (S32)strlen(gScriptLibrary.mFunctions[arg]->mArgs); /*Flawfinder: ignore*/
- arguments = new LLScriptLibData[number];
- }
- else
- {
- number = 0;
- }
-
- for (i = number - 1; i >= 0; i--)
- {
- lscript_pop_variable(&arguments[i], buffer, gScriptLibrary.mFunctions[arg]->mArgs[i]);
- }
-
- if (b_print)
- {
- printf("%s\n", gScriptLibrary.mFunctions[arg]->mDesc);
- }
-
- {
- // LLFastTimer time_in_libraries2(LLFastTimer::FTM_TEMP8);
- gScriptLibrary.mFunctions[arg]->mExecFunc(returnvalue, arguments, id);
+ printf("[0x%X]\tCALLLIB ", offset);
+ LLScriptLibraryFunction const & function = gScriptLibrary.mFunctions[arg];
+ printf("%d (%s)\n", (U32)arg, function.mName);
+ //printf("%s\n", function.mDesc);
}
- add_register_fp(buffer, LREG_ESR, -gScriptLibrary.mFunctions[arg]->mEnergyUse);
- add_register_fp(buffer, LREG_SLR, gScriptLibrary.mFunctions[arg]->mSleepTime);
+ return run_calllib_common(buffer, offset, id, arg);
+}
- if (returnvalue)
+BOOL run_calllib_two_byte(U8 *buffer, S32 &offset, BOOL b_print, const LLUUID &id)
+{
+ offset++;
+ U16 arg = safe_instruction_bytestream2u16(buffer, offset);
+ if (b_print &&
+ arg < gScriptLibrary.mFunctions.size())
{
- returnvalue->mType = char2type(*gScriptLibrary.mFunctions[arg]->mReturnType);
- lscript_push_return_variable(returnvalue, buffer);
+ printf("[0x%X]\tCALLLIB ", (offset-1));
+ LLScriptLibraryFunction const & function = gScriptLibrary.mFunctions[arg];
+ printf("%d (%s)\n", (U32)arg, function.mName);
+ //printf("%s\n", function.mDesc);
}
-
- delete [] arguments;
- delete returnvalue;
-
- // reset the BP after calling the library files
- S32 bp = lscript_pop_int(buffer);
- set_bp(buffer, bp);
-
- // pop off the spot for the instruction pointer
- lscript_poparg(buffer, 4);
- return FALSE;
+ return run_calllib_common(buffer, offset, id, arg);
}