EOS 2  1.1.0
Einfache Objektbasierte Sprache
Machine.java
gehe zur Dokumentation dieser Datei
1 package de.lathanda.eos.vm;
2 
3 import de.lathanda.eos.base.event.CleanupListener;
4 import de.lathanda.eos.vm.exceptions.MemoryAccessViolation;
5 import de.lathanda.eos.vm.exceptions.ProgramTerminationException;
6 
7 import java.util.ArrayList;
8 import java.util.LinkedList;
9 import java.util.Map;
10 import java.util.Map.Entry;
11 import java.util.TreeMap;
12 
19 public class Machine implements AbstractMachine {
20 
21  private final LinkedList<Object> stack;
22  private final LinkedList<Context> callstack;
26  private Context context;
30  private Context global;
31  private final TreeMap<String, MProcedure> userfunction;
32  private final Executer executer = new Executer();
33  private final SpeedExecuter speedexecuter = new SpeedExecuter();
34  private DebugInfo debugInfo = new DebugInfo();
35  private volatile boolean executing = false;
36  private volatile boolean running = false;
37  private volatile boolean isStarting = true;
38  private volatile boolean isFinished = false;
39  private volatile long delay = 5000;
40  private final DebugMulticaster dmc = new DebugMulticaster();
41 
42  private final LinkedList<CleanupListener> gc = new LinkedList<>();
43  private TreeMap<Integer, DebugPoint> breakpoints = new TreeMap<>();
44 
45  LinkedList<MachineListener> machineListeners = new LinkedList<>();
46 
47  public Machine() {
48  stack = new LinkedList<>();
49  callstack = new LinkedList<>();
50  context = new Context();
51  global = context;
52  userfunction = new TreeMap<>();
53  }
55  machineListeners.add(m);
56  }
58  machineListeners.remove(m);
59  }
60 
61  public void addDebugListener(DebugListener dl) {
62  dmc.add(dl);
63  }
64 
66  dmc.remove(dl);
67  }
68 
69  public void setBreakpoint(int linenumber, boolean active) {
70  DebugPoint debug = getDebugPoint(linenumber);
71  if (debug != null) {
72  debug.setActiveBreakpoint(active);
73  }
74  }
75 
76  public void addPossibleBreakpoint(DebugPoint debugPoint, int linenumber) {
77  if (!breakpoints.containsKey(linenumber)) {
78  breakpoints.put(linenumber, debugPoint);
79  }
80  }
81 
82  public boolean hasBreakpoint(int linenumber) {
83  DebugPoint debug = getDebugPoint(linenumber);
84  if (debug != null) {
85  return debug.isActiveBreakpoint();
86  } else {
87  return false;
88  }
89  }
90 
91  @Override
92  public int getBreakpointPosition(int linenumber) {
93  DebugPoint dp = getDebugPoint(linenumber);
94  if (dp != null) {
95  return dp.getMarker().getBeginPosition();
96  } else {
97  return -1;
98  }
99  }
100 
101  private DebugPoint getDebugPoint(int linenumber) {
102  if (breakpoints.containsKey(linenumber)) {
103  return breakpoints.get(linenumber);
104  } else {
105  Map.Entry<Integer, DebugPoint> entry = breakpoints.higherEntry(linenumber);
106  if (entry == null) {
107  return null;
108  } else {
109  return entry.getValue();
110  }
111  }
112  }
113 
114  public void reinit() {
115  userfunction.clear();
116  global = new Context();
117  reset();
118  }
119 
120  private void reset() {
121  isFinished = false;
122  // clear runtime informations
123  stack.clear();
124  // clear memory
125  callstack.clear();
126  // restore starting memory
127  context = global;
128  global.reset();
129  // create new debug container
130  debugInfo = new DebugInfo();
131  // destroy all windows
132  gc.forEach(w -> w.terminate());
133  gc.clear();
134  // inform debug listeners
135  dmc.fireDebugPoint(debugInfo);
136  }
137 
138  public Object pop() {
139  if (stack.isEmpty()) {
140  throw new ProgramTerminationException();
141  }
142  return stack.pop();
143  }
144 
145  public void push(Object obj) {
146  stack.push(obj);
147  }
148 
149  public Object peek() {
150  return stack.peek();
151  }
152 
153  public Object get(String variable) {
154  if (context.memory.containsKey(variable)) {
155  return context.memory.get(variable).get();
156  } else if (context.globalAccess && global.memory.containsKey(variable)) {
157  return global.memory.get(variable).get();
158  } else {
159  throw new MemoryAccessViolation(variable);
160  }
161  }
162 
163  public void set(String variable, Object data) {
164  if (context.memory.containsKey(variable)) {
165  context.memory.get(variable).set(data);
166  } else if (context.globalAccess && global.memory.containsKey(variable)) {
167  global.memory.get(variable).set(data);
168  } else {
169  throw new MemoryAccessViolation(variable);
170  }
171  }
172 
173  public LinkedList<MemoryEntry> getMemory() {
174  LinkedList<MemoryEntry> result = new LinkedList<>();
175  for (Entry<String, Variable> entry : global.memory.entrySet()) {
176  Variable v = entry.getValue();
177  result.add(new MemoryEntry(entry.getKey(), v.get(), v.type.getID()));
178  }
179  if (context != global) {
180  for (Entry<String, Variable> entry : context.memory.entrySet()) {
181  Variable v = entry.getValue();
182  result.add(new MemoryEntry(entry.getKey(), v.get(), v.type.getID()));
183  }
184  }
185  return result;
186  }
187 
188  public void jump(int relativ) {
189  context.index += relativ;
190  }
191 
192  public void create(String variable, MType type) throws Exception {
193  Variable v = createInitVariable(variable, type);
194  context.memory.put(variable, v);
195  }
196 
197  public void define(String variable, MType type) throws Exception {
198  Variable v = new Variable(type, variable);
199  context.memory.put(variable, v);
200  }
201 
202  public Variable createInitVariable(String name, MType type) throws Exception {
203  Variable v = new Variable(type, name);
204  if (!type.isAbstract()) {
205  v.set(type.newInstance(this));
206  if (v.get() instanceof CleanupListener) {
207  gc.add((CleanupListener) v.get());
208  }
209  }
210  return v;
211  }
212 
213  public void create(String variable, MType type, Object data) throws Exception {
214  Variable v = new Variable(type, variable);
215  v.set(data);
216  context.memory.put(variable, v);
217  }
218 
219  private boolean microStep() throws Exception {
220  Context actcontext = context;
221  try {
222  if (actcontext.program[actcontext.index].execute(this)) {
223  actcontext.index++;
224  }
225  } catch (ArrayIndexOutOfBoundsException aiobe) {
226  machineListeners.forEach((ml)->ml.missingProgram());
227  } catch (ProgramTerminationException pte) {
228  machineListeners.forEach((ml)->ml.handleError(pte));
229  stop();
230  return true;
231  } catch (Exception e) {
232  machineListeners.forEach((ml)->ml.handleOrThrowException(e));
233  actcontext.index++;
234  }
235  return update();
236  }
237 
238  private boolean update() {
239  // remark - operations can create a sub context
240  while (context.program.length <= context.index) {
241  if (callstack.size() == 0) {
242  isFinished = true;
243  messageFinishing();
244  return true;
245  } else {
246  context = callstack.pop();
247  }
248  }
249  return false;
250  }
251 
256  public void debugStop(Marker codeRange) {
257  executing = false;
258  debugInfo.setCodeRange(codeRange);
259  dmc.fireDebugPoint(debugInfo);
260  }
261 
267  return debugInfo;
268  }
269 
273  public synchronized void singleStep() {
274  if (!check())
275  return;
276  // stop continues execution
277  pause();
278  // execute a single step
279  try {
280  messageStarting();
281  debugStep();
282  } catch (Exception e) {
283  machineListeners.forEach((ml)->ml.handleException(e));
284  }
285  }
286 
287  private void messageStarting() {
288  if (isStarting) {
289  machineListeners.forEach((ml)->ml.startProgram());
290  isStarting = false;
291  }
292  }
293 
294  private void messageFinishing() {
295  if (!isStarting) {
296  machineListeners.forEach((ml)->ml.stopProgram());
297  isStarting = true;
298  }
299  }
300 
301  public synchronized void skip() {
302  if (!check())
303  return;
304  pause();
305  new Thread(speedexecuter).start();
306  }
307 
308  private void debugStep() throws Exception {
309  if (isFinished) {
310  reset();
311  }
312  executing = true;
313  running = true;
314  while (executing && running) {
315  if (microStep()) {
316  running = false;
317  }
318  }
319  }
320 
321  @Override
322  public void setDelay(long delay) {
323  this.delay = delay;
324  }
325 
326  @Override
327  public synchronized void stop() {
328  messageFinishing();
329  // stop continues execution
330  pause();
331  // set machine back to start
332  reset();
333  }
334 
339  private boolean check() {
340  return context.program != null;
341  }
342 
343  @Override
344  public boolean isStarting() {
345  return isStarting;
346  }
347 
348  @Override
349  public void run() {
350  if (!check())
351  return;
352  pause();
353  new Thread(executer).start();
354  }
355 
356  @Override
357  public synchronized void pause() {
358  if (running) {
359  running = false;
360  this.notifyAll();
361  }
362  }
363 
364  public void call(String signature) {
365  MProcedure uf = userfunction.get(signature);
366  call(uf);
367  }
368 
369  public void call(MProcedure proc) {
370  callstack.push(context);
371  context = new Context();
372  context.program = proc.getOps();
373  context.globalAccess = proc.getGlobalAccess();
374  context.index = 0;
375  }
376 
377  public void addUserFunction(String signature, MProcedure proc) {
378  proc.prepare(this);
379  userfunction.put(signature, proc);
380  }
381 
382  public void setProgram(ArrayList<Command> ops) {
383  for (Command command : ops) {
384  command.prepare(this);
385  }
386  context.program = new Command[ops.size()];
387  context.program = ops.toArray(context.program);
388  context.index = 0;
389  }
390 
391  private class Context {
392 
393  public int index = 0;
394  public Command[] program;
395  public boolean globalAccess;
396  public TreeMap<String, Variable> memory = new TreeMap<>();
397 
398  public void reset() {
399  index = 0;
400  memory.clear();
401  }
402  }
403 
404  private class Executer implements Runnable {
405  @Override
406  public void run() {
407  long laststep = System.nanoTime();
408  messageStarting();
409  running = true;
410  try {
411  while (running) {
412  int diff = (int) (laststep + delay - System.nanoTime());
413  if (diff > 1000000) {
414  synchronized (Machine.this) {
415  Machine.this.wait(diff / 1000000);
416  }
417  }
418 
419  laststep += delay;
420  synchronized (Machine.this) {
421  if (running) {
422  debugStep();
423  }
424  }
425 
426  }
427  } catch (ProgramTerminationException pte) {
428  // thread was killed or execution ran into an error
429  // either way generate message and terminate execution
430  machineListeners.forEach((ml)->ml.handleError(pte));
431  stop();
432  } catch (Exception e) {
433  // thread was killed or execution ran into an error
434  // either way generate message and terminate execution
435  machineListeners.forEach((ml)->ml.handleException(e));
436  stop();
437  }
438  }
439  }
440 
441  private class SpeedExecuter implements Runnable {
442  @Override
443  public void run() {
444  messageStarting();
445  running = true;
446  try {
447  while (running) {
448  synchronized (Machine.this) {
449  if (running) {
450  debugStep();
451  }
452  }
453  }
454  } catch (ProgramTerminationException pte) {
455  // thread was killed or execution ran into an error
456  // either way generate message and terminate execution
457  machineListeners.forEach((ml)->ml.handleError(pte));
458  stop();
459  } catch (Exception e) {
460  // thread was killed or execution ran into an error
461  // either way generate message and terminate execution
462  machineListeners.forEach((ml)->ml.handleException(e));
463  stop();
464  }
465  }
466  }
467 }
void setCodeRange(Marker codeRange)
Definition: DebugInfo.java:24
void setActiveBreakpoint(boolean activeBreakpoint)
Definition: DebugPoint.java:41
void call(String signature)
Definition: Machine.java:364
LinkedList< MemoryEntry > getMemory()
Definition: Machine.java:173
void create(String variable, MType type)
Definition: Machine.java:192
void setDelay(long delay)
Definition: Machine.java:322
int getBreakpointPosition(int linenumber)
Definition: Machine.java:92
boolean hasBreakpoint(int linenumber)
Definition: Machine.java:82
synchronized void pause()
Definition: Machine.java:357
synchronized void singleStep()
Definition: Machine.java:273
Variable createInitVariable(String name, MType type)
Definition: Machine.java:202
void removeMachineListener(MachineListener m)
Definition: Machine.java:57
synchronized void stop()
Definition: Machine.java:327
void push(Object obj)
Definition: Machine.java:145
synchronized void skip()
Definition: Machine.java:301
void setBreakpoint(int linenumber, boolean active)
Definition: Machine.java:69
void setProgram(ArrayList< Command > ops)
Definition: Machine.java:382
void debugStop(Marker codeRange)
Definition: Machine.java:256
void jump(int relativ)
Definition: Machine.java:188
void addPossibleBreakpoint(DebugPoint debugPoint, int linenumber)
Definition: Machine.java:76
void create(String variable, MType type, Object data)
Definition: Machine.java:213
void addUserFunction(String signature, MProcedure proc)
Definition: Machine.java:377
void addMachineListener(MachineListener m)
Definition: Machine.java:54
void removeDebugListener(DebugListener dl)
Definition: Machine.java:65
void addDebugListener(DebugListener dl)
Definition: Machine.java:61
void call(MProcedure proc)
Definition: Machine.java:369
void define(String variable, MType type)
Definition: Machine.java:197
Definition: MemoryEntry.java:3
void set(Object data)
Definition: Variable.java:25
Impressum