Skip to content

Commit 99d206d

Browse files
author
http://jneen.net/
committed
lots of comments
1 parent 57a0b14 commit 99d206d

File tree

9 files changed

+110
-17
lines changed

9 files changed

+110
-17
lines changed

lib/magvm/actions.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ def inst_action(fn):
2424

2525
return fn
2626

27+
28+
################## actions! #################
29+
# These functions implement the instructions
30+
# of the vm, and are run by a Frame whenever
31+
# it encounters the corresponding instruction.
32+
#
33+
# see inst.py for descriptions of these.
34+
# see frame.py, specifically the .step() method
35+
# to see how they're called.
36+
2737
@inst_action
2838
def pop(frame, args):
2939
frame.stack.pop()

lib/magvm/env.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
from value import *
22
from symbol import revsym
33

4+
############ environments ###############
5+
# An environment in Magritte is a simple
6+
# dictionary of keys and values, together
7+
# with a parent pointer (a "prototype").
8+
# These are used not only for variable
9+
# scopes, but also for all OOP-style
10+
# patterns.
11+
#
12+
# An environment additionally contains
13+
# input and output channels, which can
14+
# be inherited.
15+
#
16+
# see frame.py for how the channels are used
17+
# see actions.py and intrinsics.py for
18+
# the basic operations from the machine.
419
MAX_CHANNELS = 8
520
class Env(Value):
621
def __init__(self, parent=None):

lib/magvm/frame.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,24 @@
77
from actions import inst_actions
88
from value import *
99

10+
################# frame #####################
11+
# This class represents a stack frame inside
12+
# a single process. It contains a program
13+
# counter which points to the current
14+
# instruction, and an environment holding the
15+
# variables in its local scope.
16+
#
17+
# The frame also represents the main API for
18+
# intrinsics and instructions (actions) to
19+
# change the state of the machine - the
20+
# current frame is always passed in to their
21+
# implementations.
22+
#
23+
# see env.py for environments
24+
# see proc.py for the process
25+
# see actions.py and intrinsic.py for
26+
# the use of many of these methods
27+
1028
class Frame(object):
1129
def crash(self, message):
1230
assert isinstance(message, Status)

lib/magvm/inst.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,18 @@ def mkinst(name, *a):
5555
screaming_name = name.upper().replace('-', '_')
5656
setattr(InstType, screaming_name, t.id)
5757

58+
############# instruction documentation ###############
59+
# mkinst(instruction_name, argument_types, start_stack, end_stack, description)
60+
#
61+
# The argument types are needed at runtime for loading
62+
# files, so we can re-index them according to the global
63+
# tables. For example, in a compiled .magc file a `jump`
64+
# instruction may refer to an address within the file -
65+
# but once all instructions are merged together into a
66+
# global table it will need to refer to a different number.
67+
#
68+
# see actions.py for the implementations of these.
69+
5870
# jumps and spawns
5971
mkinst('frame', ['inst'], ['env'], [], 'start a new frame')
6072
mkinst('return', [], [], [], 'pop a frame off the stack')

lib/magvm/machine.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
jit_driver = JitDriver(greens=['pc'], reds=['env', 'stack'])
2020

2121
################## machine ####################
22+
# This class contains the main loop of the vm,
23+
# and implements basic scheduling among a
24+
# collection of Proc objects.
2225
class Machine(object):
2326
def __init__(self):
2427
self.procs = Table()

lib/magvm/proc.py

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,19 @@
88
from debug import debug, open_shell
99
from value import *
1010

11+
############# processes #######################
12+
# This class represents one process, running
13+
# concurrently with others. It is ticked forward
14+
# one step at a time by the machine through the
15+
# .step() method. This method tries to evaluate
16+
# as much as it can before it is set to wait.
1117
class Proc(TableEntry):
12-
INIT = 0
13-
RUNNING = 1
14-
WAITING = 2
15-
INTERRUPTED = 3
16-
DONE = 4
17-
TERMINATED = 5
18+
INIT = 0 # hasn't started running yet
19+
RUNNING = 1 # can safely step forward
20+
WAITING = 2 # waiting to be woken up by a channel
21+
INTERRUPTED = 3 # the waiting channel has closed, need to unwind the stack
22+
DONE = 4 # no more steps to run
23+
TERMINATED = 5 # there has been a crash, probably due to an error
1824

1925
def set_init(self): self.state = Proc.INIT
2026
def set_running(self): self.state = Proc.RUNNING
@@ -23,9 +29,10 @@ def set_interrupted(self): self.state = Proc.INTERRUPTED
2329
def set_done(self): self.state = Proc.DONE
2430
def set_terminated(self): self.state = Proc.TERMINATED
2531

26-
# important: a channel will set a successful write to "running". but
27-
# if that write pipes into a closed channel it will properly get set to
28-
# INTERRUPTED and we want to avoid overriding that.
32+
# Important: a channel will set a successful write to "running". but
33+
# if that write is connected to a closed channel, it needs to preserve
34+
# the INTERRUPTED state. So on a successful read or write, we only set
35+
# the state back to RUNNING if we can verify it's still WAITING.
2936
def try_set_running(self):
3037
if self.state == Proc.WAITING:
3138
debug(0, ['try_set_running: set to running', self.s()])
@@ -54,6 +61,11 @@ def __init__(self, machine):
5461
self.status = Success()
5562
self.last_cleaned = []
5663

64+
# Push a new frame on to the call stack, with a given environment
65+
# and starting instruction. This will automatically tail eliminate
66+
# any finished frames from the top. However, this can be disabled on
67+
# a case-by-case basis by the `tail_elim` parameter for things like
68+
# loading files, where we need to preserve the base environment.
5769
def frame(self, env, addr, tail_elim=True):
5870
debug(0, ['--', str(self.id), labels_by_addr[addr].name])
5971
assert isinstance(addr, int)
@@ -65,16 +77,20 @@ def frame(self, env, addr, tail_elim=True):
6577

6678
if tail_elim:
6779
eliminated = self.tail_eliminate()
68-
if eliminated:
69-
frame.env = eliminated.env.merge(env)
70-
for comp in eliminated.compensations:
80+
81+
# when we eliminate a frame, we need to preserve
82+
# its stack variables and compensations for the
83+
# new frame.
84+
for e in eliminated:
85+
frame.env = e.env.merge(frame.env)
86+
for comp in e.compensations:
7187
frame.compensations.append(comp)
7288

7389
self.frames.append(frame)
7490
return frame
7591

7692
def tail_eliminate(self):
77-
out = None
93+
out = []
7894

7995
# don't tail eliminate the root frame, for Reasons.
8096
# the root frame might have the global env and we really don't want
@@ -83,7 +99,7 @@ def tail_eliminate(self):
8399

84100
while len(self.frames) > 1 and self.current_frame().should_eliminate():
85101
debug(0, ['-- tco', self.s()])
86-
out = self.pop()
102+
out.append(self.pop())
87103

88104
debug(0, ['-- post-tco', self.s()])
89105

@@ -99,9 +115,6 @@ def pop(self):
99115

100116
def step(self):
101117
debug(0, ['=== step %s ===' % self.s()])
102-
# if not self.frames:
103-
# debug(0, ['-- out of frames', self.s()])
104-
# self.set_done()
105118

106119
if self.frames:
107120
env = self.current_frame().env

lib/magvm/symbol.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from table import Table, TableEntry
22

3+
#### the global symbol table ####
4+
35
class SymbolTable(Table):
46
def sym(self, string):
57
assert isinstance(string, str)

lib/magvm/targetmagritte.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
from rpython.rlib.objectmodel import we_are_translated
66
import os
77

8+
####### main target ##########################
9+
# This is the main target file for compilation by RPython.
10+
# The whole program will start at the `entry_point` function.
11+
812
def run_file(filename):
913
load_file(filename)
1014
machine.spawn_label(base_env, 'main')

lib/magvm/value.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,22 @@
55

66
from rpython.rlib.rarithmetic import r_uint, intmask
77

8+
######### values! ###########################
9+
# These classes implement the core values of
10+
# the VM. They can implement a number of interfaces
11+
# through the @impl function - attached objects
12+
# that implement certain features. For example,
13+
# many values can be invoked as functions, and
14+
# the behaviour is implemented in value.invokable.
15+
# This allows us to keep the top-level shared
16+
# namespace thin.
17+
#
18+
# Since RPython's support for __repr__ can be
19+
# brittle, we equip each class with a method
20+
# .s() to retrieve the string representation.
21+
#
22+
# see channel.py for the Channel value.
23+
824
class Done(Exception): pass
925
class Deadlock(Exception): pass
1026

0 commit comments

Comments
 (0)