1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140 |
- /* GCSx
- ** ENTITY.CPP
- **
- ** Entity support (instance of a script) (no edit-specific version)
- ** Includes bytecode interpreter
- */
- /*****************************************************************************
- ** 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"
- // @TODO: respect ref
- Entity::Entity(int myId) { start_func
- id = myId;
- script = NULL;
- active = 0;
- scriptLocked = 0;
- scriptType = 0;
- ref = 0;
- runStatus = RUN_UNINIT;
- i = NULL;
- endOfLocals = 0;
- createStack(&stack);
-
- varTable[PROP_NAME].p = new string;
- varTable[PROP_SPRITE].p = NULL;
- varTable[PROP_PRIORITY].i = DEFAULT_PRIORITY;
- }
- Entity::~Entity() { start_func
- // @TODO: assert ref=0?
- wipeStack();
- destroyStack(&stack);
- setScript(NULL);
- // @TODO: this is only safe if we ensure to destroy entities before sprites
- setSprite(NULL);
- delete (string*)varTable[PROP_NAME].p;
- }
- void Entity::setSprite(Sprite* newSprite) { start_func
- if (varTable[PROP_SPRITE].p) --(((ObjectBase*)varTable[PROP_SPRITE].p)->ref);
- varTable[PROP_SPRITE].p = (ObjectBase*)newSprite;
- if (newSprite) ++newSprite->ref;
- }
- void Entity::setScript(Script* newScript) { start_func
- if ((script) && (scriptLocked))
- script->markUnlock();
-
- wipeStack();
- i = NULL;
- runStatus = RUN_UNINIT;
- scriptLocked = 0;
- script = newScript;
- if (script) scriptType = newScript->getId();
- if ((script) && (active))
- activateResource();
- }
- void Entity::activateResource() { start_func
- if ((script) && (!scriptLocked)) {
- assert(!i);
- assert((runStatus == RUN_UNINIT) || (runStatus == RUN_STOPPED));
- // @TODO: throw_File
- script->markLock();
- script->link();
- scriptLocked = 1;
- if (runStatus == RUN_UNINIT) {
- i = script->getCode();
- runStatus = RUN_INIT;
- }
- }
- }
- void Entity::deactivateResource() { start_func
- if ((script) && (scriptLocked) && (!i)) {
- assert((runStatus == RUN_UNINIT) || (runStatus == RUN_STOPPED));
- script->markUnlock();
- scriptLocked = 0;
- }
- }
- void Entity::setActive() { start_func
- if (!active) {
- activateResource();
- active = 1;
- }
- }
- void Entity::setInactive() { start_func
- if (active) {
- deactivateResource();
- active = 0;
- }
- }
- /*
- ** BYTECODE INTERPRETER follows
- **
- ** All functions except main loop can be considered throw_Interpret,
- ** therefore follow dynamic allocations CAREFULLY.
- */
- // @TODO: consolidate duplicate opcode/etc functions as much as possible
- // once mostly debugged and otherwise optimized (reduce space = optimize cache)
- //
- // State data- interpreter runs outside class to prevent passing 'this'
- // and allow simple function tables; all tables and data together.
- //
- static Uint32 opdata = 0;
- static Uint8 addrmode = 0;
- static Uint32* i_p = NULL;
- // A note on stack usage- an opcode should not push onto the stack until it's
- // done with it's operands, as we sometimes reference "popped" data directly
- // at it's original, technically-invalid position
- static Stack stackP;
- static Entity* entity = NULL;
- static StackEntry* operand = NULL;
- static StackEntry* operandGrab = NULL;
- static StackEntry* operandWrite = NULL;
- static Sint32 operandDataI = 0;
- static BCfloat operandDataF = 0;
- static const char* operandDataS = NULL;
- static void* operandDataP = NULL;
- // 'toDeref' should always contain anything needing dereferencing
- #define MAX_TODEREF 8
- // (room for at least 2 derefs per operand)
- static StackEntry toDeref[MAX_TODEREF];
- static StackEntry* toDerefPos = toDeref;
- static StackEntry* toDerefLast = toDeref + MAX_TODEREF;
- // Two-element array (flip-flops) to store temporary operands that
- // DON'T need dereferencing (int, float)
- static StackEntry tempOperand[2];
- static int tempPos = 0;
- // Pre-created 'empty' int/float/entity/object operands
- static StackEntry emptyOperand[4];
- typedef void (*OperandFunc)();
- typedef void (*OperandFuncDeref)(StackEntry*);
- // Operand function sequence- (/ means 'or')
- // opcodes[]
- // ->grabbers[] -> extractors[] / copiers[] -> extractors[]
- // ->grabbersStore[] -> converters[]
- // ->grabbersWrite[]
- // ->grabbersUse[] -> copiersUse[] / converters[]
- // Anyone can call dereferencers[] or referencers[] as needed
- // Anyone can call copiersUse[] with _UNDEF for existing type to create blank entries
- // Function tables-
- // Dereferencing table- Indexed via 8 bits of existing datatype
- // Referencing- only intended to support basic types
- // May clobber operand IF you call on a RETURN type
- static OperandFuncDeref dereferencers[STACK_TYPE_COUNT];
- static OperandFuncDeref referencers[STACK_TYPE_COUNT];
- // Copy/conversion tables- Indexed via 4 bits of desired datatype concatenated with 4 bits of existing datatype
- // copiersUse[] ensures the copy is a usable, properly ref counted StackEntry and does NOT put in "toderef"
- // copiersUse[] with _UNDEF existing is gauranteed to just make a blank entry, so can be
- // used for creating empties.; copiersUse[] expects it's result to be stored via assignment
- // copiers[] calls extractors immediately after or instead.
- static OperandFunc converters[256]; // into operand
- static OperandFunc copiers[256]; // into operandData* (clobbers operandGrab/2)
- static OperandFunc copiersUse[256]; // into operand
- // Extractor table- indexed by 8 bit operand; don't call if called copiers[]
- // @TODO: create specialized types for all grabbers[] that use extractors and
- // remove this array? (some functions are still needed for copiers[] array)
- static OperandFunc extractors[256]; // into operandData* (from operandGrab)
- // Decoder (grabber) table- indexed by 8 bit operand- grabs const into operandData*
- static OperandFunc grabbers[256]; // into operandData* (clobbers operandGrab/2)
- // Grabs non-const, pointer in operand ready to store/modify directly
- // Write "destroys" AND DEREFS original contents without conversion! and
- // also does not garauntee that the 'type' field is correct.
- static OperandFunc grabbersStore[256]; // into operand
- static OperandFunc grabbersWrite[256]; // into operandWrite
- // Grabs into a ready-to-use StackEntry in operand (proper ref counting and all)
- static OperandFunc grabbersUse[256]; // into operand
- // Opcode table
- static OperandFunc opcodes[OP_LAST];
- #ifdef INTERPRETASSERT
- static void interpretError() { start_func
- interpretAssert(0);
- }
- static void interpretErrorDeref(StackEntry*) { start_func
- interpretAssert(0);
- }
- #else
- #define interpretError NULL
- #define interpretErrorDeref NULL
- #endif
- static void doNothing() { start_func
- }
- //
- // dereferencers[]
- //
- // Dereferencing/destruction (the seDeref* functions already assert)
- static void derefNothing(StackEntry* s) { start_func
- }
- static void derefString(StackEntry* s) { start_func
- seDerefString(s);
- }
- static void derefArray(StackEntry* s) { start_func
- seDerefArray(s);
- }
- static void derefHash(StackEntry* s) { start_func
- seDerefHash(s);
- }
- static void derefEntity(StackEntry* s) { start_func
- Entity::seDerefEntity(s);
- }
- static void derefObject(StackEntry* s) { start_func
- seDerefObject(s);
- }
- static void derefReturn(StackEntry* s) { start_func
- interpretAssert(s->type == STACK_RETURNPTR);
- StackEntry* target = (StackEntry*)(s->data.p);
- if (target) {
- interpretAssert(target->type & STACK_REPLYPTR);
- interpretAssert((target->type | ~STACK_REPLYPTR) <= STACK_BASETYPE);
- // Generate empty of requested type
- // Assumes STACK_UNDEF is 0 otherwise we should have | STACK_UNDEF here
- interpretAssert(STACK_UNDEF == 0);
- copiersUse[(target->type | ~STACK_REPLYPTR) << 4]();
- *target = *operand;
- }
- }
- static void derefReply(StackEntry* s) { start_func
- interpretAssert(s->type == STACK_REPLYPTR);
- StackEntry* target = (StackEntry*)(s->data.p);
- interpretAssert(target);
- interpretAssert(target->type == STACK_RETURNPTR);
- target->data.p = NULL;
- }
- //
- // referencers[]
- //
- static void refNothing(StackEntry* s) { start_func
- }
- static void refString(StackEntry* s) { start_func
- s->data.p = new string(*(string*)s->data.p);
- }
- static void refArray(StackEntry* s) { start_func
- interpretAssert(s->type == STACK_ARRAY);
- refIncArray((Array*)s->data.p);
- }
- static void refHash(StackEntry* s) { start_func
- interpretAssert(s->type == STACK_HASH);
- refIncHash((Hash*)s->data.p);
- }
- static void refEntity(StackEntry* s) { start_func
- Entity::seRefEntity(s);
- }
- static void refObject(StackEntry* s) { start_func
- interpretAssert(s->type == STACK_OBJECT);
- if (s->data.p) ++(((ObjectBase*)s->data.p)->ref);
- }
- //
- // converters[]
- //
- // Converting- dereferences old operand, replaces with new in-place
- static void convertEmptyToInt() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- // (always deref, as it's not float/int at this point)
- dereferencers[operand->type](operand);
- operand->type = STACK_INT;
- operand->data.i = 0;
- }
- static void convertEmptyToFloat() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- operand->type = STACK_FLOAT;
- operand->data.f = 0.0;
- }
- static void convertEmptyToStr() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- operand->type = STACK_STRING;
- operand->data.p = new string(blankString);
- }
- static void convertEmptyToArray() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- // @TODO:
- }
- static void convertEmptyToHash() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- // @TODO:
- }
- static void convertEmptyToEntity() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- operand->type = STACK_ENTITY;
- operand->data.p = NULL;
- }
- static void convertEmptyToObject() { start_func
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- operand->type = STACK_OBJECT;
- operand->data.p = NULL;
- }
- static void convertIntToFloat() { start_func
- operand->type = STACK_FLOAT;
- operand->data.f = (BCfloat)operand->data.i;
- }
- static void convertFloatToInt() { start_func
- operand->type = STACK_INT;
- operand->data.i = (Sint32)operand->data.f;
- }
- static void convertIntToString() { start_func
- operand->type = STACK_STRING;
- operand->data.p = new string(intToStr(operand->data.i));
- }
- static void convertStringToInt() { start_func
- operand->type = STACK_INT;
- string* myStr = (string*)operand->data.p;
- operand->data.i = strToInt(*myStr);
- delete myStr;
- }
- static void convertFloatToString() { start_func
- operand->type = STACK_STRING;
- operand->data.p = new string(floatToStr(operand->data.f));
- }
- static void convertStringToFloat() { start_func
- operand->type = STACK_FLOAT;
- string* myStr = (string*)operand->data.p;
- operand->data.f = strToFloat(*myStr);
- delete myStr;
- }
- //
- // copiers[]
- //
- // Copying- ignores old operand, replaces with new in operandData* (doesn't deref old)
- // New version is set up to deref for you automatically
- // Handles the work of extractors[] too
- static void copyCreateInt() { start_func
- operandDataI = emptyOperand[0].data.i;
- }
- static void copyCreateFloat() { start_func
- operandDataF = emptyOperand[1].data.f;
- }
- static void copyCreateStr() { start_func
- operandDataS = "";
- }
- static void copyCreateArray() { start_func
- // @TODO:
- }
- static void copyCreateHash() { start_func
- // @TODO:
- }
- static void copyCreateEntity() { start_func
- operandDataP = NULL;
- }
- static void copyCreateObject() { start_func
- operandDataP = NULL;
- }
- static void copyIntToFloat() { start_func
- operandDataF = (BCfloat)operandGrab->data.i;
- }
- static void copyFloatToInt() { start_func
- operandDataI = (Sint32)operandGrab->data.f;
- }
- static void copyIntToString() { start_func
- if (++toDerefPos == toDerefLast) toDerefPos = toDeref;
- interpretAssert(toDerefPos->type != STACK_RETURNPTR);
- dereferencers[toDerefPos->type](toDerefPos);
- // (need to set type to ensure dereferencing)
- toDerefPos->type = STACK_STRING;
- toDerefPos->data.p = new string(intToStr(toDerefPos->data.i));
- operandDataS = ((string*)toDerefPos->data.p)->c_str();
- }
- static void copyStringToInt() { start_func
- operandDataI = strToInt(*(string*)operandGrab->data.p);
- }
- static void copyFloatToString() { start_func
- if (++toDerefPos == toDerefLast) toDerefPos = toDeref;
- interpretAssert(toDerefPos->type != STACK_RETURNPTR);
- dereferencers[toDerefPos->type](toDerefPos);
- // (need to set type to ensure dereferencing)
- toDerefPos->type = STACK_STRING;
- toDerefPos->data.p = new string(floatToStr(operandGrab->data.f));
- operandDataS = ((string*)toDerefPos->data.p)->c_str();
- }
- static void copyStringToFloat() { start_func
- operandDataF = strToFloat(*(string*)operandGrab->data.p);
- }
- //
- // copiersUse[]
- //
- // Copying for Use- ignores old operand, replaces with new in operand (doesn't deref old)
- // 'Use' versions don't set new up to be deref'd either, expecting it will get stored VIA ASSIGNMENT
- static void copyCreateIntUse() { start_func
- operand = emptyOperand;
- }
- static void copyCreateFloatUse() { start_func
- operand = emptyOperand + 1;
- }
- static void copyCreateStrUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_STRING;
- operand->data.p = new string;
- }
- static void copyCreateArrayUse() { start_func
- // @TODO:
- }
- static void copyCreateHashUse() { start_func
- // @TODO:
- }
- static void copyCreateEntityUse() { start_func
- operand = emptyOperand + 2;
- }
- static void copyCreateObjectUse() { start_func
- operand = emptyOperand + 3;
- }
- static void copyStringUse() { start_func
- string* prev = (string*)operand->data.p;
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_STRING;
- operand->data.p = new string(*prev);
- }
- static void copyIntToFloatUse() { start_func
- BCfloat result = (BCfloat)operand->data.i;
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_FLOAT;
- operand->data.f = result;
- }
- static void copyFloatToIntUse() { start_func
- Sint32 result = (Sint32)operand->data.f;
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_INT;
- operand->data.i = result;
- }
- static void copyIntToStringUse() { start_func
- Uint32 val = operand->data.i;
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_STRING;
- operand->data.p = new string(intToStr(val));
- }
- static void copyStringToIntUse() { start_func
- Sint32 result = strToInt(*(string*)operand->data.p);
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_INT;
- operand->data.i = result;
- }
- static void copyFloatToStringUse() { start_func
- BCfloat val = operand->data.f;
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_STRING;
- operand->data.p = new string(floatToStr(val));
- }
- static void copyStringToFloatUse() { start_func
- BCfloat result = strToFloat(*(string*)operand->data.p);
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_FLOAT;
- operand->data.f = result;
- }
- //
- // extractors[]
- //
- // Extracting- always goes in operandData* off of operandGrab
- static void extractInt() { start_func
- interpretAssert(operandGrab->type == STACK_INT);
- operandDataI = operandGrab->data.i;
- }
- static void extractFloat() { start_func
- interpretAssert(operandGrab->type == STACK_FLOAT);
- operandDataF = operandGrab->data.f;
- }
- static void extractStringConst() { start_func
- interpretAssert(operandGrab->type == STACK_STRING);
- operandDataS = ((string*)operandGrab->data.p)->c_str();
- }
- static void extractArray() { start_func
- interpretAssert(operandGrab->type == STACK_ARRAY);
- // @TODO:
- }
- static void extractHash() { start_func
- interpretAssert(operandGrab->type == STACK_HASH);
- // @TODO:
- }
- static void extractEntity() { start_func
- interpretAssert(operandGrab->type == STACK_ENTITY);
- operandDataP = operandGrab->data.p;
- }
- static void extractObject() { start_func
- interpretAssert(operandGrab->type == STACK_OBJECT);
- operandDataP = operandGrab->data.p;
- }
- //
- // grabbers[]
- //
- // Grabbing into operandData*, via operandGrab/2
- static void grabInt() { start_func
- operandDataI = *i_p++;
- }
- static void grabFloat() { start_func
- operandDataF = *((BCfloat*)i_p);
- i_p += bcFloatSize;
- }
- static void grabStringConst() { start_func
- operandDataS = (const char*)(i_p + *i_p);
- ++i_p;
- }
- static void grabThis() { start_func
- operandDataP = entity;
- }
- static void grabNothing() { start_func
- operandDataP = NULL;
- }
- static void grabStack() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operandGrab = stackP.top - 1 - *i_p++;
- extractors[addrmode]();
- }
- // Int/Float optimized due to commonality (@TODO: strconst? all!?)
- static void grabStackInt() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandDataI = (stackP.top - 1 - *i_p++)->data.i;
- }
- static void grabStackFloat() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandDataF = (stackP.top - 1 - *i_p++)->data.f;
- }
- static void grabStackCopy() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operandGrab = stackP.top - 1 - *i_p++;
- interpretAssert(operandGrab->type <= 0x0F);
- // @TODO: can optimize (once we start testing copy/convert)
- // if operand->type is already in the 0xF0 nibble (we don't
- // use operand->type anywhere else but as a dereferencers[] index!)
- // OR flip addrmode! (addrmode is only used with OM_* for this reason!
- // but may be "converted" silently to STACK_* or DATA_* somewhere- see *Write functions)
- copiers[((addrmode & 0x0F) << 4) | operandGrab->type]();
- }
- static void grabLocal() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandGrab = stackP.data + *i_p++;
- extractors[addrmode]();
- }
- // Int/Float optimized due to commonality (@TODO: strconst? all!?)
- static void grabLocalInt() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandDataI = (stackP.data + *i_p++)->data.i;
- }
- static void grabLocalFloat() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandDataF = (stackP.data + *i_p++)->data.f;
- }
- static void grabLocalCopy() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandGrab = stackP.data + *i_p++;
- interpretAssert(operandGrab->type <= 0x0F);
- copiers[((addrmode & 0x0F) << 4) | operandGrab->type]();
- }
- static void grabPop() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
- if (++toDerefPos == toDerefLast) toDerefPos = toDeref;
- operandGrab = toDerefPos;
- interpretAssert(operandGrab->type != STACK_RETURNPTR);
- dereferencers[operandGrab->type](operandGrab);
- *operandGrab = *--stackP.top;
- extractors[addrmode]();
- }
- // Int/Float optimized due to commonality
- // @TODO: versions for other types like strconst? (do for Local/Stack versions too)
- static void grabPopInt() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
- operandDataI = (--stackP.top)->data.i;
- }
- static void grabPopFloat() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
- operandDataF = (--stackP.top)->data.f;
- }
- static void grabPopCopy() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
- operandGrab = --stackP.top;
- interpretAssert(operandGrab->type <= 0x0F);
- // Instead of dereferencing immediately, we just add to the dereferencing array
- // so the copier has the most flexibility (to point to it still, etc.)
- if (++toDerefPos == toDerefLast) toDerefPos = toDeref;
- interpretAssert(toDerefPos->type != STACK_RETURNPTR);
- dereferencers[toDerefPos->type](toDerefPos);
- *toDerefPos = *operandGrab;
- copiers[((addrmode & 0x0F) << 4) | operandGrab->type]();
- }
- //
- // grabbersStore[]
- //
- static void grabStackStore() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = stackP.top - 1 - *i_p++;
- }
- static void grabStackConvertStore() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = stackP.top - 1 - *i_p++;
- interpretAssert(operand->type <= 0x0F);
- converters[((addrmode & 0x0F) << 4) | operand->type]();
- }
- static void grabLocalStore() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operand = stackP.data + *i_p++;
- }
- static void grabLocalConvertStore() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operand = stackP.data + *i_p++;
- interpretAssert(operand->type <= 0x0F);
- converters[((addrmode & 0x0F) << 4) | operand->type]();
- }
- //
- // grabbersWrite[]
- //
- static void grabStackNumWrite() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operandWrite = stackP.top - 1 - *i_p++;
- }
- static void grabStackWrite() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operandWrite = stackP.top - 1 - *i_p++;
- dereferencers[operandWrite->type](operandWrite);
- }
- static void grabLocalNumWrite() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandWrite = stackP.data + *i_p++;
- }
- static void grabLocalWrite() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operandWrite = stackP.data + *i_p++;
- dereferencers[operandWrite->type](operandWrite);
- }
- //
- // grabbersUse[]
- //
- // Grabbing into StackEntry (properly referenced as it's own copy)
- static void grabIntUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_INT;
- operand->data.i = *i_p++;
- }
- static void grabFloatUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_INT;
- operand->data.f = *((BCfloat*)i_p);
- i_p += bcFloatSize;
- }
- static void grabStringUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_STRING;
- operand->data.p = new string((const char*)(i_p + *i_p));
- ++i_p;
- }
- static void grabThisUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- operand->type = STACK_ENTITY;
- operand->data.p = entity;
- Entity::seRefEntity(operand);
- }
- static void grabNothingUse() { start_func
- operand = tempOperand + (tempPos ^= 1);
- // @TODO: faster to assign copy from empty operand?
- operand->type = STACK_ENTITY;
- operand->data.p = NULL;
- }
- static void grabStackUse() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = tempOperand + (tempPos ^= 1);
- *operand = *(stackP.top - 1 - *i_p++);
- referencers[operand->type](operand);
- }
- static void grabStackNumUse() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = stackP.top - 1 - *i_p++;
- }
- static void grabStackCopyUse() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = stackP.top - 1 - *i_p++;
- interpretAssert(operand->type <= 0x0F);
- copiersUse[((addrmode & 0x0F) << 4) | operand->type]();
- }
- static void grabLocalUse() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operand = tempOperand + (tempPos ^= 1);
- *operand = *(stackP.data + *i_p++);
- referencers[operand->type](operand);
- }
- static void grabLocalNumUse() { start_func
- interpretAssert((stackP.top - stackP.data) - *i_p > entity->getEndOfLocals());
- interpretAssert(*i_p < (Uint32)(stackP.top - stackP.data));
- operand = stackP.data + *i_p++;
- }
- static void grabLocalCopyUse() { start_func
- interpretAssert(*i_p < entity->getEndOfLocals());
- operand = stackP.data + *i_p++;
- interpretAssert(operand->type <= 0x0F);
- copiersUse[((addrmode & 0x0F) << 4) | operand->type]();
- }
- static void grabPopUse() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
-
- operand = --stackP.top;
- }
- static void grabPopCopyUse() { start_func
- interpretAssert((Uint32)(stackP.top - stackP.data) > entity->getEndOfLocals());
- operand = --stackP.top;
- interpretAssert(operand->type <= 0x0F);
- converters[((addrmode & 0x0F) << 4) | operand->type]();
- }
- //
- // Opcode functions
- //
- // Standard operand pulling, when it can't be optimized
- #define OPERAND_0 \
- interpretAssert((opdata & 0xFFFFFF00) == 0);
- #define ASSERT_1 \
- interpretAssert(opdata & 0xFF00); \
- interpretAssert((opdata & 0xFFFF0000) == 0);
- #define OPERAND_1 \
- ASSERT_1 \
- grabbers[addrmode = opdata >> 8]();
-
- #define ASSERT_2 \
- interpretAssert(opdata & 0xFF00); \
- interpretAssert(opdata & 0xFF0000); \
- interpretAssert((opdata & 0xFF000000) == 0);
- #define OPERAND_2 \
- ASSERT_2 \
- grabbersStore[addrmode = opdata >> 8](); \
- grabbers[addrmode = opdata >> 16]();
- #define OPERAND_2CI \
- ASSERT_2 \
- grabbers[addrmode = opdata >> 8](); \
- Sint32 operandData2I = operandDataI; \
- grabbers[addrmode = opdata >> 16]();
- #define OPERAND_2CF \
- ASSERT_2 \
- grabbers[addrmode = opdata >> 8](); \
- BCfloat operandData2F = operandDataF; \
- grabbers[addrmode = opdata >> 16]();
- #define OPERAND_2CS \
- ASSERT_2 \
- grabbers[addrmode = opdata >> 8](); \
- const char* operandData2S = operandDataS; \
- grabbers[addrmode = opdata >> 16]();
- #define OPERAND_2CP \
- ASSERT_2 \
- grabbers[addrmode = opdata >> 8](); \
- void* operandData2P = operandDataP; \
- grabbers[addrmode = opdata >> 16]();
- #define ASSERT_3 \
- interpretAssert(opdata & 0xFF00); \
- interpretAssert(opdata & 0xFF0000); \
- interpretAssert(opdata & 0xFF000000);
-
- // Opcodes
- static void op_noop() { start_func
- OPERAND_0
- }
- void Entity::op_init() { start_func
- interpretAssert(entity->runStatus == RUN_INIT);
- OPERAND_0
-
- entity->runStatus = RUN_ACTIVE;
- entity->endOfLocals = stackP.top - stackP.data;
- }
- void Entity::op_idle() { start_func
- OPERAND_0
- entity->runStatus = RUN_IDLE;
- }
- static void op_jump() { start_func
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- ASSERT_1
- // @TODO: + 1 when creating?
- i_p += *((Sint32*)i_p) + 1;
- }
- void Entity::op_ret() { start_func
- interpretAssert(stackP.top);
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- interpretAssert(*i_p + *(i_p + 1) + 2 <= stackP.top - stackP.data - entity->getEndOfLocals());
- ASSERT_2
- // @TODO: this is one opcode that's had no real optimization attempts and
- // yet is reasonably important and should be looked at in more detail due to
- // its length. One specific optimization that probably isn't worth it is if
- // both parameters are 0 AND there's no return pointer, we don't have to do
- // anything. This would be better off as another opcode.
- // Return value
- operand = --stackP.top;
- // Pop function locals
- Uint32 toKill = *i_p++;
- while (toKill--) {
- --stackP.top;
- interpretAssert(stackP.top->type != STACK_RETURNPTR);
- dereferencers[stackP.top->type](stackP.top);
- }
- // (# of parameters)
- toKill = *i_p;
- // Jump back
- i_p = (Uint32*)((--stackP.top)->data.p);
- // @TODO: optimize away RUN_STOPPED and just use i_p=NULL for stopped?
- // @TODO: if stopped, assert stack is locals only left
- if (!i_p)
- entity->runStatus = RUN_STOPPED;
- // Pop parameters
- while (toKill--) {
- --stackP.top;
- interpretAssert(stackP.top->type != STACK_RETURNPTR);
- dereferencers[stackP.top->type](stackP.top);
- }
- // If at least one stack entry left and it's a return ptr...
- // (we don't need to check for endoflocals as locals can never be return ptrs)
- if ((stackP.top != stackP.data) && (stackP.top[-1].type == STACK_RETURNPTR)) {
- // Return or destroy value
- StackEntry* target = (StackEntry*)((--stackP.top)->data.p);
- if (target) {
- interpretAssert(target->type & STACK_REPLYPTR);
- interpretAssert((target->type | ~STACK_REPLYPTR) <= STACK_BASETYPE);
- interpretAssert(((target->type | ~STACK_REPLYPTR) == operand->type) ||
- ((target->type | ~STACK_REPLYPTR) == STACK_UNDEF));
- *target = *operand;
- }
- else {
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- }
- }
- // Otherwise, push back onto stack UNLESS we stopped
- else {
- if (i_p) {
- *stackP.top++ = *operand;
- }
- else {
- interpretAssert(operand->type != STACK_RETURNPTR);
- dereferencers[operand->type](operand);
- }
- }
- }
- void Entity::op_retvoid() { start_func
- interpretAssert(stackP.top);
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- interpretAssert(*i_p + *(i_p + 1) + 1 <= stackP.top - stackP.data - entity->getEndOfLocals());
- ASSERT_2
- // @TODO: this is one opcode that's had no real optimization attempts and
- // yet is reasonably important and should be looked at in more detail due to
- // its length. One specific optimization that probably isn't worth it is if
- // both parameters are 0 AND there's no return pointer, we don't have to do
- // anything. This would be better off as another opcode.
- // Pop function locals
- Uint32 toKill = *i_p++;
- while (toKill--) {
- --stackP.top;
- interpretAssert(stackP.top->type != STACK_RETURNPTR);
- dereferencers[stackP.top->type](stackP.top);
- }
- // (# of parameters)
- toKill = *i_p;
- // Jump back
- i_p = (Uint32*)((--stackP.top)->data.p);
- // @TODO: optimize away RUN_STOPPED and just use i_p=NULL for stopped?
- // @TODO: if stopped, assert stack is locals only left
- if (!i_p)
- entity->runStatus = RUN_STOPPED;
- // Pop parameters
- while (toKill--) {
- --stackP.top;
- interpretAssert(stackP.top->type != STACK_RETURNPTR);
- dereferencers[stackP.top->type](stackP.top);
- }
- // If at least one stack entry left and it's a return ptr...
- // (we don't need to check for endoflocals as locals can never be return ptrs)
- if ((stackP.top != stackP.data) && (stackP.top[-1].type == STACK_RETURNPTR)) {
- // Return empty value
- StackEntry* target = (StackEntry*)((--stackP.top)->data.p);
- if (target) {
- interpretAssert(target->type & STACK_REPLYPTR);
- interpretAssert((target->type | ~STACK_REPLYPTR) <= STACK_BASETYPE);
- // Generate empty of requested type
- // Assumes STACK_UNDEF is 0 otherwise we should have | STACK_UNDEF here
- interpretAssert(STACK_UNDEF == 0);
- copiersUse[(target->type | ~STACK_REPLYPTR) << 4]();
- *target = *operand;
- }
- }
- }
- void Entity::op_stop() { start_func
- interpretAssert(entity->runStatus != RUN_INIT);
- OPERAND_0
-
- entity->runStatus = RUN_STOPPED;
- i_p = NULL;
-
- // wipe stack minus locals (small chance stack is completely empty)
- if (stackP.top) {
- Uint32 toKill = stackP.top - stackP.data - entity->endOfLocals;
- while (toKill--) {
- --stackP.top;
- // (return ptrs ok)
- dereferencers[stackP.top->type](stackP.top);
- }
- }
- }
- static void op_subr() { start_func
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- ASSERT_1
- prepStack(stackP);
- stackP.top->type = STACK_CODEPTR;
- // @TODO: perform + 1 on return? etc
- stackP.top++->data.p = i_p + 1;
- // @TODO: + 1 when creating?
- i_p += *((Sint32*)i_p) + 1;
- }
- void Entity::op_debug() { start_func
- OPERAND_1
-
- // No need to optimize this, and could turn up ANYTHING depending on
- // how we use it
- switch (addrmode) {
- // @TODO: remove the ones of these that can't appear anyway
- // @TODO: add script/object types to @/O
- case OM_ALL:
- debugWrite("%s: @ ALL", entity->getName()->c_str());
- break;
- case OM_ALL_OTHER:
- debugWrite("%s: @ ALL_OTHER", entity->getName()->c_str());
- break;
- case OM_NOTHING:
- debugWrite("%s: @ NOTHING", entity->getName()->c_str());
- break;
- case OM_THIS:
- debugWrite("%s: @ THIS", entity->getName()->c_str());
- break;
- case OM_POINTER:
- debugWrite("%s: * %p", entity->getName()->c_str(), operandDataS);
- break;
- default:
- switch (addrmode & 0x0F) {
- case OM_INT:
- debugWrite("%s: # %d", entity->getName()->c_str(), operandDataI);
- break;
- case OM_FLOAT:
- debugWrite("%s: %% %"BC_FLOAT_PRINTF, entity->getName()->c_str(), operandDataF);
- break;
- case OM_STR_CONST:
- debugWrite("%s: $ %s", entity->getName()->c_str(), operandDataS);
- break;
- case OM_ENTITY:
- if (operandDataP)
- debugWrite("%s: @ %s", entity->getName()->c_str(), ((Entity*)operandDataP)->getName()->c_str());
- else
- debugWrite("%s: @ NOTHING", entity->getName()->c_str());
- break;
- case OM_OBJECT:
- if (operandDataP)
- debugWrite("%s: O %p", entity->getName()->c_str(), operandDataP);
- else
- debugWrite("%s: O NOTHING", entity->getName()->c_str());
- break;
- case OM_ENTRY:
- case OM_ARRAY:
- case OM_HASH:
- // @TODO:
- break;
- }
-
- break;
- }
- }
- static void op_addI() { start_func
- OPERAND_2
- operand->data.i += operandDataI;
- }
- static void op_divI() { start_func
- OPERAND_2
- if (operandDataI)
- operand->data.i /= operandDataI;
- }
- static void op_modI() { start_func
- OPERAND_2
- if (operandDataI)
- operand->data.i %= operandDataI;
- }
- static void op_multI() { start_func
- OPERAND_2
- operand->data.i *= operandDataI;
- }
- static void op_subI() { start_func
- OPERAND_2
- operand->data.i -= operandDataI;
- }
- static void op_addF() { start_func
- OPERAND_2
- operand->data.f += operandDataF;
- }
- static void op_divF() { start_func
- OPERAND_2
- // (allow floating point div/0- results in INF)
- operand->data.f /= operandDataF;
- }
- static void op_multF() { start_func
- OPERAND_2
- operand->data.f *= operandDataF;
- }
- static void op_subF() { start_func
- OPERAND_2
- operand->data.f -= operandDataF;
- }
- static void op_andI() { start_func
- OPERAND_2
- operand->data.i &= operandDataI;
- }
- static void op_orI() { start_func
- OPERAND_2
- operand->data.i |= operandDataI;
- }
- static void op_shiftlI() { start_func
- OPERAND_2
- // Uint so bit shift operators do not sign-extend
- (Uint32&)operand->data.i <<= operandDataI;
- }
- static void op_shiftrI() { start_func
- OPERAND_2
- // Uint so bit shift operators do not sign-extend
- (Uint32&)operand->data.i >>= operandDataI;
- }
- static void op_xorI() { start_func
- OPERAND_2
- operand->data.i ^= operandDataI;
- }
- static void op_concatS() { start_func
- OPERAND_2
-
- ((string*)operand->data.p)->append(operandDataS);
- }
- static void op_iffalseO() { start_func
- interpretAssert((((opdata & 0xFF0000) >> 16) == OM_OBJECT) || (((opdata & 0xFF0000) >> 16) == OM_ENTITY));
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataP == NULL) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iftrueO() { start_func
- interpretAssert((((opdata & 0xFF0000) >> 16) == OM_OBJECT) || (((opdata & 0xFF0000) >> 16) == OM_ENTITY));
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataP) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iffalseI() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataI == 0) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iftrueI() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataI) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iffalseF() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataF == 0.0) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iftrueF() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (operandDataF != 0.0) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iffalseS() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (*operandDataS == 0) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_iftrueS() { start_func
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- ASSERT_2
- grabbers[addrmode = opdata >> 8]();
- // @TODO: + 1 when creating?
- if (*operandDataS) i_p += *((Sint32*)i_p) + 1;
- else ++i_p;
- }
- static void op_eqO() { start_func
- OPERAND_2CP
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2P == operandDataP);
- }
- static void op_neO() { start_func
- OPERAND_2CP
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2P != operandDataP);
- }
- static void op_eqI() { start_func
- OPERAND_2CI
-
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I == operandDataI);
- }
- static void op_geI() { start_func
- OPERAND_2CI
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I >= operandDataI);
- }
- static void op_gtI() { start_func
- OPERAND_2CI
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I > operandDataI);
- }
- static void op_leI() { start_func
- OPERAND_2CI
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I <= operandDataI);
- }
- static void op_ltI() { start_func
- OPERAND_2CI
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I < operandDataI);
- }
- static void op_neI() { start_func
- OPERAND_2CI
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2I != operandDataI);
- }
- static void op_eqF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_FLOAT;
- stackP.top++->data.i = (operandData2F == operandDataF);
- }
- static void op_geF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2F >= operandDataF);
- }
- static void op_gtF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2F > operandDataF);
- }
- static void op_leF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2F <= operandDataF);
- }
- static void op_ltF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2F < operandDataF);
- }
- static void op_neF() { start_func
- OPERAND_2CF
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = (operandData2F != operandDataF);
- }
- static void op_eqS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) == 0;
- }
- static void op_geS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) >= 0;
- }
- static void op_gtS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) > 0;
- }
- static void op_leS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) <= 0;
- }
- static void op_ltS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) < 0;
- }
- static void op_neS() { start_func
- OPERAND_2CS
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = myStricmp(operandData2S, operandDataS) != 0;
- }
- static void op_pushI() { start_func
- OPERAND_1
- prepStack(stackP);
- stackP.top->type = STACK_INT;
- stackP.top++->data.i = operandDataI;
- }
- static void op_pushF() { start_func
- OPERAND_1
- prepStack(stackP);
- stackP.top->type = STACK_FLOAT;
- stackP.top++->data.f = operandDataF;
- }
- // @TODO: Might be faster using grabbersUse (see op_pushAHO)
- static void op_pushS() { start_func
- OPERAND_1
- prepStack(stackP);
- stackP.top->type = STACK_STRING;
- stackP.top++->data.p = new string(operandDataS);
- }
- static void op_pushAHO() { start_func
- // (must prepstack BEFORE pulling operands anytime we use operand+prepstack together)
- prepStack(stackP);
- ASSERT_1
- grabbersUse[addrmode = opdata >> 8]();
- *stackP.top++ = *operand;
- /* @TODO: this code snippet MIGHT be faster, but unlikely
- OPERAND_1
- prepStack(stackP);
- stackP.top->type = STACK_OBJECT;
- stackP.top++->data.p = operandDataP;
- referencers[...];
- */
- }
- static void op_createE() { start_func
- OPERAND_0
- prepStack(stackP);
- stackP.top->type = STACK_ENTITY;
- stackP.top++->data.p = NULL;
- }
- static void op_createO() { start_func
- OPERAND_0
- prepStack(stackP);
- stackP.top->type = STACK_OBJECT;
- stackP.top++->data.p = NULL;
- }
- // @TODO: consolidate into one, if they remain the same; may obsolete grabbersWrite[]
- static void op_storeI() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- static void op_storeF() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- static void op_storeS() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- static void op_storeO() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- static void op_storeA() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- static void op_storeH() { start_func
- ASSERT_2
- grabbersUse[addrmode = opdata >> 8]();
- grabbersWrite[addrmode = opdata >> 16]();
- *operandWrite = *operand;
- }
- // @TODO: these have not been fully optimized yet
- // further opcode splitting may be in order as well-
- // ex: versions that garauntee it's not all/all_other/string/nothing(null)
- static void op_getE() { start_func
- ASSERT_3
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 8]();
- prepStack(stackP);
- // could be NULL (nothing)
- if (operandDataP) {
- stackP.top->data = ((Entity*)operandDataP)->varTable[*i_p++];
- stackP.top->type = *i_p++;
- referencers[stackP.top->type](stackP.top++);
- }
- else {
- interpretAssert(*i_p <= STACK_BASETYPE);
- // Generate empty of requested type
- // Assumes STACK_UNDEF is 0 otherwise we should have | STACK_UNDEF here
- interpretAssert(STACK_UNDEF == 0);
- copiersUse[*i_p++ << 4]();
- *stackP.top++ = *operand;
- }
- }
- static void op_getO() { start_func
- ASSERT_3
- interpretAssert(((opdata & 0xFF0000) >> 16) == OM_INT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbers[addrmode = opdata >> 8]();
- prepStack(stackP);
- // could be NULL (nothing)
- if (operandDataP) {
- stackP.top->data = ((ObjectBase*)operandDataP)->members[*i_p++];
- stackP.top->type = *i_p++;
- referencers[stackP.top->type](stackP.top++);
- }
- else {
- interpretAssert(*i_p <= STACK_BASETYPE);
- // Generate empty of requested type
- // Assumes STACK_UNDEF is 0 otherwise we should have | STACK_UNDEF here
- interpretAssert(STACK_UNDEF == 0);
- copiersUse[*i_p++ << 4]();
- *stackP.top++ = *operand;
- }
- }
- static void op_setE() { start_func
- ASSERT_3
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbersUse[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- swap(((Entity*)operandDataP)->varTable[*i_p++], operand->data);
- dereferencers[operand->type](operand);
- }
- static void op_setO() { start_func
- ASSERT_3
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbersUse[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- swap(((ObjectBase*)operandDataP)->members[*i_p++], operand->data);
- dereferencers[operand->type](operand);
- }
- // Setting float or int can be optimized due to lack of deref need
- // @TODO: but grabbersUse might be faster anyway? dblcheck
- static void op_setEF() { start_func
- ASSERT_3
- interpretAssert((((opdata & 0xFF00) >> 8) & OM_BASETYPE) == OM_FLOAT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbers[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- ((Entity*)operandDataP)->varTable[*i_p++].f = operandDataF;
- }
- static void op_setEI() { start_func
- ASSERT_3
- interpretAssert((((opdata & 0xFF00) >> 8) & OM_BASETYPE) == OM_INT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbers[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- ((Entity*)operandDataP)->varTable[*i_p++].i = operandDataI;
- }
- static void op_setOF() { start_func
- ASSERT_3
- interpretAssert((((opdata & 0xFF00) >> 8) & OM_BASETYPE) == OM_FLOAT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbers[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- ((ObjectBase*)operandDataP)->members[*i_p++].f = operandDataF;
- }
- static void op_setOI() { start_func
- ASSERT_3
- interpretAssert((((opdata & 0xFF00) >> 8) & OM_BASETYPE) == OM_INT);
- interpretAssert(((opdata & 0xFF000000) >> 24) == OM_INT);
- grabbers[addrmode = opdata >> 8]();
- // @TODO: doesn't support all/all_other/string
- grabbers[addrmode = opdata >> 16]();
- if (operandDataP)
- ((ObjectBase*)operandDataP)->members[*i_p++].i = operandDataI;
- }
- static void op_convert() { start_func
- OPERAND_1
- // (do nothing- pulling the operand did the work of converting it)
- // @TODO: Optimization possible, as we're wasting time extracting- grabbersStore?
- }
- static void op_discard() { start_func
- interpretAssert(stackP.top);
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- interpretAssert(*i_p > 0);
- interpretAssert(*i_p <= stackP.top - stackP.data - entity->getEndOfLocals());
- ASSERT_1
-
- Uint32 toKill = *i_p++;
- do {
- --stackP.top;
- // (return ptrs ok)
- dereferencers[stackP.top->type](stackP.top);
- } while (--toKill);
- }
- static void op_discardl() { start_func
- interpretAssert(stackP.top);
- interpretAssert(((opdata & 0xFF00) >> 8) == OM_INT);
- interpretAssert(*i_p > 0);
- interpretAssert(*i_p <= stackP.top - stackP.data - entity->getEndOfLocals());
- ASSERT_1
-
- // if debugging enabled, assert everything discarded is 0/1/2/128
- #ifdef INTERPRETASSERT
- Uint32 toKill = *i_p++;
- do {
- --stackP.top;
- interpretAssert((stackP.top->type == STACK_INT) ||
- (stackP.top->type == STACK_FLOAT) ||
- (stackP.top->type == STACK_UNDEF) ||
- (stackP.top->type == STACK_CODEPTR));
- } while (--toKill);
- #else
- stackP.top -= *i_p++;
- #endif
- }
- //
- // Main interpreter loop
- //
- void Entity::cycle() { start_func
- // Entity must be active and have a script.
- if ((!active) || (!script)) return;
- // If asserts on, we need to handle exceptions
- #ifdef INTERPRETASSERT
- try {
- #endif
-
- // Entity must not be stopped.
- interpretAssert(runStatus != RUN_UNINIT);
- if (runStatus == RUN_STOPPED) return;
- if (runStatus == RUN_IDLE) runStatus = RUN_ACTIVE;
-
- /*
- // @TODO: temp chunk for benchmarking
- int startTicks2 = SDL_GetTicks();
- int a = 1;
- int b = 1;
- while (a < 10000000) {
- a = a + 1;
- if (a & 1) b = b + a;
- }
- debugWrite("(in C ticks: %d)", startTicks2 - SDL_GetTicks(), b);
- debugWrite("%d %d", a, b);
- */
- #ifndef NDEBUG
- int startTicks = SDL_GetTicks();
- if (debugLevel() & DEBUG_INTERPRET)
- debugWrite("%s [", getName()->c_str());
- #endif
- // Prepare state data
- interpretAssert(i);
- i_p = i;
- stackP = stack;
- entity = this;
- do {
- #ifndef NDEBUG
- if (debugLevel() & DEBUG_INTERPRET) {
- string toWrite;
- debugBytecode(toWrite, i_p);
- debugWrite(" %s", toWrite.c_str());
- }
- #endif
-
- // Perform next opcode; includes pulling operands
- // @TODO: assert valid opcode
- opcodes[(opdata = *i_p++) & 0xFF]();
-
- // Loop continuously until an opcode stops us
- // @TODO: could just be == RUN_ACTIVE if we get rid of INIT state
- } while ((runStatus != RUN_STOPPED) && (runStatus != RUN_IDLE));
- // @TODO: reduce stack size if significant empty space?
-
- // Copy changes in state data back
- i = i_p;
- stack = stackP;
- #ifndef NDEBUG
- if (debugLevel() & DEBUG_INTERPRET)
- debugWrite("] %s (ticks: %d)", getName()->c_str(), SDL_GetTicks() - startTicks);
- #endif
- #ifdef INTERPRETASSERT
- }
- catch (InterpretException& e) {
- runStatus = RUN_STOPPED;
- i_p = NULL;
- stack = stackP;
- debugWrite("%s", e.details);
-
- // @TODO: Display runtime error
- }
- #endif
- }
- void Entity::wipeStack() { start_func
- // wipe stack including locals
- if (stack.top) {
- Uint32 toKill = stack.top - stack.data;
- while (toKill--) {
- --stack.top;
- // (return ptrs ok)
- dereferencers[stack.top->type](stack.top);
- }
- }
-
- stack.top = stack.data;
- endOfLocals = 0;
- }
- //
- // Init/deinit
- //
- void fillInterpreterTables() { start_func
- for (int i = 0; i < 256; ++i) {
- converters[i] = interpretError;
- copiers[i] = interpretError;
- copiersUse[i] = interpretError;
- grabbers[i] = interpretError;
- grabbersStore[i] = interpretError;
- grabbersWrite[i] = interpretError;
- grabbersUse[i] = interpretError;
- extractors[i] = interpretError;
- }
- for (int i = 0; i < STACK_TYPE_COUNT; ++i) {
- dereferencers[i] = interpretErrorDeref;
- referencers[i] = interpretErrorDeref;
- }
- // Referencing
- referencers[STACK_INT] = refNothing;
- referencers[STACK_FLOAT] = refNothing;
- referencers[STACK_STRING] = refString;
- referencers[STACK_ARRAY] = refArray;
- referencers[STACK_HASH] = refHash;
- referencers[STACK_ENTITY] = refEntity;
- referencers[STACK_OBJECT] = refObject;
- // Dereferencing
- dereferencers[STACK_UNDEF] = derefNothing;
- dereferencers[STACK_INT] = derefNothing;
- dereferencers[STACK_FLOAT] = derefNothing;
- dereferencers[STACK_STRING] = derefString;
- dereferencers[STACK_ARRAY] = derefArray;
- dereferencers[STACK_HASH] = derefHash;
- dereferencers[STACK_ENTITY] = derefEntity;
- dereferencers[STACK_OBJECT] = derefObject;
- dereferencers[STACK_CODEPTR] = derefNothing;
- dereferencers[STACK_RETURNPTR] = derefReturn;
- for (int i = STACK_INDIRECT; i <= STACK_INDIRECT + STACK_BASETYPE; ++i) {
- dereferencers[i] = derefNothing;
- }
- for (int i = STACK_REPLYPTR; i <= STACK_REPLYPTR + STACK_BASETYPE; ++i) {
- dereferencers[i] = derefReply;
- }
-
- // Existing datatypes that we support (conversion)
- // We support conversion from UNDEF so that we can use these
- // arrays to quickly create empty values of any type as well
- int existTypes[8] = {
- STACK_UNDEF,
- STACK_INT,
- STACK_FLOAT,
- STACK_STRING,
- STACK_ARRAY,
- STACK_HASH,
- STACK_ENTITY,
- STACK_OBJECT,
- };
-
- // Start by assuming every conversion "fails", returning empty
- for (int i = 0; i < 8; ++i) {
- converters[(OM_INT << 4) | existTypes[i]] = convertEmptyToInt;
- copiers[(OM_INT << 4) | existTypes[i]] = copyCreateInt;
- copiersUse[(OM_INT << 4) | existTypes[i]] = copyCreateIntUse;
- converters[(OM_FLOAT << 4) | existTypes[i]] = convertEmptyToFloat;
- copiers[(OM_FLOAT << 4) | existTypes[i]] = copyCreateFloat;
- copiersUse[(OM_FLOAT << 4) | existTypes[i]] = copyCreateFloatUse;
- converters[(OM_STR << 4) | existTypes[i]] = convertEmptyToStr;
- copiers[(OM_STR_CONST << 4) | existTypes[i]] = copyCreateStr;
- copiersUse[(OM_STR_CONST << 4) | existTypes[i]] = copyCreateStrUse;
- converters[(OM_ARRAY << 4) | existTypes[i]] = convertEmptyToArray;
- copiers[(OM_ARRAY << 4) | existTypes[i]] = copyCreateArray;
- copiersUse[(OM_ARRAY << 4) | existTypes[i]] = copyCreateArrayUse;
- converters[(OM_HASH << 4) | existTypes[i]] = convertEmptyToHash;
- copiers[(OM_HASH << 4) | existTypes[i]] = copyCreateHash;
- copiersUse[(OM_HASH << 4) | existTypes[i]] = copyCreateHashUse;
- converters[(OM_ENTITY << 4) | existTypes[i]] = convertEmptyToEntity;
- copiers[(OM_ENTITY << 4) | existTypes[i]] = copyCreateEntity;
- copiersUse[(OM_ENTITY << 4) | existTypes[i]] = copyCreateEntityUse;
- converters[(OM_OBJECT << 4) | existTypes[i]] = convertEmptyToObject;
- copiers[(OM_OBJECT << 4) | existTypes[i]] = copyCreateObject;
- copiersUse[(OM_OBJECT << 4) | existTypes[i]] = copyCreateObjectUse;
- }
-
- // Conversions/copies we explicitly support-
- // int<->float<->string
- // Copy/convert from type to itself also needs to be supported
- // h<->h, a<->a, e<->e, and o<->o are special because the type may match
- // but the subtype needs to be converted
- converters[(OM_INT << 4) | STACK_INT] = doNothing;
- converters[(OM_FLOAT << 4) | STACK_FLOAT] = doNothing;
- converters[(OM_STR << 4) | STACK_STRING] = doNothing;
-
- converters[(OM_INT << 4) | STACK_FLOAT] = convertFloatToInt;
- converters[(OM_INT << 4) | STACK_STRING] = convertStringToInt;
- converters[(OM_FLOAT << 4) | STACK_INT] = convertIntToFloat;
- converters[(OM_FLOAT << 4) | STACK_STRING] = convertStringToFloat;
- converters[(OM_STR << 4) | STACK_INT] = convertIntToString;
- converters[(OM_STR << 4) | STACK_FLOAT] = convertFloatToString;
-
- // Copiers know their value will be unmodified, so if copier
- // needs to do nothing, we can just leave the old reference alone.
- copiers[(OM_INT << 4) | STACK_INT] = extractInt;
- copiers[(OM_FLOAT << 4) | STACK_FLOAT] = extractFloat;
- copiers[(OM_STR_CONST << 4) | STACK_STRING] = extractStringConst;
-
- copiers[(OM_INT << 4) | STACK_FLOAT] = copyFloatToInt;
- copiers[(OM_INT << 4) | STACK_STRING] = copyStringToInt;
- copiers[(OM_FLOAT << 4) | STACK_INT] = copyIntToFloat;
- copiers[(OM_FLOAT << 4) | STACK_STRING] = copyStringToFloat;
- copiers[(OM_STR_CONST << 4) | STACK_INT] = copyIntToString;
- copiers[(OM_STR_CONST << 4) | STACK_FLOAT] = copyFloatToString;
- // @TODO: temp, should be actual copy+convert and for hash/array
- // include making a new copy even if no conversion
- copiers[(OM_ENTITY << 4) | STACK_ENTITY] = extractEntity;
- copiers[(OM_OBJECT << 4) | STACK_OBJECT] = extractObject;
- copiers[(OM_ARRAY << 4) | STACK_ARRAY] = extractArray;
- copiers[(OM_HASH << 4) | STACK_HASH] = extractHash;
-
- // Copiers for use expect their result to be assigned somewhere,
- // but not modified before then, so we just leave the old reference alone.
- copiersUse[(OM_INT << 4) | STACK_INT] = doNothing;
- copiersUse[(OM_FLOAT << 4) | STACK_FLOAT] = doNothing;
- copiersUse[(OM_STR_CONST << 4) | STACK_STRING] = copyStringUse;
- copiersUse[(OM_INT << 4) | STACK_FLOAT] = copyFloatToIntUse;
- copiersUse[(OM_INT << 4) | STACK_STRING] = copyStringToIntUse;
- copiersUse[(OM_FLOAT << 4) | STACK_INT] = copyIntToFloatUse;
- copiersUse[(OM_FLOAT << 4) | STACK_STRING] = copyStringToFloatUse;
- copiersUse[(OM_STR_CONST << 4) | STACK_INT] = copyIntToStringUse;
- copiersUse[(OM_STR_CONST << 4) | STACK_FLOAT] = copyFloatToStringUse;
- /* @TODO:
-
- converters[(OM_ENTITY << 4) | STACK_ENTITY] (ensure if subtype doesn't match, = NULL)
- converters[(OM_OBJECT << 4) | STACK_OBJECT] (ensure if subtype doesn't match, = NULL)
- converters[(OM_ARRAY << 4) | STACK_ARRAY]
- converters[(OM_HASH << 4) | STACK_HASH]
- @TODO: copiers, note that copying to an entity/object doesn't need
- to be dereferenced if we choose to just not ref++ it in the first place!
-
- copiersUse needs to always ++ref even if nothing changes (entity/object)
-
- both types of copiers for array/hash ALWAYS create a new copy even if no change.
-
- */
-
- // Grabbers
- grabbers[OM_INT] = grabInt;
- grabbers[OM_FLOAT] = grabFloat;
- grabbers[OM_STR_CONST] = grabStringConst;
- // @TODO: OM_ALL
- // @TODO: OM_ALL_OTHER
- grabbers[OM_NOTHING] = grabNothing;
- grabbers[OM_THIS] = grabThis;
- // @TODO: OM_POINTER?
-
- grabbersUse[OM_INT] = grabIntUse;
- grabbersUse[OM_FLOAT] = grabFloatUse;
- grabbersUse[OM_STR_CONST] = grabStringUse;
- // @TODO: OM_ALL
- // @TODO: OM_ALL_OTHER
- grabbersUse[OM_NOTHING] = grabNothingUse;
- grabbersUse[OM_THIS] = grabThisUse;
- // @TODO: OM_POINTER?
-
- for (int i = OM_STACK; i < OM_STACK + OM_BASETYPE; ++i) {
- grabbersStore[i] = grabStackConvertStore;
- grabbersWrite[i] = grabStackWrite;
- }
- for (int i = OM_LOCAL; i < OM_LOCAL + OM_BASETYPE; ++i) {
- grabbersStore[i] = grabLocalConvertStore;
- grabbersWrite[i] = grabLocalWrite;
- }
- for (int i = OM_GLOBAL; i < OM_GLOBAL + OM_BASETYPE; ++i) {
- grabbersStore[i] = interpretError; // @TODO: global+convert-in-place
- grabbersWrite[i] = interpretError; // @TODO: global+convert-in-place
- }
- for (int i = OM_POP + OM_NO_CONVERT; i < OM_POP + OM_NO_CONVERT + OM_BASETYPE; ++i) {
- grabbers[i] = grabPop;
- grabbersUse[i] = grabPopUse;
- }
- grabbers[OM_POP + OM_NO_CONVERT + OM_INT] = grabPopInt;
- grabbers[OM_POP + OM_NO_CONVERT + OM_FLOAT] = grabPopFloat;
- // @TODO: specialized POP+ConstStr (shouldn't be able to have POP+Str)
- for (int i = OM_STACK + OM_NO_CONVERT; i < OM_STACK + OM_NO_CONVERT + OM_BASETYPE; ++i) {
- grabbers[i] = grabStack;
- grabbersStore[i] = grabStackStore;
- grabbersWrite[i] = grabStackWrite;
- grabbersUse[i] = grabStackUse;
- }
- grabbers[OM_STACK + OM_NO_CONVERT + OM_INT] = grabStackInt;
- grabbers[OM_STACK + OM_NO_CONVERT + OM_FLOAT] = grabStackFloat;
- grabbersUse[OM_STACK + OM_NO_CONVERT + OM_INT] = grabStackNumUse;
- grabbersUse[OM_STACK + OM_NO_CONVERT + OM_FLOAT] = grabStackNumUse;
- grabbersWrite[OM_STACK + OM_NO_CONVERT + OM_INT] = grabStackNumWrite;
- grabbersWrite[OM_STACK + OM_NO_CONVERT + OM_FLOAT] = grabStackNumWrite;
- for (int i = OM_LOCAL + OM_NO_CONVERT; i < OM_LOCAL + OM_NO_CONVERT + OM_BASETYPE; ++i) {
- grabbers[i] = grabLocal;
- grabbersStore[i] = grabLocalStore;
- grabbersWrite[i] = grabLocalWrite;
- grabbersUse[i] = grabLocalUse;
- }
- grabbers[OM_LOCAL + OM_NO_CONVERT + OM_INT] = grabLocalInt;
- grabbers[OM_LOCAL + OM_NO_CONVERT + OM_FLOAT] = grabLocalFloat;
- grabbersUse[OM_LOCAL + OM_NO_CONVERT + OM_INT] = grabLocalNumUse;
- grabbersUse[OM_LOCAL + OM_NO_CONVERT + OM_FLOAT] = grabLocalNumUse;
- grabbersWrite[OM_LOCAL + OM_NO_CONVERT + OM_INT] = grabLocalNumWrite;
- grabbersWrite[OM_LOCAL + OM_NO_CONVERT + OM_FLOAT] = grabLocalNumWrite;
- for (int i = OM_GLOBAL + OM_NO_CONVERT; i < OM_GLOBAL + OM_NO_CONVERT + OM_BASETYPE; ++i) {
- grabbers[i] = interpretError; // @TODO: global+no-convert
- grabbersStore[i] = interpretError; // @TODO: global+no-convert
- grabbersWrite[i] = interpretError; // @TODO: global+no-convert
- grabbersUse[i] = interpretError; // @TODO: global+no-convert
- }
- // @TODO: global+no-convert+int/float
- for (int i = OM_POP + OM_COPY; i < OM_POP + OM_COPY + OM_BASETYPE; ++i) {
- grabbers[i] = grabPopCopy;
- grabbersUse[i] = grabPopCopyUse;
- }
- for (int i = OM_STACK + OM_COPY; i < OM_STACK + OM_COPY + OM_BASETYPE; ++i) {
- grabbers[i] = grabStackCopy;
- grabbersUse[i] = grabStackCopyUse;
- }
- for (int i = OM_LOCAL + OM_COPY; i < OM_LOCAL + OM_COPY + OM_BASETYPE; ++i) {
- grabbers[i] = grabLocalCopy;
- grabbersUse[i] = grabLocalCopyUse;
- }
- for (int i = OM_GLOBAL + OM_COPY; i < OM_GLOBAL + OM_COPY + OM_BASETYPE; ++i) {
- grabbers[i] = interpretError; // @TODO: global+copy-convert
- grabbersUse[i] = interpretError; // @TODO: global+copy-convert
- }
-
- /* @TODO: indirects (unsure which modes will be needed yet)
-
- for (int i = OM_POP + OM_INDIRECT; i < OM_POP + OM_INDIRECT + OM_BASETYPE; ++i) {
- grabbers[i] = interpretError;
- grabbersStore[i] = interpretError;
- grabbersWrite[i] = interpretError;
- grabbersUse[i] = interpretError;
- }
- for (int i = OM_STACK + OM_INDIRECT; i < OM_STACK + OM_INDIRECT + OM_BASETYPE; ++i) {
- grabbers[i] = interpretError;
- grabbersStore[i] = interpretError;
- grabbersWrite[i] = interpretError;
- grabbersUse[i] = interpretError;
- }
-
- */
- // Extractors
- for (int i = 0; i < 256; i += 16) {
- extractors[i + OM_INT] = extractInt;
- extractors[i + OM_FLOAT] = extractFloat;
- // (should never occur) extractors[i + OM_STR] = extractStringConst;
- extractors[i + OM_STR_CONST] = extractStringConst;
- extractors[i + OM_ARRAY] = extractArray;
- extractors[i + OM_HASH] = extractHash;
- extractors[i + OM_ENTITY] = extractEntity;
- extractors[i + OM_OBJECT] = extractObject;
- }
-
- // Opcodes
- opcodes[OP_NOOP] = op_noop;
- opcodes[OP_ADD] = op_addI;
- opcodes[OP_ADDf] = op_addF;
- opcodes[OP_AND] = op_andI;
- opcodes[OP_CONCAT] = op_concatS;
- opcodes[OP_CONVERT] = op_convert;
- opcodes[OP_CREATEa] = interpretError; // @TODO:
- opcodes[OP_CREATEe] = op_createE;
- opcodes[OP_CREATEh] = interpretError; // @TODO:
- opcodes[OP_CREATEo] = op_createO;
- opcodes[OP_DEBUG] = Entity::op_debug;
- opcodes[OP_DISCARD] = op_discard;
- opcodes[OP_DISCARDL] = op_discardl;
- opcodes[OP_DIV] = op_divI;
- opcodes[OP_DIVf] = op_divF;
- opcodes[OP_EQ] = op_eqI;
- opcodes[OP_EQf] = op_eqF;
- opcodes[OP_EQo] = op_eqO;
- opcodes[OP_EQs] = op_eqS;
- opcodes[OP_GE] = op_geI;
- opcodes[OP_GEf] = op_geF;
- opcodes[OP_GEs] = op_geS;
- opcodes[OP_GT] = op_gtI;
- opcodes[OP_GTf] = op_gtF;
- opcodes[OP_GTs] = op_gtS;
- opcodes[OP_IFFALSE] = op_iffalseI;
- opcodes[OP_IFFALSEa] = interpretError; // @TODO:
- opcodes[OP_IFFALSEf] = op_iffalseF;
- opcodes[OP_IFFALSEh] = interpretError; // @TODO:
- opcodes[OP_IFFALSEo] = op_iffalseO;
- opcodes[OP_IFFALSEs] = op_iffalseS;
- opcodes[OP_IFFALSEv] = interpretError; // @TODO:
- opcodes[OP_IFTRUE] = op_iftrueI;
- opcodes[OP_IFTRUEa] = interpretError; // @TODO:
- opcodes[OP_IFTRUEf] = op_iftrueF;
- opcodes[OP_IFTRUEh] = interpretError; // @TODO:
- opcodes[OP_IFTRUEo] = op_iftrueO;
- opcodes[OP_IFTRUEs] = op_iftrueS;
- opcodes[OP_IFTRUEv] = interpretError; // @TODO:
- opcodes[OP_INIT] = Entity::op_init;
- opcodes[OP_JUMP] = op_jump;
- opcodes[OP_LE] = op_leI;
- opcodes[OP_LEf] = op_leF;
- opcodes[OP_LEs] = op_leS;
- opcodes[OP_LT] = op_ltI;
- opcodes[OP_LTf] = op_ltF;
- opcodes[OP_LTs] = op_ltS;
- opcodes[OP_MOD] = op_modI;
- opcodes[OP_MULT] = op_multI;
- opcodes[OP_MULTf] = op_multF;
- opcodes[OP_NE] = op_neI;
- opcodes[OP_NEf] = op_neF;
- opcodes[OP_NEo] = op_neO;
- opcodes[OP_NEs] = op_neS;
- opcodes[OP_OR] = op_orI;
- opcodes[OP_PUSH] = op_pushI;
- opcodes[OP_PUSHa] = op_pushAHO;
- opcodes[OP_PUSHf] = op_pushF;
- opcodes[OP_PUSHh] = op_pushAHO;
- opcodes[OP_PUSHo] = op_pushAHO;
- opcodes[OP_PUSHs] = op_pushS;
- opcodes[OP_PUSHv] = interpretError; // @TODO:
- opcodes[OP_RET] = Entity::op_ret;
- opcodes[OP_SHIFTL] = op_shiftlI;
- opcodes[OP_SHIFTR] = op_shiftrI;
- opcodes[OP_STOP] = Entity::op_stop;
- opcodes[OP_STORE] = op_storeI;
- opcodes[OP_STOREa] = op_storeA;
- opcodes[OP_STOREf] = op_storeF;
- opcodes[OP_STOREh] = op_storeH;
- opcodes[OP_STOREo] = op_storeO;
- opcodes[OP_STOREs] = op_storeS;
- opcodes[OP_STOREv] = interpretError; // @TODO:
- opcodes[OP_SUB] = op_subI;
- opcodes[OP_SUBf] = op_subF;
- opcodes[OP_SUBR] = op_subr;
- opcodes[OP_XOR] = op_xorI;
- opcodes[OP_GETe] = op_getE;
- opcodes[OP_SETe] = op_setE;
- opcodes[OP_GETo] = op_getO;
- opcodes[OP_SETo] = op_setO;
- opcodes[OP_IDLE] = Entity::op_idle;
- opcodes[OP_RETVOID] = Entity::op_retvoid;
- opcodes[OP_SETef] = op_setEF;
- opcodes[OP_SETei] = op_setEI;
- opcodes[OP_SETof] = op_setOF;
- opcodes[OP_SEToi] = op_setOI;
- // Empty operands
- emptyOperand[0].data.i = 0;
- emptyOperand[0].type = STACK_INT;
- emptyOperand[1].data.f = 0.0;
- emptyOperand[1].type = STACK_FLOAT;
- emptyOperand[2].data.p = NULL;
- emptyOperand[2].type = STACK_ENTITY;
- emptyOperand[3].data.p = NULL;
- emptyOperand[3].type = STACK_OBJECT;
- // Init deref array
- for (int i = 0; i < MAX_TODEREF; ++i) {
- toDeref[i].data.i = 0;
- toDeref[i].type = STACK_INT;
- }
- }
- void interpreterCleanup() { start_func
- // Clear deref array
- for (int i = 0; i < MAX_TODEREF; ++i) {
- dereferencers[toDeref[i].type](toDeref + i);
- toDeref[i].data.i = 0;
- toDeref[i].type = STACK_INT;
- }
- }
|