/* ....[@@@..[@@@..............[@.................. MUD++ is a written from ....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and ....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++. ....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing ....[@......[@..[@@@@@..[@@@@@.................. development project. All ................................................ contributions are welcome. ....Copyright(C).1995.Melvin.Smith.............. Enjoy. ------------------------------------------------------------------------------ Melvin Smith (aka Fusion) msmith@hom.net MUD++ development mailing list mudpp@van.ml.org ------------------------------------------------------------------------------ vmrun.cc */ #include "config.h" #include "string.h" #include "io.h" #include "memoryblock.h" #include "vmopcodes.h" #include "vmachine.h" #include "asmloader.h" #include "vmarray.h" #define PUSH_I( x ) psobj++; psobj->type = VMT_INT; psobj->val.i = x; #define PUSH_F( x ) psobj++; psobj->type = VMT_FLOAT; psobj->val.f = x; void VMachine::run() { int itmp,itmp2; float ftmp; const char * txt; vmstack otmp,otmp2; vmstack * ptmp; memorycell cell; VMarray * array; // Main execution loop while ( live ) { // Cout << (int) pmem << " " << (int) low_border << " " << (int) high_border << endl; VM_SECURE_2( (pmem < low_border) || (pmem >= high_border ), "Scope borders broken." ); cell = getCell(); switch( cell.s.opcode ) { case VMOPC_AADD: ASSURE_SSIZE(2); VM_SECURE_2( !IS_ARRAY( (psobj-1)->type ) , "non-narray" ); ((VMarray*)(psobj-1)->val.o)->add(psobj->val); psobj--; break; case VMOPC_ABORT: crit_error("Abort hit"); break; case VMOPC_ADD: ASSURE_SSIZE( 2 ); if ( psobj->type == VMT_INT ) { psobj--; VM_SECURE_2( psobj->type != VMT_INT, "Tried to add different types" ); psobj->val.i += (psobj + 1)->val.i; } else { psobj--; VM_SECURE_2( (psobj + 1)->type != VMT_FLOAT, "Tried to add strange type" ); VM_SECURE_2( psobj->type != VMT_FLOAT, "Tried to add different types" ); psobj->val.f += (psobj + 1)->val.f; } break; case VMOPC_ALEN: NEED_OSTACK( 1 ); VM_SECURE_2( !IS_ARRAY( psobj->type ) , "non-narray" ); psobj++; psobj->type = VMT_INT; psobj->val.i = ((VMarray*)(psobj-1)->val.o)->count(); break; case VMOPC_APOP: ASSURE_SSIZE( 3 ); VM_SECURE_2( !IS_ARRAY( (psobj-2)->type ) , "non-narray" ); VM_SECURE_2( (psobj-1)->type != VMT_INT, "array can be indexed only by ints."); itmp = (psobj-1)->val.i; array = (VMarray *)(psobj-2)->val.o; if ( (itmp < 0) || (itmp >= array->count()) ) { crit_error( "index of of bounds" ); break; } VM_SECURE_2( IS_VMOBJ(psobj->type) && psobj->val.o && !canCastTo( psobj->val.o->getVMType(), array->type), "wrong vmtype put into array"); dereference_obj( array->type, array->table()[itmp].val ); array->table()[itmp].val = psobj->val; array->table()[itmp].type = array->type; psobj--; break; case VMOPC_APUSH: ASSURE_SSIZE(2); VM_SECURE_2( !IS_ARRAY( (psobj-1)->type ) , "non-narray" ); VM_SECURE_2( psobj->type != VMT_INT, "array can be indexed only by ints."); itmp = psobj->val.i; array = (VMarray*)(psobj-1)->val.o; if ( (itmp < 0) || (itmp >= array->count()) ) { crit_error( (String(" index ") + itmp + " of out bounds").chars() ); break; } *psobj = array->table()[itmp]; psobj->val = reference_obj(psobj); break; case VMOPC_CALL: crit_error("CALL opcode hit - illegal outside obj file"); break; case VMOPC_CAST2F: ASSURE_STACK1( VMT_INT ); psobj->type = VMT_FLOAT; psobj->val.f = (float) psobj->val.i; break; case VMOPC_CAST2I: ASSURE_STACK1( VMT_FLOAT ); psobj->type = VMT_INT; psobj->val.i = (s32) psobj->val.f; break; case VMOPC_CHECKCAST: ASSURE_SSIZE( 1 ); VM_SECURE_2( !IS_VMOBJ(psobj->type), "Tried to checkcast non-vmobject" ); if ( !psobj->val.o ) { psobj->type = VMT_INT; psobj->val.i = 1; } else { if ( canCastTo( psobj->val.o->getVMType(), ((vmtype) cell.s.u.number) ) ) psobj->val.i = 1; else psobj->val.i = 0; psobj->type = VMT_INT; } break; case VMOPC_CLONE: ASSURE_SSIZE( 1 ); NEED_OSTACK( 1 ); psobj++; psobj->type = (psobj - 1)->type; psobj->val = reference_obj( psobj - 1 ); break; case VMOPC_DEC: ASSURE_SSIZE( 1 ); if ( psobj->type == VMT_INT ) { psobj->val.i--; } else { VM_SECURE_2( psobj->type != VMT_FLOAT, "Tried to decrease non-numeric object"); psobj->val.f--; } break; case VMOPC_DECL: ACCESS_VSTACK( cell.s.u.number ); if ( psvar[cell.s.u.number].type == VMT_INT ) { psvar[cell.s.u.number].val.i--; } else { VM_SECURE_2(psvar[cell.s.u.number].type != VMT_FLOAT, "Tried to decrease non-numeric local"); psvar[cell.s.u.number].val.f--; } break; case VMOPC_DIV: ASSURE_SSIZE( 2 ); if ( psobj->type == VMT_INT ) { psobj--; VM_SECURE_2( psobj->type != VMT_INT, "Tried to div different types" ); psobj->val.i /= (psobj + 1)->val.i; } else { psobj--; VM_SECURE_2( (psobj + 1)->type != VMT_FLOAT, "Tried to div strange type" ); VM_SECURE_2( psobj->type != VMT_FLOAT, "Tried to div different types" ); psobj->val.f /= (psobj + 1)->val.f; } break; case VMOPC_EXIT: exitCode = cell.s.conds; live = false; break; case VMOPC_FCALL: NEED_TSTACK(); leave_trace(); funID = cell.s.u.number; low_border = vmfun_table[funID].low_border; high_border = vmfun_table[funID].high_border; pmem = low_border; break; case VMOPC_FCMP: ASSURE_STACK2( VMT_FLOAT, VMT_FLOAT ); ftmp = (psobj-1)->val.f - psobj->val.f; psobj -= 2; if ( FLAG_CONDITION( ftmp ) ) pmem = low_border + cell.s.u.number; break; case VMOPC_FEVAL: ASSURE_STACK1( VMT_FLOAT ); if ( FLAG_CONDITION( psobj->val.f ) ) pmem = low_border + cell.s.u.number; psobj--; break; case VMOPC_GETFIELD: ASSURE_SSIZE( 1 ); otmp = *psobj; psobj--; live = (vmtype_table[ otmp.type ].getfield) (this, otmp.val.o, cell.s.u.number); dereference_obj( otmp.type, otmp.val ); if ( !live ) Cout << "GetField returned false"; break; case VMOPC_ICALL: NEED_TSTACK(); leave_trace(); //Cout << "Calling native fun " << cell.s.u.number << endl; (vm_interface_table[cell.s.u.number].fun) (this); collect_trace(); break; case VMOPC_ICMP: ASSURE_STACK2( VMT_INT, VMT_INT ); itmp = (psobj-1)->val.i - psobj->val.i; psobj -= 2; if ( FLAG_CONDITION( itmp ) ) pmem = low_border + cell.s.u.number; break; case VMOPC_IEVAL: ASSURE_STACK1( VMT_INT ); if ( FLAG_CONDITION( psobj->val.i ) ) pmem = low_border + cell.s.u.number; psobj--; break; case VMOPC_ILOOKUPSWITCH: ASSURE_STACK1( VMT_INT ); itmp = cell.s.conds; itmp2 = cell.s.u.number; for ( ; itmp > 0; itmp-- ) { if ( psobj->val.i == getCell().vmint ) { pmem = low_border + getCell().s.u.number; itmp2 = -1; break; } else pmem++; } if ( itmp2 != -1) pmem = low_border + itmp2; break; case VMOPC_INC: ASSURE_SSIZE( 1 ); if ( psobj->type == VMT_INT ) { psobj->val.i++; } else { VM_SECURE_2( psobj->type != VMT_FLOAT , "Tried to increase non-numeric object" ); psobj->val.f++; } break; case VMOPC_INCL: ACCESS_VSTACK( cell.s.u.number ); if (psvar[cell.s.u.number].type == VMT_INT ) { psvar[cell.s.u.number].val.i++; } else { VM_SECURE_2( psvar[cell.s.u.number].type != VMT_FLOAT, "Tried to increase non-numeric local"); psvar[cell.s.u.number].val.f++; } break; case VMOPC_INITL: NEED_VSTACK( cell.s.u.number ); // maybe memset ? otmp.type = VMT_NULL; otmp.val.o = NULL; for ( ; cell.s.u.number > 0 ; cell.s.u.number-- ) { psvar[var_count] = otmp; var_count++; } break; case VMOPC_INITP: ASSURE_SSIZE( cell.s.u.number ); NEED_VSTACK( cell.s.u.number ); for ( ; cell.s.u.number > 0 ; cell.s.u.number-- ) { psvar[var_count] = *psobj; var_count++; psobj--; } break; case VMOPC_ISNULL: ASSURE_SSIZE( 1 ); VM_SECURE_2( !IS_VMOBJ( psobj->type ), "Non VMObject compared to null" ); if ( BOOL_FLAG_CONDITION( !psobj->val.o ) ) pmem = low_border + cell.s.u.number; psobj--; break; case VMOPC_ITABLESWITCH: ASSURE_STACK1( VMT_INT ); itmp2 = cell.s.u.number; // default jump if ( (psobj->val.i < (itmp = getCell().vmint) ) || (psobj->val.i > getCell().vmint) ) { pmem = low_border + itmp2; // jump to default break; } pmem += psobj->val.i - itmp; // value - minimal pmem = low_border + getCell().s.u.number; break; case VMOPC_JMP: pmem = low_border + cell.s.u.number; break; case VMOPC_LICMP: ASSURE_STACK1( VMT_INT ); ACCESS_VSTACK( cell.s.u.number ); // vmstack == int ?? itmp = psvar[cell.s.u.number].val.i - psobj->val.i; psobj--; if ( FLAG_CONDITION( itmp ) ) pmem = low_border + getCell().s.u.number; else pmem++; break; case VMOPC_LIEVAL: ACCESS_VSTACK( cell.s.u.number ); // vstack == int ??? itmp = psvar[cell.s.u.number].val.i; if ( FLAG_CONDITION( itmp ) ) pmem = low_border + getCell().s.u.number; else pmem++; break; case VMOPC_MOD: ASSURE_STACK2( VMT_INT, VMT_INT ); psobj--; psobj->val.i %= (psobj + 1)->val.i; break; case VMOPC_MOVC: ACCESS_VSTACK( cell.s.u.number ); dereference_obj( psvar + cell.s.u.number ); psvar[cell.s.u.number] = vmconstant_table[getCell().s.u.number]; psvar[cell.s.u.number].val = reference_obj(psvar + cell.s.u.number); break; case VMOPC_MOVF: ACCESS_VSTACK( cell.s.u.number ); dereference_obj( psvar + cell.s.u.number ); psvar[cell.s.u.number].type = VMT_FLOAT; psvar[cell.s.u.number].val.f = getCell().vmfloat; break; case VMOPC_MOVI: ACCESS_VSTACK( cell.s.u.number ); dereference_obj( psvar + cell.s.u.number ); psvar[cell.s.u.number].type = VMT_INT; psvar[cell.s.u.number].val.i = getCell().vmint; break; case VMOPC_MPOP: ASSURE_SSIZE( cell.s.conds ); for ( ;cell.s.conds > 0; cell.s.conds--) { dereference_obj( psobj ); psobj--; } break; case VMOPC_MUL: ASSURE_SSIZE( 2 ); if ( psobj->type == VMT_INT ) { psobj--; VM_SECURE_2( psobj->type != VMT_INT, "Tried to mul different types" ); psobj->val.i *= (psobj + 1)->val.i; } else { psobj--; VM_SECURE_2( (psobj + 1)->type != VMT_FLOAT, "Tried to mul strange type" ); VM_SECURE_2( psobj->type != VMT_FLOAT, "Tried to mul different types" ); psobj->val.f *= (psobj + 1)->val.f; } break; case VMOPC_NOP: break; case VMOPC_OCMP: ASSURE_SSIZE( 2 ); VM_SECURE_2( !IS_VMOBJ(psobj->type), "Tried to ocmp non-vmobject" ); VM_SECURE_2( !IS_VMOBJ((psobj-1)->type), "Tried to ocmp non-vmobject" ); if ( BOOL_FLAG_CONDITION( (psobj - 1)->val.o == psobj->val.o) ) pmem = low_border + cell.s.u.number; psobj -= 2; break; case VMOPC_POP: ASSURE_SSIZE( 1 ); dereference_obj( psobj ); psobj--; break; case VMOPC_POPL: ACCESS_VSTACK( cell.s.u.number ); // Do I need to deref and then ref ? - for now just copy ptmp = (psvar + cell.s.u.number); ptmp->type = psobj->type; ptmp->val = psobj->val; psobj--; break; case VMOPC_POPSTAT: itmp = cell.s.u.number; dereference_obj( &vmstatvar_table[itmp] ); vmstatvar_table[itmp] = *psobj; psobj--; break; case VMOPC_PUSHC: NEED_OSTACK( 1 ); psobj++; *psobj = vmconstant_table[cell.s.u.number]; psobj->val = reference_obj(psobj); break; case VMOPC_PUSHF: NEED_OSTACK( 1 ); PUSH_F( getCell().vmfloat ); break; case VMOPC_PUSHFZ: NEED_OSTACK( 1 ); PUSH_F( 0 ); break; case VMOPC_PUSHI: NEED_OSTACK( 1 ); PUSH_I( getCell().vmint ); break; case VMOPC_PUSHIZ: NEED_OSTACK( 1 ); PUSH_I( 0 ); break; case VMOPC_PUSHL: NEED_OSTACK( 1 ); ACCESS_VSTACK( cell.s.u.number ); psobj++; ptmp = (psvar + cell.s.u.number); psobj->type = ptmp->type; psobj->val = reference_obj( ptmp ); break; case VMOPC_PUSHSTAT: NEED_OSTACK( 1 ); itmp = cell.s.u.number; psobj++; *psobj = vmstatvar_table[itmp]; psobj->val = reference_obj( psobj ); break; case VMOPC_PUSHTHIS: NEED_OSTACK( 1 ); // this is always variable number 0 psobj++; psobj->type = psvar->type; psobj->val = reference_obj(psvar); break; case VMOPC_RCALL: crit_error("Opcode not longer supported"); break; // obsolete case VMOPC_REDUCEL: crit_error("Opcode not longer supported"); break; case VMOPC_RET: collect_trace(); break; case VMOPC_SCHARAT: ASSURE_STACK2( VMT_STRING, VMT_INT ); itmp = psobj->val.i; psobj--; if ( itmp < psobj->val.s->len() ) itmp = (psobj->val.s->chars())[itmp]; else itmp = 0; delete psobj->val.s; psobj->type = VMT_INT; psobj->val.i = itmp; break; case VMOPC_SCHARATL: ASSURE_STACK1( VMT_INT ); ACCESS_VSTACKT( cell.s.u.number, VMT_STRING ); itmp = psobj->val.i; if ( itmp < psvar[cell.s.u.number].val.s->len() ) itmp = (psvar[cell.s.u.number].val.s->chars())[itmp]; else itmp = 0; psobj->val.i = itmp; break; case VMOPC_SCMP: ASSURE_STACK2( VMT_STRING, VMT_STRING ); if ( BOOL_FLAG_CONDITION( *(psobj->val.s) == *((psobj-1)->val.s) ) ) pmem = low_border + cell.s.u.number; delete psobj->val.s; psobj--; delete psobj->val.s; psobj--; break; case VMOPC_SCONCAT: ASSURE_STACK2( VMT_STRING, VMT_STRING ); *(psobj-1)->val.s += *psobj->val.s; delete psobj->val.s; psobj--; break; case VMOPC_SETFIELD: ASSURE_SSIZE( 2 ); otmp2 = *psobj; psobj--; otmp = *psobj; psobj--; txt = (vmtype_table[ otmp2.type ].setfield) (this, otmp2.val.o, cell.s.u.number, otmp.val); dereference_obj( otmp.type, otmp.val ); dereference_obj( otmp2.type, otmp2.val ); if ( txt ) crit_error(txt); break; case VMOPC_SFLOATCAT: ASSURE_STACK2( VMT_STRING, VMT_FLOAT ); itmp = (int) psobj->val.f; psobj--; *(psobj->val.s) += itmp; break; case VMOPC_SGETARG: NEED_OSTACK( 1 ); psobj++; psobj->type = VMT_STRING; // memory leak ? psobj->val.s = new String( current_args->getArg() ); break; case VMOPC_SGETARGREST: NEED_OSTACK( 1 ); psobj++; psobj->type = VMT_STRING; // memory leak ? psobj->val.s = new String( current_args->getArgRest() ); break; case VMOPC_SINTCAT: ASSURE_STACK2( VMT_STRING, VMT_INT ); itmp = psobj->val.i; psobj--; *(psobj->val.s) += itmp; break; case VMOPC_SISEMPTY: ASSURE_STACK1( VMT_STRING ); if ( BOOL_FLAG_CONDITION( !(bool)*(psobj->val.s) ) ) pmem = low_border + cell.s.u.number; delete psobj->val.s; psobj--; break; case VMOPC_SISNUMBER: ASSURE_STACK1( VMT_STRING ); if ( BOOL_FLAG_CONDITION( psobj->val.s->isNumber() ) ) pmem = low_border + cell.s.u.number; delete psobj->val.s; psobj--; break; case VMOPC_SLEEP: ASSURE_STACK1( VMT_FLOAT ); putToSleep( psobj->val.f ); psobj--; return; case VMOPC_SLOOKUPSWITCH: ASSURE_STACK1( VMT_STRING ); itmp = cell.s.conds; itmp2 = cell.s.u.number; for ( ; itmp > 0; itmp-- ) { if ( *(psobj->val.s) == *(vmconstant_table[getCell().s.u.number].val.s) ) { pmem = low_border + getCell().s.u.number; itmp2 = -1; break; } else pmem++; } if ( itmp2 != -1) pmem = low_border + itmp2; break; case VMOPC_SPUSHEMPTY: NEED_OSTACK( 1 ); psobj++; psobj->type = VMT_STRING; psobj->val.s = new String(); break; case VMOPC_SSTARTARGS: ASSURE_STACK1( VMT_STRING ); psobj->val.s->startArgs(); if ( current_args ) delete current_args; current_args = psobj->val.s; psobj--; break; case VMOPC_STOINT: ASSURE_STACK1( VMT_STRING ); itmp = psobj->val.s->asInt(); delete psobj->val.s; psobj->val.i = itmp; psobj->type = VMT_INT; break; case VMOPC_SUB: ASSURE_SSIZE( 2 ); if ( psobj->type == VMT_INT ) { psobj--; VM_SECURE_2( psobj->type != VMT_INT, "Tried to sub different types" ); psobj->val.i -= (psobj + 1)->val.i; } else { psobj--; VM_SECURE_2( (psobj + 1)->type != VMT_FLOAT, "Tried to sub strange type" ); VM_SECURE_2( psobj->type != VMT_FLOAT, "Tried to sub different types" ); psobj->val.f -= (psobj + 1)->val.f; } break; case VMOPC_SWAP: ASSURE_SSIZE( 2 ); otmp = *psobj; *psobj = *(psobj - 1); *(psobj-1) = otmp; break; case VMOPC_UPCAST: ASSURE_SSIZE(1); VM_SECURE_2( !IS_VMOBJ(psobj->type), "Tried to upcast non-vmobject" ); if ( !psobj->val.o ) { psobj->type = (vmtype) cell.s.u.number; } else { otmp.type = psobj->val.o->getVMType(); if ( canCastTo( otmp.type, ((vmtype) cell.s.u.number) ) ) psobj->type = (vmtype) cell.s.u.number; else crit_error("Illegal upcast"); } break; default: char buf[100]; sprintf(buf, "Unrecognized opcode %d." , cell.s.opcode ); crit_error( buf ); break; } } // dereference objects on stack and variable stack itmp = ( psobj - oStack ); // Cout << itmp << " objects on oStack"<<endl; for ( ; itmp > 0; itmp--, psobj--) { dereference_obj(psobj); } itmp = ( psvar + var_count - vStack ); // Cout << itmp << " objects on vStack"<<endl; for ( itmp--; itmp >=0; itmp-- ) { // Cout << "Dereferencing ..."; dereference_obj( &vStack[itmp] ); // Cout << "done" <<endl; } if ( current_args ) delete current_args; current_args = NULL; Cout << "VMachine exited with code " << (int) exitCode << endl; return; }