mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-12 07:04:36 +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/debugOutputConsumer.h"
|
||||||
#include "console/consoleTypes.h"
|
#include "console/consoleTypes.h"
|
||||||
#include "console/engineAPI.h"
|
#include "console/engineAPI.h"
|
||||||
|
#include "console/codeInterpreter.h"
|
||||||
|
|
||||||
#include "gfx/bitmap/gBitmap.h"
|
#include "gfx/bitmap/gBitmap.h"
|
||||||
#include "gfx/gFont.h"
|
#include "gfx/gFont.h"
|
||||||
|
|
@ -227,6 +228,9 @@ void StandardMainLoop::init()
|
||||||
ManagedSingleton< ThreadManager >::createSingleton();
|
ManagedSingleton< ThreadManager >::createSingleton();
|
||||||
FrameAllocator::init(TORQUE_FRAME_SIZE); // See comments in torqueConfig.h
|
FrameAllocator::init(TORQUE_FRAME_SIZE); // See comments in torqueConfig.h
|
||||||
|
|
||||||
|
// Initialize the TorqueScript interpreter.
|
||||||
|
CodeInterpreter::init();
|
||||||
|
|
||||||
// Yell if we can't initialize the network.
|
// Yell if we can't initialize the network.
|
||||||
if(!Net::init())
|
if(!Net::init())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -496,9 +496,9 @@ class_name_expr
|
||||||
|
|
||||||
assign_op_struct
|
assign_op_struct
|
||||||
: opPLUSPLUS
|
: opPLUSPLUS
|
||||||
{ $$.lineNumber = $1.lineNumber; $$.token = '+'; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
{ $$.lineNumber = $1.lineNumber; $$.token = opPLUSPLUS; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
||||||
| opMINUSMINUS
|
| opMINUSMINUS
|
||||||
{ $$.lineNumber = $1.lineNumber; $$.token = '-'; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
{ $$.lineNumber = $1.lineNumber; $$.token = opMINUSMINUS; $$.expr = FloatNode::alloc( $1.lineNumber, 1 ); }
|
||||||
| opPLASN expr
|
| opPLASN expr
|
||||||
{ $$.lineNumber = $1.lineNumber; $$.token = '+'; $$.expr = $2; }
|
{ $$.lineNumber = $1.lineNumber; $$.token = '+'; $$.expr = $2; }
|
||||||
| opMIASN expr
|
| opMIASN expr
|
||||||
|
|
@ -551,6 +551,8 @@ funcall_expr
|
||||||
{ $$ = FuncCallExprNode::alloc( $1.lineNumber, $3.value, $1.value, $5, false); }
|
{ $$ = FuncCallExprNode::alloc( $1.lineNumber, $3.value, $1.value, $5, false); }
|
||||||
| expr '.' IDENT '(' expr_list_decl ')'
|
| expr '.' IDENT '(' expr_list_decl ')'
|
||||||
{ $1->append($5); $$ = FuncCallExprNode::alloc( $1->dbgLineNumber, $3.value, NULL, $1, true); }
|
{ $1->append($5); $$ = FuncCallExprNode::alloc( $1->dbgLineNumber, $3.value, NULL, $1, true); }
|
||||||
|
| expr '(' expr_list_decl ')'
|
||||||
|
{ $$ = FuncPointerCallExprNode::alloc( $1->dbgLineNumber, $1, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
assert_expr
|
assert_expr
|
||||||
|
|
|
||||||
|
|
@ -774,9 +774,9 @@ YY_MALLOC_DECL
|
||||||
|
|
||||||
YY_DECL
|
YY_DECL
|
||||||
{
|
{
|
||||||
yy_state_type yy_current_state;
|
register yy_state_type yy_current_state;
|
||||||
char *yy_cp, *yy_bp;
|
register char *yy_cp, *yy_bp;
|
||||||
int yy_act;
|
register int yy_act;
|
||||||
|
|
||||||
#line 105 "CMDscan.l"
|
#line 105 "CMDscan.l"
|
||||||
|
|
||||||
|
|
@ -823,7 +823,7 @@ YY_DECL
|
||||||
yy_match:
|
yy_match:
|
||||||
do
|
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])
|
if (yy_accept[yy_current_state])
|
||||||
{
|
{
|
||||||
yy_last_accepting_state = 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_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int)yy_c];
|
||||||
++yy_cp;
|
++yy_cp;
|
||||||
}
|
} while (yy_base[yy_current_state] != 338);
|
||||||
while ( yy_base[yy_current_state] != 338 );
|
|
||||||
|
|
||||||
yy_find_action:
|
yy_find_action:
|
||||||
yy_act = yy_accept[yy_current_state];
|
yy_act = yy_accept[yy_current_state];
|
||||||
|
|
@ -1430,9 +1429,9 @@ case YY_STATE_EOF(INITIAL):
|
||||||
|
|
||||||
static int yy_get_next_buffer()
|
static int yy_get_next_buffer()
|
||||||
{
|
{
|
||||||
char *dest = yy_current_buffer->yy_ch_buf;
|
register char *dest = yy_current_buffer->yy_ch_buf;
|
||||||
char *source = yytext_ptr;
|
register char *source = yytext_ptr;
|
||||||
int number_to_move, i;
|
register int number_to_move, i;
|
||||||
int ret_val;
|
int ret_val;
|
||||||
|
|
||||||
if (yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1])
|
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()
|
static yy_state_type yy_get_previous_state()
|
||||||
{
|
{
|
||||||
yy_state_type yy_current_state;
|
register yy_state_type yy_current_state;
|
||||||
char *yy_cp;
|
register char *yy_cp;
|
||||||
|
|
||||||
yy_current_state = yy_start;
|
yy_current_state = yy_start;
|
||||||
|
|
||||||
for (yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp)
|
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])
|
if (yy_accept[yy_current_state])
|
||||||
{
|
{
|
||||||
yy_last_accepting_state = 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;
|
yy_state_type yy_current_state;
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int yy_is_jam;
|
register int yy_is_jam;
|
||||||
char *yy_cp = yy_c_buf_p;
|
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])
|
if (yy_accept[yy_current_state])
|
||||||
{
|
{
|
||||||
yy_last_accepting_state = yy_current_state;
|
yy_last_accepting_state = yy_current_state;
|
||||||
|
|
@ -1623,14 +1622,14 @@ yy_state_type yy_current_state;
|
||||||
|
|
||||||
#ifndef YY_NO_UNPUT
|
#ifndef YY_NO_UNPUT
|
||||||
#ifdef YY_USE_PROTOS
|
#ifdef YY_USE_PROTOS
|
||||||
static void yyunput( int c, char *yy_bp )
|
static void yyunput(int c, register char *yy_bp)
|
||||||
#else
|
#else
|
||||||
static void yyunput(c, yy_bp)
|
static void yyunput(c, yy_bp)
|
||||||
int c;
|
int c;
|
||||||
char *yy_bp;
|
register char *yy_bp;
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
char *yy_cp = yy_c_buf_p;
|
register char *yy_cp = yy_c_buf_p;
|
||||||
|
|
||||||
/* undo effects of setting up yytext */
|
/* undo effects of setting up yytext */
|
||||||
*yy_cp = yy_hold_char;
|
*yy_cp = yy_hold_char;
|
||||||
|
|
@ -1638,10 +1637,10 @@ char *yy_bp;
|
||||||
if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
|
if (yy_cp < yy_current_buffer->yy_ch_buf + 2)
|
||||||
{ /* need to shift things up to make room */
|
{ /* need to shift things up to make room */
|
||||||
/* +2 for EOB chars. */
|
/* +2 for EOB chars. */
|
||||||
int number_to_move = yy_n_chars + 2;
|
register int number_to_move = yy_n_chars + 2;
|
||||||
char *dest = &yy_current_buffer->yy_ch_buf[
|
register char *dest = &yy_current_buffer->yy_ch_buf[
|
||||||
yy_current_buffer->yy_buf_size + 2];
|
yy_current_buffer->yy_buf_size + 2];
|
||||||
char *source =
|
register char *source =
|
||||||
&yy_current_buffer->yy_ch_buf[number_to_move];
|
&yy_current_buffer->yy_ch_buf[number_to_move];
|
||||||
|
|
||||||
while (source > yy_current_buffer->yy_ch_buf)
|
while (source > yy_current_buffer->yy_ch_buf)
|
||||||
|
|
@ -2095,7 +2094,7 @@ yyconst char *s2;
|
||||||
int n;
|
int n;
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int i;
|
register int i;
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i)
|
||||||
s1[i] = s2[i];
|
s1[i] = s2[i];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -446,6 +446,18 @@ struct FuncCallExprNode : ExprNode
|
||||||
DBG_STMT_TYPE(FuncCallExprNode);
|
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
|
struct AssertCallExprNode : ExprNode
|
||||||
{
|
{
|
||||||
ExprNode *testExpr;
|
ExprNode *testExpr;
|
||||||
|
|
|
||||||
|
|
@ -328,6 +328,16 @@ FuncCallExprNode *FuncCallExprNode::alloc( S32 lineNumber, StringTableEntry func
|
||||||
return ret;
|
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)
|
AssertCallExprNode *AssertCallExprNode::alloc(S32 lineNumber, ExprNode *testExpr, const char *message)
|
||||||
{
|
{
|
||||||
#ifdef TORQUE_ENABLE_SCRIPTASSERTS
|
#ifdef TORQUE_ENABLE_SCRIPTASSERTS
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ struct Token
|
||||||
};
|
};
|
||||||
#include "console/cmdgram.h"
|
#include "console/cmdgram.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Compiler
|
namespace Compiler
|
||||||
{
|
{
|
||||||
U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip)
|
U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip)
|
||||||
|
|
@ -51,6 +50,81 @@ namespace Compiler
|
||||||
ip = walk->compileStmt(codeStream, ip);
|
ip = walk->compileStmt(codeStream, ip);
|
||||||
return codeStream.tell();
|
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;
|
using namespace Compiler;
|
||||||
|
|
@ -692,7 +766,13 @@ TypeReq FloatUnaryExprNode::getPreferredType()
|
||||||
|
|
||||||
U32 VarNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
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
|
// OP_LOADIMMED_IDENT
|
||||||
// varName
|
// varName
|
||||||
// OP_ADVANCE_STR
|
// OP_ADVANCE_STR
|
||||||
|
|
@ -709,18 +789,54 @@ U32 VarNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
if (type == TypeReqNone)
|
if (type == TypeReqNone)
|
||||||
return codeStream.tell();
|
return codeStream.tell();
|
||||||
|
|
||||||
precompileIdent(varName);
|
bool shortCircuit = false;
|
||||||
|
|
||||||
codeStream.emit(arrayIndex ? OP_LOADIMMED_IDENT : OP_SETCURVAR);
|
|
||||||
codeStream.emitSTE(varName);
|
|
||||||
|
|
||||||
if (arrayIndex)
|
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);
|
codeStream.emit(OP_ADVANCE_STR);
|
||||||
ip = arrayIndex->compile(codeStream, ip, TypeReqString);
|
ip = arrayIndex->compile(codeStream, ip, TypeReqString);
|
||||||
codeStream.emit(OP_REWIND_STR);
|
codeStream.emit(OP_REWIND_STR);
|
||||||
codeStream.emit(OP_SETCURVAR_ARRAY);
|
codeStream.emit(OP_SETCURVAR_ARRAY);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
codeStream.emit(OP_SETCURVAR);
|
||||||
|
codeStream.emitSTE(varName);
|
||||||
|
}
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case TypeReqUInt:
|
case TypeReqUInt:
|
||||||
|
|
@ -934,15 +1050,29 @@ U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
subType = TypeReqString;
|
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
|
// eval expr
|
||||||
// (push and pop if it's TypeReqString) OP_ADVANCE_STR
|
// (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
|
// OP_LOADIMMED_IDENT
|
||||||
// varName
|
// varName
|
||||||
// OP_ADVANCE_STR
|
// OP_ADVANCE_STR
|
||||||
// eval array
|
// eval array
|
||||||
// OP_REWIND_STR
|
// OP_REWIND_STR
|
||||||
// OP_SETCURVAR_ARRAY_CREATE
|
// OP_SETCURVAR_ARRAY_CREATE
|
||||||
|
// endif
|
||||||
// OP_TERMINATE_REWIND_STR
|
// OP_TERMINATE_REWIND_STR
|
||||||
// OP_SAVEVAR
|
// OP_SAVEVAR
|
||||||
|
|
||||||
|
|
@ -952,15 +1082,45 @@ U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
// varname
|
// varname
|
||||||
// OP_SAVEVAR
|
// OP_SAVEVAR
|
||||||
|
|
||||||
precompileIdent(varName);
|
|
||||||
|
|
||||||
ip = expr->compile(codeStream, ip, subType);
|
ip = expr->compile(codeStream, ip, subType);
|
||||||
|
|
||||||
|
bool shortCircuit = false;
|
||||||
if (arrayIndex)
|
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)
|
if (subType == TypeReqString)
|
||||||
codeStream.emit(OP_ADVANCE_STR);
|
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.emit(OP_LOADIMMED_IDENT);
|
||||||
codeStream.emitSTE(varName);
|
codeStream.emitSTE(varName);
|
||||||
|
|
||||||
|
|
@ -968,6 +1128,8 @@ U32 AssignExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
ip = arrayIndex->compile(codeStream, ip, TypeReqString);
|
ip = arrayIndex->compile(codeStream, ip, TypeReqString);
|
||||||
codeStream.emit(OP_REWIND_STR);
|
codeStream.emit(OP_REWIND_STR);
|
||||||
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
|
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
if (subType == TypeReqString)
|
if (subType == TypeReqString)
|
||||||
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||||
}
|
}
|
||||||
|
|
@ -1010,10 +1172,12 @@ static void getAssignOpTypeOp(S32 op, TypeReq &type, U32 &operand)
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case '+':
|
case '+':
|
||||||
|
case opPLUSPLUS:
|
||||||
type = TypeReqFloat;
|
type = TypeReqFloat;
|
||||||
operand = OP_ADD;
|
operand = OP_ADD;
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
|
case opMINUSMINUS:
|
||||||
type = TypeReqFloat;
|
type = TypeReqFloat;
|
||||||
operand = OP_SUB;
|
operand = OP_SUB;
|
||||||
break;
|
break;
|
||||||
|
|
@ -1056,35 +1220,112 @@ U32 AssignOpExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
{
|
{
|
||||||
|
|
||||||
// goes like this...
|
// 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
|
// 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
|
// OP_LOADIMMED_IDENT
|
||||||
// varName
|
// varName
|
||||||
// OP_ADVANCE_STR
|
// OP_ADVANCE_STR
|
||||||
// eval arrayIndex stringwise
|
// eval arrayIndex stringwise
|
||||||
// OP_REWIND_STR
|
// OP_REWIND_STR
|
||||||
// OP_SETCURVAR_ARRAY_CREATE
|
// OP_SETCURVAR_ARRAY_CREATE
|
||||||
|
// endif
|
||||||
// else
|
// else
|
||||||
// OP_SETCURVAR_CREATE
|
// OP_SETCURVAR_CREATE
|
||||||
// varName
|
// varName
|
||||||
|
// endif
|
||||||
// OP_LOADVAR_FLT or UINT
|
// OP_LOADVAR_FLT or UINT
|
||||||
// operand
|
// operand
|
||||||
// OP_SAVEVAR_FLT or UINT
|
// OP_SAVEVAR_FLT or UINT
|
||||||
|
// ENDIF
|
||||||
|
//
|
||||||
|
// if subtype != type
|
||||||
|
// convert type
|
||||||
|
// endif
|
||||||
|
|
||||||
// conversion OP if necessary.
|
// conversion OP if necessary.
|
||||||
getAssignOpTypeOp(op, subType, operand);
|
getAssignOpTypeOp(op, subType, operand);
|
||||||
|
|
||||||
|
// ++ or -- optimization support for non indexed variables.
|
||||||
|
if ((!arrayIndex) && (op == opPLUSPLUS || op == opMINUSMINUS))
|
||||||
|
{
|
||||||
precompileIdent(varName);
|
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);
|
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.emit(OP_SETCURVAR_CREATE);
|
||||||
codeStream.emitSTE(varName);
|
codeStream.emitSTE(varName);
|
||||||
}
|
}
|
||||||
else
|
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.emit(OP_LOADIMMED_IDENT);
|
||||||
codeStream.emitSTE(varName);
|
codeStream.emitSTE(varName);
|
||||||
|
|
@ -1094,9 +1335,11 @@ U32 AssignOpExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
codeStream.emit(OP_REWIND_STR);
|
codeStream.emit(OP_REWIND_STR);
|
||||||
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
|
codeStream.emit(OP_SETCURVAR_ARRAY_CREATE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
codeStream.emit((subType == TypeReqFloat) ? OP_LOADVAR_FLT : OP_LOADVAR_UINT);
|
codeStream.emit((subType == TypeReqFloat) ? OP_LOADVAR_FLT : OP_LOADVAR_UINT);
|
||||||
codeStream.emit(operand);
|
codeStream.emit(operand);
|
||||||
codeStream.emit((subType == TypeReqFloat) ? OP_SAVEVAR_FLT : OP_SAVEVAR_UINT);
|
codeStream.emit((subType == TypeReqFloat) ? OP_SAVEVAR_FLT : OP_SAVEVAR_UINT);
|
||||||
|
}
|
||||||
if (subType != type)
|
if (subType != type)
|
||||||
codeStream.emit(conversionOp(subType, type));
|
codeStream.emit(conversionOp(subType, type));
|
||||||
return codeStream.tell();
|
return codeStream.tell();
|
||||||
|
|
@ -1155,6 +1398,91 @@ U32 FuncCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
precompileIdent(funcName);
|
precompileIdent(funcName);
|
||||||
precompileIdent(nameSpace);
|
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);
|
codeStream.emit(OP_PUSH_FRAME);
|
||||||
for (ExprNode *walk = args; walk; walk = (ExprNode *)walk->getNext())
|
for (ExprNode *walk = args; walk; walk = (ExprNode *)walk->getNext())
|
||||||
{
|
{
|
||||||
|
|
@ -1174,26 +1502,20 @@ U32 FuncCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(callType == MethodCall || callType == ParentCall)
|
|
||||||
codeStream.emit(OP_CALLFUNC);
|
|
||||||
else
|
|
||||||
codeStream.emit(OP_CALLFUNC_RESOLVE);
|
|
||||||
|
|
||||||
codeStream.emitSTE(funcName);
|
ip = funcPointer->compile(codeStream, ip, TypeReqString);
|
||||||
codeStream.emitSTE(nameSpace);
|
codeStream.emit(OP_CALLFUNC_POINTER);
|
||||||
|
|
||||||
codeStream.emit(callType);
|
|
||||||
if (type != TypeReqString)
|
if (type != TypeReqString)
|
||||||
codeStream.emit(conversionOp(TypeReqString, type));
|
codeStream.emit(conversionOp(TypeReqString, type));
|
||||||
return codeStream.tell();
|
return codeStream.tell();
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeReq FuncCallExprNode::getPreferredType()
|
TypeReq FuncPointerCallExprNode::getPreferredType()
|
||||||
{
|
{
|
||||||
return TypeReqString;
|
return TypeReqString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------
|
//------------------------------------------------------------
|
||||||
|
|
||||||
U32 AssertCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
U32 AssertCallExprNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
|
|
@ -1225,6 +1547,13 @@ U32 SlotAccessNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
|
|
||||||
precompileIdent(slotName);
|
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)
|
if (arrayExpr)
|
||||||
{
|
{
|
||||||
// eval array
|
// eval array
|
||||||
|
|
@ -1249,6 +1578,7 @@ U32 SlotAccessNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||||
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
|
@ -1331,6 +1661,13 @@ U32 SlotAssignNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
precompileIdent(slotName);
|
precompileIdent(slotName);
|
||||||
|
|
||||||
ip = valueExpr->compile(codeStream, ip, TypeReqString);
|
ip = valueExpr->compile(codeStream, ip, TypeReqString);
|
||||||
|
|
||||||
|
if (isThisVar(objectExpr))
|
||||||
|
{
|
||||||
|
optimizeThisPointer(codeStream, arrayExpr, ip, slotName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
codeStream.emit(OP_ADVANCE_STR);
|
codeStream.emit(OP_ADVANCE_STR);
|
||||||
if (arrayExpr)
|
if (arrayExpr)
|
||||||
{
|
{
|
||||||
|
|
@ -1354,6 +1691,8 @@ U32 SlotAssignNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
}
|
}
|
||||||
|
|
||||||
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
codeStream.emit(OP_TERMINATE_REWIND_STR);
|
||||||
|
}
|
||||||
|
|
||||||
codeStream.emit(OP_SAVEFIELD_STR);
|
codeStream.emit(OP_SAVEFIELD_STR);
|
||||||
|
|
||||||
if (typeID != -1)
|
if (typeID != -1)
|
||||||
|
|
@ -1403,6 +1742,13 @@ U32 SlotAssignOpNode::compile(CodeStream &codeStream, U32 ip, TypeReq type)
|
||||||
precompileIdent(slotName);
|
precompileIdent(slotName);
|
||||||
|
|
||||||
ip = valueExpr->compile(codeStream, ip, subType);
|
ip = valueExpr->compile(codeStream, ip, subType);
|
||||||
|
|
||||||
|
if (isThisVar(objectExpr))
|
||||||
|
{
|
||||||
|
optimizeThisPointer(codeStream, arrayExpr, ip, slotName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (arrayExpr)
|
if (arrayExpr)
|
||||||
{
|
{
|
||||||
ip = arrayExpr->compile(codeStream, ip, TypeReqString);
|
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_TERMINATE_REWIND_STR);
|
||||||
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
codeStream.emit(OP_SETCURFIELD_ARRAY);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
codeStream.emit((subType == TypeReqFloat) ? OP_LOADFIELD_FLT : OP_LOADFIELD_UINT);
|
codeStream.emit((subType == TypeReqFloat) ? OP_LOADFIELD_FLT : OP_LOADFIELD_UINT);
|
||||||
codeStream.emit(operand);
|
codeStream.emit(operand);
|
||||||
codeStream.emit((subType == TypeReqFloat) ? OP_SAVEFIELD_FLT : OP_SAVEFIELD_UINT);
|
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;
|
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:
|
case OP_SETCURVAR:
|
||||||
{
|
{
|
||||||
StringTableEntry var = CodeToSTE(code, ip);
|
StringTableEntry var = CodeToSTE(code, ip);
|
||||||
|
|
@ -1031,12 +1045,32 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
||||||
break;
|
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:
|
case OP_SETCURVAR_ARRAY_CREATE:
|
||||||
{
|
{
|
||||||
Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE", ip - 1);
|
Con::printf("%i: OP_SETCURVAR_ARRAY_CREATE", ip - 1);
|
||||||
break;
|
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:
|
case OP_LOADVAR_UINT:
|
||||||
{
|
{
|
||||||
Con::printf("%i: OP_LOADVAR_UINT", ip - 1);
|
Con::printf("%i: OP_LOADVAR_UINT", ip - 1);
|
||||||
|
|
@ -1118,6 +1152,22 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
||||||
break;
|
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:
|
case OP_SETCURFIELD_TYPE:
|
||||||
{
|
{
|
||||||
U32 type = code[ip];
|
U32 type = code[ip];
|
||||||
|
|
@ -1298,6 +1348,21 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
||||||
break;
|
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:
|
case OP_ADVANCE_STR:
|
||||||
{
|
{
|
||||||
Con::printf("%i: OP_ADVANCE_STR", ip - 1);
|
Con::printf("%i: OP_ADVANCE_STR", ip - 1);
|
||||||
|
|
@ -1366,6 +1431,13 @@ void CodeBlock::dumpInstructions( U32 startIp, bool upToReturn )
|
||||||
break;
|
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:
|
case OP_PUSH_FRAME:
|
||||||
{
|
{
|
||||||
Con::printf("%i: OP_PUSH_FRAME", ip - 1);
|
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.
|
/// This class represents a block of code, usually mapped directly to a file.
|
||||||
class CodeBlock
|
class CodeBlock
|
||||||
{
|
{
|
||||||
|
friend class CodeInterpreter;
|
||||||
private:
|
private:
|
||||||
static CodeBlock* smCodeBlockList;
|
static CodeBlock* smCodeBlockList;
|
||||||
static CodeBlock* smCurrentCodeBlock;
|
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->len = len;
|
||||||
newStr->tag = tag;
|
newStr->tag = tag;
|
||||||
dStrcpy(newStr->string, str);
|
dStrcpy(newStr->string, str);
|
||||||
|
|
||||||
|
// Put into the hash table.
|
||||||
|
hashTable[str] = newStr;
|
||||||
|
|
||||||
return newStr->start;
|
return newStr->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,6 +193,7 @@ void CompilerStringTable::reset()
|
||||||
char *CompilerStringTable::build()
|
char *CompilerStringTable::build()
|
||||||
{
|
{
|
||||||
char *ret = new char[totalLen];
|
char *ret = new char[totalLen];
|
||||||
|
dMemset(ret, 0, totalLen);
|
||||||
for (Entry *walk = list; walk; walk = walk->next)
|
for (Entry *walk = list; walk; walk = walk->next)
|
||||||
dStrcpy(ret + walk->start, walk->string);
|
dStrcpy(ret + walk->start, walk->string);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,9 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
class Stream;
|
class Stream;
|
||||||
class DataChunker;
|
class DataChunker;
|
||||||
|
|
||||||
|
|
@ -91,10 +94,15 @@ namespace Compiler
|
||||||
OP_DIV,
|
OP_DIV,
|
||||||
OP_NEG,
|
OP_NEG,
|
||||||
|
|
||||||
|
OP_INC,
|
||||||
|
OP_DEC,
|
||||||
|
|
||||||
OP_SETCURVAR,
|
OP_SETCURVAR,
|
||||||
OP_SETCURVAR_CREATE,
|
OP_SETCURVAR_CREATE,
|
||||||
OP_SETCURVAR_ARRAY,
|
OP_SETCURVAR_ARRAY,
|
||||||
|
OP_SETCURVAR_ARRAY_VARLOOKUP,
|
||||||
OP_SETCURVAR_ARRAY_CREATE,
|
OP_SETCURVAR_ARRAY_CREATE,
|
||||||
|
OP_SETCURVAR_ARRAY_CREATE_VARLOOKUP,
|
||||||
|
|
||||||
OP_LOADVAR_UINT,// 40
|
OP_LOADVAR_UINT,// 40
|
||||||
OP_LOADVAR_FLT,
|
OP_LOADVAR_FLT,
|
||||||
|
|
@ -113,6 +121,8 @@ namespace Compiler
|
||||||
OP_SETCURFIELD,
|
OP_SETCURFIELD,
|
||||||
OP_SETCURFIELD_ARRAY, // 50
|
OP_SETCURFIELD_ARRAY, // 50
|
||||||
OP_SETCURFIELD_TYPE,
|
OP_SETCURFIELD_TYPE,
|
||||||
|
OP_SETCURFIELD_ARRAY_VAR,
|
||||||
|
OP_SETCURFIELD_THIS,
|
||||||
|
|
||||||
OP_LOADFIELD_UINT,
|
OP_LOADFIELD_UINT,
|
||||||
OP_LOADFIELD_FLT,
|
OP_LOADFIELD_FLT,
|
||||||
|
|
@ -142,6 +152,8 @@ namespace Compiler
|
||||||
|
|
||||||
OP_CALLFUNC_RESOLVE,
|
OP_CALLFUNC_RESOLVE,
|
||||||
OP_CALLFUNC,
|
OP_CALLFUNC,
|
||||||
|
OP_CALLFUNC_POINTER,
|
||||||
|
OP_CALLFUNC_THIS,
|
||||||
|
|
||||||
OP_ADVANCE_STR,
|
OP_ADVANCE_STR,
|
||||||
OP_ADVANCE_STR_APPENDCHAR,
|
OP_ADVANCE_STR_APPENDCHAR,
|
||||||
|
|
@ -155,6 +167,7 @@ namespace Compiler
|
||||||
OP_PUSH_UINT, // Integer
|
OP_PUSH_UINT, // Integer
|
||||||
OP_PUSH_FLT, // Float
|
OP_PUSH_FLT, // Float
|
||||||
OP_PUSH_VAR, // Variable
|
OP_PUSH_VAR, // Variable
|
||||||
|
OP_PUSH_THIS, // This pointer
|
||||||
OP_PUSH_FRAME, // Frame
|
OP_PUSH_FRAME, // Frame
|
||||||
|
|
||||||
OP_ASSERT,
|
OP_ASSERT,
|
||||||
|
|
@ -165,7 +178,9 @@ namespace Compiler
|
||||||
OP_ITER, ///< Enter foreach loop.
|
OP_ITER, ///< Enter foreach loop.
|
||||||
OP_ITER_END, ///< End 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;
|
Entry *list;
|
||||||
|
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
std::unordered_map<std::string, Entry*> hashTable;
|
||||||
|
|
||||||
U32 add(const char *str, bool caseSens = true, bool tag = false);
|
U32 add(const char *str, bool caseSens = true, bool tag = false);
|
||||||
U32 addIntString(U32 value);
|
U32 addIntString(U32 value);
|
||||||
|
|
|
||||||
|
|
@ -361,20 +361,22 @@ namespace Con
|
||||||
/// 12/29/04 - BJG - 33->34 Removed some opcodes, part of namespace upgrade.
|
/// 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.
|
/// 12/30/04 - BJG - 34->35 Reordered some things, further general shuffling.
|
||||||
/// 11/03/05 - BJG - 35->36 Integrated new debugger code.
|
/// 11/03/05 - BJG - 35->36 Integrated new debugger code.
|
||||||
// 09/08/06 - THB - 36->37 New opcode for internal names
|
/// 09/08/06 - THB - 36->37 New opcode for internal names
|
||||||
// 09/15/06 - THB - 37->38 Added unit conversions
|
/// 09/15/06 - THB - 37->38 Added unit conversions
|
||||||
// 11/23/06 - THB - 38->39 Added recursive internal name operator
|
/// 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
|
/// 02/15/07 - THB - 39->40 Bumping to 40 for TGB since the console has been
|
||||||
// majorly hacked without the version number being bumped
|
/// majorly hacked without the version number being bumped
|
||||||
// 02/16/07 - THB - 40->41 newmsg operator
|
/// 02/16/07 - THB - 40->41 newmsg operator
|
||||||
// 06/15/07 - THB - 41->42 script types
|
/// 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.
|
/// 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/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
|
/// 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
|
/// 01/13/09 - TMS - 45->46 Added script assert
|
||||||
/// 09/07/14 - jamesu - 46->47 64bit support
|
/// 09/07/14 - jamesu - 46->47 64bit support
|
||||||
/// 10/14/14 - jamesu - 47->48 Added opcodes to reduce reliance on strings in function calls
|
/// 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.
|
MaxLineLength = 512, ///< Maximum length of a line of console input.
|
||||||
MaxDataTypes = 256 ///< Maximum number of registered data types.
|
MaxDataTypes = 256 ///< Maximum number of registered data types.
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@
|
||||||
// IN THE SOFTWARE.
|
// IN THE SOFTWARE.
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
#include "console/console.h"
|
#include "console/console.h"
|
||||||
|
|
||||||
|
|
@ -43,6 +45,20 @@ DataChunker Namespace::mAllocator;
|
||||||
Namespace *Namespace::mNamespaceList = NULL;
|
Namespace *Namespace::mNamespaceList = NULL;
|
||||||
Namespace *Namespace::mGlobalNamespace = 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,
|
bool canTabComplete(const char *prevText, const char *bestMatch,
|
||||||
const char *newText, S32 baseLen, bool fForward)
|
const char *newText, S32 baseLen, bool fForward)
|
||||||
|
|
@ -967,11 +983,10 @@ Namespace *Namespace::find(StringTableEntry name, StringTableEntry package)
|
||||||
if (name == NULL && package == NULL)
|
if (name == NULL && package == NULL)
|
||||||
return mGlobalNamespace;
|
return mGlobalNamespace;
|
||||||
|
|
||||||
for(Namespace *walk = mNamespaceList; walk; walk = walk->mNext)
|
auto pair = std::make_pair(name, package);
|
||||||
{
|
auto pos = gNamespaceCache.find(pair);
|
||||||
if(walk->mName == name && walk->mPackage == package)
|
if (pos != gNamespaceCache.end())
|
||||||
return walk;
|
return pos->second;
|
||||||
}
|
|
||||||
|
|
||||||
Namespace *ret = (Namespace *)mAllocator.alloc(sizeof(Namespace));
|
Namespace *ret = (Namespace *)mAllocator.alloc(sizeof(Namespace));
|
||||||
constructInPlace(ret);
|
constructInPlace(ret);
|
||||||
|
|
@ -979,6 +994,10 @@ Namespace *Namespace::find(StringTableEntry name, StringTableEntry package)
|
||||||
ret->mName = name;
|
ret->mName = name;
|
||||||
ret->mNext = mNamespaceList;
|
ret->mNext = mNamespaceList;
|
||||||
mNamespaceList = ret;
|
mNamespaceList = ret;
|
||||||
|
|
||||||
|
// insert into namespace cache.
|
||||||
|
gNamespaceCache[pair] = ret;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1143,6 +1162,9 @@ void Namespace::init()
|
||||||
mGlobalNamespace->mName = NULL;
|
mGlobalNamespace->mName = NULL;
|
||||||
mGlobalNamespace->mNext = NULL;
|
mGlobalNamespace->mNext = NULL;
|
||||||
mNamespaceList = mGlobalNamespace;
|
mNamespaceList = mGlobalNamespace;
|
||||||
|
|
||||||
|
// Insert into namespace cache.
|
||||||
|
gNamespaceCache[std::make_pair(mGlobalNamespace->mName, mGlobalNamespace->mPackage)] = mGlobalNamespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
Namespace *Namespace::global()
|
Namespace *Namespace::global()
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@
|
||||||
#include "core/dataChunker.h"
|
#include "core/dataChunker.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/// @ingroup console_system Console System
|
/// @ingroup console_system Console System
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ void SimNameDictionary::remove(SimObject* obj)
|
||||||
if (*walk == obj)
|
if (*walk == obj)
|
||||||
{
|
{
|
||||||
*walk = obj->nextNameObject;
|
*walk = obj->nextNameObject;
|
||||||
obj->nextNameObject = (SimObject*)-1;
|
obj->nextNameObject = nullptr;
|
||||||
hashEntryCount--;
|
hashEntryCount--;
|
||||||
|
|
||||||
Mutex::unlockMutex(mutex);
|
Mutex::unlockMutex(mutex);
|
||||||
|
|
@ -279,7 +279,7 @@ void SimManagerNameDictionary::remove(SimObject* obj)
|
||||||
if (*walk == obj)
|
if (*walk == obj)
|
||||||
{
|
{
|
||||||
*walk = obj->nextManagerNameObject;
|
*walk = obj->nextManagerNameObject;
|
||||||
obj->nextManagerNameObject = (SimObject*)-1;
|
obj->nextManagerNameObject = nullptr;
|
||||||
hashEntryCount--;
|
hashEntryCount--;
|
||||||
|
|
||||||
Mutex::unlockMutex(mutex);
|
Mutex::unlockMutex(mutex);
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,8 @@ SimObject::SimObject()
|
||||||
objectName = NULL;
|
objectName = NULL;
|
||||||
mOriginalName = NULL;
|
mOriginalName = NULL;
|
||||||
mInternalName = NULL;
|
mInternalName = NULL;
|
||||||
nextNameObject = (SimObject*)-1;
|
nextNameObject = nullptr;
|
||||||
nextManagerNameObject = (SimObject*)-1;
|
nextManagerNameObject = nullptr;
|
||||||
nextIdObject = NULL;
|
nextIdObject = NULL;
|
||||||
|
|
||||||
mFilename = NULL;
|
mFilename = NULL;
|
||||||
|
|
@ -86,6 +86,8 @@ SimObject::SimObject()
|
||||||
mNotifyList = NULL;
|
mNotifyList = NULL;
|
||||||
mFlags.set( ModStaticFields | ModDynamicFields );
|
mFlags.set( ModStaticFields | ModDynamicFields );
|
||||||
|
|
||||||
|
mProgenitorFile = StringTable->EmptyString();
|
||||||
|
|
||||||
mFieldDictionary = NULL;
|
mFieldDictionary = NULL;
|
||||||
mCanSaveFieldDictionary = true;
|
mCanSaveFieldDictionary = true;
|
||||||
|
|
||||||
|
|
@ -122,10 +124,10 @@ SimObject::~SimObject()
|
||||||
if( mCopySource )
|
if( mCopySource )
|
||||||
mCopySource->unregisterReference( &mCopySource );
|
mCopySource->unregisterReference( &mCopySource );
|
||||||
|
|
||||||
AssertFatal(nextNameObject == (SimObject*)-1,avar(
|
AssertFatal(nextNameObject == nullptr,avar(
|
||||||
"SimObject::~SimObject: Not removed from dictionary: name %s, id %i",
|
"SimObject::~SimObject: Not removed from dictionary: name %s, id %i",
|
||||||
objectName, mId));
|
objectName, mId));
|
||||||
AssertFatal(nextManagerNameObject == (SimObject*)-1,avar(
|
AssertFatal(nextManagerNameObject == nullptr,avar(
|
||||||
"SimObject::~SimObject: Not removed from manager dictionary: name %s, id %i",
|
"SimObject::~SimObject: Not removed from manager dictionary: name %s, id %i",
|
||||||
objectName,mId));
|
objectName,mId));
|
||||||
AssertFatal(mFlags.test(Added) == 0, "SimObject::object "
|
AssertFatal(mFlags.test(Added) == 0, "SimObject::object "
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,9 @@ StringTableEntry tamlNamedObjectName = StringTable->insert( "Name" );
|
||||||
typedef Taml::TamlFormatMode _TamlFormatMode;
|
typedef Taml::TamlFormatMode _TamlFormatMode;
|
||||||
ImplementEnumType(_TamlFormatMode,
|
ImplementEnumType(_TamlFormatMode,
|
||||||
"")
|
"")
|
||||||
{ Taml::XmlFormat, "xml" },
|
{
|
||||||
|
Taml::XmlFormat, "xml"
|
||||||
|
},
|
||||||
{ Taml::BinaryFormat, "binary" }//,
|
{ Taml::BinaryFormat, "binary" }//,
|
||||||
//{ Taml::JSONFormat, "json" }
|
//{ Taml::JSONFormat, "json" }
|
||||||
EndImplementEnumType;
|
EndImplementEnumType;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue