Beginnings of the "pass everything using a native type wrapper" console code.

- ConsoleValue class is now the base value class.
- ConsoleValueRef is now used to supply function parameters. Values are disposable.
- Script functions return values instead of just strings where possible.
- Variables can be disposable strings
- Bytecode changed

Fix the issues with console method parameters and fields which prevented missions from loading.
This commit is contained in:
James Urquhart 2012-09-23 09:59:48 +01:00
parent 394d87cd54
commit 38c8e52c1d
68 changed files with 1511 additions and 529 deletions

View file

@ -102,7 +102,11 @@ IterStackRecord iterStack[ MaxStackSize ];
F64 floatStack[MaxStackSize];
S64 intStack[MaxStackSize];
StringStack STR;
ConsoleValueStack CSTK;
U32 _FLT = 0; ///< Stack pointer for floatStack.
U32 _UINT = 0; ///< Stack pointer for intStack.
@ -401,14 +405,15 @@ static void setFieldComponent( SimObject* object, StringTableEntry field, const
}
}
const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNamespace, U32 argc, const char **argv, bool noCalls, StringTableEntry packageName, S32 setFrame)
ConsoleValueRef CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNamespace, U32 argc, ConsoleValueRef *argv, bool noCalls, StringTableEntry packageName, S32 setFrame)
{
#ifdef TORQUE_DEBUG
U32 stackStart = STR.mStartStackSize;
U32 consoleStackStart = CSTK.mStackPos;
#endif
static char traceBuffer[1024];
U32 i;
S32 i;
U32 iterDepth = 0;
@ -424,7 +429,7 @@ const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNam
// assume this points into a function decl:
U32 fnArgc = code[ip + 5];
thisFunctionName = U32toSTE(code[ip]);
argc = getMin(argc-1, fnArgc); // argv[0] is func name
S32 wantedArgc = getMin(argc-1, fnArgc); // argv[0] is func name
if(gEvalState.traceOn)
{
traceBuffer[0] = 0;
@ -456,11 +461,22 @@ const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNam
}
gEvalState.pushFrame(thisFunctionName, thisNamespace);
popFrame = true;
for(i = 0; i < argc; i++)
for(i = 0; i < wantedArgc; i++)
{
StringTableEntry var = U32toSTE(code[ip + i + 6]);
gEvalState.setCurVarNameCreate(var);
gEvalState.setStringVariable(argv[i+1]);
ConsoleValueRef ref = argv[i+1];
if (argv[i+1].isString())
gEvalState.setStringVariable(argv[i+1]);
else if (argv[i+1].isInt())
gEvalState.setIntVariable(argv[i+1]);
else if (argv[i+1].isFloat())
gEvalState.setFloatVariable(argv[i+1]);
else
gEvalState.setStringVariable(argv[i+1]);
}
ip = ip + fnArgc + 6;
curFloatTable = functionFloats;
@ -497,6 +513,11 @@ const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNam
}
}
// jamesu - reset the console stack frame which at this point will contain
// either nothing or argv[] which we just copied
// NOTE: it might be better to do this when we are finished?
CSTK.resetFrame();
// Grab the state of the telenet debugger here once
// so that the push and pop frames are always balanced.
const bool telDebuggerOn = TelDebugger && TelDebugger->isConnected();
@ -530,7 +551,7 @@ const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNam
char nsDocBlockClass[nsDocLength];
U32 callArgc;
const char **callArgv;
ConsoleValueRef *callArgv;
static char curFieldArray[256];
static char prevFieldArray[256];
@ -543,6 +564,10 @@ const char *CodeBlock::exec(U32 ip, const char *functionName, Namespace *thisNam
Con::gCurrentRoot = this->modPath;
}
const char * val;
const char *retValue;
// note: anything returned is pushed to CSTK and will be invalidated on the next exec()
ConsoleValueRef returnValue;
// The frame temp is used by the variable accessor ops (OP_SAVEFIELD_* and
// OP_LOADFIELD_*) to store temporary values for the fields.
@ -615,8 +640,8 @@ breakContinue:
objectCreationStack[ objectCreationStackIndex++ ].failJump = failJump;
// Get the constructor information off the stack.
STR.getArgcArgv(NULL, &callArgc, &callArgv);
const char* objectName = callArgv[ 2 ];
CSTK.getArgcArgv(NULL, &callArgc, &callArgv);
const char *objectName = callArgv[ 2 ];
// Con::printf("Creating object...");
@ -638,6 +663,7 @@ breakContinue:
Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare data block %s with a different class.", getFileLine(ip), objectName);
ip = failJump;
STR.popFrame();
CSTK.popFrame();
break;
}
@ -650,18 +676,19 @@ breakContinue:
// IF we aren't looking at a local/internal object, then check if
// this object already exists in the global space
SimObject *obj = Sim::findObject( objectName );
SimObject *obj = Sim::findObject( (const char*)objectName );
if (obj /*&& !obj->isLocalName()*/)
{
if ( isSingleton )
{
// Make sure we're not trying to change types
if ( dStricmp( obj->getClassName(), callArgv[1] ) != 0 )
if ( dStricmp( obj->getClassName(), (const char*)callArgv[1] ) != 0 )
{
Con::errorf(ConsoleLogEntry::General, "%s: Cannot re-declare object [%s] with a different class [%s] - was [%s].",
getFileLine(ip), objectName, callArgv[1], obj->getClassName());
getFileLine(ip), objectName, (const char*)callArgv[1], obj->getClassName());
ip = failJump;
STR.popFrame();
CSTK.popFrame();
break;
}
@ -679,13 +706,29 @@ breakContinue:
// string stack and may get stomped if deleteObject triggers
// script execution.
const char* savedArgv[ StringStack::MaxArgs ];
dMemcpy( savedArgv, callArgv, sizeof( savedArgv[ 0 ] ) * callArgc );
ConsoleValueRef savedArgv[ StringStack::MaxArgs ];
for (int i=0; i<callArgc; i++) {
savedArgv[i] = callArgv[i];
}
//dMemcpy( savedArgv, callArgv, sizeof( savedArgv[ 0 ] ) * callArgc );
// Prevent stack value corruption
CSTK.pushFrame();
STR.pushFrame();
// --
obj->deleteObject();
obj = NULL;
dMemcpy( callArgv, savedArgv, sizeof( callArgv[ 0 ] ) * callArgc );
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
//dMemcpy( callArgv, savedArgv, sizeof( callArgv[ 0 ] ) * callArgc );
for (int i=0; i<callArgc; i++) {
callArgv[i] = savedArgv[i];
}
}
else if( dStricmp( redefineBehavior, "renameNew" ) == 0 )
{
@ -714,6 +757,7 @@ breakContinue:
getFileLine(ip), newName.c_str() );
ip = failJump;
STR.popFrame();
CSTK.popFrame();
break;
}
else
@ -725,6 +769,7 @@ breakContinue:
getFileLine(ip), objectName);
ip = failJump;
STR.popFrame();
CSTK.popFrame();
break;
}
}
@ -732,16 +777,17 @@ breakContinue:
}
STR.popFrame();
CSTK.popFrame();
if(!currentNewObject)
{
// Well, looks like we have to create a new object.
ConsoleObject *object = ConsoleObject::create(callArgv[1]);
ConsoleObject *object = ConsoleObject::create((const char*)callArgv[1]);
// Deal with failure!
if(!object)
{
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-conobject class %s.", getFileLine(ip), callArgv[1]);
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-conobject class %s.", getFileLine(ip), (const char*)callArgv[1]);
ip = failJump;
break;
}
@ -757,7 +803,7 @@ breakContinue:
else
{
// They tried to make a non-datablock with a datablock keyword!
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-datablock class %s.", getFileLine(ip), callArgv[1]);
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-datablock class %s.", getFileLine(ip), (const char*)callArgv[1]);
// Clean up...
delete object;
ip = failJump;
@ -771,7 +817,7 @@ breakContinue:
// Deal with the case of a non-SimObject.
if(!currentNewObject)
{
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-SimObject class %s.", getFileLine(ip), callArgv[1]);
Con::errorf(ConsoleLogEntry::General, "%s: Unable to instantiate non-SimObject class %s.", getFileLine(ip), (const char*)callArgv[1]);
delete object;
ip = failJump;
break;
@ -798,7 +844,7 @@ breakContinue:
else
{
if ( Con::gObjectCopyFailures == -1 )
Con::errorf(ConsoleLogEntry::General, "%s: Unable to find parent object %s for %s.", getFileLine(ip), objParent, callArgv[1]);
Con::errorf(ConsoleLogEntry::General, "%s: Unable to find parent object %s for %s.", getFileLine(ip), objParent, (const char*)callArgv[1]);
else
++Con::gObjectCopyFailures;
@ -821,15 +867,30 @@ breakContinue:
currentNewObject->setOriginalName( objectName );
}
// Prevent stack value corruption
CSTK.pushFrame();
STR.pushFrame();
// --
// Do the constructor parameters.
if(!currentNewObject->processArguments(callArgc-3, callArgv+3))
{
delete currentNewObject;
currentNewObject = NULL;
ip = failJump;
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
break;
}
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
// If it's not a datablock, allow people to modify bits of it.
if(!isDataBlock)
{
@ -854,6 +915,11 @@ breakContinue:
// Con::printf("Adding object %s", currentNewObject->getName());
// Prevent stack value corruption
CSTK.pushFrame();
STR.pushFrame();
// --
// Make sure it wasn't already added, then add it.
if(currentNewObject->isProperlyAdded() == false)
{
@ -877,6 +943,10 @@ breakContinue:
Con::warnf(ConsoleLogEntry::General, "%s: Register object failed for object %s of class %s.", getFileLine(ip), currentNewObject->getName(), currentNewObject->getClassName());
delete currentNewObject;
ip = failJump;
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
break;
}
}
@ -885,6 +955,8 @@ breakContinue:
SimDataBlock *dataBlock = dynamic_cast<SimDataBlock *>(currentNewObject);
static String errorStr;
// If so, preload it.
if(dataBlock && !dataBlock->preload(true, errorStr))
{
@ -892,6 +964,11 @@ breakContinue:
currentNewObject->getName(), errorStr.c_str());
dataBlock->deleteObject();
ip = failJump;
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
break;
}
@ -946,6 +1023,10 @@ breakContinue:
else
intStack[++_UINT] = currentNewObject->getId();
// Prevent stack value corruption
CSTK.popFrame();
STR.popFrame();
// --
break;
}
@ -1028,6 +1109,29 @@ breakContinue:
// We're falling thru here on purpose.
case OP_RETURN:
retValue = STR.getStringValue();
if( iterDepth > 0 )
{
// Clear iterator state.
while( iterDepth > 0 )
{
iterStack[ -- _ITER ].mIsStringIter = false;
-- iterDepth;
}
STR.rewind();
STR.setStringValue( retValue ); // Not nice but works.
retValue = STR.getStringValue();
}
// Previously the return value was on the stack and would be returned using STR.getStringValue().
// Now though we need to wrap it in a ConsoleValueRef
returnValue.value = CSTK.pushStackString(retValue);
goto execFinished;
case OP_RETURN_FLT:
if( iterDepth > 0 )
{
@ -1038,10 +1142,27 @@ breakContinue:
-- iterDepth;
}
const char* returnValue = STR.getStringValue();
STR.rewind();
STR.setStringValue( returnValue ); // Not nice but works.
}
returnValue.value = CSTK.pushFLT(floatStack[_FLT]);
_FLT--;
goto execFinished;
case OP_RETURN_UINT:
if( iterDepth > 0 )
{
// Clear iterator state.
while( iterDepth > 0 )
{
iterStack[ -- _ITER ].mIsStringIter = false;
-- iterDepth;
}
}
returnValue.value = CSTK.pushUINT(intStack[_UINT]);
_UINT--;
goto execFinished;
@ -1514,6 +1635,7 @@ breakContinue:
getFileLine(ip-4), fnNamespace ? fnNamespace : "",
fnNamespace ? "::" : "", fnName);
STR.popFrame();
CSTK.popFrame();
break;
}
// Now fall through to OP_CALLFUNC...
@ -1538,7 +1660,7 @@ breakContinue:
U32 callType = code[ip+2];
ip += 3;
STR.getArgcArgv(fnName, &callArgc, &callArgv);
CSTK.getArgcArgv(fnName, &callArgc, &callArgv);
const char *componentReturnValue = "";
@ -1555,14 +1677,15 @@ breakContinue:
else if(callType == FuncCallExprNode::MethodCall)
{
saveObject = gEvalState.thisObject;
gEvalState.thisObject = Sim::findObject(callArgv[1]);
gEvalState.thisObject = Sim::findObject((const char*)callArgv[1]);
if(!gEvalState.thisObject)
{
// Go back to the previous saved object.
gEvalState.thisObject = saveObject;
Con::warnf(ConsoleLogEntry::General,"%s: Unable to find object: '%s' attempting to call function '%s'", getFileLine(ip-4), callArgv[1], fnName);
Con::warnf(ConsoleLogEntry::General,"%s: Unable to find object: '%s' attempting to call function '%s'", getFileLine(ip-4), (const char*)callArgv[1], fnName);
STR.popFrame();
CSTK.popFrame();
break;
}
@ -1618,6 +1741,7 @@ breakContinue:
}
}
STR.popFrame();
CSTK.popFrame();
if( routingId == MethodOnComponent )
STR.setStringValue( componentReturnValue );
@ -1628,12 +1752,30 @@ breakContinue:
}
if(nsEntry->mType == Namespace::Entry::ConsoleFunctionType)
{
const char *ret = "";
ConsoleValueRef ret;
if(nsEntry->mFunctionOffset)
ret = nsEntry->mCode->exec(nsEntry->mFunctionOffset, fnName, nsEntry->mNamespace, callArgc, callArgv, false, nsEntry->mPackage);
STR.popFrame();
STR.setStringValue(ret);
STR.popFrame();
// Functions are assumed to return strings, so look ahead to see if we can skip the conversion
if(code[ip] == OP_STR_TO_UINT)
{
ip++;
intStack[++_UINT] = (U32)((S32)ret);
}
else if(code[ip] == OP_STR_TO_FLT)
{
ip++;
floatStack[++_FLT] = (F32)ret;
}
else if(code[ip] == OP_STR_TO_NONE)
ip++;
else
STR.setStringValue((const char*)ret);
// This will clear everything including returnValue
CSTK.popFrame();
STR.clearFunctionOffset();
}
else
{
@ -1654,6 +1796,7 @@ breakContinue:
callArgc, nsEntry->mMinArgs, nsEntry->mMaxArgs);
Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", getFileLine(ip-4), nsEntry->mUsage);
STR.popFrame();
CSTK.popFrame();
}
else
{
@ -1663,16 +1806,18 @@ breakContinue:
{
const char *ret = nsEntry->cb.mStringCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
STR.popFrame();
CSTK.popFrame();
if(ret != STR.getStringValue())
STR.setStringValue(ret);
else
STR.setLen(dStrlen(ret));
//else
// STR.setLen(dStrlen(ret));
break;
}
case Namespace::Entry::IntCallbackType:
{
S32 result = nsEntry->cb.mIntCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
STR.popFrame();
CSTK.popFrame();
if(code[ip] == OP_STR_TO_UINT)
{
ip++;
@ -1695,6 +1840,7 @@ breakContinue:
{
F64 result = nsEntry->cb.mFloatCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
STR.popFrame();
CSTK.popFrame();
if(code[ip] == OP_STR_TO_UINT)
{
ip++;
@ -1719,12 +1865,14 @@ breakContinue:
Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", getFileLine(ip-4), fnName, functionName);
STR.popFrame();
CSTK.popFrame();
STR.setStringValue("");
break;
case Namespace::Entry::BoolCallbackType:
{
bool result = nsEntry->cb.mBoolCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
STR.popFrame();
CSTK.popFrame();
if(code[ip] == OP_STR_TO_UINT)
{
ip++;
@ -1778,11 +1926,24 @@ breakContinue:
intStack[++_UINT] = STR.compare();
break;
case OP_PUSH:
STR.push();
STR.push();
//Con::printf("Pushing str: %s",STR.getPreviousStringValue());
CSTK.pushString(STR.getPreviousStringValue());
break;
case OP_PUSH_UINT:
//Con::printf("Pushing int: %i",(S32)intStack[_UINT]);
CSTK.pushUINT(intStack[_UINT]);
_UINT--;
break;
case OP_PUSH_FLT:
//Con::printf("Pushing float: %f",(F32)intStack[_UINT]);
CSTK.pushFLT(floatStack[_FLT]);
_FLT--;
break;
case OP_PUSH_FRAME:
STR.pushFrame();
CSTK.pushFrame();
break;
case OP_ASSERT:
@ -1961,8 +2122,9 @@ execFinished:
if ( telDebuggerOn && setFrame < 0 )
TelDebugger->popStackFrame();
if ( popFrame )
if ( popFrame ) {
gEvalState.popFrame();
}
if(argv)
{
@ -2012,7 +2174,8 @@ execFinished:
AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
#endif
return STR.getStringValue();
return returnValue;
}
//------------------------------------------------------------