瀏覽代碼

Goodbye String Stack!

Jeff Hutchinson 4 年之前
父節點
當前提交
964fde8f09

+ 46 - 139
Engine/source/console/astNodes.cpp

@@ -47,7 +47,9 @@ namespace Compiler
    U32 compileBlock(StmtNode* block, CodeStream& codeStream, U32 ip)
    {
       for (StmtNode* walk = block; walk; walk = walk->getNext())
+      {
          ip = walk->compileStmt(codeStream, ip);
+      }
       return codeStream.tell();
    }
 }
@@ -146,55 +148,6 @@ void FunctionDeclStmtNode::setPackage(StringTableEntry packageName)
 //
 //------------------------------------------------------------
 
-static U32 conversionOp(TypeReq src, TypeReq dst)
-{
-   if (src == TypeReqString)
-   {
-      switch (dst)
-      {
-      case TypeReqUInt:
-         return OP_STR_TO_UINT;
-      case TypeReqFloat:
-         return OP_STR_TO_FLT;
-      case TypeReqNone:
-         return OP_STR_TO_NONE;
-      default:
-         break;
-      }
-   }
-   else if (src == TypeReqFloat)
-   {
-      switch (dst)
-      {
-      case TypeReqUInt:
-         return OP_FLT_TO_UINT;
-      case TypeReqString:
-         return OP_FLT_TO_STR;
-      case TypeReqNone:
-         return OP_NUM_TO_NONE;
-      default:
-         break;
-      }
-   }
-   else if (src == TypeReqUInt)
-   {
-      switch (dst)
-      {
-      case TypeReqFloat:
-         return OP_UINT_TO_FLT;
-      case TypeReqString:
-         return OP_UINT_TO_STR;
-      case TypeReqNone:
-         return OP_NUM_TO_NONE;
-      default:
-         break;
-      }
-   }
-   return OP_INVALID;
-}
-
-//------------------------------------------------------------
-
 U32 BreakStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
 {
    if (codeStream.inLoop())
@@ -517,8 +470,6 @@ U32 FloatBinaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
       break;
    }
    codeStream.emit(operand);
-   if (type != TypeReqFloat)
-      codeStream.emit(conversionOp(TypeReqFloat, type));
    return codeStream.tell();
 }
 
@@ -608,8 +559,6 @@ U32 IntBinaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
       ip = left->compile(codeStream, ip, subType);
       codeStream.emit(operand);
    }
-   if (type != TypeReqUInt)
-      codeStream.emit(conversionOp(TypeReqUInt, type));
    return codeStream.tell();
 }
 
@@ -629,13 +578,10 @@ U32 StreqExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
    // optional conversion
 
    ip = left->compile(codeStream, ip, TypeReqString);
-   codeStream.emit(OP_ADVANCE_STR_NUL);
    ip = right->compile(codeStream, ip, TypeReqString);
    codeStream.emit(OP_COMPARE_STR);
    if (!eq)
       codeStream.emit(OP_NOT);
-   if (type != TypeReqUInt)
-      codeStream.emit(conversionOp(TypeReqUInt, type));
    return codeStream.tell();
 }
 
@@ -649,19 +595,13 @@ TypeReq StreqExprNode::getPreferredType()
 U32 StrcatExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
 {
    ip = left->compile(codeStream, ip, TypeReqString);
-   if (!appendChar)
-      codeStream.emit(OP_ADVANCE_STR);
-   else
+   if (appendChar)
    {
       codeStream.emit(OP_ADVANCE_STR_APPENDCHAR);
       codeStream.emit(appendChar);
    }
    ip = right->compile(codeStream, ip, TypeReqString);
    codeStream.emit(OP_REWIND_STR);
-   if (type == TypeReqUInt)
-      codeStream.emit(OP_STR_TO_UINT);
-   else if (type == TypeReqFloat)
-      codeStream.emit(OP_STR_TO_FLT);
    return codeStream.tell();
 }
 
@@ -675,7 +615,8 @@ TypeReq StrcatExprNode::getPreferredType()
 U32 CommaCatExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
 {
    ip = left->compile(codeStream, ip, TypeReqString);
-   codeStream.emit(OP_ADVANCE_STR_COMMA);
+   codeStream.emit(OP_ADVANCE_STR_APPENDCHAR);
+   codeStream.emit('_');
    ip = right->compile(codeStream, ip, TypeReqString);
    codeStream.emit(OP_REWIND_STR);
 
@@ -684,10 +625,7 @@ U32 CommaCatExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
    // But we're paranoid, so accept (but whine) if we get an oddity...
    if (type == TypeReqUInt || type == TypeReqFloat)
       Con::warnf(ConsoleLogEntry::General, "%s (%d): converting comma string to a number... probably wrong.", dbgFileName, dbgLineNumber);
-   if (type == TypeReqUInt)
-      codeStream.emit(OP_STR_TO_UINT);
-   else if (type == TypeReqFloat)
-      codeStream.emit(OP_STR_TO_FLT);
+
    return codeStream.tell();
 }
 
@@ -710,8 +648,7 @@ U32 IntUnaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
       codeStream.emit(integer ? OP_NOT : OP_NOTF);
    else if (op == '~')
       codeStream.emit(OP_ONESCOMPLEMENT);
-   if (type != TypeReqUInt)
-      codeStream.emit(conversionOp(TypeReqUInt, type));
+
    return codeStream.tell();
 }
 
@@ -726,8 +663,7 @@ U32 FloatUnaryExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
 {
    ip = expr->compile(codeStream, ip, TypeReqFloat);
    codeStream.emit(OP_NEG);
-   if (type != TypeReqFloat)
-      codeStream.emit(conversionOp(TypeReqFloat, type));
+
    return codeStream.tell();
 }
 
@@ -768,10 +704,11 @@ U32 VarNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
 
       if (arrayIndex)
       {
-         codeStream.emit(OP_ADVANCE_STR);
+         //codeStream.emit(OP_ADVANCE_STR);
          ip = arrayIndex->compile(codeStream, ip, TypeReqString);
          codeStream.emit(OP_REWIND_STR);
          codeStream.emit(OP_SETCURVAR_ARRAY);
+         codeStream.emit(OP_POP_STK);
       }
       switch (type)
       {
@@ -1013,18 +950,18 @@ U32 AssignExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
    {
       if (arrayIndex)
       {
-         if (subType == TypeReqString)
-            codeStream.emit(OP_ADVANCE_STR);
+         //if (subType == TypeReqString)
+         //   codeStream.emit(OP_ADVANCE_STR);
 
          codeStream.emit(OP_LOADIMMED_IDENT);
          codeStream.emitSTE(varName);
 
-         codeStream.emit(OP_ADVANCE_STR);
+         //codeStream.emit(OP_ADVANCE_STR);
          ip = arrayIndex->compile(codeStream, ip, TypeReqString);
          codeStream.emit(OP_REWIND_STR);
          codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
-         if (subType == TypeReqString)
-            codeStream.emit(OP_TERMINATE_REWIND_STR);
+         if (type == TypeReqNone)
+            codeStream.emit(OP_POP_STK);
       }
       else
       {
@@ -1049,11 +986,8 @@ U32 AssignExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
       codeStream.emit(getFuncVars()->assign(varName, subType == TypeReqNone ? TypeReqString : subType));
    }
 
-   if (type != subType)
-   {
-      U32 conOp = conversionOp(subType, type);
-      codeStream.emit(conOp);
-   }
+   if (type == TypeReqNone)
+      codeStream.emit(OP_POP_STK);
    return ip;
 }
 
@@ -1068,11 +1002,14 @@ static void getAssignOpTypeOp(S32 op, TypeReq& type, U32& operand)
 {
    switch (op)
    {
-   case '+':
    case opPLUSPLUS:
+      TORQUE_CASE_FALLTHROUGH;
+   case '+':
       type = TypeReqFloat;
       operand = OP_ADD;
       break;
+   case opMINUSMINUS:
+      TORQUE_CASE_FALLTHROUGH;
    case '-':
       type = TypeReqFloat;
       operand = OP_SUB;
@@ -1109,6 +1046,8 @@ static void getAssignOpTypeOp(S32 op, TypeReq& type, U32& operand)
       type = TypeReqUInt;
       operand = OP_SHR;
       break;
+   default:
+      AssertFatal(false, "Invalid opcode on operation expression");
    }
 }
 
@@ -1163,10 +1102,12 @@ U32 AssignOpExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
             codeStream.emit(OP_LOADIMMED_IDENT);
             codeStream.emitSTE(varName);
 
-            codeStream.emit(OP_ADVANCE_STR);
+            //codeStream.emit(OP_ADVANCE_STR);
             ip = arrayIndex->compile(codeStream, ip, TypeReqString);
             codeStream.emit(OP_REWIND_STR);
             codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
+            if (type == TypeReqNone)
+               codeStream.emit(OP_POP_STK);
          }
          codeStream.emit((subType == TypeReqFloat) ? OP_LOADVAR_FLT : OP_LOADVAR_UINT);
          codeStream.emit(operand);
@@ -1184,10 +1125,8 @@ U32 AssignOpExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
          codeStream.emit(varIdx);
       }
 
-      if (subType != type)
-      {
-         codeStream.emit(conversionOp(subType, type));
-      }
+      if (type == TypeReqNone)
+         codeStream.emit(OP_POP_STK);
    }
    return codeStream.tell();
 }
@@ -1259,18 +1198,7 @@ U32 FuncCallExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
          walkType = TypeReqString;
 
       ip = walk->compile(codeStream, ip, walkType);
-      switch (walk->getPreferredType())
-      {
-      case TypeReqFloat:
-         codeStream.emit(OP_PUSH_FLT);
-         break;
-      case TypeReqUInt:
-         codeStream.emit(OP_PUSH_UINT);
-         break;
-      default:
-         codeStream.emit(OP_PUSH);
-         break;
-      }
+      codeStream.emit(OP_PUSH);
    }
 
    codeStream.emit(OP_CALLFUNC);
@@ -1278,8 +1206,9 @@ U32 FuncCallExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
    codeStream.emitSTE(nameSpace);
    codeStream.emit(callType);
 
-   if (type != TypeReqString)
-      codeStream.emit(conversionOp(TypeReqString, type));
+   if (type == TypeReqNone)
+      codeStream.emit(OP_POP_STK);
+
    return codeStream.tell();
 }
 
@@ -1288,7 +1217,6 @@ TypeReq FuncCallExprNode::getPreferredType()
    return TypeReqString;
 }
 
-
 //------------------------------------------------------------
 
 U32 AssertCallExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
@@ -1322,15 +1250,7 @@ U32 SlotAccessNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
 
    if (arrayExpr)
    {
-      // eval array
-      // OP_ADVANCE_STR
-      // evaluate object expression sub (OP_SETCURFIELD)
-      // OP_TERMINATE_REWIND_STR
-      // OP_SETCURFIELDARRAY
-      // total add of 4 + array precomp
-
       ip = arrayExpr->compile(codeStream, ip, TypeReqString);
-      codeStream.emit(OP_ADVANCE_STR);
    }
    ip = objectExpr->compile(codeStream, ip, TypeReqString);
    codeStream.emit(OP_SETCUROBJECT);
@@ -1341,8 +1261,8 @@ U32 SlotAccessNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
 
    if (arrayExpr)
    {
-      codeStream.emit(OP_TERMINATE_REWIND_STR);
       codeStream.emit(OP_SETCURFIELD_ARRAY);
+      codeStream.emit(OP_POP_STK);
    }
 
    switch (type)
@@ -1381,8 +1301,6 @@ U32 InternalSlotAccessNode::compile(CodeStream& codeStream, U32 ip, TypeReq type
    codeStream.emit(OP_SETCUROBJECT_INTERNAL);
    codeStream.emit(recurse);
 
-   if (type != TypeReqUInt)
-      codeStream.emit(conversionOp(TypeReqUInt, type));
    return codeStream.tell();
 }
 
@@ -1426,11 +1344,9 @@ U32 SlotAssignNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
    precompileIdent(slotName);
 
    ip = valueExpr->compile(codeStream, ip, TypeReqString);
-   codeStream.emit(OP_ADVANCE_STR);
    if (arrayExpr)
    {
       ip = arrayExpr->compile(codeStream, ip, TypeReqString);
-      codeStream.emit(OP_ADVANCE_STR);
    }
    if (objectExpr)
    {
@@ -1444,11 +1360,10 @@ U32 SlotAssignNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
 
    if (arrayExpr)
    {
-      codeStream.emit(OP_TERMINATE_REWIND_STR);
       codeStream.emit(OP_SETCURFIELD_ARRAY);
+      codeStream.emit(OP_POP_STK);
    }
 
-   codeStream.emit(OP_TERMINATE_REWIND_STR);
    codeStream.emit(OP_SAVEFIELD_STR);
 
    if (typeID != -1)
@@ -1457,8 +1372,9 @@ U32 SlotAssignNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
       codeStream.emit(typeID);
    }
 
-   if (type != TypeReqString)
-      codeStream.emit(conversionOp(TypeReqString, type));
+   if (type == TypeReqNone)
+      codeStream.emit(OP_POP_STK);
+
    return codeStream.tell();
 }
 
@@ -1501,7 +1417,6 @@ U32 SlotAssignOpNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
    if (arrayExpr)
    {
       ip = arrayExpr->compile(codeStream, ip, TypeReqString);
-      codeStream.emit(OP_ADVANCE_STR);
    }
    ip = objectExpr->compile(codeStream, ip, TypeReqString);
    codeStream.emit(OP_SETCUROBJECT);
@@ -1510,14 +1425,15 @@ U32 SlotAssignOpNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
 
    if (arrayExpr)
    {
-      codeStream.emit(OP_TERMINATE_REWIND_STR);
       codeStream.emit(OP_SETCURFIELD_ARRAY);
+      if (subType == TypeReqNone)
+         codeStream.emit(OP_POP_STK);
    }
    codeStream.emit((subType == TypeReqFloat) ? OP_LOADFIELD_FLT : OP_LOADFIELD_UINT);
    codeStream.emit(operand);
    codeStream.emit((subType == TypeReqFloat) ? OP_SAVEFIELD_FLT : OP_SAVEFIELD_UINT);
-   if (subType != type)
-      codeStream.emit(conversionOp(subType, type));
+   if (subType == TypeReqNone)
+      codeStream.emit(OP_POP_STK);
    return codeStream.tell();
 }
 
@@ -1572,18 +1488,7 @@ U32 ObjectDeclNode::compileSubObject(CodeStream& codeStream, U32 ip, bool root)
       TypeReq walkType = exprWalk->getPreferredType();
       if (walkType == TypeReqNone) walkType = TypeReqString;
       ip = exprWalk->compile(codeStream, ip, walkType);
-      switch (exprWalk->getPreferredType())
-      {
-      case TypeReqFloat:
-         codeStream.emit(OP_PUSH_FLT);
-         break;
-      case TypeReqUInt:
-         codeStream.emit(OP_PUSH_UINT);
-         break;
-      default:
-         codeStream.emit(OP_PUSH);
-         break;
-      }
+      codeStream.emit(OP_PUSH);
    }
    codeStream.emit(OP_CREATE_OBJECT);
    codeStream.emitSTE(parentObject);
@@ -1621,8 +1526,10 @@ U32 ObjectDeclNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
    codeStream.emit(OP_LOADIMMED_UINT);
    codeStream.emit(0);
    ip = compileSubObject(codeStream, ip, true);
-   if (type != TypeReqUInt)
-      codeStream.emit(conversionOp(TypeReqUInt, type));
+
+   if (type == TypeReqNone)
+      codeStream.emit(OP_POP_STK);
+
    return codeStream.tell();
 }
 

+ 101 - 167
Engine/source/console/codeBlock.cpp

@@ -520,7 +520,7 @@ bool CodeBlock::compile(const char *codeFileName, StringTableEntry fileName, con
       lastIp = 0;
    }
 
-   codeStream.emit(OP_RETURN);
+   codeStream.emit(OP_RETURN_VOID);
    codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs);
 
    lineBreakPairCount = codeStream.getNumLineBreaks();
@@ -640,11 +640,11 @@ ConsoleValue CodeBlock::compileExec(StringTableEntry fileName, const char *inStr
    globalFloats = getGlobalFloatTable().build();
    functionFloats = getFunctionFloatTable().build();
 
-   codeStream.emit(OP_RETURN);
+   codeStream.emit(OP_RETURN_VOID);
    codeStream.emitCodeStream(&codeSize, &code, &lineBreakPairs);
 
-   if (Con::getBoolVariable("dump"))
-   dumpInstructions(0, false);
+   //if (Con::getBoolVariable("dump"))
+   //dumpInstructions(0, false);
 
    consoleAllocReset();
 
@@ -726,7 +726,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
          U32 regCount = code[ip + 9];
          endFuncIp = newIp;
 
-         Con::printf("%i: OP_FUNC_DECL name=%s nspace=%s package=%s hasbody=%i newip=%i argc=%i regCount=%i",
+         Con::printf("%i: OP_FUNC_DECL stk=+0 name=%s nspace=%s package=%s hasbody=%i newip=%i argc=%i regCount=%i",
             ip - 1, fnName, fnNamespace, fnPackage, hasBody, newIp, argc, regCount);
 
          // Skip args.
@@ -745,7 +745,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
          U32  lineNumber = code[ip + 5];
          U32 failJump = code[ip + 6];
 
-         Con::printf("%i: OP_CREATE_OBJECT objParent=%s isDataBlock=%i isInternal=%i isSingleton=%i lineNumber=%i failJump=%i",
+         Con::printf("%i: OP_CREATE_OBJECT stk=+0 objParent=%s isDataBlock=%i isInternal=%i isSingleton=%i lineNumber=%i failJump=%i",
             ip - 1, objParent, isDataBlock, isInternal, isSingleton, lineNumber, failJump);
 
          ip += 7;
@@ -755,14 +755,16 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
       case OP_ADD_OBJECT:
       {
          bool placeAtRoot = code[ip++];
-         Con::printf("%i: OP_ADD_OBJECT placeAtRoot=%i", ip - 1, placeAtRoot);
+         const char* stk = placeAtRoot ? "+1" : "0";
+         Con::printf("%i: OP_ADD_OBJECT stk=%s placeAtRoot=%i", ip - 1, stk, placeAtRoot);
          break;
       }
 
       case OP_END_OBJECT:
       {
          bool placeAtRoot = code[ip++];
-         Con::printf("%i: OP_END_OBJECT placeAtRoot=%i", ip - 1, placeAtRoot);
+         const char* stk = placeAtRoot ? "-1" : "0";
+         Con::printf("%i: OP_END_OBJECT stk=%s placeAtRoot=%i", ip - 1, stk, placeAtRoot);
          break;
       }
 
@@ -774,56 +776,56 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
 
       case OP_JMPIFFNOT:
       {
-         Con::printf("%i: OP_JMPIFFNOT ip=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_JMPIFFNOT stk=-1 ip=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_JMPIFNOT:
       {
-         Con::printf("%i: OP_JMPIFNOT ip=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_JMPIFNOT stk=-1 ip=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_JMPIFF:
       {
-         Con::printf("%i: OP_JMPIFF ip=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_JMPIFF stk=-1 ip=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_JMPIF:
       {
-         Con::printf("%i: OP_JMPIF ip=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_JMPIF stk=-1 ip=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_JMPIFNOT_NP:
       {
-         Con::printf("%i: OP_JMPIFNOT_NP ip=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_JMPIFNOT_NP stk=-1 or 0 ip=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_JMPIF_NP:
       {
-         Con::printf("%i: OP_JMPIF_NP ip=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_JMPIF_NP stk=-1 or 0 ip=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_JMP:
       {
-         Con::printf("%i: OP_JMP ip=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_JMP stk=0 ip=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
-      case OP_RETURN:
+      case OP_RETURN_VOID:
       {
-         Con::printf("%i: OP_RETURN", ip - 1);
+         Con::printf("%i: OP_RETURN_VOID stk=0", ip - 1);
 
          if (upToReturn)
             return;
@@ -831,9 +833,9 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
          break;
       }
 
-      case OP_RETURN_VOID:
+      case OP_RETURN:
       {
-         Con::printf("%i: OP_RETURNVOID", ip - 1);
+         Con::printf("%i: OP_RETURN stk=-1", ip - 1);
 
          if (upToReturn)
             return;
@@ -843,7 +845,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
 
       case OP_RETURN_UINT:
       {
-         Con::printf("%i: OP_RETURNUINT", ip - 1);
+         Con::printf("%i: OP_RETURNUINT stk=-1", ip - 1);
 
          if (upToReturn)
             return;
@@ -853,7 +855,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
 
       case OP_RETURN_FLT:
       {
-         Con::printf("%i: OP_RETURNFLT", ip - 1);
+         Con::printf("%i: OP_RETURNFLT stk=-1", ip - 1);
 
          if (upToReturn)
             return;
@@ -863,139 +865,139 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
 
       case OP_CMPEQ:
       {
-         Con::printf("%i: OP_CMPEQ", ip - 1);
+         Con::printf("%i: OP_CMPEQ stk=-1", ip - 1);
          break;
       }
 
       case OP_CMPGR:
       {
-         Con::printf("%i: OP_CMPGR", ip - 1);
+         Con::printf("%i: OP_CMPGR stk=-1", ip - 1);
          break;
       }
 
       case OP_CMPGE:
       {
-         Con::printf("%i: OP_CMPGE", ip - 1);
+         Con::printf("%i: OP_CMPGE stk=-1", ip - 1);
          break;
       }
 
       case OP_CMPLT:
       {
-         Con::printf("%i: OP_CMPLT", ip - 1);
+         Con::printf("%i: OP_CMPLT stk=-1", ip - 1);
          break;
       }
 
       case OP_CMPLE:
       {
-         Con::printf("%i: OP_CMPLE", ip - 1);
+         Con::printf("%i: OP_CMPLE stk=-1", ip - 1);
          break;
       }
 
       case OP_CMPNE:
       {
-         Con::printf("%i: OP_CMPNE", ip - 1);
+         Con::printf("%i: OP_CMPNE stk=-1", ip - 1);
          break;
       }
 
       case OP_XOR:
       {
-         Con::printf("%i: OP_XOR", ip - 1);
+         Con::printf("%i: OP_XOR stk=-1", ip - 1);
          break;
       }
 
       case OP_MOD:
       {
-         Con::printf("%i: OP_MOD", ip - 1);
+         Con::printf("%i: OP_MOD stk=-1", ip - 1);
          break;
       }
 
       case OP_BITAND:
       {
-         Con::printf("%i: OP_BITAND", ip - 1);
+         Con::printf("%i: OP_BITAND stk=-1", ip - 1);
          break;
       }
 
       case OP_BITOR:
       {
-         Con::printf("%i: OP_BITOR", ip - 1);
+         Con::printf("%i: OP_BITOR stk=-1", ip - 1);
          break;
       }
 
       case OP_NOT:
       {
-         Con::printf("%i: OP_NOT", ip - 1);
+         Con::printf("%i: OP_NOT stk=0", ip - 1);
          break;
       }
 
       case OP_NOTF:
       {
-         Con::printf("%i: OP_NOTF", ip - 1);
+         Con::printf("%i: OP_NOTF stk=0", ip - 1);
          break;
       }
 
       case OP_ONESCOMPLEMENT:
       {
-         Con::printf("%i: OP_ONESCOMPLEMENT", ip - 1);
+         Con::printf("%i: OP_ONESCOMPLEMENT stk=0", ip - 1);
          break;
       }
 
       case OP_SHR:
       {
-         Con::printf("%i: OP_SHR", ip - 1);
+         Con::printf("%i: OP_SHR stk=-1", ip - 1);
          break;
       }
 
       case OP_SHL:
       {
-         Con::printf("%i: OP_SHL", ip - 1);
+         Con::printf("%i: OP_SHL stk=-1", ip - 1);
          break;
       }
 
       case OP_AND:
       {
-         Con::printf("%i: OP_AND", ip - 1);
+         Con::printf("%i: OP_AND stk=-1", ip - 1);
          break;
       }
 
       case OP_OR:
       {
-         Con::printf("%i: OP_OR", ip - 1);
+         Con::printf("%i: OP_OR stk=-1", ip - 1);
          break;
       }
 
       case OP_ADD:
       {
-         Con::printf("%i: OP_ADD", ip - 1);
+         Con::printf("%i: OP_ADD stk=-1", ip - 1);
          break;
       }
 
       case OP_SUB:
       {
-         Con::printf("%i: OP_SUB", ip - 1);
+         Con::printf("%i: OP_SUB stk=-1", ip - 1);
          break;
       }
 
       case OP_MUL:
       {
-         Con::printf("%i: OP_MUL", ip - 1);
+         Con::printf("%i: OP_MUL stk=-1", ip - 1);
          break;
       }
 
       case OP_DIV:
       {
-         Con::printf("%i: OP_DIV", ip - 1);
+         Con::printf("%i: OP_DIV stk=-1", ip - 1);
          break;
       }
 
       case OP_NEG:
       {
-         Con::printf("%i: OP_NEG", ip - 1);
+         Con::printf("%i: OP_NEG stk=0", ip - 1);
          break;
       }
 
       case OP_INC:
       {
-         Con::printf("%i: OP_INC reg=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_INC stk=0 reg=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
@@ -1004,7 +1006,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
       {
          StringTableEntry var = CodeToSTE(code, ip);
 
-         Con::printf("%i: OP_SETCURVAR var=%s", ip - 1, var);
+         Con::printf("%i: OP_SETCURVAR stk=0 var=%s", ip - 1, var);
          ip += 2;
          break;
       }
@@ -1013,116 +1015,116 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
       {
          StringTableEntry var = CodeToSTE(code, ip);
 
-         Con::printf("%i: OP_SETCURVAR_CREATE var=%s", ip - 1, var);
+         Con::printf("%i: OP_SETCURVAR_CREATE stk=0 var=%s", ip - 1, var);
          ip += 2;
          break;
       }
 
       case OP_SETCURVAR_ARRAY:
       {
-         Con::printf("%i: OP_SETCURVAR_ARRAY", ip - 1);
+         Con::printf("%i: OP_SETCURVAR_ARRAY stk=0", ip - 1);
          break;
       }
 
       case OP_SETCURVAR_ARRAY_CREATE:
       {
-         Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE", ip - 1);
+         Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE stk=0", ip - 1);
          break;
       }
 
       case OP_LOADVAR_UINT:
       {
-         Con::printf("%i: OP_LOADVAR_UINT", ip - 1);
+         Con::printf("%i: OP_LOADVAR_UINT stk=+1", ip - 1);
          break;
       }
 
       case OP_LOADVAR_FLT:
       {
-         Con::printf("%i: OP_LOADVAR_FLT", ip - 1);
+         Con::printf("%i: OP_LOADVAR_FLT stk=+1", ip - 1);
          break;
       }
 
       case OP_LOADVAR_STR:
       {
-         Con::printf("%i: OP_LOADVAR_STR", ip - 1);
+         Con::printf("%i: OP_LOADVAR_STR stk=+1", ip - 1);
          break;
       }
 
       case OP_SAVEVAR_UINT:
       {
-         Con::printf("%i: OP_SAVEVAR_UINT", ip - 1);
+         Con::printf("%i: OP_SAVEVAR_UINT stk=0", ip - 1);
          break;
       }
 
       case OP_SAVEVAR_FLT:
       {
-         Con::printf("%i: OP_SAVEVAR_FLT", ip - 1);
+         Con::printf("%i: OP_SAVEVAR_FLT stk=0", ip - 1);
          break;
       }
 
       case OP_SAVEVAR_STR:
       {
-         Con::printf("%i: OP_SAVEVAR_STR", ip - 1);
+         Con::printf("%i: OP_SAVEVAR_STR stk=0", ip - 1);
          break;
       }
 
       case OP_LOAD_LOCAL_VAR_UINT:
       {
-         Con::printf("%i: OP_LOAD_LOCAL_VAR_UINT reg=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_LOAD_LOCAL_VAR_UINT stk=+1 reg=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_LOAD_LOCAL_VAR_FLT:
       {
-         Con::printf("%i: OP_LOAD_LOCAL_VAR_FLT reg=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_LOAD_LOCAL_VAR_FLT stk=+1 reg=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_LOAD_LOCAL_VAR_STR:
       {
-         Con::printf("%i: OP_LOAD_LOCAL_VAR_STR reg=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_LOAD_LOCAL_VAR_STR stk=+1 reg=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_SAVE_LOCAL_VAR_UINT:
       {
-         Con::printf("%i: OP_SAVE_LOCAL_VAR_UINT reg=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_SAVE_LOCAL_VAR_UINT stk=0 reg=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_SAVE_LOCAL_VAR_FLT:
       {
-         Con::printf("%i: OP_SAVE_LOCAL_VAR_FLT reg=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_SAVE_LOCAL_VAR_FLT stk=0 reg=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_SAVE_LOCAL_VAR_STR:
       {
-         Con::printf("%i: OP_SAVE_LOCAL_VAR_STR reg=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_SAVE_LOCAL_VAR_STR stk=0 reg=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
 
       case OP_SETCUROBJECT:
       {
-         Con::printf("%i: OP_SETCUROBJECT", ip - 1);
+         Con::printf("%i: OP_SETCUROBJECT stk=-1", ip - 1);
          break;
       }
 
       case OP_SETCUROBJECT_NEW:
       {
-         Con::printf("%i: OP_SETCUROBJECT_NEW", ip - 1);
+         Con::printf("%i: OP_SETCUROBJECT_NEW stk=0", ip - 1);
          break;
       }
 
       case OP_SETCUROBJECT_INTERNAL:
       {
-         Con::printf("%i: OP_SETCUROBJECT_INTERNAL", ip - 1);
+         Con::printf("%i: OP_SETCUROBJECT_INTERNAL stk=0", ip - 1);
          ++ip;
          break;
       }
@@ -1130,113 +1132,71 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
       case OP_SETCURFIELD:
       {
          StringTableEntry curField = CodeToSTE(code, ip);
-         Con::printf("%i: OP_SETCURFIELD field=%s", ip - 1, curField);
+         Con::printf("%i: OP_SETCURFIELD stk=0 field=%s", ip - 1, curField);
          ip += 2;
          break;
       }
 
       case OP_SETCURFIELD_ARRAY:
       {
-         Con::printf("%i: OP_SETCURFIELD_ARRAY", ip - 1);
+         Con::printf("%i: OP_SETCURFIELD_ARRAY stk=0", ip - 1);
          break;
       }
 
       case OP_SETCURFIELD_TYPE:
       {
          U32 type = code[ip];
-         Con::printf("%i: OP_SETCURFIELD_TYPE type=%i", ip - 1, type);
+         Con::printf("%i: OP_SETCURFIELD_TYPE stk=0 type=%i", ip - 1, type);
          ++ip;
          break;
       }
 
       case OP_LOADFIELD_UINT:
       {
-         Con::printf("%i: OP_LOADFIELD_UINT", ip - 1);
+         Con::printf("%i: OP_LOADFIELD_UINT stk=+1", ip - 1);
          break;
       }
 
       case OP_LOADFIELD_FLT:
       {
-         Con::printf("%i: OP_LOADFIELD_FLT", ip - 1);
+         Con::printf("%i: OP_LOADFIELD_FLT stk=+1", ip - 1);
          break;
       }
 
       case OP_LOADFIELD_STR:
       {
-         Con::printf("%i: OP_LOADFIELD_STR", ip - 1);
+         Con::printf("%i: OP_LOADFIELD_STR stk=+1", ip - 1);
          break;
       }
 
       case OP_SAVEFIELD_UINT:
       {
-         Con::printf("%i: OP_SAVEFIELD_UINT", ip - 1);
+         Con::printf("%i: OP_SAVEFIELD_UINT stk=0", ip - 1);
          break;
       }
 
       case OP_SAVEFIELD_FLT:
       {
-         Con::printf("%i: OP_SAVEFIELD_FLT", ip - 1);
+         Con::printf("%i: OP_SAVEFIELD_FLT stk=0", ip - 1);
          break;
       }
 
       case OP_SAVEFIELD_STR:
       {
-         Con::printf("%i: OP_SAVEFIELD_STR", ip - 1);
-         break;
-      }
-
-      case OP_STR_TO_UINT:
-      {
-         Con::printf("%i: OP_STR_TO_UINT", ip - 1);
-         break;
-      }
-
-      case OP_STR_TO_FLT:
-      {
-         Con::printf("%i: OP_STR_TO_FLT", ip - 1);
-         break;
-      }
-
-      case OP_STR_TO_NONE:
-      {
-         Con::printf("%i: OP_STR_TO_NONE", ip - 1);
-         break;
-      }
-
-      case OP_FLT_TO_UINT:
-      {
-         Con::printf("%i: OP_FLT_TO_UINT", ip - 1);
-         break;
-      }
-
-      case OP_FLT_TO_STR:
-      {
-         Con::printf("%i: OP_FLT_TO_STR", ip - 1);
-         break;
-      }
-
-      case OP_UINT_TO_FLT:
-      {
-         Con::printf("%i: OP_UINT_TO_FLT", ip - 1);
+         Con::printf("%i: OP_SAVEFIELD_STR stk=0", ip - 1);
          break;
       }
 
-      case OP_UINT_TO_STR:
+      case OP_POP_STK:
       {
-         Con::printf("%i: OP_UINT_TO_STR", ip - 1);
-         break;
-      }
-
-      case OP_NUM_TO_NONE:
-      {
-         Con::printf("%i: OP_NUM_TO_NONE", ip - 1);
+         Con::printf("%i: OP_POP_STK stk=-1", ip - 1);
          break;
       }
 
       case OP_LOADIMMED_UINT:
       {
          U32 val = code[ip];
-         Con::printf("%i: OP_LOADIMMED_UINT val=%i", ip - 1, val);
+         Con::printf("%i: OP_LOADIMMED_UINT stk=+1 val=%i", ip - 1, val);
          ++ip;
          break;
       }
@@ -1244,7 +1204,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
       case OP_LOADIMMED_FLT:
       {
          F64 val = (smInFunction ? functionFloats : globalFloats)[code[ip]];
-         Con::printf("%i: OP_LOADIMMED_FLT val=%f", ip - 1, val);
+         Con::printf("%i: OP_LOADIMMED_FLT stk=+1 val=%f", ip - 1, val);
          ++ip;
          break;
       }
@@ -1252,7 +1212,8 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
       case OP_TAG_TO_STR:
       {
          const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip];
-         Con::printf("%i: OP_TAG_TO_STR str=%s", ip - 1, str);
+         Con::printf("%i: OP_TAG_TO_STR stk=0 str=%s", ip - 1, str);
+         Con::printf("    OP_LOADIMMED_STR stk=+1 (fallthrough)");
          ++ip;
          break;
       }
@@ -1260,7 +1221,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
       case OP_LOADIMMED_STR:
       {
          const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip];
-         Con::printf("%i: OP_LOADIMMED_STR str=%s", ip - 1, str);
+         Con::printf("%i: OP_LOADIMMED_STR stk=+1 str=%s", ip - 1, str);
          ++ip;
          break;
       }
@@ -1268,7 +1229,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
       case OP_DOCBLOCK_STR:
       {
          const char* str = (smInFunction ? functionStrings : globalStrings) + code[ip];
-         Con::printf("%i: OP_DOCBLOCK_STR str=%s", ip - 1, str);
+         Con::printf("%i: OP_DOCBLOCK_STR stk=0 str=%s", ip - 1, str);
          ++ip;
          break;
       }
@@ -1276,7 +1237,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
       case OP_LOADIMMED_IDENT:
       {
          StringTableEntry str = CodeToSTE(code, ip);
-         Con::printf("%i: OP_LOADIMMED_IDENT str=%s", ip - 1, str);
+         Con::printf("%i: OP_LOADIMMED_IDENT stk=+1 str=%s", ip - 1, str);
          ip += 2;
          break;
       }
@@ -1296,77 +1257,48 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
          case FuncCallExprNode::StaticCall:   callTypeName = "StaticCall"; break;
          }
 
-         Con::printf("%i: OP_CALLFUNC name=%s nspace=%s callType=%s", ip - 1, fnName, fnNamespace, callTypeName);
+         Con::printf("%i: OP_CALLFUNC stk=+1 name=%s nspace=%s callType=%s", ip - 1, fnName, fnNamespace, callTypeName);
 
          ip += 5;
          break;
       }
 
-      case OP_ADVANCE_STR:
-      {
-         Con::printf("%i: OP_ADVANCE_STR", ip - 1);
-         break;
-      }
-
       case OP_ADVANCE_STR_APPENDCHAR:
       {
          char ch = code[ip];
-         Con::printf("%i: OP_ADVANCE_STR_APPENDCHAR char=%c", ip - 1, ch);
+         Con::printf("%i: OP_ADVANCE_STR_APPENDCHAR stk=0 char=%c", ip - 1, ch);
          ++ip;
          break;
       }
 
-      case OP_ADVANCE_STR_COMMA:
-      {
-         Con::printf("%i: OP_ADVANCE_STR_COMMA", ip - 1);
-         break;
-      }
-
-      case OP_ADVANCE_STR_NUL:
-      {
-         Con::printf("%i: OP_ADVANCE_STR_NUL", ip - 1);
-         break;
-      }
-
       case OP_REWIND_STR:
       {
-         Con::printf("%i: OP_REWIND_STR", ip - 1);
+         Con::printf("%i: OP_REWIND_STR stk=0", ip - 1);
+         Con::printf("    OP_TERMINATE_REWIND_STR stk=-1 (fallthrough)");
          break;
       }
 
       case OP_TERMINATE_REWIND_STR:
       {
-         Con::printf("%i: OP_TERMINATE_REWIND_STR", ip - 1);
+         Con::printf("%i: OP_TERMINATE_REWIND_STR stk=-1", ip - 1);
          break;
       }
 
       case OP_COMPARE_STR:
       {
-         Con::printf("%i: OP_COMPARE_STR", ip - 1);
+         Con::printf("%i: OP_COMPARE_STR stk=-1", ip - 1);
          break;
       }
 
       case OP_PUSH:
       {
-         Con::printf("%i: OP_PUSH", ip - 1);
-         break;
-      }
-
-      case OP_PUSH_UINT:
-      {
-         Con::printf("%i: OP_PUSH_UINT", ip - 1);
-         break;
-      }
-
-      case OP_PUSH_FLT:
-      {
-         Con::printf("%i: OP_PUSH_FLT", ip - 1);
+         Con::printf("%i: OP_PUSH stk=-1", ip - 1);
          break;
       }
 
       case OP_PUSH_FRAME:
       {
-         Con::printf("%i: OP_PUSH_FRAME count=%i", ip - 1, code[ip]);
+         Con::printf("%i: OP_PUSH_FRAME stk=0 count=%i", ip - 1, code[ip]);
          ++ip;
          break;
       }
@@ -1374,14 +1306,14 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
       case OP_ASSERT:
       {
          const char* message = (smInFunction ? functionStrings : globalStrings) + code[ip];
-         Con::printf("%i: OP_ASSERT message=%s", ip - 1, message);
+         Con::printf("%i: OP_ASSERT stk=-1 message=%s", ip - 1, message);
          ++ip;
          break;
       }
 
       case OP_BREAK:
       {
-         Con::printf("%i: OP_BREAK", ip - 1);
+         Con::printf("%i: OP_BREAK stk=0", ip - 1);
          break;
       }
 
@@ -1393,7 +1325,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
             StringTableEntry varName = CodeToSTE(code, ip + 1);
             U32 failIp = code[ip + 3];
 
-            Con::printf("%i: OP_ITER_BEGIN varName=%s failIp=%i isGlobal=%s", ip - 1, varName, failIp, "true");
+            Con::printf("%i: OP_ITER_BEGIN stk=0 varName=%s failIp=%i isGlobal=%s", ip - 1, varName, failIp, "true");
 
             ip += 4;
          }
@@ -1402,7 +1334,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
             S32 reg = code[ip + 1];
             U32 failIp = code[ip + 2];
 
-            Con::printf("%i: OP_ITER_BEGIN varRegister=%d failIp=%i isGlobal=%s", ip - 1, reg, failIp, "false");
+            Con::printf("%i: OP_ITER_BEGIN stk=0 varRegister=%d failIp=%i isGlobal=%s", ip - 1, reg, failIp, "false");
 
             ip += 3;
          }
@@ -1417,7 +1349,8 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
             StringTableEntry varName = CodeToSTE(code, ip + 1);
             U32 failIp = code[ip + 3];
 
-            Con::printf("%i: OP_ITER_BEGIN_STR varName=%s failIp=%i isGlobal=%s", ip - 1, varName, failIp, "true");
+            Con::printf("%i: OP_ITER_BEGIN_STR stk=0 varName=%s failIp=%i isGlobal=%s", ip - 1, varName, failIp, "true");
+            Con::printf("    OP_ITER_BEGIN stk=0 (fallthrough)");
 
             ip += 4;
          }
@@ -1426,7 +1359,8 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
             S32 reg = code[ip + 1];
             U32 failIp = code[ip + 2];
 
-            Con::printf("%i: OP_ITER_BEGIN_STR varRegister=%d failIp=%i isGlobal=%s", ip - 1, reg, failIp, "false");
+            Con::printf("%i: OP_ITER_BEGIN_STR stk=0 varRegister=%d failIp=%i isGlobal=%s", ip - 1, reg, failIp, "false");
+            Con::printf("    OP_ITER_BEGIN stk=0 (fallthrough)");
 
             ip += 3;
          }
@@ -1438,7 +1372,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
       {
          U32 breakIp = code[ip];
 
-         Con::printf("%i: OP_ITER breakIp=%i", ip - 1, breakIp);
+         Con::printf("%i: OP_ITER stk=0 breakIp=%i", ip - 1, breakIp);
 
          ++ip;
          break;
@@ -1446,7 +1380,7 @@ void CodeBlock::dumpInstructions(U32 startIp, bool upToReturn)
 
       case OP_ITER_END:
       {
-         Con::printf("%i: OP_ITER_END", ip - 1);
+         Con::printf("%i: OP_ITER_END stk=-1", ip - 1);
          break;
       }
 

+ 194 - 214
Engine/source/console/compiledEval.cpp

@@ -109,18 +109,11 @@ ConsoleValueStack<4096> gCallStack;
 
 StringStack STR;
 
-U32 _ITER = 0;    ///< Stack pointer for iterStack.
-
 IterStackRecord iterStack[MaxStackSize];
+U32 _ITER = 0;    ///< Stack pointer for iterStack.
 
-union StackValue
-{
-   F64 f;
-   S64 i;
-};
-
-StackValue numStack[MaxStackSize];
-U32 _STK = 0;
+ConsoleValue stack[MaxStackSize];
+S32 _STK = 0;
 
 char curFieldArray[256];
 char prevFieldArray[256];
@@ -166,7 +159,7 @@ static void getFieldComponent(SimObject* object, StringTableEntry field, const c
    // Otherwise, grab from the string stack. The value coming in will always
    // be a string because that is how multicomponent variables are handled.
    else
-      prevVal = STR.getStringValue();
+      prevVal = stack[_STK].getString();
 
    // Make sure we got a value.
    if (prevVal && *prevVal)
@@ -214,7 +207,7 @@ static void setFieldComponent(SimObject* object, StringTableEntry field, const c
 {
    // Copy the current string value
    char strValue[1024];
-   dStrncpy(strValue, STR.getStringValue(), 1024);
+   dStrncpy(strValue, stack[_STK].getString(), 1024);
 
    char val[1024] = "";
    const char* prevVal = NULL;
@@ -437,7 +430,7 @@ U32 gExecCount = 0;
 ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNamespace, U32 argc, ConsoleValue* argv, bool noCalls, StringTableEntry packageName, S32 setFrame)
 {
 #ifdef TORQUE_DEBUG
-   U32 stackStart = STR.mStartStackSize;
+   U32 stackStart = _STK;
    gExecCount++;
 #endif
 
@@ -452,7 +445,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
    F64* curFloatTable;
    char* curStringTable;
    S32 curStringTableLen = 0; //clint to ensure we dont overwrite it
-   STR.clearFunctionOffset();
+
    StringTableEntry thisFunctionName = NULL;
    bool popFrame = false;
    if (argv)
@@ -949,7 +942,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          }
 
          // What group will we be added to, if any?
-         U32 groupAddId = (U32)numStack[_STK].i;
+         U32 groupAddId = (U32)stack[_STK].getInt();
          SimGroup* grp = NULL;
          SimSet* set = NULL;
 
@@ -994,9 +987,9 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          // id, if one was given, otherwise getting pushed)
          S32 id = currentNewObject->getId();
          if (placeAtRoot)
-            numStack[_STK].i = id;
+            stack[_STK].setInt(id);
          else
-            numStack[++_STK].i = id;
+            stack[++_STK].setInt(id);
 
          break;
       }
@@ -1024,7 +1017,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
       }
 
       case OP_JMPIFFNOT:
-         if (numStack[_STK--].f)
+         if (stack[_STK--].getFloat())
          {
             ip++;
             break;
@@ -1032,7 +1025,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          ip = code[ip];
          break;
       case OP_JMPIFNOT:
-         if (numStack[_STK--].i)
+         if (stack[_STK--].getInt())
          {
             ip++;
             break;
@@ -1040,7 +1033,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          ip = code[ip];
          break;
       case OP_JMPIFF:
-         if (!numStack[_STK--].f)
+         if (!stack[_STK--].getFloat())
          {
             ip++;
             break;
@@ -1048,7 +1041,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          ip = code[ip];
          break;
       case OP_JMPIF:
-         if (!numStack[_STK--].i)
+         if (!stack[_STK--].getFloat())
          {
             ip++;
             break;
@@ -1056,7 +1049,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          ip = code[ip];
          break;
       case OP_JMPIFNOT_NP:
-         if (numStack[_STK].i)
+         if (stack[_STK].getInt())
          {
             _STK--;
             ip++;
@@ -1065,7 +1058,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          ip = code[ip];
          break;
       case OP_JMPIF_NP:
-         if (!numStack[_STK].i)
+         if (!stack[_STK].getInt())
          {
             _STK--;
             ip++;
@@ -1077,10 +1070,24 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          ip = code[ip];
          break;
 
-         // This fixes a bug when not explicitly returning a value.
       case OP_RETURN_VOID:
-         STR.setStringValue("");
-         // We're falling thru here on purpose.
+      {
+         if (iterDepth > 0)
+         {
+            // Clear iterator state.
+            while (iterDepth > 0)
+            {
+               iterStack[--_ITER].mIsStringIter = false;
+               --iterDepth;
+            }
+
+            _STK--; // this is a pop from foreach()
+         }
+
+         returnValue.setEmptyString();
+
+         goto execFinished;
+      }
 
       case OP_RETURN:
       {
@@ -1093,12 +1100,16 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
                --iterDepth;
             }
 
-            const char* retVal = STR.getStringValue();
-            STR.rewind();
-            STR.setStringValue(retVal); // Not nice but works.
+            
+            const char* retVal = stack[_STK].getString();
+            _STK--;
+            _STK--;
+            stack[_STK + 1].setString(retVal);
+            _STK++; // Not nice but works.
          }
 
-         returnValue.setString(STR.getStringValue(), STR.mLen);
+         returnValue.setString(stack[_STK].getString());
+         _STK--;
 
          goto execFinished;
       }
@@ -1115,7 +1126,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
 
          }
 
-         returnValue.setFloat(numStack[_STK].f);
+         returnValue.setFloat(stack[_STK].getFloat());
          _STK--;
 
          goto execFinished;
@@ -1132,116 +1143,118 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             }
          }
 
-         returnValue.setInt(numStack[_STK].i);
+         returnValue.setInt(stack[_STK].getInt());
          _STK--;
 
          goto execFinished;
 
       case OP_CMPEQ:
-         numStack[_STK - 1].i = bool(numStack[_STK].f == numStack[_STK - 1].f);
+         stack[_STK - 1].setInt(stack[_STK].getFloat() == stack[_STK - 1].getFloat());
          _STK--;
          break;
 
       case OP_CMPGR:
-         numStack[_STK - 1].i = bool(numStack[_STK].f > numStack[_STK - 1].f);
+         stack[_STK - 1].setInt(stack[_STK].getFloat() > stack[_STK - 1].getFloat());
          _STK--;
          break;
 
       case OP_CMPGE:
-         numStack[_STK - 1].i = bool(numStack[_STK].f >= numStack[_STK - 1].f);
+         stack[_STK - 1].setInt(stack[_STK].getFloat() >= stack[_STK - 1].getFloat());
          _STK--;
          break;
 
       case OP_CMPLT:
-         numStack[_STK - 1].i = bool(numStack[_STK].f < numStack[_STK - 1].f);
+         stack[_STK - 1].setInt(stack[_STK].getFloat() < stack[_STK - 1].getFloat());
          _STK--;
          break;
 
       case OP_CMPLE:
-         numStack[_STK - 1].i = bool(numStack[_STK].f <= numStack[_STK - 1].f);
+         stack[_STK - 1].setInt(stack[_STK].getFloat() <= stack[_STK - 1].getFloat());
          _STK--;
          break;
 
       case OP_CMPNE:
-         numStack[_STK - 1].i = bool(numStack[_STK].f != numStack[_STK - 1].f);
+         stack[_STK - 1].setInt(stack[_STK].getFloat() != stack[_STK - 1].getFloat());
          _STK--;
          break;
 
       case OP_XOR:
-         numStack[_STK - 1].i = numStack[_STK].i ^ numStack[_STK - 1].i;
+         stack[_STK - 1].setInt(stack[_STK].getInt() ^ stack[_STK - 1].getInt());
          _STK--;
          break;
 
       case OP_MOD:
-         if (numStack[_STK - 1].i != 0)
-            numStack[_STK - 1].i = numStack[_STK].i % numStack[_STK - 1].i;
+         if (stack[_STK - 1].getInt() != 0)
+            stack[_STK - 1].setInt(stack[_STK].getInt() % stack[_STK - 1].getInt());
          else
-            numStack[_STK - 1].i = 0;
+            stack[_STK - 1].setInt(0);
          _STK--;
          break;
 
       case OP_BITAND:
-         numStack[_STK - 1].i = numStack[_STK].i & numStack[_STK - 1].i;
+         stack[_STK - 1].setInt(stack[_STK].getInt() & stack[_STK - 1].getInt());
          _STK--;
          break;
 
       case OP_BITOR:
-         numStack[_STK - 1].i = numStack[_STK].i | numStack[_STK - 1].i;
+         stack[_STK - 1].setInt(stack[_STK].getInt() | stack[_STK - 1].getInt());
          _STK--;
          break;
 
       case OP_NOT:
-         numStack[_STK].i = !numStack[_STK].i;
+         stack[_STK].setInt(!stack[_STK].getInt());
          break;
 
       case OP_NOTF:
-         numStack[_STK].i = !numStack[_STK].f;
+         stack[_STK].setInt(!stack[_STK].getFloat());
          break;
 
       case OP_ONESCOMPLEMENT:
-         numStack[_STK].i = ~numStack[_STK].i;
+         stack[_STK].setInt(~stack[_STK].getInt());
          break;
 
       case OP_SHR:
-         numStack[_STK - 1].i = numStack[_STK].i >> numStack[_STK - 1].i;
+         stack[_STK - 1].setInt(stack[_STK].getInt() >> stack[_STK - 1].getInt());
          _STK--;
          break;
 
       case OP_SHL:
-         numStack[_STK - 1].i = numStack[_STK].i << numStack[_STK - 1].i;
+         stack[_STK - 1].setInt(stack[_STK].getInt() << stack[_STK - 1].getInt());
          _STK--;
          break;
 
       case OP_AND:
-         numStack[_STK - 1].i = numStack[_STK].i && numStack[_STK - 1].i;
+         stack[_STK - 1].setInt(stack[_STK].getInt() && stack[_STK - 1].getInt());
          _STK--;
          break;
 
       case OP_OR:
-         numStack[_STK - 1].i = numStack[_STK].i || numStack[_STK - 1].i;
+         stack[_STK - 1].setInt(stack[_STK].getInt() || stack[_STK - 1].getInt());
          _STK--;
          break;
 
       case OP_ADD:
-         numStack[_STK - 1].f = numStack[_STK].f + numStack[_STK - 1].f;
+         stack[_STK - 1].setFloat(stack[_STK].getFloat() + stack[_STK - 1].getFloat());
          _STK--;
          break;
 
       case OP_SUB:
-         numStack[_STK - 1].f = numStack[_STK].f - numStack[_STK - 1].f;
+         stack[_STK - 1].setFloat(stack[_STK].getFloat() - stack[_STK - 1].getFloat());
          _STK--;
          break;
 
       case OP_MUL:
-         numStack[_STK - 1].f = numStack[_STK].f * numStack[_STK - 1].f;
+         stack[_STK - 1].setFloat(stack[_STK].getFloat() * stack[_STK - 1].getFloat());
          _STK--;
          break;
+
       case OP_DIV:
-         numStack[_STK - 1].f = numStack[_STK].f / numStack[_STK - 1].f;
+         stack[_STK - 1].setFloat(stack[_STK].getFloat() / stack[_STK - 1].getFloat());
          _STK--;
          break;
+
       case OP_NEG:
-         numStack[_STK].f = -numStack[_STK].f;
+         stack[_STK].setFloat(-stack[_STK].getFloat());
          break;
 
       case OP_INC:
@@ -1286,7 +1299,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          break;
 
       case OP_SETCURVAR_ARRAY:
-         var = STR.getSTValue();
+         var = StringTable->insert(stack[_STK].getString());
 
          // See OP_SETCURVAR
          prevField = NULL;
@@ -1301,7 +1314,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          break;
 
       case OP_SETCURVAR_ARRAY_CREATE:
-         var = STR.getSTValue();
+         var = StringTable->insert(stack[_STK].getString());
 
          // See OP_SETCURVAR
          prevField = NULL;
@@ -1316,69 +1329,72 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          break;
 
       case OP_LOADVAR_UINT:
-         numStack[_STK + 1].i = gEvalState.getIntVariable();
+         stack[_STK + 1].setInt(gEvalState.getIntVariable());
          _STK++;
          break;
 
       case OP_LOADVAR_FLT:
-         numStack[_STK + 1].f = gEvalState.getFloatVariable();
+         stack[_STK + 1].setFloat(gEvalState.getFloatVariable());
          _STK++;
          break;
 
       case OP_LOADVAR_STR:
-         val = gEvalState.getStringVariable();
-         STR.setStringValue(val);
+         stack[_STK + 1].setString(gEvalState.getStringVariable());
+         _STK++;
          break;
 
       case OP_SAVEVAR_UINT:
-         gEvalState.setIntVariable(numStack[_STK].i);
+         gEvalState.setIntVariable(stack[_STK].getInt());
          break;
 
       case OP_SAVEVAR_FLT:
-         gEvalState.setFloatVariable(numStack[_STK].f);
+         gEvalState.setFloatVariable(stack[_STK].getFloat());
          break;
 
       case OP_SAVEVAR_STR:
-         gEvalState.setStringVariable(STR.getStringValue());
+         gEvalState.setStringVariable(stack[_STK].getString());
          break;
 
       case OP_LOAD_LOCAL_VAR_UINT:
          reg = code[ip++];
-         numStack[_STK + 1].i = gEvalState.getLocalIntVariable(reg);
+         stack[_STK + 1].setInt(gEvalState.getLocalIntVariable(reg));
          _STK++;
          break;
 
       case OP_LOAD_LOCAL_VAR_FLT:
          reg = code[ip++];
-         numStack[_STK + 1].f = gEvalState.getLocalFloatVariable(reg);
+         stack[_STK + 1].setFloat(gEvalState.getLocalFloatVariable(reg));
          _STK++;
          break;
 
       case OP_LOAD_LOCAL_VAR_STR:
          reg = code[ip++];
          val = gEvalState.getLocalStringVariable(reg);
-         STR.setStringValue(val);
+         stack[_STK + 1].setString(val);
+         _STK++;
          break;
 
       case OP_SAVE_LOCAL_VAR_UINT:
          reg = code[ip++];
-         gEvalState.setLocalIntVariable(reg, numStack[_STK].i);
+         gEvalState.setLocalIntVariable(reg, stack[_STK].getInt());
          break;
 
       case OP_SAVE_LOCAL_VAR_FLT:
          reg = code[ip++];
-         gEvalState.setLocalFloatVariable(reg, numStack[_STK].f);
+         gEvalState.setLocalFloatVariable(reg, stack[_STK].getFloat());
          break;
 
       case OP_SAVE_LOCAL_VAR_STR:
          reg = code[ip++];
-         gEvalState.setLocalStringVariable(reg, STR.getStringValue(), (S32)STR.mLen);
+         val = stack[_STK].getString();
+         gEvalState.setLocalStringVariable(reg, val, (S32)dStrlen(val));
          break;
 
       case OP_SETCUROBJECT:
          // Save the previous object for parsing vector fields.
          prevObject = curObject;
-         val = STR.getStringValue();
+         val = stack[_STK].getString();
+         _STK--;
 
          // Sim::findObject will sometimes find valid objects from
          // multi-component strings. This makes sure that doesn't
@@ -1401,16 +1417,15 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             SimGroup* group = dynamic_cast<SimGroup*>(curObject);
             if (group)
             {
-               StringTableEntry intName = StringTable->insert(STR.getStringValue());
+               StringTableEntry intName = StringTable->insert(stack[_STK].getString());
                bool recurse = code[ip - 1];
                SimObject* obj = group->findObjectByInternalName(intName, recurse);
-               numStack[_STK + 1].i = obj ? obj->getId() : 0;
-               _STK++;
+               stack[_STK].setInt(obj ? obj->getId() : 0);
             }
             else
             {
                Con::errorf(ConsoleLogEntry::Script, "%s: Attempt to use -> on non-group %s of class %s.", getFileLine(ip - 2), curObject->getName(), curObject->getClassName());
-               numStack[_STK].i = 0;
+               stack[_STK].setInt(0);
             }
          }
          break;
@@ -1429,7 +1444,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          break;
 
       case OP_SETCURFIELD_ARRAY:
-         dStrcpy(curFieldArray, STR.getStringValue(), 256);
+         dStrcpy(curFieldArray, stack[_STK].getString(), 256);
          break;
 
       case OP_SETCURFIELD_TYPE:
@@ -1440,7 +1455,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
 
       case OP_LOADFIELD_UINT:
          if (curObject)
-            numStack[_STK + 1].i = dAtol(curObject->getDataField(curField, curFieldArray));
+            stack[_STK + 1].setInt(dAtol(curObject->getDataField(curField, curFieldArray)));
          else
          {
             // The field is not being retrieved from an object. Maybe it's
@@ -1448,14 +1463,14 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             char buff[FieldBufferSizeNumeric];
             memset(buff, 0, sizeof(buff));
             getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff);
-            numStack[_STK + 1].i = dAtol(buff);
+            stack[_STK + 1].setInt(dAtol(buff));
          }
          _STK++;
          break;
 
       case OP_LOADFIELD_FLT:
          if (curObject)
-            numStack[_STK + 1].f = dAtod(curObject->getDataField(curField, curFieldArray));
+            stack[_STK + 1].setFloat(dAtod(curObject->getDataField(curField, curFieldArray)));
          else
          {
             // The field is not being retrieved from an object. Maybe it's
@@ -1463,7 +1478,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             char buff[FieldBufferSizeNumeric];
             memset(buff, 0, sizeof(buff));
             getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff);
-            numStack[_STK + 1].f = dAtod(buff);
+            stack[_STK + 1].setFloat(dAtod(buff));
          }
          _STK++;
          break;
@@ -1472,7 +1487,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          if (curObject)
          {
             val = curObject->getDataField(curField, curFieldArray);
-            STR.setStringValue(val);
+            stack[_STK + 1].setString(val);
          }
          else
          {
@@ -1481,15 +1496,14 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             char buff[FieldBufferSizeString];
             memset(buff, 0, sizeof(buff));
             getFieldComponent(prevObject, prevField, prevFieldArray, curField, buff);
-            STR.setStringValue(buff);
+            stack[_STK + 1].setString(buff);
          }
-
+         _STK++;
          break;
 
       case OP_SAVEFIELD_UINT:
-         STR.setIntValue(numStack[_STK].i);
          if (curObject)
-            curObject->setDataField(curField, curFieldArray, STR.getStringValue());
+            curObject->setDataField(curField, curFieldArray, stack[_STK].getString());
          else
          {
             // The field is not being set on an object. Maybe it's
@@ -1500,9 +1514,8 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          break;
 
       case OP_SAVEFIELD_FLT:
-         STR.setFloatValue(numStack[_STK].f);
          if (curObject)
-            curObject->setDataField(curField, curFieldArray, STR.getStringValue());
+            curObject->setDataField(curField, curFieldArray, stack[_STK].getString());
          else
          {
             // The field is not being set on an object. Maybe it's
@@ -1514,7 +1527,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
 
       case OP_SAVEFIELD_STR:
          if (curObject)
-            curObject->setDataField(curField, curFieldArray, STR.getStringValue());
+            curObject->setDataField(curField, curFieldArray, stack[_STK].getString());
          else
          {
             // The field is not being set on an object. Maybe it's
@@ -1524,51 +1537,20 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          }
          break;
 
-      case OP_STR_TO_UINT:
-         numStack[_STK + 1].i = STR.getIntValue();
-         _STK++;
-         break;
-
-      case OP_STR_TO_FLT:
-         numStack[_STK + 1].f = STR.getFloatValue();
-         _STK++;
-         break;
-
-      case OP_STR_TO_NONE:
-         // This exists simply to deal with certain typecast situations.
-         break;
-
-      case OP_FLT_TO_UINT:
-         numStack[_STK].i = (S64)numStack[_STK].f;
-         break;
-
-      case OP_FLT_TO_STR:
-         STR.setFloatValue(numStack[_STK].f);
-         _STK--;
-         break;
-
-      case OP_UINT_TO_FLT:
-         numStack[_STK].f = (F64)numStack[_STK].i;
-         break;
-
-      case OP_UINT_TO_STR:
-         STR.setIntValue(numStack[_STK].i);
-         _STK--;
-         break;
-
-      case OP_NUM_TO_NONE:
+      case OP_POP_STK:
          _STK--;
          break;
 
       case OP_LOADIMMED_UINT:
-         numStack[_STK + 1].i = code[ip++];
+         stack[_STK + 1].setInt(code[ip++]);
          _STK++;
          break;
 
       case OP_LOADIMMED_FLT:
-         numStack[_STK + 1].f = curFloatTable[code[ip++]];
+         stack[_STK + 1].setFloat(curFloatTable[code[ip++]]);
          _STK++;
          break;
+
       case OP_TAG_TO_STR:
          code[ip - 1] = OP_LOADIMMED_STR;
          // it's possible the string has already been converted
@@ -1578,8 +1560,11 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             dSprintf(curStringTable + code[ip] + 1, 7, "%d", id);
             *(curStringTable + code[ip]) = StringTagPrefixByte;
          }
+         TORQUE_CASE_FALLTHROUGH;
+
       case OP_LOADIMMED_STR:
-         STR.setStringValue(curStringTable + code[ip++]);
+         stack[_STK + 1].setString(curStringTable + code[ip++]);
+         _STK ++;
          break;
 
       case OP_DOCBLOCK_STR:
@@ -1614,7 +1599,8 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
       break;
 
       case OP_LOADIMMED_IDENT:
-         STR.setStringValue(CodeToSTE(code, ip));
+         stack[_STK + 1].setString(CodeToSTE(code, ip));
+         _STK++;
          ip += 2;
          break;
 
@@ -1652,8 +1638,10 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
                Con::warnf(ConsoleLogEntry::General,
                   "%s: Unable to find function %s",
                   getFileLine(ip - 4), fnName);
-               //STR.popFrame();
+
                gCallStack.popFrame();
+               stack[_STK + 1].setEmptyString();
+               _STK++;
                break;
             }
          }
@@ -1668,8 +1656,10 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
                   "%s: Unable to find function %s%s%s",
                   getFileLine(ip - 4), fnNamespace ? fnNamespace : "",
                   fnNamespace ? "::" : "", fnName);
-               //STR.popFrame();
+
                gCallStack.popFrame();
+               stack[_STK + 1].setEmptyString();
+               _STK++;
                break;
             }
          }
@@ -1702,9 +1692,10 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
                   simObjectLookupValue.getString(),
                   fnName
                );
-               //STR.popFrame();
+
                gCallStack.popFrame();
-               STR.setStringValue("");
+               stack[_STK + 1].setEmptyString();
+               _STK++;
                break;
             }
 
@@ -1744,8 +1735,8 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
                }
             }
             gCallStack.popFrame();
-            STR.setStringValue("");
-            STR.setStringValue("");
+            stack[_STK + 1].setEmptyString();
+            _STK++;
             break;
          }
          if (nsEntry->mType == Namespace::Entry::ConsoleFunctionType)
@@ -1754,10 +1745,11 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             {
                // TODO: not make this strings only for returns.
                ConsoleValue returnFromFn = nsEntry->mCode->exec(nsEntry->mFunctionOffset, fnName, nsEntry->mNamespace, callArgc, callArgv, false, nsEntry->mPackage);
-               STR.setStringValue(returnFromFn.getString());
+               stack[_STK + 1] = std::move(returnFromFn);
             }
             else // no body
-               STR.setStringValue("");
+               stack[_STK + 1].setEmptyString();
+            _STK++;
 
             gCallStack.popFrame();
          }
@@ -1769,7 +1761,8 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
                Con::warnf(ConsoleLogEntry::Script, "%s: %s::%s - wrong number of arguments.", getFileLine(ip - 4), nsName, fnName);
                Con::warnf(ConsoleLogEntry::Script, "%s: usage: %s", getFileLine(ip - 4), nsEntry->mUsage);
                gCallStack.popFrame();
-               STR.setStringValue("");
+               stack[_STK + 1].setEmptyString();
+               _STK++;
             }
             else
             {
@@ -1777,87 +1770,73 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
                {
                case Namespace::Entry::StringCallbackType:
                {
-                  const char* ret = nsEntry->cb.mStringCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
+                  const char* result = nsEntry->cb.mStringCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
                   gCallStack.popFrame();
-                  if (ret != STR.getStringValue())
-                     STR.setStringValue(ret);
-                  else
-                     STR.setLen(dStrlen(ret));
+                  stack[_STK + 1].setString(result);
+                  _STK++;
                   break;
                }
                case Namespace::Entry::IntCallbackType:
                {
                   S64 result = nsEntry->cb.mIntCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
                   gCallStack.popFrame();
-                  if (code[ip] == OP_STR_TO_UINT)
-                  {
-                     ip++;
-                     numStack[++_STK].i = result;
-                     break;
-                  }
-                  else if (code[ip] == OP_STR_TO_FLT)
+
+                  if (code[ip] == OP_POP_STK)
                   {
                      ip++;
-                     numStack[++_STK].f = result;
                      break;
                   }
-                  else if (code[ip] == OP_STR_TO_NONE)
-                     ip++;
-                  else
-                     STR.setIntValue(result);
+
+                  stack[_STK + 1].setInt(result);
+                  _STK++;
                   break;
                }
                case Namespace::Entry::FloatCallbackType:
                {
                   F64 result = nsEntry->cb.mFloatCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
                   gCallStack.popFrame();
-                  if (code[ip] == OP_STR_TO_UINT)
-                  {
-                     ip++;
-                     numStack[++_STK].i = (S64)result;
-                     break;
-                  }
-                  else if (code[ip] == OP_STR_TO_FLT)
+
+                  if (code[ip] == OP_POP_STK)
                   {
                      ip++;
-                     numStack[++_STK].f = result;
                      break;
                   }
-                  else if (code[ip] == OP_STR_TO_NONE)
-                     ip++;
-                  else
-                     STR.setFloatValue(result);
+
+                  stack[_STK + 1].setInt(result);
+                  _STK++;
                   break;
                }
                case Namespace::Entry::VoidCallbackType:
                {
                   nsEntry->cb.mVoidCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
-                  if (code[ip] != OP_STR_TO_NONE)
-                     Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", getFileLine(ip - 4), fnName, functionName);
                   gCallStack.popFrame();
-                  STR.setStringValue("");
+
+                  if (code[ip] == OP_POP_STK)
+                  {
+                     ip++;
+                     break;
+                  }
+
+                  Con::warnf(ConsoleLogEntry::General, "%s: Call to %s in %s uses result of void function call.", getFileLine(ip - 4), fnName, functionName);
+                  stack[_STK + 1].setEmptyString();
+                  _STK++;
+
                   break;
                }
                case Namespace::Entry::BoolCallbackType:
                {
                   bool result = nsEntry->cb.mBoolCallbackFunc(gEvalState.thisObject, callArgc, callArgv);
                   gCallStack.popFrame();
-                  if (code[ip] == OP_STR_TO_UINT)
-                  {
-                     ip++;
-                     numStack[++_STK].i = result;
-                     break;
-                  }
-                  else if (code[ip] == OP_STR_TO_FLT)
+
+                  if (code[ip] == OP_POP_STK)
                   {
                      ip++;
-                     numStack[++_STK].f = result;
                      break;
                   }
-                  else if (code[ip] == OP_STR_TO_NONE)
-                     ip++;
-                  else
-                     STR.setIntValue(result);
+
+                  stack[_STK + 1].setBool(result);
+                  _STK++;
+
                   break;
                }
                }
@@ -1868,43 +1847,45 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             gEvalState.thisObject = saveObject;
          break;
       }
-      case OP_ADVANCE_STR:
-         STR.advance();
-         break;
+
       case OP_ADVANCE_STR_APPENDCHAR:
-         STR.advanceChar(code[ip++]);
-         break;
+      {
+         // TODO: Create a better way to handle string concatination without
+         // heap allocating every time.
 
-      case OP_ADVANCE_STR_COMMA:
-         STR.advanceChar('_');
-         break;
+         val = stack[_STK].getString();
+         dsize_t len = dStrlen(val) + 2;
 
-      case OP_ADVANCE_STR_NUL:
-         STR.advanceChar(0);
-         break;
+         char buff[2];
+         buff[0] = (char)code[ip++];
+         buff[1] = '\0';
+
+         char* concat = new char[len];
+         dMemset(concat, 0, len);
+         dStrcat(concat, val, len);
+         dStrcat(concat, buff, len);
+
+         stack[_STK].setString(concat);
+
+         delete[] concat;
 
-      case OP_REWIND_STR:
-         STR.rewind();
          break;
+      }
 
+      case OP_REWIND_STR:
+         TORQUE_CASE_FALLTHROUGH;
       case OP_TERMINATE_REWIND_STR:
-         STR.rewindTerminate();
+         stack[_STK - 1].setString((String(stack[_STK - 1] + String(stack[_STK]))));
+         _STK--;
          break;
 
       case OP_COMPARE_STR:
-         numStack[++_STK].i = STR.compare();
+         stack[_STK - 1].setBool(!dStricmp(stack[_STK].getString(), stack[_STK - 1].getString()));
+         _STK--;
          break;
 
       case OP_PUSH:
-         gCallStack.pushString(STR.getStringValue(), STR.mLen);
-         break;
-
-      case OP_PUSH_UINT:
-         gCallStack.pushInt((U32)numStack[_STK--].i);
-         break;
-
-      case OP_PUSH_FLT:
-         gCallStack.pushFloat(numStack[_STK--].f);
+         gCallStack.push(std::move(stack[_STK--]));
          break;
 
       case OP_PUSH_FRAME:
@@ -1913,7 +1894,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
 
       case OP_ASSERT:
       {
-         if (!numStack[_STK--].i)
+         if (!stack[_STK--].getBool())
          {
             const char* message = curStringTable + code[ip];
 
@@ -1957,7 +1938,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
       case OP_ITER_BEGIN_STR:
       {
          iterStack[_ITER].mIsStringIter = true;
-         /* fallthrough */
+         TORQUE_CASE_FALLTHROUGH;
       }
 
       case OP_ITER_BEGIN:
@@ -1981,7 +1962,7 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
 
          if (iter.mIsStringIter)
          {
-            iter.mData.mStr.mString = STR.getStringValue();
+            iter.mData.mStr.mString = stack[_STK].getString();
             iter.mData.mStr.mIndex = 0;
          }
          else
@@ -1989,9 +1970,9 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             // Look up the object.
 
             SimSet* set;
-            if (!Sim::findObject(STR.getStringValue(), set))
+            if (!Sim::findObject(stack[_STK].getString(), set))
             {
-               Con::errorf(ConsoleLogEntry::General, "No SimSet object '%s'", STR.getStringValue());
+               Con::errorf(ConsoleLogEntry::General, "No SimSet object '%s'", stack[_STK].getString());
                Con::errorf(ConsoleLogEntry::General, "Did you mean to use 'foreach$' instead of 'foreach'?");
                ip = failIp;
                continue;
@@ -2006,8 +1987,6 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          _ITER++;
          iterDepth++;
 
-         STR.push();
-
          ip += isGlobal ? 4 : 3;
          break;
       }
@@ -2096,16 +2075,17 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
          --_ITER;
          --iterDepth;
 
-         STR.rewind();
+         _STK--;
 
          iterStack[_ITER].mIsStringIter = false;
          break;
       }
 
       case OP_INVALID:
-
+         TORQUE_CASE_FALLTHROUGH;
       default:
          // error!
+         AssertISV(false, "Invalid OPCode Processed!");
          goto execFinished;
       }
    }
@@ -2162,8 +2142,8 @@ execFinished:
    decRefCount();
 
 #ifdef TORQUE_DEBUG
-   AssertFatal(!(STR.mStartStackSize > stackStart), "String stack not popped enough in script exec");
-   AssertFatal(!(STR.mStartStackSize < stackStart), "String stack popped too much in script exec");
+   AssertFatal(!(_STK > stackStart), "String stack not popped enough in script exec");
+   AssertFatal(!(_STK < stackStart), "String stack popped too much in script exec");
 #endif
 
    return std::move(returnValue);

+ 6 - 16
Engine/source/console/compiler.h

@@ -69,6 +69,7 @@ namespace Compiler
       OP_RETURN_FLT,
       OP_RETURN_UINT,
 
+
       OP_CMPEQ,
       OP_CMPGR,
       OP_CMPGE,
@@ -132,14 +133,7 @@ namespace Compiler
       OP_SAVEFIELD_FLT,
       OP_SAVEFIELD_STR,
 
-      OP_STR_TO_UINT,
-      OP_STR_TO_FLT,
-      OP_STR_TO_NONE,  // 60
-      OP_FLT_TO_UINT,
-      OP_FLT_TO_STR,
-      OP_UINT_TO_FLT,
-      OP_UINT_TO_STR,
-      OP_NUM_TO_NONE,
+      OP_POP_STK,
 
       OP_LOADIMMED_UINT,
       OP_LOADIMMED_FLT,
@@ -150,18 +144,14 @@ namespace Compiler
 
       OP_CALLFUNC,
 
-      OP_ADVANCE_STR,
       OP_ADVANCE_STR_APPENDCHAR,
-      OP_ADVANCE_STR_COMMA,
-      OP_ADVANCE_STR_NUL,
       OP_REWIND_STR,
-      OP_TERMINATE_REWIND_STR,  // 80
+      OP_TERMINATE_REWIND_STR,
+
       OP_COMPARE_STR,
 
-      OP_PUSH,          // String
-      OP_PUSH_UINT,     // Integer
-      OP_PUSH_FLT,      // Float
-      OP_PUSH_FRAME,    // Frame
+      OP_PUSH,
+      OP_PUSH_FRAME,
 
       OP_ASSERT,
       OP_BREAK,

+ 19 - 8
Engine/source/console/console.h

@@ -174,14 +174,7 @@ class ConsoleValue
       }
    }
 
-public:
-   explicit ConsoleValue()
-   {
-      type = ConsoleValueType::cvSTEntry;
-      s = const_cast<char*>(StringTable->EmptyString());
-   }
-
-   ConsoleValue(ConsoleValue&& ref) noexcept
+   TORQUE_FORCEINLINE void _move(ConsoleValue&& ref) noexcept
    {
       type = ref.type;
 
@@ -207,6 +200,24 @@ public:
       ref.setEmptyString();
    }
 
+public:
+   ConsoleValue()
+   {
+      type = ConsoleValueType::cvSTEntry;
+      s = const_cast<char*>(StringTable->EmptyString());
+   }
+
+   ConsoleValue(ConsoleValue&& ref) noexcept
+   {
+      _move(std::move(ref));
+   }
+
+   TORQUE_FORCEINLINE ConsoleValue& operator=(ConsoleValue&& ref) noexcept
+   {
+      _move(std::move(ref));
+      return *this;
+   }
+
    ConsoleValue(const ConsoleValue&) = delete;
    ConsoleValue& operator=(const ConsoleValue&) = delete;
 

+ 2 - 14
Engine/source/console/consoleValueStack.h

@@ -89,22 +89,10 @@ public:
       stack.pop_back();
    }
 
-   TORQUE_FORCEINLINE void pushInt(S64 value)
+   TORQUE_FORCEINLINE void push(ConsoleValue&& val)
    {
       Frame& frame = stack.last();
-      frame.values[frame.internalCounter++].setInt(value);
-   }
-
-   TORQUE_FORCEINLINE void pushFloat(F64 value)
-   {
-      Frame& frame = stack.last();
-      frame.values[frame.internalCounter++].setFloat(value);
-   }
-
-   TORQUE_FORCEINLINE void pushString(const char* value, S32 len)
-   {
-      Frame& frame = stack.last();
-      frame.values[frame.internalCounter++].setString(value, len);
+      frame.values[frame.internalCounter++] = std::move(val);
    }
 
    TORQUE_FORCEINLINE void argvc(StringTableEntry fn, S32& argc, ConsoleValue** argv)

+ 139 - 0
Engine/source/console/test/ScriptTest.cpp

@@ -60,6 +60,60 @@ TEST(Script, Basic_Arithmetic)
    )");
 
    ASSERT_EQ(div.getInt(), 5);
+
+   ConsoleValue mod = RunScript(R"(
+         return 4 % 5;
+   )");
+
+   ASSERT_EQ(mod.getInt(), 4);
+
+   ConsoleValue add2 = RunScript(R"(
+         $a = 0;
+         $a += 2;
+         return $a;
+   )");
+
+   ASSERT_EQ(add2.getInt(), 2);
+
+   ConsoleValue sub2 = RunScript(R"(
+         $a = 0;
+         $a -= 2;
+         return $a;
+   )");
+
+   ASSERT_EQ(sub2.getInt(), -2);
+
+   ConsoleValue mult2 = RunScript(R"(
+         $a = 2;
+         $a *= 3;
+         return $a;
+   )");
+
+   ASSERT_EQ(mult2.getInt(), 6);
+
+   ConsoleValue div2 = RunScript(R"(
+         $a = 10;
+         $a /= 2;
+         return $a;
+   )");
+
+   ASSERT_EQ(div2.getInt(), 5);
+
+   ConsoleValue pp = RunScript(R"(
+         $a = 0;
+         $a++;
+         return $a;
+   )");
+
+   ASSERT_EQ(pp.getInt(), 1);
+
+   ConsoleValue mm = RunScript(R"(
+         $a = 2;
+         $a--;
+         return $a;
+   )");
+
+   ASSERT_EQ(mm.getInt(), 1);
 }
 
 TEST(Script, Complex_Arithmetic)
@@ -240,6 +294,20 @@ TEST(Script, Basic_Loop_Statements)
 
    ASSERT_STREQ(forValue.getString(), "aaa");
 
+   ConsoleValue forReverseLoop = RunScript(R"(
+         function t(%times) 
+         { 
+            %result = "";
+            for (%i = %times - 1; %i >= 0; %i--)
+               %result = %result @ "b";
+            return %result;
+         }
+
+         return t(3);
+   )");
+
+   ASSERT_STREQ(forReverseLoop.getString(), "bbb");
+
    ConsoleValue forIfValue = RunScript(R"(
          function t()
          {
@@ -402,6 +470,77 @@ TEST(Script, Basic_SimObject)
    )");
 
    ASSERT_STREQ(parentFn.getString(), "FooBar");
+
+   ConsoleValue grp = RunScript(R"(
+         new SimGroup(FudgeCollectorGroup)
+         {
+            theName = "fudge";
+
+            new SimObject(ChocolateFudge)
+            {
+               type = "Chocolate";
+            };
+            new SimObject(PeanutButterFudge)
+            {
+               type = "Peanut Butter";
+
+               field["a"] = "Yes";
+            };
+         };
+
+         return FudgeCollectorGroup.getId();
+   )");
+
+   SimGroup* simGroup = dynamic_cast<SimGroup*>(Sim::findObject(grp));
+   ASSERT_NE(simGroup, (SimGroup*)NULL);
+   ASSERT_EQ(simGroup->size(), 2);
+
+   simGroup->deleteObject();
+
+   ConsoleValue fieldTest = RunScript(R"(
+         function a()
+         {
+            %obj = new SimObject();
+            %obj.field = "A";
+            %obj.val[%obj.field] = "B";
+
+            %value = %obj.val["A"];
+            %obj.delete();
+            return %value;
+         }
+         return a();
+   )");
+
+   ASSERT_STREQ(fieldTest.getString(), "B");
+}
+
+TEST(Script, Internal_Name)
+{
+   ConsoleValue value = RunScript(R"(
+         function SimObject::_internalCall(%this)
+         {
+            return 5;
+         }
+
+         function a()
+         {
+            %grp = new SimGroup();
+            %obj = new SimObject()
+            {
+               internalName = "Yay";
+            };
+            %grp.add(%obj);
+
+            %val = %grp->Yay._internalCall();
+
+            %grp.delete();
+
+            return %val;
+         }
+         return a();
+   )");
+
+   ASSERT_EQ(value.getInt(), 5);
 }
 
 TEST(Script, Basic_Package)