open Printf
open MIPSOps
open Primitive
open InterpretUPP
open InterpretERTL
open LTL
open Integer
exception RuntimeError = InterpretPP.RuntimeError
module Int32Map =
Map.Make(Int32)
type 'value frame = {
incoming: 'value ref Int32Map.t;
mutable outgoing: 'value ref Int32Map.t;
local: 'value ref Int32Map.t
}
type 'value stack =
'value frame list
let slookup stack slot =
let frame, _ = destruct stack in
match slot with
| SlotLocal offset ->
begin try
Int32Map.find offset frame.local
with Not_found ->
fprintf stderr "Runtime error -- invalid local slot (%ld).\n" offset;
raise RuntimeError
end
| SlotIncoming offset ->
begin try
Int32Map.find offset frame.incoming
with Not_found ->
fprintf stderr "Runtime error -- invalid incoming slot (%ld).\n" offset;
raise RuntimeError
end
| SlotOutgoing offset ->
begin try
Int32Map.find offset frame.outgoing
with Not_found ->
let cell = ref default in
frame.outgoing <- Int32Map.add offset cell frame.outgoing;
cell
end
let sread stack slot =
!(slookup stack slot)
let swrite stack slot v =
(slookup stack slot) := v
let empty_stack =
[]
let allocate_locals locals =
let rec loop offset m =
if offset = locals then
m
else
loop (offset + MIPS.word) (Int32Map.add offset (ref default) m)
in
loop 0l Int32Map.empty
let newframe stack locals =
match stack with
| [] ->
[{
incoming = Int32Map.empty;
outgoing = Int32Map.empty;
local = allocate_locals locals
}]
| frame :: _ ->
{
incoming = frame.outgoing;
outgoing = Int32Map.empty;
local = allocate_locals locals
} :: stack
let deleteframe stack =
let _, stack = destruct stack in
stack
let interpret p =
let henv = MIPS.RegisterMap.lift allocate MIPS.registers in
hwrite henv MIPS.gp (VArray (Array.make (p.globals / MIPS.word) (VInt 0l), 0l));
let interpret_call stack callee next =
match callee with
| CPrimitiveFunction p ->
interpret_primitive henv p;
stack,
next
| CUserFunction f ->
let proc =
try
StringMap.find f p.defs
with Not_found ->
assert false
in
hwrite henv MIPS.ra (VCode next);
stack,
AddrCode (proc, proc.entry)
in
let interpret_instruction stack proc i =
match i with
| INewFrame l ->
newframe stack proc.locals,
AddrCode (proc, l)
| IDeleteFrame l ->
deleteframe stack,
AddrCode (proc, l)
| IGetStack (destr, slot, l) ->
hwrite henv destr (sread stack slot);
stack, AddrCode (proc, l)
| ISetStack (slot, sourcer, l) ->
swrite stack slot (hread henv sourcer);
stack, AddrCode (proc, l)
| IConst (destr, i, l) ->
hwrite henv destr (VInt i);
stack, AddrCode (proc, l)
| IUnOp (op, destr, sourcer, l) ->
hwrite henv destr (unop op (hread henv sourcer));
stack, AddrCode (proc, l)
| IBinOp (op, destr, sourcer1, sourcer2, l) ->
hwrite henv destr (binop op (hread henv sourcer1) (hread henv sourcer2));
stack, AddrCode (proc, l)
| ICall (callee, l) ->
interpret_call stack callee (AddrCode (proc, l))
| ILoad (destr, addressr, offset, l) ->
hwrite henv destr (load (hread henv addressr) offset);
stack, AddrCode (proc, l)
| IStore (addressr, offset, valuer, l) ->
store (hread henv addressr) offset (hread henv valuer);
stack, AddrCode (proc, l)
| IGoto l ->
stack, AddrCode (proc, l)
| IUnBranch (cond, sourcer, l1, l2) ->
stack,
AddrCode (proc,
if InterpretMIPS.uncon cond (asInt (hread henv sourcer)) then l1 else l2
)
| IBinBranch (cond, sourcer1, sourcer2, l1, l2) ->
stack,
AddrCode (proc,
if InterpretMIPS.bincon cond (asInt (hread henv sourcer1)) (asInt (hread henv sourcer2)) then l1 else l2
)
| IReturn ->
stack,
asAddress (hread henv MIPS.ra)
| ITailCall callee ->
interpret_call stack callee (asAddress (hread henv MIPS.ra))
in
let interpret_instruction_at stack proc l i =
try
interpret_instruction stack proc i
with RuntimeError as e ->
fprintf stderr "Runtime error -- at label: %s\n" (Label.print l);
raise e
in
let rec fetch_and_execute stack proc l : unit =
let i =
try
Label.Map.find l proc.graph
with Not_found ->
fprintf stderr
"Runtime error -- no instruction is associated with the current label (%s).\n" (Label.print l);
raise RuntimeError
in
continue (interpret_instruction_at stack proc l i)
and continue (stack, next) : unit =
match next with
| AddrInit ->
()
| AddrCode (proc, l) ->
fetch_and_execute stack proc l
in
continue (interpret_call empty_stack (CUserFunction "_main") AddrInit)