#include #include #include #include #include #include "vcpu.h" #include "opcodes.h" #include #include #include #include #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 *typetable = SOM::getSystemObjectByScriptId(id)->getTypesList(); typetable->removeAll(); if (!translateobjects) { int nGuids = *(int *)p; p+=sizeof(int); for (int z=0;zaddItem(t); } } // ------------------------------------------------------------- // Load DLF Table int DLFEntryBase = DLFentryTable.getNumItems(); int nDLFentries = *(int *)p; p+=sizeof(int); for (i=0;i= 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;iisaclass = 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;iv.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= 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;iscriptId == 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;iscriptId == 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;iscriptId == 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 *l = SystemObject::getAllScriptObjects(); int i; for (i=0;igetNumItems();i++) { ScriptObject *o = l->enumItem(i); o->vcpu_delMembers(id); } int dlfdeleted=0; int vardeleted=0; for (i=0;iscriptId == 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;iscriptId == id) { delete eventsTable.enumItem(i); eventsTable.delByPos(i); i--; } } for (i=0;iscriptId == 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;iscriptId == id) { VCPUcodeBlock *b = codeTable.enumItem(i); delete b; codeTable.removeByPos(i); for (;idlfBase-=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 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;zscriptId, 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;zvcpu_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;iv); 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;iscriptId == 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;iscriptId == 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 *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 *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(t)); } // ------------------------------------------------------------- // Calls the DLF function scriptVar VCPU::callDLF(VCPUdlfEntry *e, int np) { static Stack 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;ivcpu_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;iscriptId == 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;iscriptId == 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(p1))->id < (static_cast(p2))->id) return -1; if ((static_cast(p1))->id > (static_cast(p2))->id) return 1; return 0; } // ------------------------------------------------------------- int OrphanQuickSort::compareAttrib(const wchar_t *attr, void *p2) { int id = *(reinterpret_cast(attr)); int eid = (static_cast(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 *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 VCPU::variablesTable; PtrList VCPU::eventsTable; PtrList VCPU::DLFentryTable; PtrList VCPU::globalDlfList; PtrList VCPU::codeTable; PtrList VCPU::statementStringList; PtrListInsertSorted VCPU::orphans; PtrListQuickSorted VCPU::atoms; int VCPU::orphanid=0; // stacks Stack VCPU::CpuStack; Stack VCPU::CallStack; // registers int VCPU::VIP=0; int VCPU::VSP=0; int VCPU::VSD=0; int VCPU::VCC=0; Stack VCPU::VIPstack; Stack VCPU::VSPstack; Stack VCPU::VSDstack; Stack VCPU::VCCstack; // misc int VCPU::numScripts=0; int VCPU::highestDLFId=0; scriptVar VCPU::paramList[SCRIPT_MAXARGS]; int VCPU::complete; TList 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 : 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] ----------------------------------------------------------------------------- */