123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928 |
- /* GCSx
- ** BYTECODE.CPP
- **
- ** Bytecode-related utilities/datatypes/structures
- */
- /*****************************************************************************
- ** Copyright (C) 2003-2006 Janson
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program; if not, write to the Free Software
- ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
- #include "all.h"
- string dataTypeToWart(const DataType& dt) { start_func
- string result = string(1, dt.baseType + 'C');
- result += 'A' + dt.flags;
- if (((dt.baseType == DATA_ENTITY) || (dt.baseType == DATA_OBJECT)) && (dt.subType))
- result = result + formatString("%X", dt.subType);
- return result;
- }
- const char* wartToDataType(const char* wart, DataType& result) { start_func
- assert(wart);
-
- int base = *wart++ - 'C';
- if ((base != DATA_VOID) && (base != DATA_VAR) && (base != DATA_INT) &&
- (base != DATA_FLOAT) && (base != DATA_STR) && (base != DATA_ENTITY) &&
- (base != DATA_OBJECT))
- return NULL;
- result.baseType = base;
-
- int flags = *wart++ - 'A';
- if ((flags != 0) && (flags != DATA_ARRAY) && (flags != DATA_HASH) &&
- (flags != DATA_CONST))
- return NULL;
- result.flags = flags;
-
- char* endptr;
- result.subType = strtol(wart, &endptr, 16);
- return endptr;
- }
- void destroyLabelMap(LabelMap* map) { start_func
- if (map) {
- // We clear one at a time to ensure we can delete hash keys at the right times
- LabelMap::iterator pos = map->begin();
- while (pos != map->end()) {
- const char* toDel = (*pos).first;
- map->erase(pos);
- delete[] toDel;
- pos = map->begin();
- }
- }
- }
- list<Label>& addLabelMap(LabelMap* map, const string& name) { start_func
- const char* cName = name.c_str();
- // (create new element with new name allocation?)
- if (map->find(cName) == map->end()) cName = newCpCopy(name);
- // Find or create new element
- return (*map)[cName];
- }
- void destroyFunctionMap(FunctionMap* map) { start_func
- if (map) {
- // We clear one at a time to ensure we can delete hash keys at the right times
- FunctionMap::iterator pos = map->begin();
- while (pos != map->end()) {
- const char* toDel = (*pos).first;
- delete[] (*pos).second.parameters;
- map->erase(pos);
- delete[] toDel;
- pos = map->begin();
- }
- }
- }
- Function& addFunctionMap(FunctionMap* map, const string& name) { start_func
- const char* cName = name.c_str();
- // (create new element with new name allocation?)
- if (map->find(cName) == map->end()) cName = newCpCopy(name);
- // Find or create new element
- return (*map)[cName];
- }
- void destroyVariableMap(VariableMap* map) { start_func
- if (map) {
- // We clear one at a time to ensure we can delete hash keys at the right times
- VariableMap::iterator pos = map->begin();
- while (pos != map->end()) {
- const char* toDel = (*pos).first;
- for (list<Variable>::iterator pos2 = (*pos).second.begin(); pos2 != (*pos).second.end(); ++pos2) {
- if (((*pos2).datatype.baseType == DATA_STR) &&
- ((*pos2).datatype.flags == DATA_CONST))
- delete[] (*pos2).val.constS;
- }
- map->erase(pos);
- delete[] toDel;
- pos = map->begin();
- }
- }
- }
- list<Variable>& addVariableMap(VariableMap* map, const string& name, const char*& storeName) { start_func
- const char* cName = name.c_str();
- VariableMap::iterator found = map->find(cName);
- // (create new element with new name allocation?)
- if (found == map->end()) {
- storeName = cName = newCpCopy(name);
- return (*map)[cName];
- }
- // Existing element and name allocation
- else {
- storeName = (*found).first;
- return (*found).second;
- }
- }
- #ifdef COMPILEASSERT
- void checkOpcode(Opcode opc, Uint8 mode1, Uint8 mode2, Uint8 mode3) { start_func
- // Basic checks
- bytecodeAssert((opc >= 0) && (opc < OP_LAST));
- // More detailed checks- validate mode combinations are legal
- Uint8 modes[3] = { mode1, mode2, mode3 };
- for (int pos = 0; pos < 3; ++pos) {
- Uint8 check = modes[pos];
- Uint8 basetype = check & OM_BASETYPE;
-
- // Reserved (unallocated) types or non-allowed literal types
- if (OM_IS_LITERAL(check)) {
- bytecodeAssert(basetype != OM_STR);
- bytecodeAssert(basetype != OM_ARRAY);
- bytecodeAssert(basetype != OM_HASH);
- bytecodeAssert((basetype <= OM_THIS) || (basetype == OM_POINTER));
-
- }
- else {
- bytecodeAssert(basetype < OM_RESERVED_1);
- }
-
- // Cannot use OM_INDIRECT with entry, array, hash, local, global (or const, see below)
- if (OM_IS_INDIRECT(check)) {
- bytecodeAssert(basetype != OM_ENTRY);
- bytecodeAssert(basetype != OM_ARRAY);
- bytecodeAssert(basetype != OM_HASH);
- bytecodeAssert(!OM_IS_LOCAL(check));
- bytecodeAssert(!OM_IS_GLOBAL(check));
- }
- // Cannot use OM_POP with entry, non-const, or convert
- if (OM_IS_POP(check)) {
- bytecodeAssert(basetype != OM_ENTRY);
- bytecodeAssert(basetype != OM_STR);
- bytecodeAssert(OM_IS_COPY(check) || OM_IS_KNOWN(check) || OM_IS_INDIRECT(check));
- }
-
- // CONST str must be copy, not convert
- // Regular str must be convert, not copy
- if (basetype == OM_STR) {
- bytecodeAssert(!OM_IS_COPY(check));
- }
- else if (basetype == OM_STR_CONST && !OM_IS_LITERAL(check)) {
- bytecodeAssert(OM_IS_COPY(check) || OM_IS_KNOWN(check) || OM_IS_INDIRECT(check));
- }
- }
- // @TODO: redo bytecode checks below using newer #defines
-
- /*
- // Most detailed of checks- validate mode combination for specific opcode
- int numP = 1;
- int goalTemplate = 0;
- int goalConst1 = 0;
- int goalConst2 = 0;
- int goalType;
- switch (opc) {
- case OP_NOOP:
- case OP_INIT:
- case OP_LOGAND:
- case OP_LOGOR:
- case OP_NOT:
- case OP_PRECALL:
- case OP_STOP:
- case OP_WAIT: {
- // No parameters
- bytecodeAssert(mode1 == OM_NONE);
- break;
- }
-
- case OP_DEBUG: // @TODO: debug changed use; replace with something else
- case OP_RET: {
- bytecodeAssert(mode1 == OM_INT);
- bytecodeAssert(mode2 == OM_INT);
- numP = 2;
- break;
- }
-
- case OP_CALL: {
- bytecodeAssert(mode1 == OM_CFUNCTION);
- break;
- }
-
- case OP_FORCEARRAY:
- case OP_FORCEHASH: {
- bytecodeAssert(mode1 == OM_STACK);
- bytecodeAssert(mode2 == OM_INT);
- numP = 2;
- break;
- }
- case OP_ITOF:
- case OP_ITOS:
- case OP_FTOI:
- case OP_FTOS:
- case OP_STOI:
- case OP_STOF:
- case OP_FORCEFLOAT:
- case OP_FORCEINT:
- case OP_FORCESTRING: {
- bytecodeAssert(mode1 == OM_STACK);
- break;
- }
- case OP_IFFALSE:
- case OP_IFTRUE: {
- // 1) [Pop]/[Stack]/[Local]/[Ptr](#)
- // 2) [Offset]
- bytecodeAssert((mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- ((mode1 & OM_POP) == OM_POP));
- bytecodeAssert((mode1 & OM_BASETYPE) == OM_INT);
- bytecodeAssert(mode2 == OM_OFFSET);
- numP = 2;
- break;
- }
- case OP_IFFALSEf:
- case OP_IFTRUEf: {
- // 1) [Pop]/[Stack]/[Local]/[Ptr](%)
- // 2) [Offset]
- bytecodeAssert((mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- ((mode1 & OM_POP) == OM_POP));
- bytecodeAssert((mode1 & OM_BASETYPE) == OM_FLOAT);
- bytecodeAssert(mode2 == OM_OFFSET);
- numP = 2;
- break;
- }
-
- case OP_JUMP: {
- bytecodeAssert(mode1 == OM_OFFSET);
- break;
- }
-
- case OP_CREATEARRAY:
- case OP_CREATEHASH:
- case OP_REPLY: {
- bytecodeAssert(mode1 == OM_INT);
- break;
- }
-
- case OP_SUBR: {
- bytecodeAssert((mode1 == OM_OFFSET) ||
- (mode1 == OM_FUNCTION));
- break;
- }
-
- case OP_SWAP: {
- bytecodeAssert(mode1 == OM_STACK);
- bytecodeAssert(mode2 == OM_STACK);
- numP = 2;
- break;
- }
-
- case OP_TYPEOF:
- case OP_COPY:
- case OP_PUSHv:
- case OP_POPv: {
- bytecodeAssert((mode1 == OM_STACK) ||
- (mode1 == OM_LOCAL) ||
- (mode1 == OM_GLOBAL));
- break;
- }
-
- case OP_DISCARD:
- case OP_DISCARDL: {
- // [Pop]/[Stack]/[Local]/[Ptr](#) or [Int]
- bytecodeAssert((mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- ((mode1 & OM_POP) == OM_POP) ||
- (mode1 == OM_INT));
- bytecodeAssert((mode1 & OM_BASETYPE) == OM_INT);
- break;
- }
-
- case OP_ARRAY:
- case OP_POPARRAY: {
- // 1) [Stack]/[Local]/[Ptr](a)
- // 2) [Pop]/[Stack]/[Local]/[Ptr](#) or [Int]
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert(mode1 & OM_ARRAY);
- bytecodeAssert((mode1 & OM_POP) != OM_POP);
- bytecodeAssert((mode2 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- ((mode2 & OM_POP) == OM_POP) ||
- (mode2 == OM_INT));
- bytecodeAssert((mode2 & OM_BASETYPE) == OM_INT);
- numP = 2;
- break;
- }
-
- case OP_HASH:
- case OP_POPHASH: {
- // 1) [Stack]/[Local]/[Ptr](h)
- // 2) [Pop]/[Stack]/[Local]/[Ptr](c$) or [String]
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert(mode1 & OM_HASH);
- bytecodeAssert((mode1 & OM_POP) != OM_POP);
- bytecodeAssert((mode2 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- ((mode2 & OM_POP) == OM_POP) ||
- (mode2 == OM_STR));
- bytecodeAssert((mode2 & OM_BASETYPE) == OM_STR);
- goalConst2 = 1;
- numP = 2;
- break;
- }
-
- case OP_CONCAT: {
- // 1) [Stack]/[Local]/[Ptr]($)
- // 2) [Pop]/[Stack]/[Local]/[Ptr](c$) or [String]
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert((mode1 & OM_BASETYPE) == OM_STR);
- bytecodeAssert(!(mode1 & OM_CONST));
- bytecodeAssert((mode2 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- ((mode2 & OM_POP) == OM_POP) ||
- (mode2 == OM_STR));
- bytecodeAssert((mode2 & OM_BASETYPE) == OM_STR);
- goalConst2 = 1;
- numP = 2;
- break;
- }
-
- case OP_QUERY:
- case OP_SEND: {
- // 1) [Stack]/[Local]/[Ptr](#)
- // 2) [Pop]/[Stack]/[Local]/[Ptr](c$) or [String]
- // 3) [Int]
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert((mode1 & OM_BASETYPE) == OM_INT);
- bytecodeAssert((mode2 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- ((mode2 & OM_POP) == OM_POP) ||
- (mode2 == OM_STR));
- bytecodeAssert((mode2 & OM_BASETYPE) == OM_STR);
- bytecodeAssert(mode3 == OM_INT);
- goalConst2 = 1;
- numP = 3;
- break;
- }
-
- case OP_QUERYs:
- case OP_SENDs: {
- // 1) [Pop]/[Stack]/[Local]/[Ptr](c$) or [String]
- // 2) [Pop]/[Stack]/[Local]/[Ptr](c$) or [String]
- // 3) [Int]
- bytecodeAssert((mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- ((mode1 & OM_POP) == OM_POP) ||
- (mode1 == OM_STR));
- bytecodeAssert((mode1 & OM_BASETYPE) == OM_STR);
- bytecodeAssert((mode2 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- ((mode2 & OM_POP) == OM_POP) ||
- (mode2 == OM_STR));
- bytecodeAssert((mode2 & OM_BASETYPE) == OM_STR);
- bytecodeAssert(mode3 == OM_INT);
- goalConst1 = 1;
- goalConst2 = 1;
- numP = 3;
- break;
- }
-
- case OP_SUBRs: {
- // 1) [Stack]/[Local]/[Ptr]($)
- // 2) [Int]
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert((mode1 & OM_BASETYPE) == OM_STR);
- bytecodeAssert(!(mode1 & OM_CONST));
- bytecodeAssert(mode2 == OM_INT);
- numP = 2;
- break;
- }
-
- case OP_STORE: {
- // 1) [Stack]/[Local]/[Ptr](#)
- // 2) [Stack]/[Local]/[Ptr](#) or [Int]
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert((mode1 & OM_BASETYPE) == OM_INT);
- bytecodeAssert((mode2 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- (mode2 == OM_INT));
- bytecodeAssert((mode2 & OM_BASETYPE) == OM_INT);
- numP = 2;
- break;
- }
-
- case OP_STOREf: {
- // 1) [Stack]/[Local]/[Ptr](%)
- // 2) [Stack]/[Local]/[Ptr](%) or [Float]
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert((mode1 & OM_BASETYPE) == OM_FLOAT);
- bytecodeAssert((mode2 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- (mode2 == OM_FLOAT));
- bytecodeAssert((mode2 & OM_BASETYPE) == OM_FLOAT);
- numP = 2;
- break;
- }
-
- case OP_STOREs: {
- // 1) [Stack]/[Local]/[Ptr]($)
- // 2) [Stack]/[Local]/[Ptr](c$) or [String]
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert((mode1 & OM_BASETYPE) == OM_STR);
- bytecodeAssert(!(mode1 & OM_CONST));
- bytecodeAssert((mode2 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- (mode2 == OM_STR));
- bytecodeAssert((mode2 & OM_BASETYPE) == OM_STR);
- goalConst2 = 1;
- numP = 2;
- break;
- }
-
- case OP_STOREa: {
- // 1) [Stack]/[Local]/[Ptr](a)
- // 2) [Stack]/[Local]/[Ptr](a)
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert(mode1 & OM_ARRAY);
- bytecodeAssert((mode1 & OM_POP) != OM_POP);
- bytecodeAssert(mode2 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert(mode2 & OM_ARRAY);
- bytecodeAssert((mode2 & OM_POP) != OM_POP);
- numP = 2;
- break;
- }
-
- case OP_STOREh: {
- // 1) [Stack]/[Local]/[Ptr](h)
- // 2) [Stack]/[Local]/[Ptr](h)
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert(mode1 & OM_HASH);
- bytecodeAssert((mode1 & OM_POP) != OM_POP);
- bytecodeAssert(mode2 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert(mode2 & OM_HASH);
- bytecodeAssert((mode2 & OM_POP) != OM_POP);
- numP = 2;
- break;
- }
-
- case OP_NEG:
- case OP_POP: {
- // [Stack]/[Local]/[Ptr](#)
- goalType = OM_INT;
- goalTemplate = 4;
- break;
- }
- case OP_NEGf:
- case OP_POPf: {
- // [Stack]/[Local]/[Ptr](%)
- goalType = OM_FLOAT;
- goalTemplate = 4;
- break;
- }
-
- case OP_POPs: {
- // [Stack]/[Local]/[Ptr]($)
- bytecodeAssert(!(mode1 & OM_CONST));
- goalType = OM_STR;
- goalTemplate = 4;
- break;
- }
- case OP_PUSH: {
- // [Stack]/[Local]/[Ptr](#) or [Int]
- goalType = OM_INT;
- goalTemplate = 3;
- break;
- }
- case OP_PUSHf: {
- // [Stack]/[Local]/[Ptr](%) or [Float]
- goalType = OM_FLOAT;
- goalTemplate = 3;
- break;
- }
- case OP_PUSHs: {
- // [Stack]/[Local]/[Ptr](c$) or [String]
- goalType = OM_STR;
- goalTemplate = 3;
- goalConst1 = 1;
- break;
- }
- case OP_POPa:
- case OP_PUSHa: {
- // [Stack]/[Local]/[Ptr](a)
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert(mode1 & OM_ARRAY);
- bytecodeAssert((mode1 & OM_POP) != OM_POP);
- break;
- }
- case OP_POPh:
- case OP_PUSHh: {
- // [Stack]/[Local]/[Ptr](h)
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert(mode1 & OM_HASH);
- bytecodeAssert((mode1 & OM_POP) != OM_POP);
- break;
- }
-
- case OP_ADD:
- case OP_AND:
- case OP_DIV:
- case OP_MOD:
- case OP_MULT:
- case OP_OR:
- case OP_SHIFTL:
- case OP_SHIFTR:
- case OP_SUB:
- case OP_XOR: {
- // 1) [Stack]/[Local]/[Ptr](#)
- // 2) [Pop]/[Stack]/[Local]/[Ptr](#) or [Int]
- goalType = OM_INT;
- goalTemplate = 1;
- break;
- }
-
- case OP_EQ:
- case OP_GE:
- case OP_GT:
- case OP_LE:
- case OP_LT:
- case OP_NE: {
- // 1) [Pop]/[Stack]/[Local]/[Ptr](#)
- // 2) [Pop]/[Stack]/[Local]/[Ptr](#) or [Int]
- goalType = OM_INT;
- goalTemplate = 2;
- break;
- }
-
- case OP_ADDf:
- case OP_DIVf:
- case OP_MULTf:
- case OP_SUBf: {
- // 1) [Stack]/[Local]/[Ptr](%)
- // 2) [Pop]/[Stack]/[Local]/[Ptr](%) or [Float]
- goalType = OM_FLOAT;
- goalTemplate = 1;
- break;
- }
-
- case OP_EQf:
- case OP_GEf:
- case OP_GTf:
- case OP_LEf:
- case OP_LTf:
- case OP_NEf: {
- // 1) [Pop]/[Stack]/[Local]/[Ptr](%)
- // 2) [Pop]/[Stack]/[Local]/[Ptr](%) or [Float]
- goalType = OM_FLOAT;
- goalTemplate = 2;
- break;
- }
- case OP_EQs:
- case OP_GEs:
- case OP_GTs:
- case OP_LEs:
- case OP_LTs:
- case OP_NEs: {
- // 1) [Pop]/[Stack]/[Local]/[Ptr](c$)
- // 2) [Pop]/[Stack]/[Local]/[Ptr](c$) or [String]
- goalType = OM_STR;
- goalTemplate = 2;
- goalConst1 = 1;
- goalConst2 = 1;
- break;
- }
-
- // To prevent warning
- case OP_LAST:
- bytecodeAssert(0);
- break;
- }
-
- // Some standardized templates
- switch (goalTemplate) {
- case 1:
- case 2: {
- // gT1)
- // p1) [Stack]/[Local]/[Ptr](type)
- // p2) [Pop]/[Stack]/[Local]/[Ptr](type) or [type]
- // gT2) same but p1) can be [Pop]
- if (goalTemplate == 1)
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- else
- bytecodeAssert((mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- ((mode1 & OM_POP) == OM_POP));
- bytecodeAssert((mode1 & OM_BASETYPE) == goalType);
- bytecodeAssert((mode2 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- ((mode2 & OM_POP) == OM_POP) ||
- (mode2 == (mode2 & OM_BASETYPE)));
- bytecodeAssert((mode2 & OM_BASETYPE) == goalType);
- numP = 2;
- break;
- }
-
- case 3: {
- // [Stack]/[Local]/[Ptr](type) or [type]
- bytecodeAssert((mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK)) ||
- (mode1 == (mode1 & OM_BASETYPE)));
- bytecodeAssert((mode1 & OM_BASETYPE) == goalType);
- break;
- }
-
- case 4: {
- // [Stack]/[Local]/[Ptr](type)
- bytecodeAssert(mode1 & (OM_LOCAL | OM_GLOBAL | OM_STACK));
- bytecodeAssert((mode1 & OM_BASETYPE) == goalType);
- break;
- }
- }
-
- if (goalConst1)
- bytecodeAssert((mode1 == OM_STR) || (mode1 & OM_CONST));
- if (goalConst2)
- bytecodeAssert((mode2 == OM_STR) || (mode2 & OM_CONST));
-
- if (numP < 3) bytecodeAssert(mode3 == OM_NONE);
- if (numP < 2) bytecodeAssert(mode2 == OM_NONE);
- */
- }
- #endif
- const char* opcodeNames[] = {
- "NOOP ",
- "ADD ",
- "ADDf ",
- "AND ",
- "CONCAT ",
- "CONVERT ",
- "CREATEa ",
- "CREATEe ",
- "CREATEh ",
- "CREATEo ",
- "DEBUG ",
- "DISCARD ",
- "DISCARDL",
- "DIV ",
- "DIVf ",
- "EQ ",
- "EQf ",
- "EQo ",
- "EQs ",
- "GE ",
- "GEf ",
- "GEs ",
- "GT ",
- "GTf ",
- "GTs ",
- "IFFALSE ",
- "IFFALSEa",
- "IFFALSEf",
- "IFFALSEh",
- "IFFALSEo",
- "IFFALSEs",
- "IFFALSEv",
- "IFTRUE ",
- "IFTRUEa ",
- "IFTRUEf ",
- "IFTRUEh ",
- "IFTRUEo ",
- "IFTRUEs ",
- "IFTRUEv ",
- "INIT ",
- "JUMP ",
- "LE ",
- "LEf ",
- "LEs ",
- "LT ",
- "LTf ",
- "LTs ",
- "MOD ",
- "MULT ",
- "MULTf ",
- "NE ",
- "NEf ",
- "NEo ",
- "NEs ",
- "OR ",
- "PUSH ",
- "PUSHa ",
- "PUSHf ",
- "PUSHh ",
- "PUSHo ",
- "PUSHs ",
- "PUSHv ",
- "RET ",
- "SHIFTL ",
- "SHIFTR ",
- "STOP ",
- "STORE ",
- "STOREa ",
- "STOREf ",
- "STOREh ",
- "STOREo ",
- "STOREs ",
- "STOREv ",
- "SUB ",
- "SUBf ",
- "SUBR ",
- "XOR ",
- "GETe ",
- "SETe ",
- "GETo ",
- "SETo ",
- "IDLE ",
- "RETVOID ",
- "SETef ",
- "SETei ",
- "SETof ",
- "SEToi ",
- };
- typedef map<int, const LinkEntry*> LinkMap;
- LinkMap* linkMap = NULL;
- int linkPos = 0;
- void decompileBytecode(const Uint32* bytecode, const list<LinkEntry>* links) { start_func
- assert(bytecode);
- assert(links);
- Uint32 size = *bytecode++;
- Uint32 strOffset = *bytecode++;
- Uint32 pos = 0;
-
- debugWrite("Code: %d dw; Strings: %d dw; Links: %d", strOffset, size - strOffset, links->size());
-
- // Turn links into a map by position
- linkMap = new LinkMap;
- list<LinkEntry>::const_iterator end = links->end();
- for (list<LinkEntry>::const_iterator pos = links->begin(); pos != end; ++pos) {
- (*linkMap)[(*pos).offset] = &(*pos);
- }
- while (pos < strOffset) {
- string line = formatString("%04X ", pos);
- linkPos = pos;
- int sz = debugBytecode(line, bytecode);
- pos += sz;
- bytecode += sz;
- debugWrite("%s", line.c_str());
- }
-
- delete linkMap;
- linkMap = NULL;
-
- // Display strings
- while (pos < size) {
- debugWrite("%04X %s", pos, (const char*)bytecode);
- int sz = strlen((const char*)bytecode) / 4 + 1;
- pos += sz;
- bytecode += sz;
- }
- }
- int debugBytecode(string& line, const Uint32* bytecode) { start_func
- int used = 1;
-
- // Opcode
- Uint32 opcode = *bytecode++;
- line += opcodeNames[opcode & 0xFF];
- // Operands
- for (int o = 0; o < 3; ++o) {
- opcode >>= 8;
- Uint8 addrmode = opcode & 0xFF;
-
- if (addrmode) {
- // All operand modes pull a single 32bit operand out of bytecode except-
- // pop or 'none/all/this/all_other'- pull nothing
- // obj_entity+subtype- pulls an extra 32bit for subtype FIRST
- // literal/global pointer- pulls pointer size (may be 32bit or 64bit etc)
- // literal float- pulls float size (may be 32bit or more)
-
- if (OM_IS_POINTER(addrmode)) {
- void* operand = *(void**)(bytecode);
- bytecode += vPtrSize;
- used += vPtrSize;
-
- line += " [Ptr]";
- // (only show address if actually linked)
- if (operand) line += formatString("<%p>", operand);
- if (linkMap) ;// @TODO: display function from links
- }
- else {
- line += " ";
-
- // (copy OR convert in {})
- if (!OM_IS_LITERAL(addrmode) && OM_IS_CONVERT(addrmode)) line += "{";
-
- switch (addrmode & OM_BASETYPE) {
- case OM_ENTRY: line += "*"; break;
- case OM_INT: line += "#"; break;
- case OM_FLOAT: line += "%"; break;
- case OM_STR: line += "$"; break;
- case OM_STR_CONST: line += "c$"; break;
- case OM_ARRAY: line += "A"; break;
- case OM_HASH: line += "H"; break;
- case OM_ENTITY:
- if (!OM_IS_LITERAL(addrmode)) line += "e@";
- break;
- case OM_OBJECT:
- if (!OM_IS_LITERAL(addrmode)) line += "@";
- break;
- default:
- break;
- };
- // Subtype modes (any non literal object/entity conversion/copy, all, all_other)
- // @TODO: will also need 2 subtypes on array/hash conversion/copy
- if ((((addrmode & OM_BASETYPE) == OM_ENTITY || (addrmode & OM_BASETYPE) == OM_OBJECT) &&
- (addrmode & OM_FLAGS) != OM_NO_CONVERT && (addrmode & OM_FLAGS) != OM_INDIRECT &&
- (addrmode & OM_BASETYPE) != addrmode)
- || addrmode == OM_ALL || addrmode == OM_ALL_OTHER) {
- int subtype = *bytecode++;
- ++used;
- if (subtype) {
- line += "'";
- // @TODO: actual script or type name
- line += intToStr(subtype);
- line += "'";
- }
- }
- if (OM_IS_INDIRECT(addrmode)) line += "<-";
- else if (OM_IS_COPY(addrmode)) line += "}";
- else if (!OM_IS_LITERAL(addrmode) && OM_IS_CONVERT(addrmode)) line += "/Conv}";
- if (OM_IS_GLOBAL(addrmode)) line += "[G]";
- else if (OM_IS_LOCAL(addrmode)) line += "[L]";
- else if (OM_IS_STACK(addrmode)) line += "[S]";
- else if (OM_IS_POP(addrmode)) line += "[Pop]";
- // (else literal)
-
- if (!OM_IS_POP(addrmode)) {
- if (OM_IS_LITERAL(addrmode)) {
- switch (addrmode & OM_BASETYPE) {
- case OM_INT:
- line += intToStr(*bytecode++);
- ++used;
- break;
- case OM_FLOAT: {
- BCfloat operand = *(BCfloat*)(bytecode);
- bytecode += bcFloatSize;
- used += bcFloatSize;
- line += formatString("%"BC_FLOAT_PRINTF, operand);
- break;
- }
- case OM_STR_CONST: {
- int showString = *bytecode;
- line += intToStr(showString);
- ++used;
- // (show actual string)
- line += "\"";
- line += (const char*)(bytecode + showString);
- line += "\"";
- ++bytecode;
- break;
- }
- case OM_ALL:
- line += "ALL";
- break;
- case OM_ALL_OTHER:
- line += "ALL_OTHER";
- break;
- case OM_NOTHING:
- line += "NOTHING";
- break;
- case OM_THIS:
- line += "THIS";
- break;
- default:
- break;
- };
- }
- else if (OM_IS_GLOBAL(addrmode)) {
- void* operand = *(void**)(bytecode);
- bytecode += vPtrSize;
- used += vPtrSize;
-
- // (only show address if actually linked)
- if (operand) line += formatString("<%p>", operand);
- if (linkMap) {
- LinkMap::iterator found = linkMap->find(linkPos + used);
- if (found != linkMap->end()) line += (*found).second->name.c_str();
- }
- }
- else {
- line += intToStr(*bytecode++);
- ++used;
- }
- }
- }
- }
- }
-
- return used;
- }
|