mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-16 00:54:54 +00:00
Merge pull request #2121 from JeffProgrammer/TSImprovementsDevMerge
TorqueScript Improvements - Faster Interpreter.
This commit is contained in:
commit
4f78143dc8
23 changed files with 10231 additions and 8513 deletions
|
|
@ -45,6 +45,7 @@
|
|||
#include "console/debugOutputConsumer.h"
|
||||
#include "console/consoleTypes.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "console/codeInterpreter.h"
|
||||
|
||||
#include "gfx/bitmap/gBitmap.h"
|
||||
#include "gfx/gFont.h"
|
||||
|
|
@ -227,6 +228,9 @@ void StandardMainLoop::init()
|
|||
ManagedSingleton< ThreadManager >::createSingleton();
|
||||
FrameAllocator::init(TORQUE_FRAME_SIZE); // See comments in torqueConfig.h
|
||||
|
||||
// Initialize the TorqueScript interpreter.
|
||||
CodeInterpreter::init();
|
||||
|
||||
// Yell if we can't initialize the network.
|
||||
if(!Net::init())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -496,9 +496,9 @@ class_name_expr
|
|||
|
||||
assign_op_struct
|
||||
: opPLUSPLUS
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = '+'; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = opPLUSPLUS; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
||||
| opMINUSMINUS
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = '-'; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = opMINUSMINUS; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
||||
| opPLASN expr
|
||||
{ $$.lineNumber = $1.lineNumber; $$.token = '+'; $$.expr = $2; }
|
||||
| opMIASN expr
|
||||
|
|
@ -551,6 +551,8 @@ funcall_expr
|
|||
{ $$ = FuncCallExprNode::alloc( $1.lineNumber, $3.value, $1.value, $5, false); }
|
||||
| expr '.' IDENT '(' expr_list_decl ')'
|
||||
{ $1->append($5); $$ = FuncCallExprNode::alloc( $1->dbgLineNumber, $3.value, NULL, $1, true); }
|
||||
| expr '(' expr_list_decl ')'
|
||||
{ $$ = FuncPointerCallExprNode::alloc( $1->dbgLineNumber, $1, $3); }
|
||||
;
|
||||
|
||||
assert_expr
|
||||
|
|
|
|||
|
|
@ -774,9 +774,9 @@ YY_MALLOC_DECL
|
|||
|
||||
YY_DECL
|
||||
{
|
||||
yy_state_type yy_current_state;
|
||||
char *yy_cp, *yy_bp;
|
||||
int yy_act;
|
||||
register yy_state_type yy_current_state;
|
||||
register char *yy_cp, *yy_bp;
|
||||
register int yy_act;
|
||||
|
||||
#line 105 "CMDscan.l"
|
||||
|
||||
|
|
@ -823,7 +823,7 @@ YY_DECL
|
|||
yy_match:
|
||||
do
|
||||
{
|
||||
YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
|
||||
register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
|
||||
if (yy_accept[yy_current_state])
|
||||
{
|
||||
yy_last_accepting_state = yy_current_state;
|
||||
|
|
@ -837,8 +837,7 @@ yy_match:
|
|||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int)yy_c];
|
||||
++yy_cp;
|
||||
}
|
||||
while ( yy_base[yy_current_state] != 338 );
|
||||
} while (yy_base[yy_current_state] != 338);
|
||||
|
||||
yy_find_action:
|
||||
yy_act = yy_accept[yy_current_state];
|
||||
|
|
@ -1430,9 +1429,9 @@ case YY_STATE_EOF(INITIAL):
|
|||
|
||||
static int yy_get_next_buffer()
|
||||
{
|
||||
char *dest = yy_current_buffer->yy_ch_buf;
|
||||
char *source = yytext_ptr;
|
||||
int number_to_move, i;
|
||||
register char *dest = yy_current_buffer->yy_ch_buf;
|
||||
register char *source = yytext_ptr;
|
||||
register int number_to_move, i;
|
||||
int ret_val;
|
||||
|
||||
if (yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1])
|
||||
|
|
@ -1560,14 +1559,14 @@ static int yy_get_next_buffer()
|
|||
|
||||
static yy_state_type yy_get_previous_state()
|
||||
{
|
||||
yy_state_type yy_current_state;
|
||||
char *yy_cp;
|
||||
register yy_state_type yy_current_state;
|
||||
register char *yy_cp;
|
||||
|
||||
yy_current_state = yy_start;
|
||||
|
||||
for (yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp)
|
||||
{
|
||||
YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
|
||||
register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
|
||||
if (yy_accept[yy_current_state])
|
||||
{
|
||||
yy_last_accepting_state = yy_current_state;
|
||||
|
|
@ -1599,10 +1598,10 @@ static yy_state_type yy_try_NUL_trans( yy_current_state )
|
|||
yy_state_type yy_current_state;
|
||||
#endif
|
||||
{
|
||||
int yy_is_jam;
|
||||
char *yy_cp = yy_c_buf_p;
|
||||
register int yy_is_jam;
|
||||
register char *yy_cp = yy_c_buf_p;
|
||||
|
||||
YY_CHAR yy_c = 1;
|
||||
register YY_CHAR yy_c = 1;
|
||||
if (yy_accept[yy_current_state])
|
||||
{
|
||||
yy_last_accepting_state = yy_current_state;
|
||||
|
|
@ -1623,14 +1622,14 @@ yy_state_type yy_current_state;
|
|||
|
||||
#ifndef YY_NO_UNPUT
|
||||
#ifdef YY_USE_PROTOS
|
||||
static void yyunput( int c, char *yy_bp )
|
||||
static void yyunput(int c, register char *yy_bp)
|
||||
#else
|
||||
static void yyunput(c, yy_bp)
|
||||
int c;
|
||||
char *yy_bp;
|
||||
register char *yy_bp;
|
||||
#endif
|
||||
{
|
||||
char *yy_cp = yy_c_buf_p;
|
||||
register char *yy_cp = yy_c_buf_p;
|
||||
|
||||
/* undo effects of setting up yytext */
|
||||
*yy_cp = yy_hold_char;
|
||||
|
|
@ -1638,10 +1637,10 @@ char *yy_bp;
|
|||
if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
|
||||
{ /* need to shift things up to make room */
|
||||
/* +2 for EOB chars. */
|
||||
int number_to_move = yy_n_chars + 2;
|
||||
char *dest = &yy_current_buffer->yy_ch_buf[
|
||||
register int number_to_move = yy_n_chars + 2;
|
||||
register char *dest = &yy_current_buffer->yy_ch_buf[
|
||||
yy_current_buffer->yy_buf_size + 2];
|
||||
char *source =
|
||||
register char *source =
|
||||
&yy_current_buffer->yy_ch_buf[number_to_move];
|
||||
|
||||
while (source > yy_current_buffer->yy_ch_buf)
|
||||
|
|
@ -2095,7 +2094,7 @@ yyconst char *s2;
|
|||
int n;
|
||||
#endif
|
||||
{
|
||||
int i;
|
||||
register int i;
|
||||
for (i = 0; i < n; ++i)
|
||||
s1[i] = s2[i];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -446,6 +446,18 @@ struct FuncCallExprNode : ExprNode
|
|||
DBG_STMT_TYPE(FuncCallExprNode);
|
||||
};
|
||||
|
||||
struct FuncPointerCallExprNode : ExprNode
|
||||
{
|
||||
ExprNode *funcPointer;
|
||||
ExprNode *args;
|
||||
|
||||
static FuncPointerCallExprNode *alloc(S32 lineNumber, ExprNode *stmt, ExprNode *args);
|
||||
|
||||
U32 compile(CodeStream &codeStream, U32 ip, TypeReq type);
|
||||
TypeReq getPreferredType();
|
||||
DBG_STMT_TYPE(FuncPointerCallExprNode);
|
||||
};
|
||||
|
||||
struct AssertCallExprNode : ExprNode
|
||||
{
|
||||
ExprNode *testExpr;
|
||||
|
|
|
|||
|
|
@ -328,6 +328,16 @@ FuncCallExprNode *FuncCallExprNode::alloc( S32 lineNumber, StringTableEntry func
|
|||
return ret;
|
||||
}
|
||||
|
||||
FuncPointerCallExprNode *FuncPointerCallExprNode::alloc(S32 lineNumber, ExprNode *funcPointer, ExprNode *args)
|
||||
{
|
||||
FuncPointerCallExprNode *ret = (FuncPointerCallExprNode *)consoleAlloc(sizeof(FuncPointerCallExprNode));
|
||||
constructInPlace(ret);
|
||||
ret->dbgLineNumber = lineNumber;
|
||||
ret->funcPointer = funcPointer;
|
||||
ret->args = args;
|
||||
return ret;
|
||||
}
|
||||
|
||||
AssertCallExprNode *AssertCallExprNode::alloc(S32 lineNumber, ExprNode *testExpr, const char *message)
|
||||
{
|
||||
#ifdef TORQUE_ENABLE_SCRIPTASSERTS
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ struct Token
|
|||
};
|
||||
#include "console/cmdgram.h"
|
||||
|
||||
|
||||
namespace Compiler
|
||||
{
|
||||
U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip)
|
||||
|
|
@ -51,6 +50,81 @@ namespace Compiler
|
|||
ip = walk->compileStmt(codeStream, ip);
|
||||
return codeStream.tell();
|
||||
}
|
||||
|
||||
inline bool isSimpleVarLookup(ExprNode *arrayExpr, StringTableEntry &varName)
|
||||
{
|
||||
if (arrayExpr == nullptr)
|
||||
{
|
||||
varName = StringTable->insert("");
|
||||
return false;
|
||||
}
|
||||
|
||||
// No double arrays allowed for optimization.
|
||||
VarNode *var = dynamic_cast<VarNode*>(arrayExpr);
|
||||
if (var && !var->arrayIndex)
|
||||
{
|
||||
StringTableEntry arrayVar = StringTable->insert(var->varName);
|
||||
precompileIdent(arrayVar);
|
||||
varName = arrayVar;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do not allow 'recursive' %this optimizations. It can lead to weird bytecode
|
||||
// generation since we can only optimize one expression at a time.
|
||||
static bool OnlyOneThisOptimization = false;
|
||||
|
||||
inline bool isThisVar(ExprNode *objectExpr)
|
||||
{
|
||||
// If we are currently optimizing a this var, don't allow extra optimization.
|
||||
if (objectExpr == nullptr || OnlyOneThisOptimization)
|
||||
return false;
|
||||
|
||||
VarNode *thisVar = dynamic_cast<VarNode*>(objectExpr);
|
||||
if (thisVar && thisVar->varName == StringTable->insert("%this"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void optimizeThisPointer(CodeStream &codeStream, ExprNode *arrayExpr, U32 &ip, StringTableEntry slotName)
|
||||
{
|
||||
OnlyOneThisOptimization = true;
|
||||
|
||||
// Is the array a simple variable? If so, we can optimize that.
|
||||
StringTableEntry varName = nullptr;
|
||||
bool simple = false;
|
||||
|
||||
if (arrayExpr)
|
||||
{
|
||||
simple = isSimpleVarLookup(arrayExpr, varName);
|
||||
if (!simple)
|
||||
{
|
||||
// Less optimized array setting.
|
||||
codeStream.emit(OP_ADVANCE_STR);
|
||||
ip = arrayExpr->compile(codeStream, ip, TypeReqString);
|
||||
}
|
||||
}
|
||||
|
||||
codeStream.emit(OP_SETCURFIELD_THIS);
|
||||
codeStream.emitSTE(slotName);
|
||||
|
||||
if (arrayExpr)
|
||||
{
|
||||
if (simple)
|
||||
{
|
||||
codeStream.emit(OP_SETCURFIELD_ARRAY_VAR);
|
||||
codeStream.emitSTE(varName);
|
||||
}
|
||||
else
|
||||
{
|
||||
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
||||
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||
}
|
||||
}
|
||||
|
||||
OnlyOneThisOptimization = false;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace Compiler;
|
||||
|
|
@ -692,7 +766,13 @@ TypeReq FloatUnaryExprNode::getPreferredType()
|
|||
|
||||
U32 VarNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||
{
|
||||
// if this has an arrayIndex...
|
||||
// if this has an arrayIndex and we are not short circuiting from a constant.
|
||||
// if we are a var node
|
||||
// OP_SETCURVAR_ARRAY_VARLOOKUP
|
||||
// varName
|
||||
// varNodeVarName
|
||||
|
||||
// else
|
||||
// OP_LOADIMMED_IDENT
|
||||
// varName
|
||||
// OP_ADVANCE_STR
|
||||
|
|
@ -709,18 +789,54 @@ U32 VarNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
if (type == TypeReqNone)
|
||||
return codeStream.tell();
|
||||
|
||||
precompileIdent(varName);
|
||||
|
||||
codeStream.emit(arrayIndex ? OP_LOADIMMED_IDENT : OP_SETCURVAR);
|
||||
codeStream.emitSTE(varName);
|
||||
|
||||
bool shortCircuit = false;
|
||||
if (arrayIndex)
|
||||
{
|
||||
// If we have a constant, shortcircuit the array logic.
|
||||
|
||||
IntNode *intNode = dynamic_cast<IntNode*>(arrayIndex);
|
||||
StrConstNode *strNode = dynamic_cast<StrConstNode*>(arrayIndex);
|
||||
if (intNode)
|
||||
{
|
||||
varName = StringTable->insert(avar("%s%d", varName, intNode->value));
|
||||
shortCircuit = true;
|
||||
}
|
||||
else if (strNode)
|
||||
{
|
||||
varName = StringTable->insert(avar("%s%s", varName, strNode->str));
|
||||
shortCircuit = true;
|
||||
}
|
||||
}
|
||||
|
||||
precompileIdent(varName);
|
||||
|
||||
if (arrayIndex && !shortCircuit)
|
||||
{
|
||||
// Ok, lets try to optimize %var[%someothervar] as this is
|
||||
// a common case for array usage.
|
||||
StringTableEntry varNodeVarName;
|
||||
if (isSimpleVarLookup(arrayIndex, varNodeVarName))
|
||||
{
|
||||
codeStream.emit(OP_SETCURVAR_ARRAY_VARLOOKUP);
|
||||
codeStream.emitSTE(varName);
|
||||
codeStream.emitSTE(varNodeVarName);
|
||||
}
|
||||
else
|
||||
{
|
||||
codeStream.emit(OP_LOADIMMED_IDENT);
|
||||
codeStream.emitSTE(varName);
|
||||
codeStream.emit(OP_ADVANCE_STR);
|
||||
ip = arrayIndex->compile(codeStream, ip, TypeReqString);
|
||||
codeStream.emit(OP_REWIND_STR);
|
||||
codeStream.emit(OP_SETCURVAR_ARRAY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
codeStream.emit(OP_SETCURVAR);
|
||||
codeStream.emitSTE(varName);
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case TypeReqUInt:
|
||||
|
|
@ -934,15 +1050,29 @@ U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
subType = TypeReqString;
|
||||
}
|
||||
}
|
||||
// if it's an array expr, the formula is:
|
||||
|
||||
//if we are an array index and we are gonna short circuit
|
||||
// eval expr
|
||||
// compute new varName
|
||||
// OP_SETCURVAR_CREATE
|
||||
// varName
|
||||
// OP_SAVEVAR
|
||||
|
||||
//else if it's an array expr and we don't short circuit, the formula is:
|
||||
// eval expr
|
||||
// (push and pop if it's TypeReqString) OP_ADVANCE_STR
|
||||
// if array lookup is varnode
|
||||
// OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP
|
||||
// varName
|
||||
// varNodeVarName
|
||||
// else
|
||||
// OP_LOADIMMED_IDENT
|
||||
// varName
|
||||
// OP_ADVANCE_STR
|
||||
// eval array
|
||||
// OP_REWIND_STR
|
||||
// OP_SETCURVAR_ARRAY_CREATE
|
||||
// endif
|
||||
// OP_TERMINATE_REWIND_STR
|
||||
// OP_SAVEVAR
|
||||
|
||||
|
|
@ -952,15 +1082,45 @@ U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
// varname
|
||||
// OP_SAVEVAR
|
||||
|
||||
precompileIdent(varName);
|
||||
|
||||
ip = expr->compile(codeStream, ip, subType);
|
||||
|
||||
bool shortCircuit = false;
|
||||
if (arrayIndex)
|
||||
{
|
||||
// If we have a constant, shortcircuit the array logic.
|
||||
|
||||
IntNode *intNode = dynamic_cast<IntNode*>(arrayIndex);
|
||||
StrConstNode *strNode = dynamic_cast<StrConstNode*>(arrayIndex);
|
||||
if (intNode)
|
||||
{
|
||||
varName = StringTable->insert(avar("%s%d", varName, intNode->value));
|
||||
shortCircuit = true;
|
||||
}
|
||||
else if (strNode)
|
||||
{
|
||||
varName = StringTable->insert(avar("%s%s", varName, strNode->str));
|
||||
shortCircuit = true;
|
||||
}
|
||||
}
|
||||
|
||||
precompileIdent(varName);
|
||||
|
||||
if (arrayIndex && !shortCircuit)
|
||||
{
|
||||
if (subType == TypeReqString)
|
||||
codeStream.emit(OP_ADVANCE_STR);
|
||||
|
||||
// Ok, lets try to optimize %var[%someothervar] as this is
|
||||
// a common case for array usage.
|
||||
StringTableEntry varNodeVarName;
|
||||
if (isSimpleVarLookup(arrayIndex, varNodeVarName))
|
||||
{
|
||||
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP);
|
||||
codeStream.emitSTE(varName);
|
||||
codeStream.emitSTE(varNodeVarName);
|
||||
}
|
||||
else
|
||||
{
|
||||
codeStream.emit(OP_LOADIMMED_IDENT);
|
||||
codeStream.emitSTE(varName);
|
||||
|
||||
|
|
@ -968,6 +1128,8 @@ U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
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);
|
||||
}
|
||||
|
|
@ -1010,10 +1172,12 @@ static void getAssignOpTypeOp(S32 op, TypeReq &type, U32 &operand)
|
|||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
case opPLUSPLUS:
|
||||
type = TypeReqFloat;
|
||||
operand = OP_ADD;
|
||||
break;
|
||||
case '-':
|
||||
case opMINUSMINUS:
|
||||
type = TypeReqFloat;
|
||||
operand = OP_SUB;
|
||||
break;
|
||||
|
|
@ -1056,35 +1220,112 @@ U32 AssignOpExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
{
|
||||
|
||||
// goes like this...
|
||||
//
|
||||
// IF no array index && (op == OPPLUSPLUS or op == OPMINUSMINUS)
|
||||
// if op == OPPLUSPLUS
|
||||
// OP_INC
|
||||
// varName
|
||||
// else if op == OPMINUSMINUS
|
||||
// OP_DEC
|
||||
// varName
|
||||
// else
|
||||
// OP_INVALID
|
||||
// endif
|
||||
// ELSE
|
||||
// eval expr as float or int
|
||||
// if there's an arrayIndex
|
||||
|
||||
// if there's an arrayIndex and we don't short circuit
|
||||
// if arrayIndex is a var node
|
||||
// OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP
|
||||
// varName
|
||||
// varNodeVarName
|
||||
// else
|
||||
// OP_LOADIMMED_IDENT
|
||||
// varName
|
||||
// OP_ADVANCE_STR
|
||||
// eval arrayIndex stringwise
|
||||
// OP_REWIND_STR
|
||||
// OP_SETCURVAR_ARRAY_CREATE
|
||||
|
||||
// endif
|
||||
// else
|
||||
// OP_SETCURVAR_CREATE
|
||||
// varName
|
||||
|
||||
// endif
|
||||
// OP_LOADVAR_FLT or UINT
|
||||
// operand
|
||||
// OP_SAVEVAR_FLT or UINT
|
||||
// ENDIF
|
||||
//
|
||||
// if subtype != type
|
||||
// convert type
|
||||
// endif
|
||||
|
||||
// conversion OP if necessary.
|
||||
getAssignOpTypeOp(op, subType, operand);
|
||||
|
||||
// ++ or -- optimization support for non indexed variables.
|
||||
if ((!arrayIndex) && (op == opPLUSPLUS || op == opMINUSMINUS))
|
||||
{
|
||||
precompileIdent(varName);
|
||||
|
||||
if (op == opPLUSPLUS)
|
||||
{
|
||||
codeStream.emit(OP_INC);
|
||||
codeStream.emitSTE(varName);
|
||||
}
|
||||
else if (op == opMINUSMINUS)
|
||||
{
|
||||
codeStream.emit(OP_DEC);
|
||||
codeStream.emitSTE(varName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This should NEVER happen. This is just for sanity.
|
||||
AssertISV(false, "Tried to use ++ or -- but something weird happened.");
|
||||
codeStream.emit(OP_INVALID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ip = expr->compile(codeStream, ip, subType);
|
||||
if(!arrayIndex)
|
||||
|
||||
bool shortCircuit = false;
|
||||
if (arrayIndex)
|
||||
{
|
||||
// If we have a constant, shortcircuit the array logic.
|
||||
|
||||
IntNode *intNode = dynamic_cast<IntNode*>(arrayIndex);
|
||||
StrConstNode *strNode = dynamic_cast<StrConstNode*>(arrayIndex);
|
||||
if (intNode)
|
||||
{
|
||||
varName = StringTable->insert(avar("%s%d", varName, intNode->value));
|
||||
shortCircuit = true;
|
||||
}
|
||||
else if (strNode)
|
||||
{
|
||||
varName = StringTable->insert(avar("%s%s", varName, strNode->str));
|
||||
shortCircuit = true;
|
||||
}
|
||||
}
|
||||
|
||||
precompileIdent(varName);
|
||||
|
||||
if (!arrayIndex || shortCircuit)
|
||||
{
|
||||
codeStream.emit(OP_SETCURVAR_CREATE);
|
||||
codeStream.emitSTE(varName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ok, lets try to optimize %var[%someothervar] as this is
|
||||
// a common case for array usage.
|
||||
StringTableEntry varNodeVarName;
|
||||
if (isSimpleVarLookup(arrayIndex, varNodeVarName))
|
||||
{
|
||||
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP);
|
||||
codeStream.emitSTE(varName);
|
||||
codeStream.emitSTE(varNodeVarName);
|
||||
}
|
||||
else
|
||||
{
|
||||
codeStream.emit(OP_LOADIMMED_IDENT);
|
||||
codeStream.emitSTE(varName);
|
||||
|
|
@ -1094,9 +1335,11 @@ U32 AssignOpExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
codeStream.emit(OP_REWIND_STR);
|
||||
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
|
||||
}
|
||||
}
|
||||
codeStream.emit((subType == TypeReqFloat) ? OP_LOADVAR_FLT : OP_LOADVAR_UINT);
|
||||
codeStream.emit(operand);
|
||||
codeStream.emit((subType == TypeReqFloat) ? OP_SAVEVAR_FLT : OP_SAVEVAR_UINT);
|
||||
}
|
||||
if (subType != type)
|
||||
codeStream.emit(conversionOp(subType, type));
|
||||
return codeStream.tell();
|
||||
|
|
@ -1155,6 +1398,91 @@ U32 FuncCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
precompileIdent(funcName);
|
||||
precompileIdent(nameSpace);
|
||||
|
||||
codeStream.emit(OP_PUSH_FRAME);
|
||||
|
||||
bool isThisCall = false;
|
||||
|
||||
ExprNode *walk = args;
|
||||
|
||||
// Try to optimize the this pointer call if it is a variable
|
||||
// that we are loading.
|
||||
if (callType == MethodCall)
|
||||
{
|
||||
// We cannot optimize array indices because it can have quite
|
||||
// a bit of code to figure out the array index.
|
||||
VarNode *var = dynamic_cast<VarNode*>(args);
|
||||
if (var && !var->arrayIndex)
|
||||
{
|
||||
precompileIdent(var->varName);
|
||||
|
||||
// Are we a %this call?
|
||||
isThisCall = (var->varName == StringTable->insert("%this"));
|
||||
|
||||
codeStream.emit(OP_PUSH_THIS);
|
||||
codeStream.emitSTE(var->varName);
|
||||
|
||||
// inc args since we took care of first arg.
|
||||
walk = (ExprNode*)walk ->getNext();
|
||||
}
|
||||
}
|
||||
|
||||
for (; walk; walk = (ExprNode *)walk->getNext())
|
||||
{
|
||||
TypeReq walkType = walk->getPreferredType();
|
||||
if (walkType == TypeReqNone) 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (isThisCall)
|
||||
{
|
||||
codeStream.emit(OP_CALLFUNC_THIS);
|
||||
codeStream.emitSTE(funcName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (callType == MethodCall || callType == ParentCall)
|
||||
codeStream.emit(OP_CALLFUNC);
|
||||
else
|
||||
codeStream.emit(OP_CALLFUNC_RESOLVE);
|
||||
|
||||
codeStream.emitSTE(funcName);
|
||||
codeStream.emitSTE(nameSpace);
|
||||
codeStream.emit(callType);
|
||||
}
|
||||
|
||||
if (type != TypeReqString)
|
||||
codeStream.emit(conversionOp(TypeReqString, type));
|
||||
return codeStream.tell();
|
||||
}
|
||||
|
||||
TypeReq FuncCallExprNode::getPreferredType()
|
||||
{
|
||||
return TypeReqString;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
U32 FuncPointerCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||
{
|
||||
// OP_PUSH_FRAME
|
||||
// arg OP_PUSH arg OP_PUSH arg OP_PUSH
|
||||
// eval all the args, then call the function.
|
||||
|
||||
// eval fn pointer
|
||||
// OP_CALLFUNC_POINTER
|
||||
|
||||
codeStream.emit(OP_PUSH_FRAME);
|
||||
for (ExprNode *walk = args; walk; walk = (ExprNode *)walk->getNext())
|
||||
{
|
||||
|
|
@ -1174,26 +1502,20 @@ U32 FuncCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if(callType == MethodCall || callType == ParentCall)
|
||||
codeStream.emit(OP_CALLFUNC);
|
||||
else
|
||||
codeStream.emit(OP_CALLFUNC_RESOLVE);
|
||||
|
||||
codeStream.emitSTE(funcName);
|
||||
codeStream.emitSTE(nameSpace);
|
||||
ip = funcPointer->compile(codeStream, ip, TypeReqString);
|
||||
codeStream.emit(OP_CALLFUNC_POINTER);
|
||||
|
||||
codeStream.emit(callType);
|
||||
if (type != TypeReqString)
|
||||
codeStream.emit(conversionOp(TypeReqString, type));
|
||||
return codeStream.tell();
|
||||
}
|
||||
|
||||
TypeReq FuncCallExprNode::getPreferredType()
|
||||
TypeReq FuncPointerCallExprNode::getPreferredType()
|
||||
{
|
||||
return TypeReqString;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
U32 AssertCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||
|
|
@ -1225,6 +1547,13 @@ U32 SlotAccessNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
|
||||
precompileIdent(slotName);
|
||||
|
||||
// check if object is %this. If we are, we can do additional optimizations.
|
||||
if (isThisVar(objectExpr))
|
||||
{
|
||||
optimizeThisPointer(codeStream, arrayExpr, ip, slotName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arrayExpr)
|
||||
{
|
||||
// eval array
|
||||
|
|
@ -1249,6 +1578,7 @@ U32 SlotAccessNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
||||
}
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
|
|
@ -1331,6 +1661,13 @@ U32 SlotAssignNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
precompileIdent(slotName);
|
||||
|
||||
ip = valueExpr->compile(codeStream, ip, TypeReqString);
|
||||
|
||||
if (isThisVar(objectExpr))
|
||||
{
|
||||
optimizeThisPointer(codeStream, arrayExpr, ip, slotName);
|
||||
}
|
||||
else
|
||||
{
|
||||
codeStream.emit(OP_ADVANCE_STR);
|
||||
if (arrayExpr)
|
||||
{
|
||||
|
|
@ -1354,6 +1691,8 @@ U32 SlotAssignNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
}
|
||||
|
||||
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||
}
|
||||
|
||||
codeStream.emit(OP_SAVEFIELD_STR);
|
||||
|
||||
if (typeID != -1)
|
||||
|
|
@ -1403,6 +1742,13 @@ U32 SlotAssignOpNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
precompileIdent(slotName);
|
||||
|
||||
ip = valueExpr->compile(codeStream, ip, subType);
|
||||
|
||||
if (isThisVar(objectExpr))
|
||||
{
|
||||
optimizeThisPointer(codeStream, arrayExpr, ip, slotName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arrayExpr)
|
||||
{
|
||||
ip = arrayExpr->compile(codeStream, ip, TypeReqString);
|
||||
|
|
@ -1418,6 +1764,7 @@ U32 SlotAssignOpNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
|||
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
||||
}
|
||||
}
|
||||
codeStream.emit((subType == TypeReqFloat) ? OP_LOADFIELD_FLT : OP_LOADFIELD_UINT);
|
||||
codeStream.emit(operand);
|
||||
codeStream.emit((subType == TypeReqFloat) ? OP_SAVEFIELD_FLT : OP_SAVEFIELD_UINT);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1007,6 +1007,20 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
|||
break;
|
||||
}
|
||||
|
||||
case OP_INC:
|
||||
{
|
||||
Con::printf("%i: OP_INC varName=%s", ip - 1, CodeToSTE(code, ip));
|
||||
ip += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_DEC:
|
||||
{
|
||||
Con::printf("%i: OP_DEC varName=%s", ip - 1, CodeToSTE(code, ip));
|
||||
ip += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_SETCURVAR:
|
||||
{
|
||||
StringTableEntry var = CodeToSTE(code, ip);
|
||||
|
|
@ -1031,12 +1045,32 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
|||
break;
|
||||
}
|
||||
|
||||
case OP_SETCURVAR_ARRAY_VARLOOKUP:
|
||||
{
|
||||
StringTableEntry arrayName = CodeToSTE(code, ip);
|
||||
StringTableEntry arrayLookup = CodeToSTE(code, ip + 2);
|
||||
|
||||
Con::printf("%i: OP_SETCURVAR_ARRAY_VARLOOKUP arrayName=%s arrayLookup=%s", ip - 1, arrayName, arrayLookup);
|
||||
ip += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_SETCURVAR_ARRAY_CREATE:
|
||||
{
|
||||
Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE", ip - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP:
|
||||
{
|
||||
StringTableEntry arrayName = CodeToSTE(code, ip);
|
||||
StringTableEntry arrayLookup = CodeToSTE(code, ip + 2);
|
||||
|
||||
Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP arrayName=%s arrayLookup=%s", ip - 1, arrayName, arrayLookup);
|
||||
ip += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_LOADVAR_UINT:
|
||||
{
|
||||
Con::printf("%i: OP_LOADVAR_UINT", ip - 1);
|
||||
|
|
@ -1118,6 +1152,22 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
|||
break;
|
||||
}
|
||||
|
||||
case OP_SETCURFIELD_ARRAY_VAR:
|
||||
{
|
||||
StringTableEntry var = CodeToSTE(code, ip);
|
||||
Con::printf("%i: OP_SETCURFIELD_ARRAY_VAR var=%s", ip - 1, var);
|
||||
ip += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_SETCURFIELD_THIS:
|
||||
{
|
||||
StringTableEntry curField = CodeToSTE(code, ip);
|
||||
Con::printf("%i: OP_SETCURFIELD_THIS field=%s", ip - 1, curField);
|
||||
ip += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_SETCURFIELD_TYPE:
|
||||
{
|
||||
U32 type = code[ip];
|
||||
|
|
@ -1298,6 +1348,21 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
|||
break;
|
||||
}
|
||||
|
||||
case OP_CALLFUNC_POINTER:
|
||||
{
|
||||
Con::printf("%i: OP_CALLFUNC_POINTER", ip - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_CALLFUNC_THIS:
|
||||
{
|
||||
StringTableEntry fnName = CodeToSTE(code, ip);
|
||||
Con::printf("%i: OP_CALLFUNC_THIS name=%s ", ip - 1, fnName);
|
||||
|
||||
ip += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_ADVANCE_STR:
|
||||
{
|
||||
Con::printf("%i: OP_ADVANCE_STR", ip - 1);
|
||||
|
|
@ -1366,6 +1431,13 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
|||
break;
|
||||
}
|
||||
|
||||
case OP_PUSH_THIS:
|
||||
{
|
||||
Con::printf("%i: OP_PUSH_THIS varName=%s", ip - 1, CodeToSTE(code, ip));
|
||||
ip += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_PUSH_FRAME:
|
||||
{
|
||||
Con::printf("%i: OP_PUSH_FRAME", ip - 1);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class ConsoleValueRef;
|
|||
/// This class represents a block of code, usually mapped directly to a file.
|
||||
class CodeBlock
|
||||
{
|
||||
friend class CodeInterpreter;
|
||||
private:
|
||||
static CodeBlock* smCodeBlockList;
|
||||
static CodeBlock* smCurrentCodeBlock;
|
||||
|
|
|
|||
2979
Engine/source/console/codeInterpreter.cpp
Normal file
2979
Engine/source/console/codeInterpreter.cpp
Normal file
File diff suppressed because it is too large
Load diff
262
Engine/source/console/codeInterpreter.h
Normal file
262
Engine/source/console/codeInterpreter.h
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (c) 2012 GarageGames, LLC
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _CODEINTERPRETER_H_
|
||||
#define _CODEINTERPRETER_H_
|
||||
|
||||
#include "console/codeBlock.h"
|
||||
#include "console/console.h"
|
||||
#include "console/consoleInternal.h"
|
||||
|
||||
/// Frame data for a foreach/foreach$ loop.
|
||||
struct IterStackRecord
|
||||
{
|
||||
/// If true, this is a foreach$ loop; if not, it's a foreach loop.
|
||||
bool mIsStringIter;
|
||||
|
||||
/// The iterator variable.
|
||||
Dictionary::Entry* mVariable;
|
||||
|
||||
/// Information for an object iterator loop.
|
||||
struct ObjectPos
|
||||
{
|
||||
/// The set being iterated over.
|
||||
SimSet* mSet;
|
||||
|
||||
/// Current index in the set.
|
||||
U32 mIndex;
|
||||
};
|
||||
|
||||
/// Information for a string iterator loop.
|
||||
struct StringPos
|
||||
{
|
||||
/// The raw string data on the string stack.
|
||||
StringStackPtr mString;
|
||||
|
||||
/// Current parsing position.
|
||||
U32 mIndex;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
ObjectPos mObj;
|
||||
StringPos mStr;
|
||||
} mData;
|
||||
};
|
||||
|
||||
enum OPCodeReturn
|
||||
{
|
||||
exitCode = -1,
|
||||
success = 0,
|
||||
breakContinue = 1
|
||||
};
|
||||
|
||||
class CodeInterpreter
|
||||
{
|
||||
public:
|
||||
CodeInterpreter(CodeBlock *cb);
|
||||
~CodeInterpreter();
|
||||
|
||||
ConsoleValueRef exec(U32 ip,
|
||||
StringTableEntry functionName,
|
||||
Namespace *thisNamespace,
|
||||
U32 argc,
|
||||
ConsoleValueRef *argv,
|
||||
bool noCalls,
|
||||
StringTableEntry packageName,
|
||||
S32 setFrame);
|
||||
|
||||
static void init();
|
||||
|
||||
// Methods
|
||||
private:
|
||||
void parseArgs(U32 &ip);
|
||||
|
||||
/// Group op codes
|
||||
/// @{
|
||||
|
||||
OPCodeReturn op_func_decl(U32 &ip);
|
||||
OPCodeReturn op_create_object(U32 &ip);
|
||||
OPCodeReturn op_add_object(U32 &ip);
|
||||
OPCodeReturn op_end_object(U32 &ip);
|
||||
OPCodeReturn op_finish_object(U32 &ip);
|
||||
OPCodeReturn op_jmpiffnot(U32 &ip);
|
||||
OPCodeReturn op_jmpifnot(U32 &ip);
|
||||
OPCodeReturn op_jmpiff(U32 &ip);
|
||||
OPCodeReturn op_jmpif(U32 &ip);
|
||||
OPCodeReturn op_jmpifnot_np(U32 &ip);
|
||||
OPCodeReturn op_jmpif_np(U32 &ip);
|
||||
OPCodeReturn op_jmp(U32 &ip);
|
||||
OPCodeReturn op_return_void(U32 &ip);
|
||||
OPCodeReturn op_return(U32 &ip);
|
||||
OPCodeReturn op_return_flt(U32 &ip);
|
||||
OPCodeReturn op_return_uint(U32 &ip);
|
||||
OPCodeReturn op_cmpeq(U32 &ip);
|
||||
OPCodeReturn op_cmpgr(U32 &ip);
|
||||
OPCodeReturn op_cmpge(U32 &ip);
|
||||
OPCodeReturn op_cmplt(U32 &ip);
|
||||
OPCodeReturn op_cmple(U32 &ip);
|
||||
OPCodeReturn op_cmpne(U32 &ip);
|
||||
OPCodeReturn op_xor(U32 &ip);
|
||||
OPCodeReturn op_mod(U32 &ip);
|
||||
OPCodeReturn op_bitand(U32 &ip);
|
||||
OPCodeReturn op_bitor(U32 &ip);
|
||||
OPCodeReturn op_not(U32 &ip);
|
||||
OPCodeReturn op_notf(U32 &ip);
|
||||
OPCodeReturn op_onescomplement(U32 &ip);
|
||||
OPCodeReturn op_shr(U32 &ip);
|
||||
OPCodeReturn op_shl(U32 &ip);
|
||||
OPCodeReturn op_and(U32 &ip);
|
||||
OPCodeReturn op_or(U32 &ip);
|
||||
OPCodeReturn op_add(U32 &ip);
|
||||
OPCodeReturn op_sub(U32 &ip);
|
||||
OPCodeReturn op_mul(U32 &ip);
|
||||
OPCodeReturn op_div(U32 &ip);
|
||||
OPCodeReturn op_neg(U32 &ip);
|
||||
OPCodeReturn op_inc(U32 &ip);
|
||||
OPCodeReturn op_dec(U32 &ip);
|
||||
OPCodeReturn op_setcurvar(U32 &ip);
|
||||
OPCodeReturn op_setcurvar_create(U32 &ip);
|
||||
OPCodeReturn op_setcurvar_array(U32 &ip);
|
||||
OPCodeReturn op_setcurvar_array_varlookup(U32 &ip);
|
||||
OPCodeReturn op_setcurvar_array_create(U32 &ip);
|
||||
OPCodeReturn op_setcurvar_array_create_varlookup(U32 &ip);
|
||||
OPCodeReturn op_loadvar_uint(U32 &ip);
|
||||
OPCodeReturn op_loadvar_flt(U32 &ip);
|
||||
OPCodeReturn op_loadvar_str(U32 &ip);
|
||||
OPCodeReturn op_loadvar_var(U32 &ip);
|
||||
OPCodeReturn op_savevar_uint(U32 &ip);
|
||||
OPCodeReturn op_savevar_flt(U32 &ip);
|
||||
OPCodeReturn op_savevar_str(U32 &ip);
|
||||
OPCodeReturn op_savevar_var(U32 &ip);
|
||||
OPCodeReturn op_setcurobject(U32 &ip);
|
||||
OPCodeReturn op_setcurobject_internal(U32 &ip);
|
||||
OPCodeReturn op_setcurobject_new(U32 &ip);
|
||||
OPCodeReturn op_setcurfield(U32 &ip);
|
||||
OPCodeReturn op_setcurfield_array(U32 &ip);
|
||||
OPCodeReturn op_setcurfield_type(U32 &ip);
|
||||
OPCodeReturn op_setcurfield_this(U32 &ip);
|
||||
OPCodeReturn op_setcurfield_array_var(U32 &ip);
|
||||
OPCodeReturn op_loadfield_uint(U32 &ip);
|
||||
OPCodeReturn op_loadfield_flt(U32 &ip);
|
||||
OPCodeReturn op_loadfield_str(U32 &ip);
|
||||
OPCodeReturn op_savefield_uint(U32 &ip);
|
||||
OPCodeReturn op_savefield_flt(U32 &ip);
|
||||
OPCodeReturn op_savefield_str(U32 &ip);
|
||||
OPCodeReturn op_str_to_uint(U32 &ip);
|
||||
OPCodeReturn op_str_to_flt(U32 &ip);
|
||||
OPCodeReturn op_str_to_none(U32 &ip);
|
||||
OPCodeReturn op_flt_to_uint(U32 &ip);
|
||||
OPCodeReturn op_flt_to_str(U32 &ip);
|
||||
OPCodeReturn op_flt_to_none(U32 &ip);
|
||||
OPCodeReturn op_uint_to_flt(U32 &ip);
|
||||
OPCodeReturn op_uint_to_str(U32 &ip);
|
||||
OPCodeReturn op_uint_to_none(U32 &ip);
|
||||
OPCodeReturn op_copyvar_to_none(U32 &ip);
|
||||
OPCodeReturn op_loadimmed_uint(U32 &ip);
|
||||
OPCodeReturn op_loadimmed_flt(U32 &ip);
|
||||
OPCodeReturn op_tag_to_str(U32 &ip);
|
||||
OPCodeReturn op_loadimmed_str(U32 &ip);
|
||||
OPCodeReturn op_docblock_str(U32 &ip);
|
||||
OPCodeReturn op_loadimmed_ident(U32 &ip);
|
||||
OPCodeReturn op_callfunc_resolve(U32 &ip);
|
||||
OPCodeReturn op_callfunc(U32 &ip);
|
||||
OPCodeReturn op_callfunc_pointer(U32 &ip);
|
||||
OPCodeReturn op_callfunc_this(U32 &ip);
|
||||
OPCodeReturn op_advance_str(U32 &ip);
|
||||
OPCodeReturn op_advance_str_appendchar(U32 &ip);
|
||||
OPCodeReturn op_advance_str_comma(U32 &ip);
|
||||
OPCodeReturn op_advance_str_nul(U32 &ip);
|
||||
OPCodeReturn op_rewind_str(U32 &ip);
|
||||
OPCodeReturn op_terminate_rewind_str(U32 &ip);
|
||||
OPCodeReturn op_compare_str(U32 &ip);
|
||||
OPCodeReturn op_push(U32 &ip);
|
||||
OPCodeReturn op_push_uint(U32 &ip);
|
||||
OPCodeReturn op_push_flt(U32 &ip);
|
||||
OPCodeReturn op_push_var(U32 &ip);
|
||||
OPCodeReturn op_push_this(U32 &ip);
|
||||
OPCodeReturn op_push_frame(U32 &ip);
|
||||
OPCodeReturn op_assert(U32 &ip);
|
||||
OPCodeReturn op_break(U32 &ip);
|
||||
OPCodeReturn op_iter_begin_str(U32 &ip);
|
||||
OPCodeReturn op_iter_begin(U32 &ip);
|
||||
OPCodeReturn op_iter(U32 &ip);
|
||||
OPCodeReturn op_iter_end(U32 &ip);
|
||||
OPCodeReturn op_invalid(U32 &ip);
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
CodeBlock *mCodeBlock;
|
||||
|
||||
/// Group exec arguments.
|
||||
struct
|
||||
{
|
||||
StringTableEntry functionName;
|
||||
Namespace *thisNamespace;
|
||||
U32 argc;
|
||||
ConsoleValueRef *argv;
|
||||
bool noCalls;
|
||||
StringTableEntry packageName;
|
||||
S32 setFrame;
|
||||
} mExec;
|
||||
|
||||
U32 mIterDepth;
|
||||
F64 *mCurFloatTable;
|
||||
char *mCurStringTable;
|
||||
StringTableEntry mThisFunctionName;
|
||||
bool mPopFrame;
|
||||
|
||||
// Add local object creation stack [7/9/2007 Black]
|
||||
static const U32 objectCreationStackSize = 32;
|
||||
U32 mObjectCreationStackIndex;
|
||||
struct
|
||||
{
|
||||
SimObject *newObject;
|
||||
U32 failJump;
|
||||
} mObjectCreationStack[objectCreationStackSize];
|
||||
|
||||
SimObject *mCurrentNewObject;
|
||||
U32 mFailJump;
|
||||
StringTableEntry mPrevField;
|
||||
StringTableEntry mCurField;
|
||||
SimObject *mPrevObject;
|
||||
SimObject *mCurObject;
|
||||
SimObject *mSaveObject;
|
||||
SimObject *mThisObject;
|
||||
Namespace::Entry *mNSEntry;
|
||||
StringTableEntry mCurFNDocBlock;
|
||||
StringTableEntry mCurNSDocBlock;
|
||||
U32 mCallArgc;
|
||||
ConsoleValueRef *mCallArgv;
|
||||
CodeBlock *mSaveCodeBlock;
|
||||
|
||||
// note: anything returned is pushed to CSTK and will be invalidated on the next exec()
|
||||
ConsoleValueRef mReturnValue;
|
||||
|
||||
U32 mCurrentInstruction;
|
||||
|
||||
static const S32 nsDocLength = 128;
|
||||
char mNSDocBlockClass[nsDocLength];
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -165,6 +165,10 @@ U32 CompilerStringTable::add(const char *str, bool caseSens, bool tag)
|
|||
newStr->len = len;
|
||||
newStr->tag = tag;
|
||||
dStrcpy(newStr->string, str);
|
||||
|
||||
// Put into the hash table.
|
||||
hashTable[str] = newStr;
|
||||
|
||||
return newStr->start;
|
||||
}
|
||||
|
||||
|
|
@ -189,6 +193,7 @@ void CompilerStringTable::reset()
|
|||
char *CompilerStringTable::build()
|
||||
{
|
||||
char *ret = new char[totalLen];
|
||||
dMemset(ret, 0, totalLen);
|
||||
for (Entry *walk = list; walk; walk = walk->next)
|
||||
dStrcpy(ret + walk->start, walk->string);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@
|
|||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class Stream;
|
||||
class DataChunker;
|
||||
|
||||
|
|
@ -91,10 +94,15 @@ namespace Compiler
|
|||
OP_DIV,
|
||||
OP_NEG,
|
||||
|
||||
OP_INC,
|
||||
OP_DEC,
|
||||
|
||||
OP_SETCURVAR,
|
||||
OP_SETCURVAR_CREATE,
|
||||
OP_SETCURVAR_ARRAY,
|
||||
OP_SETCURVAR_ARRAY_VARLOOKUP,
|
||||
OP_SETCURVAR_ARRAY_CREATE,
|
||||
OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP,
|
||||
|
||||
OP_LOADVAR_UINT,// 40
|
||||
OP_LOADVAR_FLT,
|
||||
|
|
@ -113,6 +121,8 @@ namespace Compiler
|
|||
OP_SETCURFIELD,
|
||||
OP_SETCURFIELD_ARRAY, // 50
|
||||
OP_SETCURFIELD_TYPE,
|
||||
OP_SETCURFIELD_ARRAY_VAR,
|
||||
OP_SETCURFIELD_THIS,
|
||||
|
||||
OP_LOADFIELD_UINT,
|
||||
OP_LOADFIELD_FLT,
|
||||
|
|
@ -142,6 +152,8 @@ namespace Compiler
|
|||
|
||||
OP_CALLFUNC_RESOLVE,
|
||||
OP_CALLFUNC,
|
||||
OP_CALLFUNC_POINTER,
|
||||
OP_CALLFUNC_THIS,
|
||||
|
||||
OP_ADVANCE_STR,
|
||||
OP_ADVANCE_STR_APPENDCHAR,
|
||||
|
|
@ -155,6 +167,7 @@ namespace Compiler
|
|||
OP_PUSH_UINT, // Integer
|
||||
OP_PUSH_FLT, // Float
|
||||
OP_PUSH_VAR, // Variable
|
||||
OP_PUSH_THIS, // This pointer
|
||||
OP_PUSH_FRAME, // Frame
|
||||
|
||||
OP_ASSERT,
|
||||
|
|
@ -165,7 +178,9 @@ namespace Compiler
|
|||
OP_ITER, ///< Enter foreach loop.
|
||||
OP_ITER_END, ///< End foreach loop.
|
||||
|
||||
OP_INVALID // 90
|
||||
OP_INVALID, // 90
|
||||
|
||||
MAX_OP_CODELEN ///< The amount of op codes.
|
||||
};
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
|
@ -207,6 +222,7 @@ namespace Compiler
|
|||
Entry *list;
|
||||
|
||||
char buf[256];
|
||||
std::unordered_map<std::string, Entry*> hashTable;
|
||||
|
||||
U32 add(const char *str, bool caseSens = true, bool tag = false);
|
||||
U32 addIntString(U32 value);
|
||||
|
|
|
|||
|
|
@ -361,20 +361,22 @@ namespace Con
|
|||
/// 12/29/04 - BJG - 33->34 Removed some opcodes, part of namespace upgrade.
|
||||
/// 12/30/04 - BJG - 34->35 Reordered some things, further general shuffling.
|
||||
/// 11/03/05 - BJG - 35->36 Integrated new debugger code.
|
||||
// 09/08/06 - THB - 36->37 New opcode for internal names
|
||||
// 09/15/06 - THB - 37->38 Added unit conversions
|
||||
// 11/23/06 - THB - 38->39 Added recursive internal name operator
|
||||
// 02/15/07 - THB - 39->40 Bumping to 40 for TGB since the console has been
|
||||
// majorly hacked without the version number being bumped
|
||||
// 02/16/07 - THB - 40->41 newmsg operator
|
||||
// 06/15/07 - THB - 41->42 script types
|
||||
/// 09/08/06 - THB - 36->37 New opcode for internal names
|
||||
/// 09/15/06 - THB - 37->38 Added unit conversions
|
||||
/// 11/23/06 - THB - 38->39 Added recursive internal name operator
|
||||
/// 02/15/07 - THB - 39->40 Bumping to 40 for TGB since the console has been
|
||||
/// majorly hacked without the version number being bumped
|
||||
/// 02/16/07 - THB - 40->41 newmsg operator
|
||||
/// 06/15/07 - THB - 41->42 script types
|
||||
/// 07/31/07 - THB - 42->43 Patch from Andreas Kirsch: Added opcode to support nested new declarations.
|
||||
/// 09/12/07 - CAF - 43->44 remove newmsg operator
|
||||
/// 09/27/07 - RDB - 44->45 Patch from Andreas Kirsch: Added opcode to support correct void return
|
||||
/// 01/13/09 - TMS - 45->46 Added script assert
|
||||
/// 09/07/14 - jamesu - 46->47 64bit support
|
||||
/// 10/14/14 - jamesu - 47->48 Added opcodes to reduce reliance on strings in function calls
|
||||
DSOVersion = 48,
|
||||
/// 10/07/17 - JTH - 48->49 Added opcode for function pointers and revamp of interpreter
|
||||
/// from switch to function calls.
|
||||
DSOVersion = 49,
|
||||
|
||||
MaxLineLength = 512, ///< Maximum length of a line of console input.
|
||||
MaxDataTypes = 256 ///< Maximum number of registered data types.
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "platform/platform.h"
|
||||
#include "console/console.h"
|
||||
|
||||
|
|
@ -43,6 +45,20 @@ DataChunker Namespace::mAllocator;
|
|||
Namespace *Namespace::mNamespaceList = NULL;
|
||||
Namespace *Namespace::mGlobalNamespace = NULL;
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<std::pair<StringTableEntry, StringTableEntry>>
|
||||
{
|
||||
typedef std::pair<StringTableEntry, StringTableEntry> argument_type;
|
||||
typedef size_t result_type;
|
||||
result_type operator()(argument_type const& s) const
|
||||
{
|
||||
return HashPointer(s.first) ^ (HashPointer(s.second) << 1);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
std::unordered_map<std::pair<StringTableEntry, StringTableEntry>, Namespace*> gNamespaceCache;
|
||||
|
||||
bool canTabComplete(const char *prevText, const char *bestMatch,
|
||||
const char *newText, S32 baseLen, bool fForward)
|
||||
|
|
@ -967,11 +983,10 @@ Namespace *Namespace::find(StringTableEntry name, StringTableEntry package)
|
|||
if (name == NULL && package == NULL)
|
||||
return mGlobalNamespace;
|
||||
|
||||
for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
|
||||
{
|
||||
if(walk->mName == name && walk->mPackage == package)
|
||||
return walk;
|
||||
}
|
||||
auto pair = std::make_pair(name, package);
|
||||
auto pos = gNamespaceCache.find(pair);
|
||||
if (pos != gNamespaceCache.end())
|
||||
return pos->second;
|
||||
|
||||
Namespace *ret = (Namespace *)mAllocator.alloc(sizeof(Namespace));
|
||||
constructInPlace(ret);
|
||||
|
|
@ -979,6 +994,10 @@ Namespace *Namespace::find(StringTableEntry name, StringTableEntry package)
|
|||
ret->mName = name;
|
||||
ret->mNext = mNamespaceList;
|
||||
mNamespaceList = ret;
|
||||
|
||||
// insert into namespace cache.
|
||||
gNamespaceCache[pair] = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1143,6 +1162,9 @@ void Namespace::init()
|
|||
mGlobalNamespace->mName = NULL;
|
||||
mGlobalNamespace->mNext = NULL;
|
||||
mNamespaceList = mGlobalNamespace;
|
||||
|
||||
// Insert into namespace cache.
|
||||
gNamespaceCache[std::make_pair(mGlobalNamespace->mName, mGlobalNamespace->mPackage)] = mGlobalNamespace;
|
||||
}
|
||||
|
||||
Namespace *Namespace::global()
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@
|
|||
#include "core/dataChunker.h"
|
||||
#endif
|
||||
|
||||
|
||||
/// @ingroup console_system Console System
|
||||
/// @{
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ void SimNameDictionary::remove(SimObject* obj)
|
|||
if (*walk == obj)
|
||||
{
|
||||
*walk = obj->nextNameObject;
|
||||
obj->nextNameObject = (SimObject*)-1;
|
||||
obj->nextNameObject = nullptr;
|
||||
hashEntryCount--;
|
||||
|
||||
Mutex::unlockMutex(mutex);
|
||||
|
|
@ -279,7 +279,7 @@ void SimManagerNameDictionary::remove(SimObject* obj)
|
|||
if (*walk == obj)
|
||||
{
|
||||
*walk = obj->nextManagerNameObject;
|
||||
obj->nextManagerNameObject = (SimObject*)-1;
|
||||
obj->nextManagerNameObject = nullptr;
|
||||
hashEntryCount--;
|
||||
|
||||
Mutex::unlockMutex(mutex);
|
||||
|
|
|
|||
|
|
@ -72,8 +72,8 @@ SimObject::SimObject()
|
|||
objectName = NULL;
|
||||
mOriginalName = NULL;
|
||||
mInternalName = NULL;
|
||||
nextNameObject = (SimObject*)-1;
|
||||
nextManagerNameObject = (SimObject*)-1;
|
||||
nextNameObject = nullptr;
|
||||
nextManagerNameObject = nullptr;
|
||||
nextIdObject = NULL;
|
||||
|
||||
mFilename = NULL;
|
||||
|
|
@ -86,6 +86,8 @@ SimObject::SimObject()
|
|||
mNotifyList = NULL;
|
||||
mFlags.set( ModStaticFields | ModDynamicFields );
|
||||
|
||||
mProgenitorFile = StringTable->EmptyString();
|
||||
|
||||
mFieldDictionary = NULL;
|
||||
mCanSaveFieldDictionary = true;
|
||||
|
||||
|
|
@ -122,10 +124,10 @@ SimObject::~SimObject()
|
|||
if( mCopySource )
|
||||
mCopySource->unregisterReference( &mCopySource );
|
||||
|
||||
AssertFatal(nextNameObject == (SimObject*)-1,avar(
|
||||
AssertFatal(nextNameObject == nullptr,avar(
|
||||
"SimObject::~SimObject: Not removed from dictionary: name %s, id %i",
|
||||
objectName, mId));
|
||||
AssertFatal(nextManagerNameObject == (SimObject*)-1,avar(
|
||||
AssertFatal(nextManagerNameObject == nullptr,avar(
|
||||
"SimObject::~SimObject: Not removed from manager dictionary: name %s, id %i",
|
||||
objectName,mId));
|
||||
AssertFatal(mFlags.test(Added) == 0, "SimObject::object "
|
||||
|
|
|
|||
|
|
@ -95,7 +95,9 @@ StringTableEntry tamlNamedObjectName = StringTable->insert( "Name" );
|
|||
typedef Taml::TamlFormatMode _TamlFormatMode;
|
||||
ImplementEnumType(_TamlFormatMode,
|
||||
"")
|
||||
{ Taml::XmlFormat, "xml" },
|
||||
{
|
||||
Taml::XmlFormat, "xml"
|
||||
},
|
||||
{ Taml::BinaryFormat, "binary" }//,
|
||||
//{ Taml::JSONFormat, "json" }
|
||||
EndImplementEnumType;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue