forked from Mirrors/openclonk
Script: Split SPos out of the bytecode into an extra vector for speed
SPos is only needed to display debug messages. Not having that data in the cache for normal execution speeds up script execution by ten percent on at least one artificial benchmark.
parent
7f899cc1b0
commit
d02c424dab
|
@ -169,8 +169,8 @@ void C4AulScript::Default()
|
|||
// not compiled
|
||||
State = ASS_NONE;
|
||||
Script = NULL;
|
||||
Code = CPos = NULL;
|
||||
CodeSize = CodeBufSize = 0;
|
||||
Code.clear();
|
||||
CPos = NULL;
|
||||
IncludesResolved = false;
|
||||
|
||||
// defaults
|
||||
|
|
|
@ -235,8 +235,7 @@ struct C4AulBCC
|
|||
C4ValueArray * a;
|
||||
C4AulFunc * f;
|
||||
intptr_t X;
|
||||
} Par; // extra info (long for use with amd64)
|
||||
const char *SPos;
|
||||
} Par; // extra info
|
||||
};
|
||||
|
||||
// call context
|
||||
|
@ -445,16 +444,54 @@ public:
|
|||
void Unreg(); // remove from list
|
||||
virtual bool Delete() { return true; } // allow deletion on pure class
|
||||
|
||||
StdCopyStrBuf ScriptName; // script name
|
||||
C4Def *Def; // owning def file
|
||||
C4ValueMapNames LocalNamed;
|
||||
enum Strict { NONSTRICT = 0, STRICT1 = 1, STRICT2 = 2, MAXSTRICT=STRICT2 };
|
||||
enum Strict Strict; // new or even newer syntax?
|
||||
bool Temporary; // set for DirectExec-scripts; do not parse those
|
||||
|
||||
const char *GetScript() const { return Script.getData(); }
|
||||
|
||||
C4AulFunc *GetFuncRecursive(const char *pIdtf); // search function by identifier, including global funcs
|
||||
C4AulScriptFunc *GetSFunc(const char *pIdtf, C4AulAccess AccNeeded, bool fFailSafe = false); // get local sfunc, check access, check '~'-safety
|
||||
C4AulScriptFunc *GetSFunc(const char *pIdtf); // get local script function by name
|
||||
C4AulScriptFunc *GetSFunc(int iIndex, const char *szPattern = NULL); // get local script function by index
|
||||
C4AulScriptFunc *GetSFuncWarn(const char *pIdtf, C4AulAccess AccNeeded, const char *WarnStr); // get function; return NULL and warn if not existant
|
||||
|
||||
void AddFunc(const char *pIdtf, C4ScriptFnDef* Def); // add def def func to table
|
||||
|
||||
C4Value DirectExec(C4Object *pObj, const char *szScript, const char *szContext, bool fPassErrors = false, enum Strict Strict = MAXSTRICT, C4AulScriptContext* context = NULL); // directly parse uncompiled script (WARG! CYCLES!)
|
||||
void ResetProfilerTimes(); // zero all profiler times of owned functions
|
||||
void CollectProfilerTimes(class C4AulProfiler &rProfiler);
|
||||
|
||||
bool IsReady() { return State == ASS_PARSED; } // whether script calls may be done
|
||||
|
||||
// helper functions
|
||||
void Warn(const char *pMsg, const char *pIdtf);
|
||||
int GetLineOfCode(C4AulBCC * CPos);
|
||||
|
||||
friend class C4AulParseError;
|
||||
friend class C4AulFunc;
|
||||
friend class C4AulScriptFunc;
|
||||
friend class C4AulScriptEngine;
|
||||
friend class C4AulParseState;
|
||||
|
||||
// Translate a string using the script's lang table
|
||||
std::string Translate(const std::string &text) const;
|
||||
|
||||
protected:
|
||||
C4LangStringTable *stringTable;
|
||||
|
||||
C4AulFunc *Func0, *FuncL; // owned functions
|
||||
C4AulScriptEngine *Engine; //owning engine
|
||||
C4AulScript *Owner, *Prev, *Next, *Child0, *ChildL; // tree structure
|
||||
|
||||
StdStrBuf Script; // script
|
||||
C4AulBCC *Code, *CPos; // compiled script (/pos)
|
||||
std::vector<C4AulBCC> Code;
|
||||
std::vector<const char *> PosForCode;
|
||||
C4AulBCC *CPos; // compiled script (/pos)
|
||||
C4AulScriptState State; // script state
|
||||
int CodeSize; // current number of byte code chunks in Code
|
||||
int CodeBufSize; // size of Code buffer
|
||||
bool Preparsing; // set while preparse
|
||||
bool Resolving; // set while include-resolving, to catch circular includes
|
||||
|
||||
|
@ -484,48 +521,8 @@ protected:
|
|||
|
||||
C4AulScript *FindFirstNonStrictScript(); // find first script that is not #strict
|
||||
|
||||
int GetCodePos() const { return CPos - Code; }
|
||||
C4AulBCC *GetCodeByPos(int iPos) { return Code + iPos; }
|
||||
|
||||
public:
|
||||
StdCopyStrBuf ScriptName; // script name
|
||||
C4Def *Def; // owning def file
|
||||
C4ValueMapNames LocalNamed;
|
||||
enum Strict { NONSTRICT = 0, STRICT1 = 1, STRICT2 = 2, MAXSTRICT=STRICT2 };
|
||||
enum Strict Strict; // new or even newer syntax?
|
||||
bool Temporary; // set for DirectExec-scripts; do not parse those
|
||||
|
||||
const char *GetScript() const { return Script.getData(); }
|
||||
|
||||
C4AulFunc *GetFuncRecursive(const char *pIdtf); // search function by identifier, including global funcs
|
||||
C4AulScriptFunc *GetSFunc(const char *pIdtf, C4AulAccess AccNeeded, bool fFailSafe = false); // get local sfunc, check access, check '~'-safety
|
||||
C4AulScriptFunc *GetSFunc(const char *pIdtf); // get local script function by name
|
||||
C4AulScriptFunc *GetSFunc(int iIndex, const char *szPattern = NULL); // get local script function by index
|
||||
C4AulScriptFunc *GetSFuncWarn(const char *pIdtf, C4AulAccess AccNeeded, const char *WarnStr); // get function; return NULL and warn if not existant
|
||||
|
||||
void AddFunc(const char *pIdtf, C4ScriptFnDef* Def); // add def def func to table
|
||||
|
||||
public:
|
||||
C4Value DirectExec(C4Object *pObj, const char *szScript, const char *szContext, bool fPassErrors = false, enum Strict Strict = MAXSTRICT, C4AulScriptContext* context = NULL); // directly parse uncompiled script (WARG! CYCLES!)
|
||||
void ResetProfilerTimes(); // zero all profiler times of owned functions
|
||||
void CollectProfilerTimes(class C4AulProfiler &rProfiler);
|
||||
|
||||
bool IsReady() { return State == ASS_PARSED; } // whether script calls may be done
|
||||
|
||||
// helper functions
|
||||
void Warn(const char *pMsg, const char *pIdtf);
|
||||
|
||||
friend class C4AulParseError;
|
||||
friend class C4AulFunc;
|
||||
friend class C4AulScriptFunc;
|
||||
friend class C4AulScriptEngine;
|
||||
friend class C4AulParseState;
|
||||
|
||||
// Translate a string using the script's lang table
|
||||
std::string Translate(const std::string &text) const;
|
||||
|
||||
protected:
|
||||
C4LangStringTable *stringTable;
|
||||
int GetCodePos() const { return CPos - &Code[0]; }
|
||||
C4AulBCC *GetCodeByPos(int iPos) { return &Code[iPos]; }
|
||||
};
|
||||
|
||||
// holds all C4AulScripts
|
||||
|
|
|
@ -223,13 +223,14 @@ void C4AulDebug::ProcessLine(const StdStrBuf &Line)
|
|||
{
|
||||
C4AulBCC* foundDebugChunk = NULL;
|
||||
const char* scriptText = script->GetScript();
|
||||
for (C4AulBCC* chunk = script->Code; chunk; chunk++)
|
||||
for (C4AulBCC* chunk = &script->Code[0]; chunk; chunk++)
|
||||
{
|
||||
switch (chunk->bccType)
|
||||
{
|
||||
case AB_DEBUG:
|
||||
int lineOfThisOne;
|
||||
if ((lineOfThisOne = SGetLine(scriptText, chunk->SPos)) == line)
|
||||
{
|
||||
int lineOfThisOne = script->GetLineOfCode(chunk);
|
||||
if (lineOfThisOne == line)
|
||||
{
|
||||
foundDebugChunk = chunk;
|
||||
goto Done;
|
||||
|
@ -237,7 +238,7 @@ void C4AulDebug::ProcessLine(const StdStrBuf &Line)
|
|||
/*else {
|
||||
DebugLogF("Debug chunk at %d", lineOfThisOne);
|
||||
}*/
|
||||
|
||||
}
|
||||
break;
|
||||
case AB_EOF:
|
||||
goto Done;
|
||||
|
@ -472,8 +473,7 @@ void C4AulDebug::ObtainStackTrace(C4AulScriptContext* pCtx, C4AulBCC* pCPos)
|
|||
StdStrBuf C4AulDebug::FormatCodePos(C4AulScriptContext *pCtx, C4AulBCC *pCPos)
|
||||
{
|
||||
// Get position in script
|
||||
const char *szScript = pCtx->Func->pOrgScript->GetScript();
|
||||
int iLine = SGetLine(szScript, pCPos->SPos);
|
||||
int iLine = pCtx->Func->pOrgScript->GetLineOfCode(pCPos);
|
||||
// Format
|
||||
return FormatString("%s:%d", RelativePath(pCtx->Func->pOrgScript->ScriptName), iLine);
|
||||
}
|
||||
|
|
|
@ -95,10 +95,10 @@ StdStrBuf C4AulScriptContext::ReturnDump(StdStrBuf Dump)
|
|||
else if (Func->Owner->Def != NULL)
|
||||
Dump.AppendFormat(" (def %s)", Func->Owner->Def->GetName());
|
||||
// Script
|
||||
if (!fDirectExec && Func->Owner)
|
||||
if (!fDirectExec && Func->pOrgScript)
|
||||
Dump.AppendFormat(" (%s:%d)",
|
||||
Func->pOrgScript->ScriptName.getData(),
|
||||
SGetLine(Func->pOrgScript->GetScript(), CPos ? CPos->SPos : Func->Script));
|
||||
CPos ? Func->pOrgScript->GetLineOfCode(CPos) : SGetLine(Func->pOrgScript->GetScript(), Func->Script));
|
||||
// Return it
|
||||
return Dump;
|
||||
}
|
||||
|
@ -1178,7 +1178,7 @@ C4Value C4AulScript::DirectExec(C4Object *pObj, const char *szScript, const char
|
|||
delete pScript;
|
||||
return C4VNull;
|
||||
}
|
||||
pFunc->Code = pScript->Code;
|
||||
pFunc->Code = &pScript->Code[0];
|
||||
pScript->State = ASS_PARSED;
|
||||
// Execute. The TemporaryScript-parameter makes sure the script will be deleted later on.
|
||||
C4Value vRetVal(AulExec.Exec(pFunc, pObj, NULL, fPassErrors, true));
|
||||
|
|
|
@ -888,13 +888,13 @@ static const char * GetTTName(C4AulBCCType e)
|
|||
case AB_CALLFS: return "CALLFS"; // failsafe direct call
|
||||
case AB_STACK: return "STACK"; // push nulls / pop
|
||||
case AB_INT: return "INT"; // constant: int
|
||||
case AB_BOOL: return "bool"; // constant: bool
|
||||
case AB_BOOL: return "BOOL"; // constant: bool
|
||||
case AB_STRING: return "STRING"; // constant: string
|
||||
case AB_CPROPLIST: return "CPROPLIST"; // constant: proplist
|
||||
case AB_CARRAY: return "CARRAY"; // constant: array
|
||||
case AB_NIL: return "NIL"; // constant: nil
|
||||
case AB_DUP: return "DUP"; // constant: nil
|
||||
case AB_ARRAY: return "ARRAY"; // semi-constant: array
|
||||
case AB_DUP: return "DUP"; // constant: nil
|
||||
case AB_PROPLIST: return "PROPLIST"; // semi-constant: array
|
||||
case AB_IPROPLIST: return "IPROPLIST";
|
||||
case AB_IVARN: return "IVARN"; // initialization of named var
|
||||
|
@ -906,6 +906,7 @@ static const char * GetTTName(C4AulBCCType e)
|
|||
case AB_FOREACH_NEXT: return "FOREACH_NEXT"; // foreach: next element
|
||||
case AB_RETURN: return "RETURN"; // return statement
|
||||
case AB_ERR: return "ERR"; // parse error at this position
|
||||
case AB_DEBUG: return "DEBUG"; // debug break
|
||||
case AB_EOFN: return "EOFN"; // end of function
|
||||
case AB_EOF: return "EOF";
|
||||
|
||||
|
@ -915,59 +916,50 @@ static const char * GetTTName(C4AulBCCType e)
|
|||
|
||||
void C4AulScript::AddBCC(C4AulBCCType eType, intptr_t X, const char * SPos)
|
||||
{
|
||||
// range check
|
||||
if (CodeSize >= CodeBufSize)
|
||||
{
|
||||
// create new buffer
|
||||
CodeBufSize = CodeBufSize ? 2 * CodeBufSize : C4AUL_CodeBufSize;
|
||||
C4AulBCC *nCode = new C4AulBCC [CodeBufSize];
|
||||
// copy data
|
||||
memcpy(nCode, Code, sizeof(*Code) * CodeSize );
|
||||
// replace buffer
|
||||
delete[] Code;
|
||||
Code = nCode;
|
||||
// adjust pointer
|
||||
CPos = Code + CodeSize;
|
||||
}
|
||||
// store chunk
|
||||
CPos->bccType = eType;
|
||||
CPos->Par.X = X;
|
||||
CPos->SPos = SPos;
|
||||
C4AulBCC bcc;
|
||||
bcc.bccType = eType;
|
||||
bcc.Par.X = X;
|
||||
Code.push_back(bcc);
|
||||
PosForCode.push_back(SPos);
|
||||
|
||||
CPos = &Code.back();
|
||||
switch (eType)
|
||||
{
|
||||
case AB_STRING: case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_PROP:
|
||||
/* case AB_LOCALN_SET/AB_PROP_SET: -- expected to already have a reference upon creation, see MakeSetter */
|
||||
CPos->Par.s->IncRef();
|
||||
break;
|
||||
default:
|
||||
// TODO
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
CPos++; CodeSize++;
|
||||
CPos++;
|
||||
}
|
||||
|
||||
void C4AulScript::RemoveLastBCC()
|
||||
{
|
||||
C4AulBCC *pBCC = Code + CodeSize - 1;
|
||||
C4AulBCC *pBCC = &Code.back();
|
||||
switch (pBCC->bccType)
|
||||
{
|
||||
case AB_STRING: case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_LOCALN_SET: case AB_PROP: case AB_PROP_SET:
|
||||
pBCC->Par.s->DecRef();
|
||||
break;
|
||||
default: break; // I don't want to do anything, thank you very much. Stupid warnings.
|
||||
default: break;
|
||||
}
|
||||
CodeSize--;
|
||||
Code.pop_back();
|
||||
PosForCode.pop_back();
|
||||
CPos--;
|
||||
}
|
||||
|
||||
void C4AulScript::ClearCode()
|
||||
{
|
||||
while(CodeSize > 0)
|
||||
while(Code.size() > 0)
|
||||
RemoveLastBCC();
|
||||
delete[] Code;
|
||||
Code = 0;
|
||||
CodeSize = CodeBufSize = 0;
|
||||
CPos = Code;
|
||||
CPos = 0;
|
||||
}
|
||||
|
||||
int C4AulScript::GetLineOfCode(C4AulBCC * bcc)
|
||||
{
|
||||
return SGetLine(GetScript(), PosForCode[bcc - &Code[0]]);
|
||||
}
|
||||
|
||||
bool C4AulScript::Preparse()
|
||||
|
@ -981,7 +973,7 @@ bool C4AulScript::Preparse()
|
|||
however, this is just a few bytes per updated definition in developer mode, which
|
||||
seems acceptable for me. The mem will be released when destroying the list */
|
||||
Includes = NULL; Appends=NULL;
|
||||
CPos = Code;
|
||||
CPos = &Code[0];
|
||||
while (Func0)
|
||||
{
|
||||
// belongs to this script?
|
||||
|
@ -1125,7 +1117,7 @@ void C4AulParseState::AddBCC(C4AulBCCType eType, intptr_t X)
|
|||
}
|
||||
|
||||
// Join checks only if it's not a jump target
|
||||
if (!fJump && a->CPos > a->Code)
|
||||
if (!fJump && a->CPos > &a->Code[0])
|
||||
{
|
||||
// Join together stack operations
|
||||
C4AulBCC *pCPos1 = a->CPos - 1;
|
||||
|
@ -1381,7 +1373,7 @@ void C4AulScript::ParseFn(C4AulScriptFunc *Fn, bool fExprOnly, C4AulScriptContex
|
|||
// store byte code pos
|
||||
// (relative position to code start; code pointer may change while
|
||||
// parsing)
|
||||
Fn->Code = (C4AulBCC *) (CPos - Code);
|
||||
Fn->Code = (C4AulBCC *) (CPos - &Code[0]);
|
||||
// parse
|
||||
C4AulParseState state(Fn, this, C4AulParseState::PARSER);
|
||||
state.ContextToExecIn = context;
|
||||
|
@ -3103,8 +3095,8 @@ bool C4AulScript::Parse()
|
|||
{
|
||||
C4ScriptHost * scripthost = 0;
|
||||
if (Def) scripthost = &Def->Script;
|
||||
if (scripthost) LogSilentF("parsing %s...\n", scripthost->GetFilePath());
|
||||
else LogSilentF("parsing unknown...\n");
|
||||
if (scripthost) fprintf(stderr, "parsing %s...\n", scripthost->GetFilePath());
|
||||
else fprintf(stderr, "parsing unknown...\n");
|
||||
}
|
||||
// parse children
|
||||
C4AulScript *s = Child0;
|
||||
|
@ -3151,12 +3143,12 @@ bool C4AulScript::Parse()
|
|||
delete err;
|
||||
// make all jumps that don't have their destination yet jump here
|
||||
// intptr_t to make it work on 64bit
|
||||
for (intptr_t i = reinterpret_cast<intptr_t>(Fn->Code); i < CPos - Code; i++)
|
||||
for (intptr_t i = reinterpret_cast<intptr_t>(Fn->Code); i < CPos - &Code[0]; i++)
|
||||
{
|
||||
C4AulBCC *pBCC = Code + i;
|
||||
C4AulBCC *pBCC = &Code[i];
|
||||
if (IsJump(pBCC->bccType))
|
||||
if (!pBCC->Par.i)
|
||||
pBCC->Par.i = CPos - Code - i;
|
||||
pBCC->Par.i = CPos - &Code[0] - i;
|
||||
}
|
||||
// add an error chunk
|
||||
AddBCC(AB_ERR);
|
||||
|
@ -3181,7 +3173,7 @@ bool C4AulScript::Parse()
|
|||
if (Fn) if (Fn->Owner != Engine) Fn=NULL;
|
||||
}
|
||||
if (Fn)
|
||||
Fn->Code = Code + (intptr_t) Fn->Code;
|
||||
Fn->Code = &Code[(intptr_t) Fn->Code];
|
||||
}
|
||||
|
||||
// save line count
|
||||
|
@ -3197,23 +3189,30 @@ bool C4AulScript::Parse()
|
|||
if (f->LinkedTo) Fn = f->LinkedTo->SFunc();
|
||||
if (Fn) if (Fn->Owner != Engine) Fn=NULL;
|
||||
}
|
||||
if (Fn)
|
||||
if (!Fn)
|
||||
continue;
|
||||
fprintf(stderr, "%s:\n", Fn->Name);
|
||||
for (C4AulBCC *pBCC = Fn->Code;; pBCC++)
|
||||
{
|
||||
LogSilentF("%s:", Fn->Name);
|
||||
for (C4AulBCC *pBCC = Fn->Code;; pBCC++)
|
||||
C4AulBCCType eType = pBCC->bccType;
|
||||
fprintf(stderr, "\t%d\t%s", GetLineOfCode(pBCC), GetTTName(eType));
|
||||
switch (eType)
|
||||
{
|
||||
C4AulBCCType eType = pBCC->bccType;
|
||||
switch (eType)
|
||||
{
|
||||
case AB_FUNC:
|
||||
LogSilentF("%s\t'%s'\n", GetTTName(eType), pBCC->Par.f->Name); break;
|
||||
case AB_STRING: case AB_CALL: case AB_CALLFS:
|
||||
LogSilentF("%s\t'%s'\n", GetTTName(eType), pBCC->Par.s->GetCStr()); break;
|
||||
default:
|
||||
LogSilentF("%s\t%ld\n", GetTTName(eType), static_cast<long>(pBCC->Par.X)); break;
|
||||
}
|
||||
if (eType == AB_EOFN) break;
|
||||
case AB_FUNC:
|
||||
fprintf(stderr, "\t%s\n", pBCC->Par.f->Name); break;
|
||||
case AB_CALL: case AB_CALLFS: case AB_LOCALN: case AB_PROP:
|
||||
fprintf(stderr, "\t%s\n", pBCC->Par.s->GetCStr()); break;
|
||||
case AB_STRING:
|
||||
fprintf(stderr, "\t\"%s\"\n", pBCC->Par.s->GetCStr()); break;
|
||||
case AB_DEBUG: case AB_NIL: case AB_RETURN:
|
||||
case AB_PROPLIST: case AB_IPROPLIST: case AB_PAR:
|
||||
case AB_ARRAYA: case AB_ARRAY_SLICE: case AB_ERR:
|
||||
case AB_EOFN: case AB_EOF:
|
||||
assert(!pBCC->Par.X); fprintf(stderr, "\n"); break;
|
||||
default:
|
||||
fprintf(stderr, "\t%ld\n", static_cast<long>(pBCC->Par.X)); break;
|
||||
}
|
||||
if (eType == AB_EOFN) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue