compiler.h
Engine/source/console/compiler.h
Classes:
class
class
Utility class to emit and patch bytecode.
class
Namespaces:
namespace
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24 25#ifndef _COMPILER_H_ 26#define _COMPILER_H_ 27 28//#define DEBUG_CODESTREAM 29 30#ifdef DEBUG_CODESTREAM 31#include <stdio.h> 32#endif 33 34class Stream; 35class DataChunker; 36 37#include "platform/platform.h" 38#include "console/ast.h" 39#include "console/codeBlock.h" 40 41#ifndef _TVECTOR_H_ 42#include "core/util/tVector.h" 43#endif 44 45namespace Compiler 46{ 47 /// The opcodes for the TorqueScript VM. 48 enum CompiledInstructions 49 { 50 OP_FUNC_DECL, 51 OP_CREATE_OBJECT, 52 OP_ADD_OBJECT, 53 OP_END_OBJECT, 54 // Added to fix the stack issue [7/9/2007 Black] 55 OP_FINISH_OBJECT, 56 57 OP_JMPIFFNOT, 58 OP_JMPIFNOT, 59 OP_JMPIFF, 60 OP_JMPIF, 61 OP_JMPIFNOT_NP, 62 OP_JMPIF_NP, // 10 63 OP_JMP, 64 OP_RETURN, 65 // fixes a bug when not explicitly returning a value 66 OP_RETURN_VOID, 67 OP_RETURN_FLT, 68 OP_RETURN_UINT, 69 70 OP_CMPEQ, 71 OP_CMPGR, 72 OP_CMPGE, 73 OP_CMPLT, 74 OP_CMPLE, 75 OP_CMPNE, 76 OP_XOR, // 20 77 OP_MOD, 78 OP_BITAND, 79 OP_BITOR, 80 OP_NOT, 81 OP_NOTF, 82 OP_ONESCOMPLEMENT, 83 84 OP_SHR, 85 OP_SHL, 86 OP_AND, 87 OP_OR, // 30 88 89 OP_ADD, 90 OP_SUB, 91 OP_MUL, 92 OP_DIV, 93 OP_NEG, 94 95 OP_SETCURVAR, 96 OP_SETCURVAR_CREATE, 97 OP_SETCURVAR_ARRAY, 98 OP_SETCURVAR_ARRAY_CREATE, 99 100 OP_LOADVAR_UINT,// 40 101 OP_LOADVAR_FLT, 102 OP_LOADVAR_STR, 103 OP_LOADVAR_VAR, 104 105 OP_SAVEVAR_UINT, 106 OP_SAVEVAR_FLT, 107 OP_SAVEVAR_STR, 108 OP_SAVEVAR_VAR, 109 110 OP_SETCUROBJECT, 111 OP_SETCUROBJECT_NEW, 112 OP_SETCUROBJECT_INTERNAL, 113 114 OP_SETCURFIELD, 115 OP_SETCURFIELD_ARRAY, // 50 116 OP_SETCURFIELD_TYPE, 117 118 OP_LOADFIELD_UINT, 119 OP_LOADFIELD_FLT, 120 OP_LOADFIELD_STR, 121 122 OP_SAVEFIELD_UINT, 123 OP_SAVEFIELD_FLT, 124 OP_SAVEFIELD_STR, 125 126 OP_STR_TO_UINT, 127 OP_STR_TO_FLT, 128 OP_STR_TO_NONE, // 60 129 OP_FLT_TO_UINT, 130 OP_FLT_TO_STR, 131 OP_FLT_TO_NONE, 132 OP_UINT_TO_FLT, 133 OP_UINT_TO_STR, 134 OP_UINT_TO_NONE, 135 OP_COPYVAR_TO_NONE, 136 137 OP_LOADIMMED_UINT, 138 OP_LOADIMMED_FLT, 139 OP_TAG_TO_STR, 140 OP_LOADIMMED_STR, // 70 141 OP_DOCBLOCK_STR, 142 OP_LOADIMMED_IDENT, 143 144 OP_CALLFUNC_RESOLVE, 145 OP_CALLFUNC, 146 147 OP_ADVANCE_STR, 148 OP_ADVANCE_STR_APPENDCHAR, 149 OP_ADVANCE_STR_COMMA, 150 OP_ADVANCE_STR_NUL, 151 OP_REWIND_STR, 152 OP_TERMINATE_REWIND_STR, // 80 153 OP_COMPARE_STR, 154 155 OP_PUSH, // String 156 OP_PUSH_UINT, // Integer 157 OP_PUSH_FLT, // Float 158 OP_PUSH_VAR, // Variable 159 OP_PUSH_FRAME, // Frame 160 161 OP_ASSERT, 162 OP_BREAK, 163 164 OP_ITER_BEGIN, ///< Prepare foreach iterator. 165 OP_ITER_BEGIN_STR, ///< Prepare foreach$ iterator. 166 OP_ITER, ///< Enter foreach loop. 167 OP_ITER_END, ///< End foreach loop. 168 169 OP_INVALID // 90 170 }; 171 172 //------------------------------------------------------------ 173 174 F64 consoleStringToNumber(const char *str, StringTableEntry file = 0, U32 line = 0); 175 176 U32 compileBlock(StmtNode *block, CodeStream &codeStream, U32 ip); 177 178 //------------------------------------------------------------ 179 180 struct CompilerIdentTable 181 { 182 struct Entry 183 { 184 U32 offset; 185 U32 ip; 186 Entry *next; 187 Entry *nextIdent; 188 }; 189 Entry *list; 190 void add(StringTableEntry ste, U32 ip); 191 void reset(); 192 void write(Stream &st); 193 }; 194 195 //------------------------------------------------------------ 196 197 struct CompilerStringTable 198 { 199 U32 totalLen; 200 struct Entry 201 { 202 char *string; 203 U32 start; 204 U32 len; 205 bool tag; 206 Entry *next; 207 }; 208 Entry *list; 209 210 char buf[256]; 211 212 U32 add(const char *str, bool caseSens = true, bool tag = false); 213 U32 addIntString(U32 value); 214 U32 addFloatString(F64 value); 215 void reset(); 216 char *build(); 217 void write(Stream &st); 218 }; 219 220 //------------------------------------------------------------ 221 222 struct CompilerFloatTable 223 { 224 struct Entry 225 { 226 F64 val; 227 Entry *next; 228 }; 229 U32 count; 230 Entry *list; 231 232 U32 add(F64 value); 233 void reset(); 234 F64 *build(); 235 void write(Stream &st); 236 }; 237 238 //------------------------------------------------------------ 239 240 inline StringTableEntry CodeToSTE(U32 *code, U32 ip) 241 { 242#ifdef TORQUE_CPU_X64 243 return (StringTableEntry)(*((U64*)(code+ip))); 244#else 245 return (StringTableEntry)(*(code+ip)); 246#endif 247 } 248 249 extern void (*STEtoCode)(StringTableEntry ste, U32 ip, U32 *ptr); 250 251 void evalSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr); 252 void compileSTEtoCode(StringTableEntry ste, U32 ip, U32 *ptr); 253 254 CompilerStringTable *getCurrentStringTable(); 255 CompilerStringTable &getGlobalStringTable(); 256 CompilerStringTable &getFunctionStringTable(); 257 258 void setCurrentStringTable (CompilerStringTable* cst); 259 260 CompilerFloatTable *getCurrentFloatTable(); 261 CompilerFloatTable &getGlobalFloatTable(); 262 CompilerFloatTable &getFunctionFloatTable(); 263 264 void setCurrentFloatTable (CompilerFloatTable* cst); 265 266 CompilerIdentTable &getIdentTable(); 267 268 void precompileIdent(StringTableEntry ident); 269 270 /// Helper function to reset the float, string, and ident tables to a base 271 /// starting state. 272 void resetTables(); 273 274 void *consoleAlloc(U32 size); 275 void consoleAllocReset(); 276 277 extern bool gSyntaxError; 278}; 279 280/// Utility class to emit and patch bytecode 281class CodeStream 282{ 283public: 284 285 enum FixType 286 { 287 // For loops 288 FIXTYPE_LOOPBLOCKSTART, 289 FIXTYPE_BREAK, 290 FIXTYPE_CONTINUE 291 }; 292 293 enum Constants 294 { 295 BlockSize = 16384, 296 }; 297 298protected: 299 300 typedef struct PatchEntry 301 { 302 U32 addr; ///< Address to patch 303 U32 value; ///< Value to place at addr 304 305 PatchEntry() {;} 306 PatchEntry(U32 a, U32 v) : addr(a), value(v) {;} 307 } PatchEntry; 308 309 typedef struct CodeData 310 { 311 U8 *data; ///< Allocated data (size is BlockSize) 312 U32 size; ///< Bytes used in data 313 CodeData *next; ///< Next block 314 } CodeData; 315 316 /// @name Emitted code 317 /// { 318 CodeData *mCode; 319 CodeData *mCodeHead; 320 U32 mCodePos; 321 /// } 322 323 /// @name Code fixing stacks 324 /// { 325 Vector<U32> mFixList; 326 Vector<U32> mFixStack; 327 Vector<bool> mFixLoopStack; 328 Vector<PatchEntry> mPatchList; 329 /// } 330 331 Vector<U32> mBreakLines; ///< Line numbers 332 333public: 334 335 CodeStream() : mCode(0), mCodeHead(NULL), mCodePos(0) 336 { 337 } 338 339 ~CodeStream() 340 { 341 reset(); 342 343 if (mCode) 344 { 345 dFree(mCode->data); 346 delete mCode; 347 } 348 } 349 350 U8 *allocCode(U32 sz); 351 352 inline U32 emit(U32 code) 353 { 354 U32 *ptr = (U32*)allocCode(4); 355 *ptr = code; 356#ifdef DEBUG_CODESTREAM 357 printf("code[%u] = %u\n", mCodePos, code); 358#endif 359 return mCodePos++; 360 } 361 362 inline void patch(U32 addr, U32 code) 363 { 364#ifdef DEBUG_CODESTREAM 365 printf("patch[%u] = %u\n", addr, code); 366#endif 367 mPatchList.push_back(PatchEntry(addr, code)); 368 } 369 370 inline U32 emitSTE(const char *code) 371 { 372 U64 *ptr = (U64*)allocCode(8); 373 *ptr = 0; 374 Compiler::STEtoCode(code, mCodePos, (U32*)ptr); 375#ifdef DEBUG_CODESTREAM 376 printf("code[%u] = %s\n", mCodePos, code); 377#endif 378 mCodePos += 2; 379 return mCodePos-2; 380 } 381 382 inline U32 tell() 383 { 384 return mCodePos; 385 } 386 387 inline bool inLoop() 388 { 389 for (U32 i=0; i<mFixLoopStack.size(); i++) 390 { 391 if (mFixLoopStack[i]) 392 return true; 393 } 394 return false; 395 } 396 397 inline U32 emitFix(FixType type) 398 { 399 U32 *ptr = (U32*)allocCode(4); 400 *ptr = (U32)type; 401 402#ifdef DEBUG_CODESTREAM 403 printf("code[%u] = [FIX:%u]\n", mCodePos, (U32)type); 404#endif 405 406 mFixList.push_back(mCodePos); 407 mFixList.push_back((U32)type); 408 return mCodePos++; 409 } 410 411 inline void pushFixScope(bool isLoop) 412 { 413 mFixStack.push_back(mFixList.size()); 414 mFixLoopStack.push_back(isLoop); 415 } 416 417 inline void popFixScope() 418 { 419 AssertFatal(mFixStack.size() > 0, "Fix stack mismatch"); 420 421 U32 newSize = mFixStack[mFixStack.size()-1]; 422 while (mFixList.size() > newSize) 423 mFixList.pop_back(); 424 mFixStack.pop_back(); 425 mFixLoopStack.pop_back(); 426 } 427 428 void fixLoop(U32 loopBlockStart, U32 breakPoint, U32 continuePoint); 429 430 inline void addBreakLine(U32 lineNumber, U32 ip) 431 { 432 mBreakLines.push_back(lineNumber); 433 mBreakLines.push_back(ip); 434 } 435 436 inline U32 getNumLineBreaks() 437 { 438 return mBreakLines.size() / 2; 439 } 440 441 void emitCodeStream(U32 *size, U32 **stream, U32 **lineBreaks); 442 443 void reset(); 444}; 445 446#endif 447
