Go to the documentation of this file.00001 #include "LocalVirtualMachine.h"
00002 #include "../common/consts.h"
00003 #include <QMessageBox>
00004 #include <QtDebug>
00005
00006 #include <stdio.h>
00007 #include <stdlib.h>
00008
00009 Aseba::LocalVirtualMachine *target = 0;
00010
00011 void AsebaSendEvent(AsebaVMState *vm, uint16 event, uint16 start, uint16 length)
00012 {
00013 Q_UNUSED(vm);
00014 target->emitEvent(event, start, length);
00015
00016
00017
00018
00019
00020 }
00021
00022 void AsebaArrayAccessOutOfBoundsException(AsebaVMState *vm, uint16 index)
00023 {
00024 target->emitArrayAccessOutOfBounds(vm->pc, vm->sp, index);
00025
00026
00027
00028 }
00029
00030 void AsebaDivisionByZeroException(AsebaVMState *vm)
00031 {
00032 target->emitDivisionByZero(vm->pc, vm->sp);
00033 }
00034
00035 void AsebaNativeFunction(AsebaVMState *vm, uint16 id)
00036 {
00037 QString message = QObject::tr("Native function %0 (sp = %1)").arg(id).arg(vm->sp);
00038 QMessageBox::information(0, QObject::tr("Native function called"), message);
00039 }
00040
00041 #ifdef ASEBA_ASSERT
00042
00043 void AsebaAssert(AsebaVMState *vm, AsebaAssertReason reason)
00044 {
00045
00046 uint16 pc = vm->pc;
00047 uint16 sp = vm->sp;
00048 QString message = QObject::tr("Assertion at 0x%0 (sp = %2):\n").arg(pc, 16).arg(sp);
00049 switch (reason)
00050 {
00051 case ASEBA_ASSERT_UNKNOWN: message += QObject::tr("unknown"); break;
00052 case ASEBA_ASSERT_UNKNOWN_BINARY_OPERATOR: message += QObject::tr("unknown arithmetic binary operator"); break;
00053 case ASEBA_ASSERT_UNKNOWN_BYTECODE: message += QObject::tr("unknown bytecode"); break;
00054 case ASEBA_ASSERT_STACK_UNDERFLOW: message += QObject::tr("execution stack underflow"); break;
00055 case ASEBA_ASSERT_STACK_OVERFLOW: message += QObject::tr("stack overflow"); break;
00056 case ASEBA_ASSERT_OUT_OF_VARIABLES_BOUNDS: message += QObject::tr("out of variables bounds"); break;
00057 case ASEBA_ASSERT_OUT_OF_BYTECODE_BOUNDS: message += QObject::tr("out of bytecode bounds"); break;
00058 case ASEBA_ASSERT_STEP_OUT_OF_RUN: message += QObject::tr("step called while not thread running"); break;
00059 case ASEBA_ASSERT_BREAKPOINT_OUT_OF_BYTECODE_BOUNDS: message += QObject::tr("a breakpoint has been set out of bytecode bounds"); break;
00060 case ASEBA_ASSERT_EMIT_BUFFER_TOO_LONG: message += QObject::tr("tried to emit a buffer too long"); break;
00061 default: message = QObject::tr("unknown assert define, your code seems broken"); break;
00062 }
00063
00064
00065 QMessageBox::critical(0, QObject::tr("VM Assertion Failed"), message);
00066 }
00067
00068 #endif
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 namespace Aseba
00084 {
00085 LocalVirtualMachine::LocalVirtualMachine()
00086 {
00087 AsebaVMInit(&vmState);
00088 vmState.flags = ASEBA_VM_DEBUGGER_ATTACHED_MASK;
00089
00090 target = this;
00091
00092 description.variablesSize = 64;
00093 description.bytecodeSize = 256;
00094 description.stackSize = 32;
00095
00096 sizesChanged();
00097 runEvent = false;
00098 startTimer(40);
00099 }
00100
00101 void LocalVirtualMachine::sizesChanged()
00102 {
00103
00104 stop();
00105
00106
00107 vmBytecode.resize(description.bytecodeSize);
00108 vmState.bytecodeSize = description.bytecodeSize;
00109 vmState.bytecode = &vmBytecode[0];
00110
00111 vmVariables.resize(description.variablesSize);
00112 vmState.variablesSize = description.variablesSize;
00113 vmState.variables = &vmVariables[0];
00114
00115 vmStack.resize(description.stackSize);
00116 vmState.stackSize = description.stackSize;
00117 vmState.stack = &vmStack[0];
00118 }
00119
00120 void LocalVirtualMachine::uploadBytecode(const BytecodeVector &bytecode)
00121 {
00122 Q_ASSERT(bytecode.size() <= vmBytecode.size());
00123
00124 for (size_t i = 0; i < bytecode.size(); i++)
00125 vmBytecode[i] = bytecode[i].bytecode;
00126 debugBytecode = bytecode;
00127 }
00128
00129 void LocalVirtualMachine::setupEvent(unsigned id)
00130 {
00131 AsebaVMSetupEvent(&vmState, id);
00132
00133 if (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK))
00134 {
00135 Q_ASSERT(vmState.pc < debugBytecode.size());
00136 if (AsebaMaskIsClear(vmState.flags, ASEBA_VM_RUN_BACKGROUND_MASK))
00137 {
00138 emit executionModeChanged(EXECUTION_STEP_BY_STEP);
00139 emit executionPosChanged(debugBytecode[vmState.pc].line);
00140 }
00141 }
00142 }
00143
00144 void LocalVirtualMachine::next()
00145 {
00146 Q_ASSERT(vmState.pc < debugBytecode.size());
00147
00148
00149 unsigned short previousPC = vmState.pc;
00150 unsigned previousLine = debugBytecode[previousPC].line;
00151 do
00152 {
00153
00154 AsebaVMStep(&vmState);
00155 Q_ASSERT(!AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK) || (vmState.pc < debugBytecode.size()));
00156 }
00157 while (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK) && (vmState.pc != previousPC) && (debugBytecode[vmState.pc].line == previousLine));
00158
00159
00160 emit variablesMemoryChanged(vmVariables);
00161 if (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK))
00162 emit executionPosChanged(debugBytecode[vmState.pc].line);
00163 else
00164 emit executionModeChanged(EXECUTION_INACTIVE);
00165 }
00166
00167 void LocalVirtualMachine::runStepSwitch()
00168 {
00169 if (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK))
00170 {
00171 if (runEvent)
00172 emit executionModeChanged(EXECUTION_STEP_BY_STEP);
00173 else
00174 emit executionModeChanged(EXECUTION_RUN_EVENT);
00175 runEvent = !runEvent;
00176 }
00177 }
00178
00179 void LocalVirtualMachine::runBackground()
00180 {
00181 runEvent = false;
00182 AsebaMaskSet(vmState.flags, ASEBA_VM_RUN_BACKGROUND_MASK);
00183 emit executionModeChanged(EXECUTION_RUN_BACKGROUND);
00184 }
00185
00186 void LocalVirtualMachine::stop()
00187 {
00188 runEvent = false;
00189 AsebaMaskClear(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK | ASEBA_VM_RUN_BACKGROUND_MASK);
00190 emit executionModeChanged(EXECUTION_INACTIVE);
00191 }
00192
00193 bool LocalVirtualMachine::setBreakpoint(unsigned line)
00194 {
00195 for (size_t i = 0; i < debugBytecode.size(); i++)
00196 if (debugBytecode[i].line == line)
00197 return AsebaVMSetBreakpoint(&vmState, i) != 0;
00198 return false;
00199 }
00200
00201 bool LocalVirtualMachine::clearBreakpoint(unsigned line)
00202 {
00203 for (size_t i = 0; i < debugBytecode.size(); i++)
00204 if (debugBytecode[i].line == line)
00205 return AsebaVMClearBreakpoint(&vmState, i) != 0;
00206 return false;
00207 }
00208
00209 void LocalVirtualMachine::clearBreakpoints()
00210 {
00211 AsebaVMClearBreakpoints(&vmState);
00212 }
00213
00214 void LocalVirtualMachine::timerEvent(QTimerEvent *event)
00215 {
00216 Q_UNUSED(event);
00217
00218
00219 if (AsebaMaskIsClear(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK))
00220 return;
00221 if (!runEvent && AsebaMaskIsClear(vmState.flags, ASEBA_VM_RUN_BACKGROUND_MASK))
00222 return;
00223
00224
00225 const unsigned maxStepsPerTimeSlice = 100;
00226 unsigned i = 0;
00227 while (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK) && (i < maxStepsPerTimeSlice))
00228 {
00229
00230 if (AsebaVMStepBreakpoint(&vmState))
00231 {
00232 runEvent = false;
00233 AsebaMaskClear(vmState.flags, ASEBA_VM_RUN_BACKGROUND_MASK);
00234 emit executionModeChanged(EXECUTION_STEP_BY_STEP);
00235 break;
00236 }
00237 i++;
00238 }
00239
00240
00241 if (i != 0)
00242 emit variablesMemoryChanged(vmVariables);
00243
00244 if (AsebaMaskIsSet(vmState.flags, ASEBA_VM_EVENT_ACTIVE_MASK))
00245 {
00246 Q_ASSERT(vmState.pc < debugBytecode.size());
00247 emit executionPosChanged(debugBytecode[vmState.pc].line);
00248 }
00249 else if (AsebaMaskIsClear(vmState.flags, ASEBA_VM_RUN_BACKGROUND_MASK))
00250 stop();
00251 }
00252
00253 void LocalVirtualMachine::emitEvent(unsigned short id, unsigned short start, unsigned short length)
00254 {
00255 emit variablesMemoryChanged(vmVariables);
00256 emit event(id, start, length);
00257 }
00258
00259 void LocalVirtualMachine::emitArrayAccessOutOfBounds(unsigned short pc, unsigned short sp, unsigned short index)
00260 {
00261 Q_UNUSED(sp);
00262
00263 stop();
00264 emit variablesMemoryChanged(vmVariables);
00265
00266 Q_ASSERT(pc < debugBytecode.size());
00267 unsigned line = debugBytecode[pc].line;
00268 emit arrayAccessOutOfBounds(line, index);
00269 }
00270
00271 void LocalVirtualMachine::emitDivisionByZero(unsigned short pc, unsigned short sp)
00272 {
00273 Q_UNUSED(sp);
00274
00275 stop();
00276 emit variablesMemoryChanged(vmVariables);
00277
00278 Q_ASSERT(pc < debugBytecode.size());
00279 unsigned line = debugBytecode[pc].line;
00280 emit divisionByZero(line);
00281 }
00282 };