Browse Source

Added error checking for using a local variable in global scope, and added optimization to method object parameter.

Jeff Hutchinson 4 years ago
parent
commit
bb12638ea5
2 changed files with 25 additions and 10 deletions
  1. 15 9
      Engine/source/console/astNodes.cpp
  2. 10 1
      Engine/source/console/compiledEval.cpp

+ 15 - 9
Engine/source/console/astNodes.cpp

@@ -101,6 +101,12 @@ private:
 
 FuncVars* gFuncVars = NULL;
 
+inline FuncVars* getFuncVars()
+{
+   AssertISV(gFuncVars, "Attemping to use local variable in global scope.");
+   return gFuncVars;
+}
+
 //-----------------------------------------------------------------------------
 
 void StmtNode::addBreakLine(CodeStream& code)
@@ -424,7 +430,7 @@ U32 IterStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
    if (isGlobal)
       codeStream.emitSTE(varName);
    else
-      codeStream.emit(gFuncVars->assign(varName, varType));
+      codeStream.emit(getFuncVars()->assign(varName, varType));
    const U32 finalFix = codeStream.emit(0);
    const U32 continueIp = codeStream.emit(OP_ITER);
    codeStream.emitFix(CodeStream::FIXTYPE_BREAK);
@@ -793,7 +799,7 @@ U32 VarNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
       default:           codeStream.emit(OP_LOAD_LOCAL_VAR_STR);
       }
 
-      codeStream.emit(gFuncVars->lookup(varName));
+      codeStream.emit(getFuncVars()->lookup(varName));
    }
 
    return codeStream.tell();
@@ -802,7 +808,7 @@ U32 VarNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
 TypeReq VarNode::getPreferredType()
 {
    bool oldVariables = arrayIndex || varName[0] == '$';
-   return oldVariables ? TypeReqNone : gFuncVars->lookupType(varName);
+   return oldVariables ? TypeReqNone : getFuncVars()->lookupType(varName);
 }
 
 //------------------------------------------------------------
@@ -1040,7 +1046,7 @@ U32 AssignExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
       case TypeReqFloat: codeStream.emit(OP_SAVE_LOCAL_VAR_FLT); break;
       default:           codeStream.emit(OP_SAVE_LOCAL_VAR_STR);
       }
-      codeStream.emit(gFuncVars->assign(varName, subType == TypeReqNone ? TypeReqString : subType));
+      codeStream.emit(getFuncVars()->assign(varName, subType == TypeReqNone ? TypeReqString : subType));
    }
 
    if (type != subType)
@@ -1136,7 +1142,7 @@ U32 AssignOpExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
 
    if (op == opPLUSPLUS && !oldVariables)
    {
-      const S32 varIdx = gFuncVars->assign(varName, TypeReqFloat);
+      const S32 varIdx = getFuncVars()->assign(varName, TypeReqFloat);
 
       codeStream.emit(OP_INC);
       codeStream.emit(varIdx);
@@ -1169,7 +1175,7 @@ U32 AssignOpExprNode::compile(CodeStream& codeStream, U32 ip, TypeReq type)
       else
       {
          const bool isFloat = subType == TypeReqFloat;
-         const S32 varIdx = gFuncVars->assign(varName, subType == TypeReqNone ? TypeReqString : subType);
+         const S32 varIdx = getFuncVars()->assign(varName, subType == TypeReqNone ? TypeReqString : subType);
 
          codeStream.emit(isFloat ? OP_LOAD_LOCAL_VAR_FLT : OP_LOAD_LOCAL_VAR_UINT);
          codeStream.emit(varIdx);
@@ -1649,7 +1655,7 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
    for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext())
    {
       precompileIdent(walk->varName);
-      gFuncVars->assign(walk->varName, TypeReqNone);
+      getFuncVars()->assign(walk->varName, TypeReqNone);
       argc++;
    }
 
@@ -1673,7 +1679,7 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
    for (VarNode* walk = args; walk; walk = (VarNode*)((StmtNode*)walk)->getNext())
    {
       StringTableEntry name = walk->varName;
-      codeStream.emit(gFuncVars->lookup(name));
+      codeStream.emit(getFuncVars()->lookup(name));
    }
    CodeBlock::smInFunction = true;
    ip = compileBlock(stmts, codeStream, ip);
@@ -1685,7 +1691,7 @@ U32 FunctionDeclStmtNode::compileStmt(CodeStream& codeStream, U32 ip)
    CodeBlock::smInFunction = false;
    codeStream.emit(OP_RETURN_VOID);
 
-   codeStream.patch(localNumVarsIP, gFuncVars->count());
+   codeStream.patch(localNumVarsIP, getFuncVars()->count());
    codeStream.patch(endIp, codeStream.tell());
 
    setCurrentStringTable(&getGlobalStringTable());

+ 10 - 1
Engine/source/console/compiledEval.cpp

@@ -1682,7 +1682,16 @@ ConsoleValue CodeBlock::exec(U32 ip, const char* functionName, Namespace* thisNa
             if (simObjectLookupValue.getType() == ConsoleValueType::cvInteger)
                gEvalState.thisObject = Sim::findObject(static_cast<SimObjectId>(simObjectLookupValue.getInt()));
             else
-               gEvalState.thisObject = Sim::findObject(simObjectLookupValue.getString());
+            {
+               SimObject *foundObject = Sim::findObject(simObjectLookupValue.getString());
+
+               // Optimization: If we're not an integer, let's make it so that the fast path exists
+               // on the first argument of the method call (speeds up future usage of %this, for example)
+               if (foundObject != NULL)
+                  callArgv[1].setInt(static_cast<S64>(foundObject->getId()));
+
+               gEvalState.thisObject = foundObject;
+            }
 
             if (gEvalState.thisObject == NULL)
             {