Merge pull request #2121 from JeffProgrammer/TSImprovementsDevMerge

TorqueScript Improvements - Faster Interpreter.
This commit is contained in:
Areloch 2017-11-27 01:35:17 -06:00 committed by GitHub
commit 4f78143dc8
23 changed files with 10231 additions and 8513 deletions

View file

@ -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())
{ {

View file

@ -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

View file

@ -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];
} }

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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;

File diff suppressed because it is too large Load diff

View 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

View file

@ -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;

View file

@ -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);

View file

@ -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.

View file

@ -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()

View file

@ -39,7 +39,6 @@
#include "core/dataChunker.h" #include "core/dataChunker.h"
#endif #endif
/// @ingroup console_system Console System /// @ingroup console_system Console System
/// @{ /// @{

View file

@ -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);

View file

@ -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 "

View file

@ -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;