// // debug // Specialised bytecode set support for debugging // F.J. Alberti // case kBreak: // Suspends the current evaluation thread m->top[--m->pp] = NIL; // always return nil checkOverflow(m, 0) #if defined(INCLUDE_DEBUGGER) // Break! if (debug.sock) { MMechostr(MSKRUNTIME, "User break\n"); DBGRequestBreak(m, kBrksrcUserBreak); } #elif defined(SCOL_DEBUG) _asm {int 3} #endif break; case kAssert: { // Raises an exception if 'assert' condition is false (or nil) uint32 line = *(uint32*)&fetch(pc); pc += ALIGNMENT(4); int cond = m->top[m->pp]; // assertion m->top[m->pp] = NIL; // always return nil if (cond == NIL || cond>>1 == 0) { #if defined(RELEASE_DEVELOPER) int s = m->tape[(m->top[bp+OFFHFUN]>>1)+SizeHeader+OFFPVAR]>>1; #endif MMechostr(MSKRUNTIME, "(!) "MSGEASSERT"\n", #if defined(RELEASE_DEVELOPER) (char*)&m->tape[(m->tape[(m->tape[s+SizeHeader+OFFVPKG]>>1)+SizeHeader+OFFPKNAME]>>1)+SizeHeader], line, (char*)&m->tape[(m->tape[s+SizeHeader+OFFVNAME]>>1)+SizeHeader], m->top[bp+OFFHFUN]>>1, #else m->top[bp+OFFHFUN]>>1, line, #endif (cond == NIL) ? "Null assertion" : "Assertion violated"); #if defined(INCLUDE_DEBUGGER) // If debugger is online, send a break request; // otherwise, raise a runtime exception if (debug.sock) { if (res = DBGNotifyAssertionViolated(m, "")) throw Exception(res); DBGRequestBreak(m, kBrksrcUserAssert); } else throw Exception(MERRTYP); #else throw Exception(MERRTYP); #endif } break; } case kAddloc: { // to be deprecated // Adds a local variable (index, name) pair into the list of locals // of the currently executing thread #if defined(INCLUDE_DEBUGGER) byte i = fetch(pc); // local variable index pc += ALIGNMENT(1); uint32 len = *(uint32*)&fetch(pc); // local variable name length pc += ALIGNMENT(4); // Allocate a SCOL string to hold identifier SEPTR p = MMmalloc(m, ((len+1)/sizeof(int32)+((len+1)%sizeof(int32)>0))+1, TYPEBUF); if (p == NIL) throw Exception(MERRMEM); m->tape[p+SizeHeader] = len; char* name = (char*)&m->tape[p+SizeHeader+1]; strncpy(name, (char*)&fetch(pc), len); name[len] = '\0'; pc += ALIGNMENT(1)*len; // Add string into the list of local variables m->top[--m->pp] = p<<1|0x00000001; // save pointer to heap block checkOverflow(m, 0) int32 pp = m->pp; checkOverflow(m, 4) m->top[--m->pp] = i<<1; m->top[--m->pp] = m->top[pp]; m->top[--m->pp] = m->top[bp+OFFHLOC]; m->top[--m->pp] = DBG_LOC_SIZE<<1; if (res = MBdeftab(m)) throw Exception(res); m->top[bp+OFFHLOC] = m->top[m->pp++]; // Notify debugger that a new local has been added m->top[--m->pp] = i<<1; m->top[--m->pp] = m->top[pp]; m->top[--m->pp] = m->top[fp-i]; if (res = DBGNotifyLocalVariablePushed(m)) throw Exception(res); m->pp++; #else throw Exception(MERRTYP, "Interpreter::exec(): internal error: 'addloc'\n"); #endif break; } case kRemloc: { // to be deprecated // Removes 'nlocs' local variables from the list of locals #if defined(INCLUDE_DEBUGGER) uint16 nlocs = *(uint16*)&fetch(pc); pc += ALIGNMENT(2); // Drop the first 'nlocs' variables of the list of locals for (int i = nlocs; i > 0; i--) m->top[bp+OFFHLOC] = m->tape[(m->top[bp+OFFHLOC]>>1)+SizeHeader+DBG_LOC_NEXT]; // Notify debugger that we are leaving the scope of 'nlocs' variables m->top[--m->pp] = nlocs<<1; checkOverflow(m, 0) if (res = DBGNotifyLocalVariablePopped(m)) throw Exception(res); #else throw Exception(MERRTYP, "Interpreter::exec(): internal error: 'remloc'\n"); #endif break; } case kDebug: // Break if debugger is online and the trace mode has been activated #if defined(SCOL_DEBUGGER_AWARE) if (debug.sock && debug.traceMode != kTraceNone) { DBGUpdatePosition(m, pc-ALIGNMENT(1)); DBGRequestBreak(m, kBrksrcTraceFunction); } #endif break;