123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 |
- //-----------------------------------------------------------------------------
- // 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 _COMPILER_H_
- #define _COMPILER_H_
- //#define DEBUG_CODESTREAM
- #ifdef DEBUG_CODESTREAM
- #include <stdio.h>
- #endif
- #include <string>
- #include <unordered_map>
- class Stream;
- class DataChunker;
- #include "platform/platform.h"
- #include "console/ast.h"
- #include "console/codeBlock.h"
- #ifndef _TVECTOR_H_
- #include "core/util/tVector.h"
- #endif
- //------------------------------------------------------------
- namespace Compiler
- {
- /// The opcodes for the TorqueScript VM.
- enum CompiledInstructions
- {
- OP_FUNC_DECL,
- OP_CREATE_OBJECT,
- OP_ADD_OBJECT,
- OP_END_OBJECT,
- // Added to fix the stack issue [7/9/2007 Black]
- OP_FINISH_OBJECT,
- OP_JMPIFFNOT,
- OP_JMPIFNOT,
- OP_JMPIFF,
- OP_JMPIF,
- OP_JMPIFNOT_NP,
- OP_JMPIF_NP, // 10
- OP_JMP,
- OP_RETURN,
- // fixes a bug when not explicitly returning a value
- OP_RETURN_VOID,
- OP_RETURN_FLT,
- OP_RETURN_UINT,
- OP_CMPEQ,
- OP_CMPGR,
- OP_CMPGE,
- OP_CMPLT,
- OP_CMPLE,
- OP_CMPNE,
- OP_XOR, // 20
- OP_MOD,
- OP_BITAND,
- OP_BITOR,
- OP_NOT,
- OP_NOTF,
- OP_ONESCOMPLEMENT,
- OP_SHR,
- OP_SHL,
- OP_AND,
- OP_OR, // 30
- OP_ADD,
- OP_SUB,
- OP_MUL,
- OP_DIV,
- OP_NEG,
- OP_INC,
- OP_SETCURVAR,
- OP_SETCURVAR_CREATE,
- OP_SETCURVAR_ARRAY,
- OP_SETCURVAR_ARRAY_CREATE,
- OP_LOADVAR_UINT,// 40
- OP_LOADVAR_FLT,
- OP_LOADVAR_STR,
- OP_SAVEVAR_UINT,
- OP_SAVEVAR_FLT,
- OP_SAVEVAR_STR,
- OP_LOAD_LOCAL_VAR_UINT,
- OP_LOAD_LOCAL_VAR_FLT,
- OP_LOAD_LOCAL_VAR_STR,
- OP_SAVE_LOCAL_VAR_UINT,
- OP_SAVE_LOCAL_VAR_FLT,
- OP_SAVE_LOCAL_VAR_STR,
- OP_SETCUROBJECT,
- OP_SETCUROBJECT_NEW,
- OP_SETCUROBJECT_INTERNAL,
- OP_SETCURFIELD,
- OP_SETCURFIELD_ARRAY, // 50
- OP_SETCURFIELD_TYPE,
- OP_LOADFIELD_UINT,
- OP_LOADFIELD_FLT,
- OP_LOADFIELD_STR,
- OP_SAVEFIELD_UINT,
- OP_SAVEFIELD_FLT,
- OP_SAVEFIELD_STR,
- OP_POP_STK,
- OP_LOADIMMED_UINT,
- OP_LOADIMMED_FLT,
- OP_TAG_TO_STR,
- OP_LOADIMMED_STR, // 70
- OP_DOCBLOCK_STR, // 76
- OP_LOADIMMED_IDENT,
- OP_CALLFUNC,
- OP_ADVANCE_STR_APPENDCHAR,
- OP_REWIND_STR,
- OP_TERMINATE_REWIND_STR,
- OP_COMPARE_STR,
- OP_PUSH,
- OP_PUSH_FRAME,
- OP_ASSERT,
- OP_BREAK,
- OP_ITER_BEGIN, ///< Prepare foreach iterator.
- OP_ITER_BEGIN_STR, ///< Prepare foreach$ iterator.
- OP_ITER, ///< Enter foreach loop.
- OP_ITER_END, ///< End foreach loop.
- OP_INVALID, // 90
- MAX_OP_CODELEN ///< The amount of op codes.
- };
- //------------------------------------------------------------
- F64 consoleStringToNumber(const char *str, StringTableEntry file = 0, U32 line = 0);
- U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip);
- //------------------------------------------------------------
- struct CompilerIdentTable
- {
- struct Entry
- {
- U32 offset;
- U32 ip;
- Entry *next;
- Entry *nextIdent;
- };
- Entry *list;
- void add(StringTableEntry ste, U32 ip);
- void reset();
- void write(Stream &st);
- };
- //------------------------------------------------------------
- struct CompilerStringTable
- {
- U32 totalLen;
- struct Entry
- {
- char *string;
- U32 start;
- U32 len;
- bool tag;
- Entry *next;
- };
- Entry *list;
- char buf[256];
- std::unordered_map<std::string, Entry*> hashTable;
- U32 add(const char *str, bool caseSens = true, bool tag = false);
- U32 addIntString(U32 value);
- U32 addFloatString(F64 value);
- void reset();
- char *build();
- void write(Stream &st);
- };
- //------------------------------------------------------------
- struct CompilerFloatTable
- {
- struct Entry
- {
- F64 val;
- Entry *next;
- };
- U32 count;
- Entry *list;
- U32 add(F64 value);
- void reset();
- F64 *build();
- void write(Stream &st);
- };
- //------------------------------------------------------------
- inline StringTableEntry CodeToSTE(U32 *code, U32 ip)
- {
- #if defined(TORQUE_CPU_X64) || defined(TORQUE_CPU_ARM64)
- return (StringTableEntry)(*((U64*)(code + ip)));
- #else
- return (StringTableEntry)(*(code + ip));
- #endif
- }
- extern void(*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr);
- void evalSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr);
- void compileSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr);
- CompilerStringTable *getCurrentStringTable();
- CompilerStringTable &getGlobalStringTable();
- CompilerStringTable &getFunctionStringTable();
- CompilerLocalVariableToRegisterMappingTable& getFunctionVariableMappingTable();
- void setCurrentStringTable(CompilerStringTable* cst);
- CompilerFloatTable *getCurrentFloatTable();
- CompilerFloatTable &getGlobalFloatTable();
- CompilerFloatTable &getFunctionFloatTable();
- void setCurrentFloatTable(CompilerFloatTable* cst);
- CompilerIdentTable &getIdentTable();
- void precompileIdent(StringTableEntry ident);
- /// Helper function to reset the float, string, and ident tables to a base
- /// starting state.
- void resetTables();
- void *consoleAlloc(U32 size);
- void consoleAllocReset();
- void scriptErrorHandler(const char* str);
- extern bool gSyntaxError;
- extern bool gIsEvalCompile;
- };
- class FuncVars
- {
- struct Var
- {
- S32 reg;
- TypeReq currentType;
- StringTableEntry name;
- bool isConstant;
- };
- public:
- S32 assign(StringTableEntry var, TypeReq currentType, S32 lineNumber, bool isConstant = false);
- S32 lookup(StringTableEntry var, S32 lineNumber);
- TypeReq lookupType(StringTableEntry var, S32 lineNumber);
-
- inline S32 count() { return counter; }
- std::unordered_map<S32, StringTableEntry> variableNameMap;
- void clear();
-
- private:
- std::unordered_map<StringTableEntry, Var> vars;
- S32 counter = 0;
- };
- /// Utility class to emit and patch bytecode
- class CodeStream
- {
- public:
- enum FixType
- {
- // For loops
- FIXTYPE_LOOPBLOCKSTART,
- FIXTYPE_BREAK,
- FIXTYPE_CONTINUE
- };
- enum Constants
- {
- BlockSize = 16384,
- };
- protected:
- typedef struct PatchEntry
- {
- U32 addr; ///< Address to patch
- U32 value; ///< Value to place at addr
- PatchEntry(): addr(0), value(0) { ; }
- PatchEntry(U32 a, U32 v) : addr(a), value(v) { ; }
- } PatchEntry;
- typedef struct CodeData
- {
- U8 *data; ///< Allocated data (size is BlockSize)
- U32 size; ///< Bytes used in data
- CodeData *next; ///< Next block
- } CodeData;
- /// @name Emitted code
- /// {
- CodeData *mCode;
- CodeData *mCodeHead;
- U32 mCodePos;
- /// }
- /// @name Code fixing stacks
- /// {
- Vector<U32> mFixList;
- Vector<U32> mFixStack;
- Vector<bool> mFixLoopStack;
- Vector<PatchEntry> mPatchList;
- /// }
- Vector<U32> mBreakLines; ///< Line numbers
- public:
- CodeStream() : mCode(0), mCodeHead(NULL), mCodePos(0)
- {
- }
- ~CodeStream()
- {
- reset();
- if (mCode)
- {
- dFree(mCode->data);
- delete mCode;
- }
- }
- U8 *allocCode(U32 sz);
- inline U32 emit(U32 code)
- {
- U32 *ptr = (U32*)allocCode(4);
- *ptr = code;
- #ifdef DEBUG_CODESTREAM
- printf("code[%u] = %u\n", mCodePos, code);
- #endif
- return mCodePos++;
- }
- inline void patch(U32 addr, U32 code)
- {
- #ifdef DEBUG_CODESTREAM
- printf("patch[%u] = %u\n", addr, code);
- #endif
- mPatchList.push_back(PatchEntry(addr, code));
- }
- inline U32 emitSTE(const char *code)
- {
- U64 *ptr = (U64*)allocCode(8);
- *ptr = 0;
- Compiler::STEtoCode(code, mCodePos, (U32*)ptr);
- #ifdef DEBUG_CODESTREAM
- printf("code[%u] = %s\n", mCodePos, code);
- #endif
- mCodePos += 2;
- return mCodePos - 2;
- }
- inline U32 tell()
- {
- return mCodePos;
- }
- inline bool inLoop()
- {
- for (U32 i = 0; i<mFixLoopStack.size(); i++)
- {
- if (mFixLoopStack[i])
- return true;
- }
- return false;
- }
- inline U32 emitFix(FixType type)
- {
- U32 *ptr = (U32*)allocCode(4);
- *ptr = (U32)type;
- #ifdef DEBUG_CODESTREAM
- printf("code[%u] = [FIX:%u]\n", mCodePos, (U32)type);
- #endif
- mFixList.push_back(mCodePos);
- mFixList.push_back((U32)type);
- return mCodePos++;
- }
- inline void pushFixScope(bool isLoop)
- {
- mFixStack.push_back(mFixList.size());
- mFixLoopStack.push_back(isLoop);
- }
- inline void popFixScope()
- {
- AssertFatal(mFixStack.size() > 0, "Fix stack mismatch");
- U32 newSize = mFixStack[mFixStack.size() - 1];
- while (mFixList.size() > newSize)
- mFixList.pop_back();
- mFixStack.pop_back();
- mFixLoopStack.pop_back();
- }
- void fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint);
- inline void addBreakLine(U32 lineNumber, U32 ip)
- {
- mBreakLines.push_back(lineNumber);
- mBreakLines.push_back(ip);
- }
- inline U32 getNumLineBreaks()
- {
- return mBreakLines.size() / 2;
- }
- void emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks);
- void reset();
- };
- #endif
|