// Goes over the list of nodes that needs to be freed // and frees them if no HP points at them. void scan(HPLocal localData) { int i; //Stage 1: scan HP list and insert non-null values to plist Set plist = localData->plist; setReset(plist); HPRecord* curr = localData->HPRecHead; while (curr != NULL) { for (i = 0; i < localData->hpData->HP_COUNT; i++) { if (curr->hp[i] != NULL) { setAdd(plist, (long) (curr->hp[i])); } } curr = curr->next; } //Stage 2: search plist //uses two stacks instead of allocating a new one each time scan() is called SwapStacks(&localData->rlist, &localData->temp); stackReset(localData->rlist); ReclaimationData* recData = stackPop(localData->temp); while (recData != NULL) { if (setContains(plist, (long) recData->address)) { stackPush(localData->rlist, recData->address, recData->reclaimationFunc); } else { (*((ReclaimationFunc*)recData->reclaimationFunc))(recData->address); } recData = stackPop(localData->temp); } setReset(plist); }
void stackInit( Stack *theStack, NewStack *theNewStack, long Index ) { stackReset( theStack ); theStack->st_Left = theNewStack->ns_Left; theStack->st_Top = theNewStack->ns_Top; theStack->st_Index = ( uchar )Index; theStack->st_ClassIdx = theNewStack->ns_ClassIdx; theStack->st_Owner = theNewStack->ns_Owner; theStack->st_Suit = theNewStack->ns_Suit; }
/* Run a compiled script */ bool interpRunScript(SCRIPT_CONTEXT *psContext, INTERP_RUNTYPE runType, UDWORD index, UDWORD offset) { UDWORD data; OPCODE opcode; INTERP_VAL sVal, *psVar,*InstrPointer; VAL_CHUNK *psGlobals; UDWORD numGlobals = 0; INTERP_VAL *pCodeStart, *pCodeEnd, *pCodeBase; SCRIPT_FUNC scriptFunc = 0; SCRIPT_VARFUNC scriptVarFunc = 0; SCRIPT_CODE *psProg; SDWORD instructionCount = 0; UDWORD CurEvent = 0; bool bStop = false, bEvent = false; UDWORD callDepth = 0; bool bTraceOn=false; //enable to debug function/event calls ASSERT(psContext != NULL, "Invalid context pointer"); psProg = psContext->psCode; psCurProg = psProg; //remember for future use ASSERT(psProg != NULL, "Invalid script code pointer"); if (bInterpRunning) { debug(LOG_ERROR, "Interpreter already running" " - callback being called from within a script function?"); goto exit_with_error; } // note that the interpreter is running to stop recursive script calls bInterpRunning = true; // Reset the stack in case another script messed up stackReset(); //reset return stack retStackReset(); // Turn off tracing initially interpTrace = false; /* Get the global variables */ numGlobals = psProg->numGlobals; psGlobals = psContext->psGlobals; bEvent = false; // Find the code range switch (runType) { case IRT_TRIGGER: if (index > psProg->numTriggers) { ASSERT(false, "Trigger index out of range"); return false; } pCodeBase = psProg->pCode + psProg->pTriggerTab[index]; pCodeStart = pCodeBase; pCodeEnd = psProg->pCode + psProg->pTriggerTab[index+1]; bCurCallerIsEvent = false; // find the debug info for the trigger strcpy(last_called_script_event, eventGetTriggerID(psProg, index)); if(bTraceOn) debug(LOG_SCRIPT,"Trigger: %s", last_called_script_event); break; case IRT_EVENT: if (index > psProg->numEvents) { ASSERT(false, "Trigger index out of range"); return false; } pCodeBase = psProg->pCode + psProg->pEventTab[index]; pCodeStart = pCodeBase + offset; //offset only used for pause() script function pCodeEnd = psProg->pCode + psProg->pEventTab[index+1]; bEvent = true; //remember it's an event bCurCallerIsEvent = true; // remember last called event/function strcpy(last_called_script_event, eventGetEventID(psProg, index)); if(bTraceOn) debug(LOG_SCRIPT,"Original event name: %s", last_called_script_event); break; default: ASSERT(false, "Unknown run type"); return false; } // Get the first opcode InstrPointer = pCodeStart; /* Make sure we start with an opcode */ ASSERT(InstrPointer->type == VAL_PKOPCODE || InstrPointer->type == VAL_OPCODE, "Expected an opcode at the beginning of the interpreting process (type=%d)", InstrPointer->type); //opcode = InstrPointer->v.ival >> OPCODE_SHIFT; instructionCount = 0; CurEvent = index; bStop = false; // create new variable environment for this call if (bEvent) { createVarEnvironment(psContext, CurEvent); } while(!bStop) { // Run the code if (InstrPointer < pCodeEnd)// && opcode != OP_EXIT) { if (instructionCount > INTERP_MAXINSTRUCTIONS) { debug( LOG_ERROR, "interpRunScript: max instruction count exceeded - infinite loop ?" ); goto exit_with_error; } instructionCount++; TRCPRINTF( "%-6d ", (int)(InstrPointer - psProg->pCode) ); opcode = (OPCODE)(InstrPointer->v.ival >> OPCODE_SHIFT); //get opcode data = (SDWORD)(InstrPointer->v.ival & OPCODE_DATAMASK); //get data - only used with packed opcodes switch (opcode) { /* Custom function call */ case OP_FUNC: //debug( LOG_SCRIPT, "-OP_FUNC" ); //debug( LOG_SCRIPT, "OP_FUNC: remember event %d, ip=%d", CurEvent, (ip + 2) ); if(!retStackPush(CurEvent, (InstrPointer + aOpSize[opcode]))) //Remember where to jump back later { debug( LOG_ERROR, "interpRunScript() - retStackPush() failed."); return false; } ASSERT(((INTERP_VAL *)(InstrPointer+1))->type == VAL_EVENT, "wrong value type passed for OP_FUNC: %d", ((INTERP_VAL *)(InstrPointer+1))->type); // get index of the new event CurEvent = ((INTERP_VAL *)(InstrPointer+1))->v.ival; //Current event = event to jump to if (CurEvent > psProg->numEvents) { debug( LOG_ERROR, "interpRunScript: trigger index out of range"); goto exit_with_error; } // create new variable environment for this call createVarEnvironment(psContext, CurEvent); //Set new code execution boundaries //---------------------------------- pCodeBase = psProg->pCode + psProg->pEventTab[CurEvent]; pCodeStart = pCodeBase; pCodeEnd = psProg->pCode + psProg->pEventTab[CurEvent+1]; InstrPointer = pCodeStart; //Start at the beginning of the new event //remember last called event/index strcpy(last_called_script_event, eventGetEventID(psProg, CurEvent)); if(bTraceOn) debug(LOG_SCRIPT,"Called: '%s'", last_called_script_event); //debug( LOG_SCRIPT, "-OP_FUNC: jumped to event %d; ip=%d, numLocalVars: %d", CurEvent, ip, psContext->psCode->numLocalVars[CurEvent] ); //debug( LOG_SCRIPT, "-END OP_FUNC" ); break; //handle local variables case OP_PUSHLOCAL: //debug( LOG_SCRIPT, "OP_PUSHLOCAL"); //debug( LOG_SCRIPT, "OP_PUSHLOCAL, (CurEvent=%d, data =%d) num loc vars: %d; pushing: %d", CurEvent, data, psContext->psCode->numLocalVars[CurEvent], psContext->psCode->ppsLocalVarVal[CurEvent][data].v.ival); if (data >= psContext->psCode->numLocalVars[CurEvent]) { debug(LOG_ERROR, "interpRunScript: OP_PUSHLOCAL: variable index out of range"); goto exit_with_error; } //debug(LOG_SCRIPT, "OP_PUSHLOCAL type: %d", psContext->psCode->ppsLocalVarVal[CurEvent][data].type); if (!stackPush( &(varEnvironment[retStackCallDepth()][data]) )) { debug(LOG_ERROR, "interpRunScript: OP_PUSHLOCAL: push failed"); goto exit_with_error; } InstrPointer += aOpSize[opcode]; break; case OP_POPLOCAL: //debug( LOG_SCRIPT, "OP_POPLOCAL, event index: '%d', data: '%d'", CurEvent, data); //debug( LOG_SCRIPT, "OP_POPLOCAL, numLocalVars: '%d'", psContext->psCode->numLocalVars[CurEvent]); if (data >= psContext->psCode->numLocalVars[CurEvent]) { debug(LOG_ERROR, "interpRunScript: OP_POPLOCAL: variable index out of range"); goto exit_with_error; } //DbgMsg("OP_POPLOCAL type: %d, CurEvent=%d, data=%d", psContext->psCode->ppsLocalVarVal[CurEvent][data].type, CurEvent, data); if ( !stackPopType( &(varEnvironment[retStackCallDepth()][data]) ) ) { debug(LOG_ERROR, "interpRunScript: OP_POPLOCAL: pop failed"); goto exit_with_error; } //debug(LOG_SCRIPT, "OP_POPLOCAL: type=%d, val=%d", psContext->psCode->ppsLocalVarVal[CurEvent][data].type, psContext->psCode->ppsLocalVarVal[CurEvent][data].v.ival); InstrPointer += aOpSize[opcode]; break; case OP_PUSHLOCALREF: // The type of the variable is stored in with the opcode sVal.type = (INTERP_TYPE)(InstrPointer->v.ival & OPCODE_DATAMASK); ASSERT( ((INTERP_VAL *)(InstrPointer + 1))->type == VAL_INT, "wrong value type passed for OP_PUSHLOCALREF: %d", ((INTERP_VAL *)(InstrPointer + 1))->type); /* get local var index */ data = ((INTERP_VAL *)(InstrPointer + 1))->v.ival; if (data >= psContext->psCode->numLocalVars[CurEvent]) { debug(LOG_ERROR, "interpRunScript: OP_PUSHLOCALREF: variable index out of range"); goto exit_with_error; } /* get local variable */ sVal.v.oval = &(varEnvironment[retStackCallDepth()][data]); TRCPRINTOPCODE(opcode); TRCPRINTVAL(sVal); TRCPRINTF( "\n" ); if (!stackPush(&sVal)) { debug(LOG_ERROR, "interpRunScript: OP_PUSHLOCALREF: push failed"); goto exit_with_error; } InstrPointer += aOpSize[opcode]; break; case OP_PUSH: // The type of the value is stored in with the opcode sVal.type = (INTERP_TYPE)(InstrPointer->v.ival & OPCODE_DATAMASK); //ASSERT( ((INTERP_VAL *)(InstrPointer + 1))->type == sVal.type, // "wrong value type passed for OP_PUSH: %d, expected: %d", ((INTERP_VAL *)(InstrPointer + 1))->type, sVal.type ); ASSERT(interpCheckEquiv(((INTERP_VAL *)(InstrPointer + 1))->type, sVal.type), "wrong value type passed for OP_PUSH: %d, expected: %d", ((INTERP_VAL *)(InstrPointer + 1))->type, sVal.type); /* copy value */ memcpy(&sVal, (INTERP_VAL *)(InstrPointer + 1), sizeof(INTERP_VAL)); TRCPRINTOPCODE(opcode); TRCPRINTVAL(sVal); TRCPRINTF( "\n" ); if (!stackPush(&sVal)) { // Eeerk, out of memory debug( LOG_ERROR, "interpRunScript: out of memory!" ); goto exit_with_error; } InstrPointer += aOpSize[opcode]; break; case OP_PUSHREF: // The type of the variable is stored in with the opcode sVal.type = (INTERP_TYPE)(InstrPointer->v.ival & OPCODE_DATAMASK); // store pointer to INTERP_VAL sVal.v.oval = interpGetVarData(psGlobals, ((INTERP_VAL *)(InstrPointer + 1))->v.ival); TRCPRINTOPCODE(opcode); TRCPRINTVAL(sVal); TRCPRINTF( "\n" ); if (!stackPush(&sVal)) { // Eeerk, out of memory debug( LOG_ERROR, "interpRunScript: out of memory!" ); goto exit_with_error; } InstrPointer += aOpSize[opcode]; break; case OP_POP: ASSERT( InstrPointer->type == VAL_OPCODE, "wrong value type passed for OP_POP: %d", InstrPointer->type); TRCPRINTOPCODE(opcode); if (!stackPop(&sVal)) { debug( LOG_ERROR, "interpRunScript: could not do stack pop" ); goto exit_with_error; } InstrPointer += aOpSize[opcode]; break; case OP_BINARYOP: ASSERT( InstrPointer->type == VAL_PKOPCODE, "wrong value type passed for OP_BINARYOP: %d", InstrPointer->type); TRCPRINTOPCODE(data); if (!stackBinaryOp((OPCODE)data)) { debug( LOG_ERROR, "interpRunScript: could not do binary op" ); goto exit_with_error; } TRCPRINTSTACKTOP(); TRCPRINTF( "\n" ); InstrPointer += aOpSize[opcode]; break; case OP_UNARYOP: ASSERT( InstrPointer->type == VAL_PKOPCODE, "wrong value type passed for OP_UNARYOP: %d", InstrPointer->type); TRCPRINTOPCODE(data); if (!stackUnaryOp((OPCODE)data)) { debug( LOG_ERROR, "interpRunScript: could not do unary op" ); goto exit_with_error; } TRCPRINTSTACKTOP(); TRCPRINTF( "\n" ); InstrPointer += aOpSize[opcode]; break; case OP_PUSHGLOBAL: ASSERT( InstrPointer->type == VAL_PKOPCODE, "wrong value type passed for OP_PUSHGLOBAL: %d", InstrPointer->type); TRCPRINTF( "PUSHGLOBAL %d\n", data ); if (data >= numGlobals) { debug( LOG_ERROR, "interpRunScript: variable index out of range" ); goto exit_with_error; } if (!stackPush(interpGetVarData(psGlobals, data))) { debug( LOG_ERROR, "interpRunScript: could not do stack push" ); goto exit_with_error; } InstrPointer += aOpSize[opcode]; break; case OP_POPGLOBAL: ASSERT( InstrPointer->type == VAL_PKOPCODE, "wrong value type passed for OP_POPGLOBAL: %d", InstrPointer->type); TRCPRINTF( "POPGLOBAL %d ", data ); TRCPRINTSTACKTOP(); TRCPRINTF( "\n" ); if (data >= numGlobals) { debug( LOG_ERROR, "interpRunScript: variable index out of range" ); goto exit_with_error; } if (!stackPopType(interpGetVarData(psGlobals, data))) { debug( LOG_ERROR, "interpRunScript: could not do stack pop" ); goto exit_with_error; } InstrPointer += aOpSize[opcode]; break; case OP_PUSHARRAYGLOBAL: ASSERT( InstrPointer->type == VAL_PKOPCODE, "wrong value type passed for OP_PUSHARRAYGLOBAL: %d", InstrPointer->type); TRCPRINTOPCODE(opcode); if (!interpGetArrayVarData(&InstrPointer, psGlobals, psProg, &psVar)) { debug( LOG_ERROR, "interpRunScript: could not get array var data, CurEvent=%d", CurEvent ); goto exit_with_error; } TRCPRINTF( "\n" ); if (!stackPush(psVar)) { debug( LOG_ERROR, "interpRunScript: could not do stack push" ); goto exit_with_error; } break; case OP_POPARRAYGLOBAL: ASSERT( InstrPointer->type == VAL_PKOPCODE, "wrong value type passed for OP_POPARRAYGLOBAL: %d", InstrPointer->type); TRCPRINTOPCODE(opcode); if (!interpGetArrayVarData(&InstrPointer, psGlobals, psProg, &psVar)) { debug( LOG_ERROR, "interpRunScript: could not get array var data" ); goto exit_with_error; } TRCPRINTSTACKTOP(); TRCPRINTF( "\n" ); if (!stackPopType(psVar)) { debug( LOG_ERROR, "interpRunScript: could not do pop stack of type" ); goto exit_with_error; } break; case OP_JUMPFALSE: ASSERT( InstrPointer->type == VAL_PKOPCODE, "wrong value type passed for OP_JUMPFALSE: %d", InstrPointer->type); TRCPRINTF( "JUMPFALSE %d (%d)", (SWORD)data, (int)(InstrPointer - psProg->pCode + (SWORD)data) ); if (!stackPop(&sVal)) { debug( LOG_ERROR, "interpRunScript: could not do pop of stack" ); goto exit_with_error; } if (!sVal.v.bval) { // Do the jump TRCPRINTF( " - done -\n" ); InstrPointer += (SWORD)data; if (InstrPointer < pCodeStart || InstrPointer > pCodeEnd) { debug( LOG_ERROR, "interpRunScript: jump out of range" ); goto exit_with_error; } } else { TRCPRINTF( "\n" ); InstrPointer += aOpSize[opcode]; } break; case OP_JUMP: ASSERT( InstrPointer->type == VAL_PKOPCODE, "wrong value type passed for OP_JUMP: %d", InstrPointer->type); TRCPRINTF( "JUMP %d (%d)\n", (SWORD)data, (int)(InstrPointer - psProg->pCode + (SWORD)data) ); // Do the jump InstrPointer += (SWORD)data; if (InstrPointer < pCodeStart || InstrPointer > pCodeEnd) { debug( LOG_ERROR, "interpRunScript: jump out of range" ); goto exit_with_error; } break; case OP_CALL: //debug(LOG_SCRIPT, "OP_CALL"); ASSERT( InstrPointer->type == VAL_OPCODE, "wrong value type passed for OP_CALL: %d", InstrPointer->type); scriptFunc = ((INTERP_VAL *)(InstrPointer+1))->v.pFuncExtern; TRCPRINTFUNC( scriptFunc ); TRCPRINTF( "\n" ); //debug(LOG_SCRIPT, "OP_CALL 1"); if (!scriptFunc()) { debug( LOG_ERROR, "interpRunScript: could not do func" ); goto exit_with_error; } //debug(LOG_SCRIPT, "OP_CALL 2"); InstrPointer += aOpSize[opcode]; //debug(LOG_SCRIPT, "OP_CALL 3"); break; case OP_VARCALL: ASSERT( InstrPointer->type == VAL_PKOPCODE, "wrong value type passed for OP_VARCALL: %d", InstrPointer->type); TRCPRINTOPCODE(opcode); TRCPRINTVARFUNC( ((INTERP_VAL *)(InstrPointer+1))->v.pObjGetSet, data ); TRCPRINTF( "(%d)\n", data ); ASSERT( ((INTERP_VAL *)(InstrPointer+1))->type == VAL_OBJ_GETSET, "wrong set/get function pointer type passed for OP_VARCALL: %d", ((INTERP_VAL *)(InstrPointer+1))->type); scriptVarFunc =((INTERP_VAL *)(InstrPointer+1))->v.pObjGetSet; if (!scriptVarFunc(data)) { debug( LOG_ERROR, "interpRunScript: could not do var func" ); goto exit_with_error; } InstrPointer += aOpSize[opcode]; break; case OP_EXIT: /* end of function/event, "exit" or "return" statements */ ASSERT( InstrPointer->type == VAL_OPCODE, "wrong value type passed for OP_EXIT: %d", InstrPointer->type); // jump out of the code InstrPointer = pCodeEnd; break; case OP_PAUSE: ASSERT( InstrPointer->type == VAL_PKOPCODE, "wrong value type passed for OP_PAUSE: %d", InstrPointer->type); TRCPRINTF( "PAUSE %d\n", data ); ASSERT( stackEmpty(), "interpRunScript: OP_PAUSE without empty stack" ); InstrPointer += aOpSize[opcode]; // tell the event system to reschedule this event if (!eventAddPauseTrigger(psContext, index, (UDWORD)(InstrPointer - pCodeBase), data)) //only original caller can be paused since we pass index and not CurEvent (not sure if that's what we want) { debug( LOG_ERROR, "interpRunScript: could not add pause trigger" ); goto exit_with_error; } // now jump out of the event InstrPointer = pCodeEnd; break; case OP_TO_FLOAT: ASSERT( InstrPointer->type == VAL_OPCODE, "wrong value type passed for OP_TO_FLOAT: %d", InstrPointer->type); if(!stackCastTop(VAL_FLOAT)) { debug( LOG_ERROR, "interpRunScript: OP_TO_FLOAT failed" ); goto exit_with_error; } InstrPointer += aOpSize[opcode]; break; case OP_TO_INT: ASSERT( InstrPointer->type == VAL_OPCODE, "wrong value type passed for OP_TO_INT: %d", InstrPointer->type); if(!stackCastTop(VAL_INT)) { debug( LOG_ERROR, "interpRunScript: OP_TO_INT failed" ); goto exit_with_error; } InstrPointer += aOpSize[opcode]; break; default: debug(LOG_ERROR, "interpRunScript: unknown opcode: %d, type: %d", opcode, InstrPointer->type); goto exit_with_error; break; } } else //End of the event reached, see if we have to jump back to the caller function or just exit { //debug(LOG_SCRIPT, "End of event reached"); if(!retStackIsEmpty()) //There was a caller function before this one { // destroy current variable environment destroyVarEnvironment(psContext, retStackCallDepth(), CurEvent); //pop caller function index and return address if (!retStackPop(&CurEvent, &InstrPointer)) { debug( LOG_ERROR, "interpRunScript() - retStackPop() failed."); return false; } //remember last called event/index strcpy(last_called_script_event, eventGetEventID(psProg, CurEvent)); if(bTraceOn) debug(LOG_SCRIPT,"Returned to: '%s'", last_called_script_event); //debug( LOG_SCRIPT, "RETURNED TO CALLER EVENT %d", CurEvent ); //Set new boundaries //-------------------------- if(retStackIsEmpty()) //if we jumped back to the original caller { if(!bEvent) //original caller was a trigger (is it possible at all?) { pCodeBase = psProg->pCode + psProg->pTriggerTab[CurEvent]; pCodeStart = pCodeBase; pCodeEnd = psProg->pCode + psProg->pTriggerTab[CurEvent+1]; } else //original caller was an event { pCodeBase = psProg->pCode + psProg->pEventTab[CurEvent]; pCodeStart = pCodeBase + offset; //also use the offset passed, since it's an original caller event (offset is used for pause() ) pCodeEnd = psProg->pCode + psProg->pEventTab[CurEvent+1]; } } else //we are still jumping thru functions (this can't be a callback, since it can't/should not be called) { pCodeBase = psProg->pCode + psProg->pEventTab[CurEvent]; pCodeStart = pCodeBase; pCodeEnd = psProg->pCode + psProg->pEventTab[CurEvent+1]; } } else //we have returned to the original caller event/function { //debug( LOG_SCRIPT, " *** CALL STACK EMPTY ***" ); //reset local vars only if original caller was an event, not a trigger if(bEvent) { // destroy current variable environment destroyVarEnvironment(psContext, retStackCallDepth(), CurEvent); } bStop = true; //Stop execution of this event here, no more calling functions stored } } }