diff options
Diffstat (limited to 'Src/Wasabi/api/script/vcpu.cpp')
-rw-r--r-- | Src/Wasabi/api/script/vcpu.cpp | 2069 |
1 files changed, 2069 insertions, 0 deletions
diff --git a/Src/Wasabi/api/script/vcpu.cpp b/Src/Wasabi/api/script/vcpu.cpp new file mode 100644 index 00000000..1002ee57 --- /dev/null +++ b/Src/Wasabi/api/script/vcpu.cpp @@ -0,0 +1,2069 @@ +#include <precomp.h> +#include <wasabicfg.h> +#include <api/skin/widgets/mb/scriptbrowser.h> +#include <api/script/scriptmgr.h> +#include <api/script/script.h> +#include "vcpu.h" +#include "opcodes.h" +#include <api/wndmgr/container.h> +#include <api/wndmgr/msgbox.h> +#include <api/script/objecttable.h> +#include <api/syscb/callbacks/consolecb.h> +#include "../nu/AutoWide.h" + +ScriptObjectManager *VCPU::scriptManager = NULL; + +void VCPU::shutdown() +{ + foreach(globalDlfList) + FREE(globalDlfList.getfor()->functionName); + delete globalDlfList.getfor(); + endfor + globalDlfList.removeAll(); + atoms.deleteAll(); +} + +// ------------------------------------------------------------- +void VCPU::push(VCPUscriptVar v) { + CpuStack.push(v); + VSP++; +} + +// ------------------------------------------------------------- +void VCPU::push(scriptVar v) { + VCPUscriptVar _v; + _v.v = v; + CpuStack.push(_v); + VSP++; +} + +void VCPU::RemoveOldScripts() +{ + while (scriptsToRemove.getNumItems()) + { + int id = scriptsToRemove.getFirst(); + VCPU::removeScript(id); + scriptsToRemove.delByPos(0); + } +} + +// ------------------------------------------------------------- +VCPUscriptVar VCPU::pop() { + if (VSP <= 0) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_POPEMPTYSTACK); + VCPUscriptVar v; + MEMSET(&v, 0, sizeof(v)); + return v; +// ASSERT(0); + } + VCPUscriptVar v; + CpuStack.pop(&v); + VSP--; + if (VSP == 0) + VCPU::RemoveOldScripts(); // benski> TODO: dunno if this is the best place for this + return v; +} + +// ------------------------------------------------------------- +VCPUscriptVar VCPU::peekAt(int n) { + if (VSP <= n) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_INVALIDPEEKSTACK); + VCPUscriptVar v; + MEMSET(&v, 0, sizeof(v)); + return v; +// ASSERT(0); + } + VCPUscriptVar v={0,{0},0}; + CpuStack.peekAt(&v, n); + return v; +} + +// ------------------------------------------------------------- +int VCPU::assignNewScriptId() { + return numScripts++; +} + +// ------------------------------------------------------------- +int VCPU::oldClassToClassId(int id) { + if (id < SCRIPT_OBJECT) return id; + if (id >= 0x10000) return id; + switch (id) { + case 7 : return ObjectTable::getClassFromName(L"Object"); + case 8 : return ObjectTable::getClassFromName(L"SystemObject"); + case 9 : return ObjectTable::getClassFromName(L"Container"); + case 10: return ObjectTable::getClassFromName(L"Layout"); + case 11: return ObjectTable::getClassFromName(L"Button"); + case 12: return ObjectTable::getClassFromName(L"Slider"); + case 13: return ObjectTable::getClassFromName(L"Text"); + case 14: return ObjectTable::getClassFromName(L"Image"); + case 15: return ObjectTable::getClassFromName(L"Anim"); + case 16: return ObjectTable::getClassFromName(L"Vis"); + case 17: return ObjectTable::getClassFromName(L"Component"); + case 18: return ObjectTable::getClassFromName(L"ToggleButton"); + case 19: return ObjectTable::getClassFromName(L"Timer"); + case 20: return ObjectTable::getClassFromName(L"Layer"); + case 21: return ObjectTable::getClassFromName(L"GuiObject"); + case 22: return ObjectTable::getClassFromName(L"AnimatedLayer"); + case 23: return ObjectTable::getClassFromName(L"Browser"); + case 24: return ObjectTable::getClassFromName(L"Edit"); + case 25: return ObjectTable::getClassFromName(L"Map"); + case 26: return ObjectTable::getClassFromName(L"Popup"); + case 27: return ObjectTable::getClassFromName(L"Title"); + case 28: return ObjectTable::getClassFromName(L"ComponentBucket"); + case 29: return ObjectTable::getClassFromName(L"Status"); + case 30: return ObjectTable::getClassFromName(L"Region"); + case 31: return ObjectTable::getClassFromName(L"Wac"); + case 32: return ObjectTable::getClassFromName(L"List"); + case 33: return ObjectTable::getClassFromName(L"SBitList"); + case 34: return ObjectTable::getClassFromName(L"SEqVis"); + default: Script::guruMeditation(NULL, GURU_INVALIDOLDID, L"xlat error", id); + break; + } + return SCRIPT_INT; // heh =) +} + + +// ------------------------------------------------------------- +int VCPU::addScript(void *mem, int memsize, int id) { + + int i,j; + int translateobjects = 0; + + char *p = (char *)mem; + + int hdr=0; + if (!MEMCMP(p, "FG\x03\x04\x14\00\00\00\00", 8)) + hdr=1; + else if (!MEMCMP(p, "FG\x03\x04\x15\00\00\00\00", 8)) + hdr=2; + else if (!MEMCMP(p, "FG\x03\x04\x16\00\00\00\00", 8)) + hdr=3; + else if (!MEMCMP(p, "FG\x03\x04\x17\00\00\00\00", 8)) + hdr=4; + else if (!MEMCMP(p, "FG\x03\x04", 4)) { + if (*(p+4) > 0x17) + hdr = -1; + } + + switch (hdr) { + case -1: + Script::guruMeditation(SOM::getSystemObjectByScriptId(id), GURU_FUTUREFORMAT, L"NEED LATEST VERSION"); + return -1; + case 0: + Script::guruMeditation(SOM::getSystemObjectByScriptId(id), GURU_INVALIDHEADER); + return -1; + case 1: + Script::guruMeditation(SOM::getSystemObjectByScriptId(id), GURU_OLDFORMAT, L"DEPRECATED BINARY"); + return -1; + case 2: + translateobjects=1; + break; + case 3: + case 4: + break; + } + + SOM::getSystemObjectByScriptId(id)->setIsOldFormat(translateobjects); + + p+=8; + + TList<int> *typetable = SOM::getSystemObjectByScriptId(id)->getTypesList(); + typetable->removeAll(); + + if (!translateobjects) { + + int nGuids = *(int *)p; + p+=sizeof(int); + + for (int z=0;z<nGuids;z++) { + GUID g; + MEMCPY(&g, p, sizeof(GUID)); + p+=sizeof(GUID); + char zz[256] = {0}; + nsGUID::toChar(g, zz); + int t = ObjectTable::getClassFromGuid(g); + if (t == -1) { + DebugStringW(L"maki class entry %d not found : %s\n", z, zz); +// __asm int 3; + } + typetable->addItem(t); + } + } + + // ------------------------------------------------------------- + // Load DLF Table + + int DLFEntryBase = DLFentryTable.getNumItems(); + + int nDLFentries = *(int *)p; + p+=sizeof(int); + + for (i=0;i<nDLFentries;i++) { + + int basetype = *(int *)p; + int pt = basetype; + int type = basetype; + p+=sizeof(int); + + if (translateobjects) { + basetype = oldClassToClassId(basetype); + } else + if (basetype >= CLASS_ID_BASE && basetype < 0x10000) + basetype = typetable->enumItem(basetype - CLASS_ID_BASE); + + if (basetype == -1) { +//CUT!!!! so annoying Std::messageBox("Error while loading a script, a component is missing", "Oops", 0); + DebugStringW(L"Tried to link DLF %d (class entry %d) but the class isn't here\n", i, pt - CLASS_ID_BASE); + //return -1; + } + + type = basetype; + + uint16_t stringLen = *(uint16_t *)p; + p+=sizeof(uint16_t); + char functionName[65536+1] = {0}; + MEMCPY(functionName, p, stringLen); + functionName[stringLen]=0; + p+=stringLen; + + // check if entry seems valid + + if (!*functionName) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(id), GURU_INVALIDFUNCINDLF); +// api->messageBox("Invalid function name in DLF table", "Script Error", MSGBOX_OK, NULL, NULL); + return -1; + } + + // ok, register this function + VCPUdlfEntry *e = new VCPUdlfEntry; + e->basetype = type; +#ifdef _WIN32 + int size = MultiByteToWideChar(CP_UTF8, 0, functionName, -1, 0,0); + if (size) + { + wchar_t *wide = (wchar_t *)MALLOC(size*sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, functionName, -1, wide,size); + e->functionName = wide; + } + else + e->functionName = 0; +#else + e->functionName = WCSDUP(AutoWide(functionName)); +#warning port me +#endif + e->scriptId = id; + // insert safe values + e->nparams = -1; + e->DLFid = -1; + e->ptr = NULL; + DLFentryTable.addItem(e); + + setupDLF(e, DLFEntryBase); + + } + + // ------------------------------------------------------------- + // Load VAR Table + + int variableBase = variablesTable.getNumItems(); + + int nVariables = *(int *)p; + p+=sizeof(int); + + for (i=0;i<nVariables;i++) { + scriptVar e; + MEMCPY(&e, p, sizeof(scriptVar)); + p+=sizeof(scriptVar); + + VCPUscriptVar *v = new VCPUscriptVar; + v->isaclass = 0; + + if (e.type >= 0x10000) { + int type = e.type; + int id; + + do { + id = type - 0x10000; + VCPUscriptVar *v = variablesTable.enumItem(id+variableBase); + v->isaclass = 1; + type = v->v.type; + } while (type >= 0x10000); + + } + + if (translateobjects) { + e.type = oldClassToClassId(e.type); + } else + if (e.type >= CLASS_ID_BASE && e.type < 0x10000) + e.type = typetable->enumItem(e.type - CLASS_ID_BASE); + + v->scriptId = id; + v->varId = i; + v->transcient = (*p++ == 0); + if (hdr >= 4) + v->isstatic = *p++; + else + v->isstatic = 0; + + if (hdr < 4) { + // Autoassign system variables + if (e.type == ObjectTable::getClassFromName(L"SystemObject")) { + SystemObject *so = SOM::getSystemObjectByScriptId(id); + if (so) e.data.odata = so->getScriptObject(); else e.data.odata = NULL; + } + } else { + if (v->isstatic && e.type == ObjectTable::getClassFromName(L"SystemObject")) { + SystemObject *so = SOM::getSystemObjectByScriptId(id); + if (so) e.data.odata = so->getScriptObject(); else e.data.odata = NULL; + v->isstatic = 0; // disable deletion + } else if (v->isstatic) { + // Autoassign class variables + e.data.odata = ObjectTable::instantiate(e.type); + if (e.data.odata) + e.data.odata->vcpu_setScriptId(VSD); + } + } + + if (e.type == SCRIPT_STRING) + { + wchar_t *emptyString = WMALLOC(1); + emptyString[0]=0; + e.data.sdata = emptyString; + } + + if (e.type == SCRIPT_DOUBLE) + e.data.ddata = e.data.fdata; + + v->v = e; + variablesTable.addItem(v); + } + + // ------------------------------------------------------------- + // Load Strings into string vars + + int nStrings = *(int *)p; + p+=sizeof(int); + + j=0; + //CUT: int count=0; + + char string_buf[65536+1] = {0}; + for (i=0;i<nStrings;i++) + { + int attach_id = *(int *)p; + p+=4; + uint16_t stringLen = *(uint16_t *)p; + p+=2; + //char *string; + //string = (char *)MALLOC(stringLen+1); + MEMCPY(string_buf, p, stringLen); + string_buf[stringLen]=0; + p+=stringLen; + + // find next variable in this script that needs a string attached, and attach it + VCPUscriptVar *v = variablesTable.enumItem(attach_id+variableBase); + if (!v) + { + Script::guruMeditation(SOM::getSystemObjectByScriptId(id), GURU_EXCEPTION, L"Invalid String ID"); + return -1; + } + FREE((wchar_t *)(v->v.data.sdata)); + // strings are stored in UTF-8, but we're using UTF-16 here +#ifdef _WIN32 + int size = MultiByteToWideChar(CP_UTF8, 0, string_buf, -1, 0,0); + if (size) + { + wchar_t *wide = (wchar_t *)MALLOC(size*sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, string_buf, -1, wide,size); + v->v.data.sdata = wide; + } + else + v->v.data.sdata = 0; + +#else +#warning port me + // TODO: benski> change to do one malloc + v->v.data.sdata = WCSDUP(AutoWide(string_buf)); +#endif + //FREE(string); + + } + + + // ------------------------------------------------------------- + // Load Events into table + + int nEvents = *(int *)p; + p+=sizeof(int); + + for (i=0;i<nEvents;i++) { + + int varId = *(int *)p; + p+=sizeof(int); + int DLFentry = *(int *)p; + p+=sizeof(int); + int pointer = *(int *)p; + p+=sizeof(int); + + // check if this event seems valid + if (DLFentry >= nDLFentries || DLFentry < 0) { +// api->messageBox("Invalid event DLF descriptor", "Script Error", MSGBOX_OK, NULL, NULL); + Script::guruMeditation(SOM::getSystemObjectByScriptId(id), GURU_INVALIDEVENTDLF); + return -1; + } + + if (pointer < 0) { +// api->messageBox("Invalid event address", "Script Error", MSGBOX_OK, NULL, NULL); + Script::guruMeditation(SOM::getSystemObjectByScriptId(id), GURU_INVALIDEVENTADDR); + return -1; + } + + if (varId < 0 || varId >= nVariables) { +// api->messageBox("Invalid event variable", "Script Error", MSGBOX_OK, NULL, NULL); + Script::guruMeditation(SOM::getSystemObjectByScriptId(id), GURU_INVALIDEVENTVAR); + return -1; + } + + // insert event into table + + VCPUeventEntry *e = new VCPUeventEntry; + //e->DLFentry = DLFentry + DLFEntryBase; + e->DLFid = DLFentryTable.enumItem(DLFEntryBase+DLFentry)->DLFid; + e->pointer = pointer; + e->scriptId = id; + e->varId = varId; + + eventsTable.addItem(e); + } + + // ------------------------------------------------------------- + // Load Code block into code table + + int codeSize = *(int *)p; + p+=sizeof(int); + VCPUcodeBlock *c = new VCPUcodeBlock; + c->codeBlock = p; + c->dlfBase = DLFEntryBase; + c->varBase = variableBase; + c->scriptId = id; + c->size = codeSize; + + codeTable.addItem(c); + + SystemObject *so = SOM::getSystemObjectByScriptId(id); + if (so) { + ScriptObject *sso = so->getScriptObject(); + if (sso) + sso->vcpu_addAssignedVariable(0, id); + } + + cacheCount++; + + c->debugsymbols = c->codeBlock+codeSize; + c->debugsize = memsize - (c->debugsymbols-(char *)mem); + + //WASABI_API_MAKIDEBUG->debugger_createJITD(id); // fucko !! + + return id; +} + + +// ------------------------------------------------------------- +int VCPU::varBase(int scriptId) { + static int lasti=-1;; + static int lastb=0; + static int lastid=0; + if (lastid == scriptId && lasti>=0 && lasti < codeTable.getNumItems()) { + if (lastid == codeTable.enumItem(lasti)->scriptId) + return lastb; + } + for (int i=0;i<codeTable.getNumItems();i++ ){ + if (codeTable.enumItem(i)->scriptId == scriptId) { + lasti = i; + lastid = scriptId; + lastb = codeTable.enumItem(i)->varBase; + return lastb; + } + } + Script::guruMeditation(SOM::getSystemObjectByScriptId(scriptId), GURU_INVALIDSCRIPTID); + ASSERT(0); + return 0; +} + +// ------------------------------------------------------------- +int VCPU::nVars(int scriptId) { + for (int i=0;i<codeTable.getNumItems();i++ ){ + if (codeTable.enumItem(i)->scriptId == scriptId) { + if (codeTable.getNumItems() == i+1) + return variablesTable.getNumItems() - codeTable.enumItem(i)->varBase; + return codeTable.enumItem(i+1)->varBase - codeTable.enumItem(i)->varBase; + } + } + Script::guruMeditation(SOM::getSystemObjectByScriptId(scriptId), GURU_INVALIDSCRIPTID); + ASSERT(0); + return 0; +} + +// ------------------------------------------------------------- +int VCPU::dlfBase(int scriptId) { + for (int i=0;i<codeTable.getNumItems();i++ ){ + if (codeTable.enumItem(i)->scriptId == scriptId) + return codeTable.enumItem(i)->dlfBase; + } + Script::guruMeditation(SOM::getSystemObjectByScriptId(scriptId), GURU_INVALIDSCRIPTID); + ASSERT(0); + return 0; +} + +// ------------------------------------------------------------- +void VCPU::removeScript(int id) +{ +// ASSERTPR(VCPU::VSP==0, "Can't unload script while in script"); + if (VCPU::VSP != 0) + { + scriptsToRemove.addItem(id); + return; + } + + SystemObject *s = SOM::getSystemObjectByScriptId(id); + if (s) + { + s->onUnload(); + delete s; + } + + PtrList<ScriptObject> *l = SystemObject::getAllScriptObjects(); + int i; + for (i=0;i<l->getNumItems();i++) { + ScriptObject *o = l->enumItem(i); + o->vcpu_delMembers(id); + } + + int dlfdeleted=0; + int vardeleted=0; + + for (i=0;i<DLFentryTable.getNumItems();i++) { + if (DLFentryTable.enumItem(i)->scriptId == id) { + delrefDLF(DLFentryTable.enumItem(i)); + if (DLFentryTable.enumItem(i)->functionName) + FREE(DLFentryTable.enumItem(i)->functionName); + delete DLFentryTable.enumItem(i); + DLFentryTable.delByPos(i); + dlfdeleted++; + i--; + } + } + + for (i=0;i<eventsTable.getNumItems();i++) { + if (eventsTable.enumItem(i)->scriptId == id) { + delete eventsTable.enumItem(i); + eventsTable.delByPos(i); + i--; + } + } + + for (i=0;i<variablesTable.getNumItems();i++) { + if (variablesTable.enumItem(i)->scriptId == id) { + VCPUscriptVar *v = variablesTable.enumItem(i); + if (v->isstatic && v->v.type) { + ObjectTable::destroy(v->v.data.odata); + } + if (v->v.type == SCRIPT_STRING) + if (v->v.data.sdata) + FREE((wchar_t *)v->v.data.sdata); + delete v; + variablesTable.delByPos(i); + vardeleted++; + i--; + } + } + + for (i=0;i<codeTable.getNumItems();i++) { + if (codeTable.enumItem(i)->scriptId == id) { + VCPUcodeBlock *b = codeTable.enumItem(i); + delete b; + codeTable.removeByPos(i); + for (;i<codeTable.getNumItems();i++) { + codeTable.enumItem(i)->dlfBase-=dlfdeleted; + codeTable.enumItem(i)->varBase-=vardeleted; + } + } + } + + + cacheCount++; +} + +// ------------------------------------------------------------- +// Find next matching object, starting from start +int VCPU::findObject(ScriptObject *o, int start, int dlfid, int vcpuid) { +/* int stop; + if (vcpuid != -1) { + int b = varBase(vcpuid); + if (start < b) + start = b; + stop = b + nVars(vcpuid); + } else { + stop = variablesTable.getNumItems(); + if (start < 0) + start = 0; + }*/ + +/* while (start < stop) { + VCPUscriptVar *v = variablesTable.enumItem(start); + if (v->v.data.odata == o && !v->transcient && (vcpuid == -1 || v->scriptId == vcpuid)) + return start; + start++; + }*/ + return -1; +} + + + +// ------------------------------------------------------------- +// Assign DLF functionId to class exported functions, starting from the last non initialized DLF +void VCPU::setupDLF(VCPUdlfEntry *e, int dlfEntryBase) { + if (ObjectTable::addrefDLF(e, highestDLFId)) { + newDlf(); + } + +} + +int VCPU::newDlf() { + return highestDLFId++; +} + +void VCPU::resetDlf() { + highestDLFId = 0; +} + +void VCPU::registerGlobalDlf(VCPUdlfEntry *e, int dlf) { + ASSERT(dlf == globalDlfList.getNumItems()); + VCPUdlfEntry *_e = new VCPUdlfEntry; + MEMCPY(_e, e, sizeof(VCPUdlfEntry)); + _e->functionName = WCSDUP(e->functionName); + globalDlfList.addItem(_e); +} + +void VCPU::delrefDLF(VCPUdlfEntry *e) { + ObjectTable::delrefDLF(e); +} + +// ------------------------------------------------------------- + +TList<VCPUscriptVar> VCPU::plist; + +// ------------------------------------------------------------- +int VCPU::runEvent(VCPUeventEntry *e, int np, int pbase) { + +#ifdef WASABI_COMPILE_MAKIDEBUG + /*if (WASABI_API_MAKIDEBUG && WASABI_API_MAKIDEBUG->debugger_isActive()) { + if (WASABI_API_MAKIDEBUG->debugger_filterEvent(e->scriptId, e->DLFid)) { + DebugString("Skipping event\n"); + scriptVar v; + v.type = SCRIPT_INT; + v.data.idata = 0; + VCPU::push(v); + return 1; + } + }*/ +#endif + + for (int z=0;z<np;z++) { + VCPU::push(plist[z+pbase]); + } + + runCode(e->scriptId, e->pointer, np); + +#ifdef WASABI_COMPILE_MAKIDEBUG +/* if (WASABI_API_MAKIDEBUG && WASABI_API_MAKIDEBUG->debugger_isActive()) + WASABI_API_MAKIDEBUG->debugger_eventComplete();*/ +#endif + + return 1; +} + +// This is the function that actually executes the event. In the future, it will sequencially parse all loaded scripts in reversed load order and stop +// either at the end of the chain OR as soon as one of the event used "complete;" in its code + +// ------------------------------------------------------------- +scriptVar VCPU::executeEvent(scriptVar v, int functionId, int np, int vcpuid) { + + VCPUscriptVar retvar={0,{0},0}; + int pbase = plist.getNumItems(); + + int varId=0; + + complete = 0; + + for (int z=0;z<np;z++) { + VCPUscriptVar vcpuv = VCPU::pop(); + plist.addItem(vcpuv); + } + + // find all variables containing this object, and run their event if it's traped + + int next = 0; + + while (!complete) { + VCPUscriptVar *vclass=NULL; + int inheritedevent=0; +// varId = VCPU::findObject(v.data.odata, varId, vcpuid); + int event; + ASSERT(v.data.odata != NULL); + varId = ((ScriptObject *)v.data.odata)->vcpu_getAssignedVariable(next, vcpuid, functionId, &next, &event, &inheritedevent); + + if (varId < 0) break; + + VCPUscriptVar *vc = variablesTable.enumItem(varId); + ScriptObject *thisobject = (ScriptObject *)v.data.odata; + + VCPUeventEntry *e = eventsTable.enumItem(event); + + int r_varId = varId; + + if (!vc->isaclass && !inheritedevent) { + if (e && runEvent(e, np, pbase)) + retvar = pop(); + if (getComplete()) + break; + } + + while (vc->isaclass) { + ASSERT(r_varId < variablesTable.getNumItems()); + vclass = variablesTable.enumItem(r_varId); + vclass->v.data.odata = thisobject; + + if (runEvent(e, np, pbase)) + retvar = pop(); + + if (getComplete()) + break; + + vc = vclass; + if (vc->varId < 0x10000) break; + r_varId = varBase(vc->scriptId) + vc->v.type - 0x10000; + } + + if (getComplete()) + break; + + varId++; + } + + for (int i=0;i<np;i++) + plist.delByPos(pbase); + + return retvar.v; +} + +void VCPU::callDlfCommand(void *ptr, int nargs, maki_cmd *cmd) { + try { + + scriptVar v={0,0}; + switch (nargs) { + case 0: + ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *))ptr)(cmd, -1, NULL); + break; + case 1: + ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar))ptr)(cmd, -1, NULL, v); + break; + case 2: + ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar))ptr)(cmd, -1, NULL, v, v); + break; + case 3: + ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar))ptr)(cmd, -1, NULL, v, v, v); + break; + case 4: + ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar))ptr)(cmd, -1, NULL, v, v, v, v); + break; + case 5: + ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))ptr)(cmd, -1, NULL, v, v, v, v, v); + break; + case 6: + ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))ptr)(cmd, -1, NULL, v, v, v, v, v, v); + break; + case 7: + ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))ptr)(cmd, -1, NULL, v, v, v, v, v, v, v); + break; + case 8: + ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))ptr)(cmd, -1, NULL, v, v, v, v, v, v, v, v); + break; + case 9: + ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))ptr)(cmd, -1, NULL, v, v, v, v, v, v, v, v, v); + break; + case 10: + ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))ptr)(cmd, -1, NULL, v, v, v, v, v, v, v, v, v, v); + break; + } + } + + catch(...) + { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VCPU::VSD), GURU_EXCEPTION, L"Script Fatal Error", -1); + #ifdef ON_FATAL_SKIN_ERROR + ON_FATAL_SKIN_ERROR + #endif + } + +} + +int VCPU::getDLFFromPointer(void *ptr, int nargs) { + maki_cmd cmd={MAKI_CMD_GETDLF, -1}; + callDlfCommand(ptr, nargs, &cmd); + return cmd.id; +} + +// This sends the DLFId to the function itself. +void VCPU::setupDLFFunction(void *ptr, int nargs, int DLFid, VCPUdlfEntry *e) { + registerGlobalDlf(e, DLFid); + maki_cmd cmd={MAKI_CMD_SETDLF, DLFid}; + callDlfCommand(ptr, nargs, &cmd); +} + +// This sends the DLFId to the function itself. +void VCPU::DLF_reset(void *ptr, int nargs) { + maki_cmd cmd={MAKI_CMD_RESETDLF, -1}; + callDlfCommand(ptr, nargs, &cmd); +} + +void VCPU::DLF_addref(void *ptr, int nargs) { + maki_cmd cmd={MAKI_CMD_ADDREF, -1}; + callDlfCommand(ptr, nargs, &cmd); +} + +void VCPU::DLF_remref(void *ptr, int nargs) { + maki_cmd cmd={MAKI_CMD_REMREF, -1}; + callDlfCommand(ptr, nargs, &cmd); +} + +// ------------------------------------------------------------- +scriptVar VCPU::safeDiv(VCPUscriptVar *v1, VCPUscriptVar *v2) { + double _r=0; + double _v1=SOM::makeDouble(&v1->v); + double _v2=SOM::makeDouble(&v2->v); + if (_v2 != 0.0) + _r = _v1 / _v2; + else + Script::guruMeditation(SOM::getSystemObjectByScriptId(v1->scriptId), GURU_DIVBYZERO, L"Division by zero"); + + scriptVar r = SOM::makeVar(SCRIPT_DOUBLE); + SOM::assign(&r, _r); + return r; +} + +/* + +Registers : + +VIP : Instruction Pointer +VSP : Stack Pointer +VSD : Script Descriptor (ID of script we're in) + + +CALLM calls member function, pops a variable ID and a DLF entry, and pushs the result of +the function. CallC calls an address, so pushs the return address on its stack +(independant from the Push/Pop stack), and jumps to the code. Ret gets the last +address pushed and returns there. JIZ jumps to an address if the first value on the stack +is an int zero. JMP jumps unconditionnaly. + +The stack is a stack of 4 bytes integers containing scriptVar IDs. +Var IDs from binaries are being added the base ID of the current script so we +have only one variables segment for all scripts. Same for DLF entries. Events +aren't references in the bytecode other than in the event table that links +addresses in code to DLF entries, so we don't need that kind of tweaking. + +*/ + +// ------------------------------------------------------------- +char *VCPU::getCodeBlock(int id, int *size) { + for (int i=0;i<codeTable.getNumItems();i++) { + if (codeTable.enumItem(i)->scriptId == id) { + if (size != NULL) *size = codeTable.enumItem(i)->size; + return codeTable.enumItem(i)->codeBlock; + } + } + return NULL; +} + +// ------------------------------------------------------------- +VCPUcodeBlock *VCPU::getCodeBlockEntry(int id) { + for (int i=0;i<codeTable.getNumItems();i++) { + if (codeTable.enumItem(i)->scriptId == id) { + return codeTable.enumItem(i); + } + } + return NULL; +} + +// ------------------------------------------------------------- +void VCPU::runCode(int scriptId, int pointer, int np) { + int quit=0; + VIP = pointer; + VSD = scriptId; + +#ifdef WASABI_COMPILE_MAKIDEBUG + int debugger_present = debugApi ? debugApi->debugger_isActive() : 0; +#endif + + char *codeblock = (char *)getCodeBlock(VSD); + char *p = codeblock + VIP; + unsigned char opcode; + + int stackbase = VSP-np; + int callcbase = CallStack.peek(); + VCC = callcbase; + + while (!quit) { +#ifdef WASABI_COMPILE_MAKIDEBUG + if (debugger_present) { + VIPstack.push(VIP); + VSDstack.push(VSD); +// VSPstack.push(VSP); + VCCstack.push(VCC); + debugApi->debugger_trace(); + VIPstack.pop(&VIP); + VSDstack.pop(&VSD); +// VSPstack.pop(&VSP); + VCCstack.pop(&VCC); + } +#endif + opcode = *p; + p+=sizeof(opcode); + VIP+=sizeof(opcode); + + switch (opcode) { + case OPCODE_PUSH: { + int id; // var id + id = *(int *)p; + p+=sizeof(int); VIP+=sizeof(int); + VCPUscriptVar *var = variablesTable.enumItem(id+varBase(VSD)); + push(*var); + break; + } + case OPCODE_POPI: { + pop(); // discard + if (VSP == stackbase) + statementStringList.freeAll(); + break; + } + case OPCODE_POP: { + int id = *(int *)p; // var id + p+=sizeof(int); VIP+=sizeof(int); + VCPUscriptVar v = pop(); + VCPUassign(id, v.v, VSD); + break; + } + case OPCODE_SET: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + if (v1.varId == -1) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_SETNONINTERNAL); + ASSERT(0); + } + scriptVar r = VCPUassign(v1.varId, v2.v, VSD); + push(r); + break; + } + case OPCODE_RETF: { + if (/*VSP == stackbase+1 && */CallStack.peek() == callcbase) { + quit = 1; + break; + } + CallStack.pop(&p); + VIP = p-(char *)getCodeBlock(VSD); + break; + } + case OPCODE_CALLC: { + int shift; // jump length + shift = *(int *)p; + p+=sizeof(int); VIP+=sizeof(int); + CallStack.push(p); + VCC++; + p+=shift; + VIP+=shift; + break; + } + case OPCODE_CALLM: { + int id; // DLF id + id = *(int *)p; + p+=sizeof(int); VIP+=sizeof(int); + VCPUdlfEntry *e = DLFentryTable.enumItem(id+dlfBase(VSD)); + int np = *(int *)p; + // OLD stack protection - was relying on a shody test based on the fact that the compiler should not be able to generate two FF's at this offset, replaced by new opcode but remains for backward compatibility + if ((np & 0xFFFF0000) == 0xFFFF0000) { + p += sizeof(int); + VIP += sizeof(int); + np &= 0xFFFF; + } else np = -1; + scriptVar r = callDLF(e, np); + VCPUscriptVar vr; + vr.scriptId = VSD; + vr.varId = -1; + vr.v = r; + push(vr); + break; + } + case OPCODE_CALLM2: { + int id; // DLF id + id = *(int *)p; + p+=sizeof(int); VIP+=sizeof(int); + VCPUdlfEntry *e = DLFentryTable.enumItem(id+dlfBase(VSD)); + int np = *(unsigned char *)p; p++; VIP+=1; + scriptVar r = callDLF(e, np); + VCPUscriptVar vr; + vr.scriptId = VSD; + vr.varId = -1; + vr.v = r; + push(vr); + break; + } + case OPCODE_UMV: + { + VCPUscriptVar name = pop(); + VCPUscriptVar obj = pop(); + ASSERT(obj.v.data.odata!=NULL); + ASSERT(name.v.data.sdata!=NULL); + + int rettype = *(int *)p; + p+=sizeof(int); VIP+=sizeof(int); + + if (rettype >= CLASS_ID_BASE) { + SystemObject *so = SOM::getSystemObjectByScriptId(VSD); + TList<int> *typeslist = so->getTypesList(); + rettype = typeslist->enumItem(rettype - CLASS_ID_BASE); + } + + int oid = ((ScriptObject *)obj.v.data.odata)->vcpu_getMember(name.v.data.sdata, VSD, rettype); + VCPUscriptVar *v = getOrphan(oid); + ASSERT(v != NULL); + push(*v); + break; + } + case OPCODE_CMPEQ: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + VCPUscriptVar r; + r.v = SOM::makeVar(SCRIPT_INT); + SOM::assign(&r.v, SOM::compEq(&v1.v, &v2.v)); + push(r); + break; + } + case OPCODE_CMPNE: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + VCPUscriptVar r; + r.v = SOM::makeVar(SCRIPT_INT); + SOM::assign(&r.v, SOM::compNeq(&v1.v, &v2.v)); + push(r); + break; + } + case OPCODE_CMPA: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + VCPUscriptVar r; + r.v = SOM::makeVar(SCRIPT_INT); + SOM::assign(&r.v, SOM::compA(&v1.v, &v2.v)); + push(r); + break; + } + case OPCODE_CMPAE: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + VCPUscriptVar r; + r.v = SOM::makeVar(SCRIPT_INT); + SOM::assign(&r.v, SOM::compAe(&v1.v, &v2.v)); + push(r); + break; + } + case OPCODE_CMPB: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + VCPUscriptVar r; + r.v = SOM::makeVar(SCRIPT_INT); + SOM::assign(&r.v, SOM::compB(&v1.v, &v2.v)); + push(r); + break; + } + case OPCODE_CMPBE: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + VCPUscriptVar r; + r.v = SOM::makeVar(SCRIPT_INT); + SOM::assign(&r.v, SOM::compBe(&v1.v, &v2.v)); + push(r); + break; + } + case OPCODE_JIZ: { + int shift; // jump length + shift = *(int *)p; + p+=sizeof(int); VIP+=sizeof(int); + VCPUscriptVar v = pop(); + if (v.v.data.idata == 0) { + p+=shift; + VIP+=shift; + } + break; + } + case OPCODE_JNZ: { + int shift; // jump length + shift = *(int *)p; + p+=sizeof(int); VIP+=sizeof(int); + VCPUscriptVar v = pop(); + if (v.v.data.idata != 0) { + p+=shift; + VIP+=shift; + } + break; + } + case OPCODE_JMP: { + int shift; // jump length + shift = *(int *)p; + p+=sizeof(int); VIP+=sizeof(int); + p+=shift; + VIP+=shift; + break; + } + case OPCODE_NOT: { + VCPUscriptVar v = pop(); + VCPUscriptVar r; + r.v = SOM::makeVar(SCRIPT_BOOLEAN); + switch (v.v.type) { + case SCRIPT_BOOLEAN: + case SCRIPT_INT: + case SCRIPT_FLOAT: + case SCRIPT_DOUBLE: { + int i = SOM::makeBoolean(&v.v); + r.v.data.idata = i == 0 ? 1 : 0; + } + break; + case SCRIPT_STRING: + r.v.data.idata = (!v.v.data.sdata || !*v.v.data.sdata) ? 1 : 0; + break; + default: + r.v.data.idata = (v.v.data.odata == NULL) ? 1 : 0; + break; + } + push(r); + break; + } + case OPCODE_INCS: { + VCPUscriptVar v = pop(); + push(v); + switch (v.v.type) { + case SCRIPT_BOOLEAN: + v.v.data.idata = 1; + break; + case SCRIPT_INT: + v.v.data.idata++; + break; + case SCRIPT_FLOAT: + v.v.data.fdata = v.v.data.fdata+1; + break; + case SCRIPT_DOUBLE: + v.v.data.ddata = v.v.data.ddata+1; + break; + default: + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_INCSNONNUM); + ASSERT(0); + break; + } + if (v.varId != -1) + VCPUassign(v.varId, v.v, VSD); + break; + } + case OPCODE_DECS: { + VCPUscriptVar v = pop(); + push(v); + switch (v.v.type) { + case SCRIPT_BOOLEAN: + v.v.data.idata = 0; + break; + case SCRIPT_INT: + v.v.data.idata--; + break; + case SCRIPT_FLOAT: + v.v.data.fdata = v.v.data.fdata-1; + break; + case SCRIPT_DOUBLE: + v.v.data.ddata = v.v.data.ddata-1; + break; + default: + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_DECSNONNUM); + ASSERT(0); + break; + } + if (v.varId != -1) + VCPUassign(v.varId, v.v, VSD); + break; + } + case OPCODE_INCP: { + VCPUscriptVar v = pop(); + switch (v.v.type) { + case SCRIPT_BOOLEAN: + v.v.data.idata = 1; + break; + case SCRIPT_INT: + v.v.data.idata++; + break; + case SCRIPT_FLOAT: + v.v.data.fdata = v.v.data.fdata+1; + break; + case SCRIPT_DOUBLE: + v.v.data.ddata = v.v.data.ddata+1; + break; + default: + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_INCPNONNUM); + ASSERT(0); + break; + } + if (v.varId != -1) + VCPUassign(v.varId, v.v, VSD); + push(v); + break; + } + case OPCODE_DECP: { + VCPUscriptVar v = pop(); + switch (v.v.type) { + case SCRIPT_BOOLEAN: + v.v.data.idata = 0; + break; + case SCRIPT_INT: + v.v.data.idata--; + break; + case SCRIPT_FLOAT: + v.v.data.fdata = v.v.data.fdata-1; + break; + case SCRIPT_DOUBLE: + v.v.data.ddata = v.v.data.ddata-1; + break; + default: + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_DECSNONNUM); + ASSERT(0); + break; + } + if (v.varId != -1) + VCPUassign(v.varId, v.v, VSD); + push(v); + break; + } + case OPCODE_ADD: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + ASSERT(v1.v.type == SCRIPT_STRING || SOM::isNumeric(&v1.v)); + ASSERT(v2.v.type == SCRIPT_STRING || SOM::isNumeric(&v2.v)); + if (v2.v.type == SCRIPT_STRING) + { + int n=0; + if (!v2.v.data.sdata) break; + if (v1.v.data.sdata) n+= wcslen(v1.v.data.sdata); + n+= wcslen(v2.v.data.sdata); + wchar_t *s = (wchar_t *)WMALLOC((n+1)); + ASSERT(s != NULL); + + if (v1.v.data.sdata) + { + wcsncpy(s, v1.v.data.sdata, n); + wcsncat(s, (v2.v.data.sdata ? v2.v.data.sdata : L""), n); + } else + wcsncpy(s, (v2.v.data.sdata ? v2.v.data.sdata : L""), n); + + v1.v = SOM::makeVar(SCRIPT_STRING); + SOM::assign(&v1.v, s); + FREE(s); + push(v1); + } else { + scriptVar r = SOM::makeVar(SCRIPT_DOUBLE); + SOM::assign(&r, SOM::makeDouble(&v1.v) + SOM::makeDouble(&v2.v)); + push(r); + } + break; + } + case OPCODE_SUB: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + ASSERT(SOM::isNumeric(&v1.v)); + ASSERT(SOM::isNumeric(&v2.v)); + scriptVar r = SOM::makeVar(SCRIPT_DOUBLE); + SOM::assign(&r, SOM::makeDouble(&v1.v) - SOM::makeDouble(&v2.v)); + push(r); + break; + } + case OPCODE_MUL: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + ASSERT(SOM::isNumeric(&v1.v)); + ASSERT(SOM::isNumeric(&v2.v)); + scriptVar r = SOM::makeVar(SCRIPT_DOUBLE); + SOM::assign(&r, SOM::makeDouble(&v1.v) * SOM::makeDouble(&v2.v)); + push(r); + break; + } + case OPCODE_DIV: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + scriptVar r = safeDiv(&v1, &v2); + push(r); + break; + } + + case OPCODE_MOD: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + if (!SOM::isNumeric(&v2.v) || !SOM::isNumeric(&v1.v)) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_MODNONNUM); + ASSERT(0); + } + SOM::assign(&v1.v, SOM::makeInt(&v1.v) % SOM::makeInt(&v2.v)); + push(v1); + break; + } + + case OPCODE_NEG: { + VCPUscriptVar v = pop(); + switch (v.v.type) { + case SCRIPT_BOOLEAN: + break; + case SCRIPT_INT: + v.v.data.idata = -v.v.data.idata; + break; + case SCRIPT_FLOAT: + v.v.data.fdata = -v.v.data.fdata; + break; + case SCRIPT_DOUBLE: + v.v.data.ddata = -v.v.data.ddata; + break; + default: + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_NEGNONNUM); + ASSERT(0); + break; + } + push(v); + break; + } + + case OPCODE_BNOT: { + VCPUscriptVar v = pop(); + if (!SOM::isNumeric(&v.v)) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_BNOTNONNUM); + ASSERT(0); + } + SOM::assign(&v.v, ~SOM::makeInt(&v.v)); + push(v); + break; + } + + case OPCODE_SHL: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + if (!SOM::isNumeric(&v1.v) || !SOM::isNumeric(&v2.v)) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_SHLNONNUM); + ASSERT(0); + } + SOM::assign(&v1.v, SOM::makeInt(&v1.v) << SOM::makeInt(&v2.v)); + push(v1); + break; + } + case OPCODE_SHR: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + if (!SOM::isNumeric(&v1.v) || !SOM::isNumeric(&v2.v)) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_SHRNONNUM); + ASSERT(0); + } + SOM::assign(&v1.v, SOM::makeInt(&v1.v) >> SOM::makeInt(&v2.v)); + push(v1); + break; + } + + case OPCODE_XOR: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + if (!SOM::isNumeric(&v1.v) || !SOM::isNumeric(&v2.v)) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_XORNONNUM); + ASSERT(0); + } + SOM::assign(&v1.v, SOM::makeInt(&v1.v) ^ SOM::makeInt(&v2.v)); + push(v1); + break; + } + + case OPCODE_AND: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + if (!SOM::isNumeric(&v1.v) || !SOM::isNumeric(&v2.v)) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_ANDNONNUM); + ASSERT(0); + } + SOM::assign(&v1.v, SOM::makeInt(&v1.v) & SOM::makeInt(&v2.v)); + push(v1); + break; + } + case OPCODE_OR: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + if (!SOM::isNumeric(&v1.v) || !SOM::isNumeric(&v2.v)) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_ANDNONNUM); + ASSERT(0); + } + SOM::assign(&v1.v, SOM::makeInt(&v1.v) | SOM::makeInt(&v2.v)); + push(v1); + break; + } + + case OPCODE_LAND: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + VCPUscriptVar r; + r.v = SOM::makeVar(SCRIPT_BOOLEAN); + int a2 = SOM::makeBoolean(&v2.v); + int a1 = SOM::makeBoolean(&v1.v); + r.v.data.idata = (a2 && a1) ? 1 : 0; + push(r); + break; + } + case OPCODE_LOR: { + VCPUscriptVar v2 = pop(); + VCPUscriptVar v1 = pop(); + VCPUscriptVar r; + r.v = SOM::makeVar(SCRIPT_BOOLEAN); + int a2 = SOM::makeBoolean(&v2.v); + int a1 = SOM::makeBoolean(&v1.v); + r.v.data.idata = (a2 || a1) ? 1 : 0; + push(r); + break; + } + + case OPCODE_DELETE: { + VCPUscriptVar v1 = pop(); + int id = 0; + int type = v1.v.type; + if (type >= 0x10000) + do { + id = type - 0x10000; + VCPUscriptVar *v = variablesTable.enumItem(id+varBase(VSD)); + type = v->v.type; + } while (type >= 0x10000); + + if (isInstantiable(type)) { + ScriptObject *s = (ScriptObject *)v1.v.data.odata; + scriptVar v = SOM::makeVar(v1.v.type); + VCPUassign(v1.varId, v, v1.scriptId); + SystemObject *so = SOM::getSystemObjectByScriptId(VSD); + so->removeInstantiatedObject(s); + ObjectTable::destroy(s); + } + VCPU::push(v1); + break; + } + + + case OPCODE_NEW: { + int id = *(int *)p; // class id + p+=sizeof(int); VIP+=sizeof(int); + + SystemObject *so = SOM::getSystemObjectByScriptId(VSD); + TList<int> *typeslist = so->getTypesList(); + + int _id; + if (id >= 0x10000) + do { + _id = id - 0x10000; + VCPUscriptVar *v = variablesTable.enumItem(_id+varBase(VSD)); + id = v->v.type; + } while (id >= 0x10000); + + if (SOM::getSystemObjectByScriptId(VSD)->isOldFormat()) + id = oldClassToClassId(id); + else + id = typeslist->enumItem(id); + + if (isInstantiable(id)) { + ScriptObject *s = ObjectTable::instantiate(id); + if (s) s->vcpu_setScriptId(VSD); + + so->addInstantiatedObject(s); + + if (s == NULL) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VSD), GURU_NEWFAILED); + } + VCPUscriptVar v={{SCRIPT_OBJECT, {0}}, 0}; + SOM::assign(&v.v, s); + push(v); + } else { + VCPUscriptVar n = {{SCRIPT_OBJECT,NULL}, 0}; + push(n); + } + break; + } + + case OPCODE_CMPLT : { + complete = 1; + break; + } + + case OPCODE_NOP : + { +#if defined(_WIN32) || defined(_WIN64) + OutputDebugStringA("Opcode 0 - NOP encountered, please check!\n"); +#else +#warning port me +#endif + break; + } + default: { + ASSERTALWAYS(StringPrintf("Opcode %X not implemented", opcode)); + break; + } + } + } + + ASSERT(VSP == stackbase + 1); +} + +// ------------------------------------------------------------- +scriptVar VCPU::VCPUassign(int id, scriptVar sv, int scriptId) { + VCPUscriptVar *v = NULL; + + if (id & (1 << 31)) { + id = id & ~(1 << 31); + v = getOrphan(id); + } else + v = variablesTable.enumItem(id+varBase(scriptId)); + + if (v->v.type != SCRIPT_STRING) { + if (!SOM::isNumeric(&v->v)) { + // assigning an object + + scriptVar _sv = sv; + + if (_sv.data.odata != NULL && !SystemObject::isObjectValid(_sv.data.odata)) + _sv.data.odata = NULL; + + if (v->v.data.odata != _sv.data.odata) { + + if (v->v.data.odata != NULL && !v->transcient && SystemObject::isObjectValid(v->v.data.odata)) + ((ScriptObject *)v->v.data.odata)->vcpu_removeAssignedVariable(v->varId, v->scriptId); + + if (_sv.data.odata == NULL) { + v->v.data.odata = NULL; + } else { + SOM::assign(&v->v, &sv); + if (SOM::typeCheck(v, 0)) { + if (!v->isaclass && !v->transcient) + ((ScriptObject *)sv.data.odata)->vcpu_addAssignedVariable(v->varId, v->scriptId); + } else { + int type = v->v.type; + if (type >= 0x10000) + do { + id = type - 0x10000; + VCPUscriptVar *v = variablesTable.enumItem(id+varBase(VSD)); + type = v->v.type; + } while (type >= 0x10000); + class_entry *e = ObjectTable::getClassEntry(type); + ASSERT(e != NULL); + GUID g = e->classGuid; + ScriptObject *o = NULL; + v->v.data.odata->vcpu_getInterfaceObject(g, &o); + if (o != NULL) { + v->v.data.odata = o; + if (!v->isaclass && !v->transcient) + o->vcpu_addAssignedVariable(v->varId, v->scriptId); + } else { + v->v.data.odata = NULL; + } + } + } + } + + } else { + // assigning a number + SOM::assign(&v->v, &sv); + } + } else { + ASSERT(sv.type == SCRIPT_STRING); + SOM::persistentstrassign(&v->v, sv.data.sdata); + } + + return v->v; +} + +// ------------------------------------------------------------- +void VCPU::traceState(VCPUscriptVar object, VCPUdlfEntry *e) { + _DebugString("vcpu[%2X]: %04X [%04X].%s", VCPU::VSD, VCPU::VIP, object.varId, e->functionName); +// CallbackManager::issueCallback(SysCallback::CONSOLE, ConsoleCallback::DEBUGMESSAGE, 0, reinterpret_cast<int>(t)); +} + +// ------------------------------------------------------------- +// Calls the DLF function +scriptVar VCPU::callDLF(VCPUdlfEntry *e, int np) { + + static Stack<int> cpuidstack; + + cpuidstack.push(VSD); + cpuidstack.push(VIP); + cpuidstack.push(VCC); + +/* if (e->external) { + char t[256] = {0}; + VCPUscriptVar v = VCPU::peekAt(e->nparams); + SPRINTF(t, "vcpu: %04X [%04X].%s", VCPU::VIP, v.varId, e->functionName); + Console::outputString(0, t); + DebugString("%s", t); + ((void(*)(int))e->ptr)(-1); + scriptVar rv = pop().v; // returned val + cpuidstack.pop(&VCC); + cpuidstack.pop(&VIP); + cpuidstack.pop(&VSD); + return rv; + }*/ + + +/* char t[256] = {0}; + SPRINTF(t, "e->nparams = %d\n", e->nparams); + DebugString("%s", t); */ + + //ASSERT(np == -1 || np == e->nparams); // fucko!!!!!!!! + + if (np == -1) { + np = e->nparams; + } + + for (int i=0;i<np;i++) { + paramList[i] = pop().v; + } + + VCPUscriptVar object = pop(); + scriptVar r = MAKE_SCRIPT_INT(0); + + //traceState(object, e); + + if (object.v.data.odata == NULL) { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VCPU::VSD), GURU_NULLCALLED, L"Null object called", object.varId); + cpuidstack.pop(&VCC); + cpuidstack.pop(&VIP); + cpuidstack.pop(&VSD); + return MAKE_SCRIPT_INT(0); + //ASSERT(0); + } +#ifndef _DEBUG + try +#endif + { + if (object.v.data.odata) object.v.data.odata->vcpu_setScriptId(object.scriptId); + + if (e->ptr != NULL) { + switch (np) { + case 0: + r = ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *))e->ptr)(NULL, VCPU::VSD, object.v.data.odata); + break; + case 1: + r = ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar))e->ptr)(NULL, VCPU::VSD, object.v.data.odata, paramList[0]); + break; + case 2: + r = ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar))e->ptr)(NULL, VCPU::VSD, object.v.data.odata, paramList[0], paramList[1]); + break; + case 3: + r = ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar))e->ptr)(NULL, VCPU::VSD, object.v.data.odata, paramList[0], paramList[1], paramList[2]); + break; + case 4: + r = ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar))e->ptr)(NULL, VCPU::VSD, object.v.data.odata, paramList[0], paramList[1], paramList[2], paramList[3]); + break; + case 5: + r = ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))e->ptr)(NULL, VCPU::VSD, object.v.data.odata, paramList[0], paramList[1], paramList[2], paramList[3], paramList[4]); + break; + case 6: + r = ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))e->ptr)(NULL, VCPU::VSD, object.v.data.odata, paramList[0], paramList[1], paramList[2], paramList[3], paramList[4], paramList[5]); + break; + case 7: + r = ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))e->ptr)(NULL, VCPU::VSD, object.v.data.odata, paramList[0], paramList[1], paramList[2], paramList[3], paramList[4], paramList[5], paramList[6]); + break; + case 8: + r = ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))e->ptr)(NULL, VCPU::VSD, object.v.data.odata, paramList[0], paramList[1], paramList[2], paramList[3], paramList[4], paramList[5], paramList[6], paramList[7]); + break; + case 9: + r = ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))e->ptr)(NULL, VCPU::VSD, object.v.data.odata, paramList[0], paramList[1], paramList[2], paramList[3], paramList[4], paramList[5], paramList[6], paramList[7], paramList[8]); + break; + case 10: + r = ((scriptVar (*)(maki_cmd *, int vsd, class ScriptObject *, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar, scriptVar))e->ptr)(NULL, VCPU::VSD, object.v.data.odata, paramList[0], paramList[1], paramList[2], paramList[3], paramList[4], paramList[5], paramList[6], paramList[7], paramList[8], paramList[9]); + break; + } + } + } +#ifndef _DEBUG + catch(...) + { + Script::guruMeditation(SOM::getSystemObjectByScriptId(VCPU::VSD), GURU_EXCEPTION, L"Script Fatal Error", object.varId); + cpuidstack.pop(&VCC); + cpuidstack.pop(&VIP); + cpuidstack.pop(&VSD); + #ifdef ON_FATAL_SKIN_ERROR + ON_FATAL_SKIN_ERROR + #endif + return MAKE_SCRIPT_INT(0); + } +#endif + cpuidstack.pop(&VCC); + cpuidstack.pop(&VIP); + cpuidstack.pop(&VSD); + + return r; +} + +// ------------------------------------------------------------- +void VCPU::addStatementString(wchar_t *s) +{ + statementStringList.addItem(s); +} + +// ------------------------------------------------------------- +int VCPU::getComplete() { + return complete; +} + +// ------------------------------------------------------------- +int VCPU::isInstantiable(int id) { + ASSERT(!SOM::isNumericType(id)); + return ObjectTable::isClassInstantiable(id); +} + +// ------------------------------------------------------------- +int VCPU::getDlfGlobalIndex(int dlfid, int scriptid) { + static int lasti=-1; + static int lastid=0; + static int lastsid=0; + if (lasti>=0 && lasti < DLFentryTable.getNumItems()) { + if (lastsid == scriptid && lastid == dlfid) { + VCPUdlfEntry *e = DLFentryTable.enumItem(lasti); + if (e->DLFid == dlfid && e->scriptId == scriptid) + return lasti; + } + } + for (int i=0;i<DLFentryTable.getNumItems();i++ ){ + VCPUdlfEntry *e = DLFentryTable.enumItem(i); + if (e->scriptId == scriptid && e->DLFid == dlfid) { + lasti = i; + lastsid = scriptid; + lastid = dlfid; + return lasti; + } + } + Script::guruMeditation(SOM::getSystemObjectByScriptId(scriptid), GURU_INVALIDEVENTDLF); + return -1; +} + +// ------------------------------------------------------------- +int VCPU::isValidScriptId(int id) { + for (int i=0;i<codeTable.getNumItems();i++) + if (codeTable[i]->scriptId == id) return 1; + return 0; +} + +// ------------------------------------------------------------- +int VCPU::getCacheCount() { + return cacheCount; +} + +// ------------------------------------------------------------- +int VCPU::getUserAncestor(int varid, int scriptid) { + VCPUscriptVar *vc = variablesTable.enumItem(varid+varBase(scriptid)) ; + if (vc->v.type < 0x10000) return -1; + int r_varId = vc->v.type - 0x10000; + ASSERT(r_varId < variablesTable.getNumItems()); + return r_varId; +} + +// ------------------------------------------------------------- +void VCPU::pushObject(void *o) { + scriptVar v = SOM::makeVar(SCRIPT_OBJECT, (ScriptObject *)o); + VCPU::push(v); +} + +// ------------------------------------------------------------- +void VCPU::pushInt(int i) { + scriptVar v = SOM::makeVar(SCRIPT_INT); + SOM::assign(&v, i); + VCPU::push(v); +} + +// ------------------------------------------------------------- +void VCPU::pushBoolean(int b) { + scriptVar v = SOM::makeVar(SCRIPT_BOOLEAN); + SOM::assign(&v, b); + VCPU::push(v); +} + +// ------------------------------------------------------------- +void VCPU::pushFloat(float f) { + scriptVar v = SOM::makeVar(SCRIPT_FLOAT); + SOM::assign(&v, f); + VCPU::push(v); +} + +// ------------------------------------------------------------- +void VCPU::pushDouble(double d) { + scriptVar v = SOM::makeVar(SCRIPT_DOUBLE); + SOM::assign(&v, d); + VCPU::push(v); +} + +// ------------------------------------------------------------- +void VCPU::pushString(const wchar_t *s) +{ + scriptVar v = SOM::makeVar(SCRIPT_STRING); + SOM::assign(&v, s); + VCPU::push(v); +} + +// ------------------------------------------------------------- +void VCPU::pushVoid() { + scriptVar v = SOM::makeVar(SCRIPT_VOID); + VCPU::push(v); +} + +// ------------------------------------------------------------- +void *VCPU::popObject() { + return (void *)VCPU::pop().v.data.odata; +} + +// ------------------------------------------------------------- +int VCPU::popInt() { + scriptVar v = VCPU::pop().v; + ASSERT(SOM::isNumeric(&v)); + return SOM::makeInt(&v); +} + +// ------------------------------------------------------------- +bool VCPU::popBoolean() { + scriptVar v = VCPU::pop().v; + ASSERT(SOM::isNumeric(&v)); + return SOM::makeBoolean(&v); +} + +// ------------------------------------------------------------- +float VCPU::popFloat() { + scriptVar v = VCPU::pop().v; + ASSERT(SOM::isNumeric(&v)); + return SOM::makeFloat(&v); +} + +// ------------------------------------------------------------- +double VCPU::popDouble() { + scriptVar v = VCPU::pop().v; + ASSERT(SOM::isNumeric(&v)); + return SOM::makeDouble(&v); +} + +// ------------------------------------------------------------- +const wchar_t *VCPU::popString() +{ + scriptVar v = VCPU::pop().v; + ASSERT(v.type == SCRIPT_STRING); + return v.data.sdata; +} + +// ------------------------------------------------------------- +void VCPU::popDiscard() { + VCPU::pop(); +} + +// ------------------------------------------------------------- +VCPUdlfEntry *VCPU::getGlobalDlfEntry(int dlfid) { + return globalDlfList.enumItem(dlfid); +} + +// ------------------------------------------------------------- +int VCPU::createOrphan(int type) { + orphans.addItem(new OrphanEntry(orphanid, type)); + return orphanid++; +} + +// ------------------------------------------------------------- +void VCPU::killOrphan(int id) { + int pos; + OrphanEntry *p = orphans.findItem((const wchar_t *)&id, &pos); + ASSERT(p != NULL && pos >= 0); + if (p->v.v.type == SCRIPT_STRING) + FREE((void *)p->v.v.data.sdata); + delete p; + orphans.removeByPos(pos); +} + +// ------------------------------------------------------------- +VCPUscriptVar *VCPU::getOrphan(int id) { + OrphanEntry *p = orphans.findItem((const wchar_t *)&id); + ASSERT(p != NULL); + return &p->v; +} + +// ------------------------------------------------------------- +int OrphanQuickSort::compareItem(void *p1, void *p2) { + if ((static_cast<OrphanEntry *>(p1))->id < (static_cast<OrphanEntry *>(p2))->id) return -1; + if ((static_cast<OrphanEntry *>(p1))->id > (static_cast<OrphanEntry *>(p2))->id) return 1; + return 0; +} + +// ------------------------------------------------------------- +int OrphanQuickSort::compareAttrib(const wchar_t *attr, void *p2) +{ + int id = *(reinterpret_cast<const int *>(attr)); + int eid = (static_cast<OrphanEntry *>(p2))->id; + if (id < eid) return -1; + if (id > eid) return 1; + return 0; +} + +// ------------------------------------------------------------- +OrphanEntry::OrphanEntry(int _id, int type) { + id = _id; + MEMSET(&v, 0, sizeof(VCPUscriptVar)); + v.v.type = type; + v.scriptId = -1; + v.varId = id | (1 << 31); + v.transcient = 1; // so no event is trapped, will change later when compiler supports it +} + +// ------------------------------------------------------------- +void VCPU::setAtom(const wchar_t *atomname, ScriptObject *o) { + int pos; + ScriptAtom *sa = atoms.findItem(atomname, &pos); + if (pos >= 0) { + delete sa; + atoms.removeByPos(pos); + } + if (o) + atoms.addItem(new ScriptAtom(atomname, o)); +} + +// ------------------------------------------------------------- +ScriptObject *VCPU::getAtom(const wchar_t *atomname) { + ScriptAtom *sa = atoms.findItem(atomname); + if (sa) { + return sa->getAtomObject(); + } + return NULL; +} + +// ------------------------------------------------------------- +const wchar_t *VCPU::getClassName(int vcpuid, int localclassid) { + SystemObject *so = SOM::getSystemObject(vcpuid); + if (so != NULL) { + TList<int> *l = so->getTypesList(); + if (l != NULL) { + int global = l->enumItem(localclassid); + class_entry *e = ObjectTable::getClassEntry(global); + if (e != NULL) + return e->classname; + } + } + return NULL; +} + + +// ------------------------------------------------------------- +int VCPU::cacheCount = 0; + +// segments +PtrList<VCPUscriptVar> VCPU::variablesTable; +PtrList<VCPUeventEntry> VCPU::eventsTable; +PtrList<VCPUdlfEntry> VCPU::DLFentryTable; +PtrList<VCPUdlfEntry> VCPU::globalDlfList; +PtrList<VCPUcodeBlock> VCPU::codeTable; +PtrList<wchar_t> VCPU::statementStringList; +PtrListInsertSorted<OrphanEntry, OrphanQuickSort> VCPU::orphans; +PtrListQuickSorted<ScriptAtom, ScriptAtomSort> VCPU::atoms; +int VCPU::orphanid=0; + +// stacks +Stack<VCPUscriptVar> VCPU::CpuStack; +Stack<char *> VCPU::CallStack; + +// registers +int VCPU::VIP=0; +int VCPU::VSP=0; +int VCPU::VSD=0; +int VCPU::VCC=0; + +Stack<int> VCPU::VIPstack; +Stack<int> VCPU::VSPstack; +Stack<int> VCPU::VSDstack; +Stack<int> VCPU::VCCstack; + +// misc +int VCPU::numScripts=0; +int VCPU::highestDLFId=0; +scriptVar VCPU::paramList[SCRIPT_MAXARGS]; +int VCPU::complete; + +TList<int> VCPU::scriptsToRemove; +// NOTES + +// There is no reason why people would cast System, Layout and Container +// back to the common base class... so... +// GUI objects should descend from a GUIObject rather than ScriptObject +// GUIObject would descend from ScriptObject for the compiler and should +// be exported as "Object" for the script, ScriptObject should then not +// be exported at all, thus preventing someone from doing "Object o = System;" +// which makes no sense since System is not a GUI object. Of course you +// could still do "Layout l = System.getContainer("mqlksd").getLayout("lqsdkj");" +// but you won't be able to cast that to an "Object". Furthermore, to get a +// GUI object, you'll use the layout's function "getObject", so this +// will add consistency to the overall thing. + +/* +-------------------------------------------------------------------------------- + + VCPU: Virtual CPU, The virtual machine processor. + The VCPU actually takes care of some kinds of segments of variables, + events, and so on. The VCPU's task is to run any number of scripts + serially in reversed loading order. Last script loaded takes precedence + over previous ones. Events and functions fall back to the the previous + script if it also defines them, unless explicitly prevented via 'complete;' + The VCPU links DLFs in reverse hierarchy order, allowing overriding of + functions in objects. + + DLF : Dynamically Linked Function. Function name is used to link it to + whatever layout of functions we have in any release of the VCPU, allowing + us to reorder our functions in objects. + + TODO: Add versionning info so we can safely expand this format. + + Binaries format : + + <obsolete> + + Size Desc What + ----------------------------------------------------------------------------- + 8 Header FG\x03\x04\x14\00\00\00\00 + ----------------------------------------------------------------------------- + 4 # of DLF int + ----------------------------------------------------------------------------- + 4 DLF base type int + 1 Size of func name char + N Function name char[n] + ... + ----------------------------------------------------------------------------- + 4 # of variables int + ----------------------------------------------------------------------------- + 8 variable scriptVar + ... + ----------------------------------------------------------------------------- + 4 # of strings int + ----------------------------------------------------------------------------- + 1 Size of string char 1st string assigned to 1st string var + N String char[n] 2nd string assigned to 2nd string var... + ... + ----------------------------------------------------------------------------- + 4 # of events int + ----------------------------------------------------------------------------- + 4 variable id int Matching variable table + 4 DLF entry int Matching DLF table + 4 Function pointer int Pointer in code from base of code + ... + ----------------------------------------------------------------------------- + 4 Size of code int + ----------------------------------------------------------------------------- + N Compiled code char[n] + ----------------------------------------------------------------------------- + +*/ |