-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathProcess.hs
661 lines (605 loc) · 24.5 KB
/
Process.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
module Process where
-- hp
import Control.Concurrent
import Control.Monad.State.Strict
import qualified Data.ByteString as B
import qualified Data.Char as Char
import Data.Int
import Data.List (intersperse)
import Data.Maybe (fromJust, listToMaybe, maybeToList)
import Text.Show (showListWith)
-- 3rd party
import qualified Data.Vector as V
import Text.Show.Pretty
-- this project
import AtomTable (AtomTable)
import qualified AtomTable as AT
import qualified AtomTableErlang as AT
import Beam
import EModule
-- import ErlangContext
import ETerm
import ExtTerm
data Process =
Process
{ pXreg :: ![ETerm]
, pYreg :: ![ETerm]
, pIp :: !Int
, pEModule :: !EModule
, pStack :: ![StackFrame]
, pCatches :: ![CatchContext]
, pAtomTable :: AtomTable
, pFault :: Maybe AtomNo
, pStackTrace :: Maybe ETerm
, pIncommingMessages :: MVar [ETerm]
, pAllModules :: [(AtomNo, EModule)]
}
data StackFrame
= StackFrame {-# UNPACK #-} !AtomNo {-# UNPACK #-} !Int
deriving Show
data CatchContext =
CatchContext
{ catchModule :: {-# UNPACK #-} !AtomNo
, catchIp :: {-# UNPACK #-} !Int
, catchCallStackLength :: {-# UNPACK #-} !Int
, catchActiveYRegs :: {-# UNPACK #-} !Int
} deriving Show
runBeam :: [String] -> B.ByteString -> B.ByteString -> [ETerm] -> IO (Maybe ETerm)
runBeam files mod fun args = do
beams <- mapM readBeamFile files
let (at, emods) = foldr (\beam (at,emods) -> let (emod, at', beam') = beamToModule beam at in (at', emod:emods)) (AT.basic,[]) beams
funNameAtom = AT.lookupByName at fun
modNameAtom = AT.lookupByName at mod
p0 <- makeProcess emods at modNameAtom funNameAtom args
ctx <- newMVar (EC [(emodModNameAtom e, e) | e <- emods] at [p0])
p <- runProcess ctx p0
case pXreg p of
(r0:_) -> return (Just r0)
_ -> return Nothing
makeProcess :: [EModule] -> AtomTable -> AtomNo -> AtomNo -> [ETerm] -> IO Process
makeProcess emods at emodAN funAtomName args = do
let argsArity = fromIntegral (length args)
(emod, ip) = case [ (emod', ip) | emod' <- emods
, emodModNameAtom emod' == emodAN
, (fun', Arity arity, label) <- emodExports emod'
, fun' == funAtomName
, arity == argsArity
, ip <- maybeToList (lookup label (emodLabelToIp emod')) ] of
[res] -> res
_ -> error $ showString "no such label: " . showFA at funAtomName (Arity argsArity) $ []
incomming <- newMVar []
return $ Process args [] ip emod [] [] at Nothing Nothing incomming [ (emodModNameAtom emod, emod) | emod <- emods ]
runProcess :: MVar ErlangContext -> Process -> IO Process
runProcess ctx p0 = do
--putStrLn $ ppShow $ pAtomTable p0
(steps, (_ctx, p)) <- runStateT stepper (ctx, p0)
let val = head $ [ v | Left v <- steps ]
let rendered = renderETerm (pAtomTable p) val
-- liftIO $ putStrLn ("Process ended, x0: " ++ rendered)
return p
where
stepper = do
p <- getProcess
let at = pAtomTable p
--liftIO $ putStrLn $ "X: " ++ showListWith showString (map (renderETerm at) (pXreg p)) []
--liftIO $ putStrLn $ "Y: " ++ showListWith showString (map (renderETerm at) (pYreg p)) []
--liftIO $ putStrLn $ "Catches: " ++ ppShow (pCatches p)
--liftIO $ putStrLn $ "Stack: " ++ ppShow (pStack p)
--liftIO $ putStrLn ""
--liftIO $ putStrLn $ show (pIp p) ++ ": " ++ show (opAtIp (emodCode (pEModule p)) (pIp p))
--liftIO $ putStrLn ""
r <- step
case r of
Nothing -> do
ps <- stepper
return (Right (opAtIp (emodCode (pEModule p)) (pIp p), p) : ps)
Just v -> do
return [Right (opAtIp (emodCode (pEModule p)) (pIp p), p), Left v]
showByteString :: B.ByteString -> ShowS
showByteString bs = showString (map (Char.chr . fromIntegral) (B.unpack bs))
showMFA :: AtomTable -> AtomNo -> AtomNo -> Arity -> ShowS
showMFA at m0 f0 a0 = showByteString m . showString ":" . showByteString f . showString "/" . shows a
where
m = AT.lookupByCode at m0
f = AT.lookupByCode at f0
a = unArity a0
showFA :: AtomTable -> AtomNo -> Arity -> ShowS
showFA at f0 a0 = showByteString f . showString "/" . shows a
where
f = AT.lookupByCode at f0
a = unArity a0
type PM a = StateT (MVar ErlangContext, Process) IO a
data ErlangContext = EC {
ctx_mods :: [(AtomNo, EModule)],
ctx_atomtable :: AT.AtomTable,
ctx_runningProcessess :: [Process]
}
spawn3 :: MVar ErlangContext -> AtomNo -> AtomNo -> ETerm -> IO ()
spawn3 ec_mvar emod_atom fun_atom args = modifyMVar_ ec_mvar $ \ec -> do
(emod, at, emods) <- case lookup emod_atom (ctx_mods ec) of
Just emod -> return (emod, ctx_atomtable ec, ctx_mods ec)
Nothing -> do
beam <- readBeamFile "oh-noes-not-implemented.beam"
let (emod, at, beam') = beamToModule beam (ctx_atomtable ec)
return (emod, at, (emod_atom, emod) : ctx_mods ec)
proc <- makeProcess (map snd emods) at emod_atom fun_atom (fromErlangList args)
forkIO (runProcess ec_mvar proc >> return ())
--liftIO $ threadDelay 2000000
return ec { ctx_runningProcessess = proc : ctx_runningProcessess ec
, ctx_mods = emods
, ctx_atomtable = at }
getProcess :: PM Process
getProcess = gets snd
getsProcess :: (Process -> a) -> PM a
getsProcess f = gets (f . snd)
modifyProcess :: (Process -> Process) -> PM ()
modifyProcess f = modify (\(ctx,p) -> (ctx, f p))
getErlangContextMVar :: PM (MVar ErlangContext)
getErlangContextMVar = gets fst
runBif :: AtomNo -> AtomNo -> Arity -> PM ()
runBif emod fun arity =
case lookup (emod, fun, arity) bifs of
Just func -> func
Nothing -> error "bif not found"
bifs :: [((AtomNo, AtomNo, Arity), PM ())]
bifs = [ ((AT.am_erlang, AT.am_now, Arity 0), erlangNow0)
, ((AT.am_erlang, AT.am_throw, Arity 1), erlangThrow1)
, ((AT.am_erlang, AT.am_exit, Arity 1), erlangExit1)
, ((AT.am_erlang, AT.am_error, Arity 1), erlangError1)
, ((AT.am_erlang, AT.am_get_stacktrace, Arity 0), erlangGetStacktrace0)
, ((AT.am_erlang, AT.am_spawn, Arity 3), erlangSpawn3)
, ((AT.am_io, AT.am_format, Arity 1), ioFormat1)
]
erlangNow0 :: PM ()
erlangNow0 =
writeDestination (Destination (OperandXReg 0)) $
ETuple [EInteger 0, EInteger 0, EInteger 0]
erlangThrow1 :: PM ()
erlangThrow1 = do
liftIO $ putStrLn "executing erlang:throw/1"
t <- readSource (Source (OperandXReg 0))
fault t ExcThrown
return ()
erlangExit1 :: PM ()
erlangExit1 = do
liftIO $ putStrLn "executing erlang:exit/1"
t <- readSource (Source (OperandXReg 0))
fault t ExcExit
return ()
erlangError1 :: PM ()
erlangError1 = do
liftIO $ putStrLn "executing erlang:error/1"
t <- readSource (Source (OperandXReg 0))
fault t (ExcError JustError) --TODO: justerror?
return ()
erlangSpawn3 :: PM ()
erlangSpawn3 = do
liftIO $ putStrLn "executing erlang:spawn/3"
ctx <- getErlangContextMVar
emod_ <- readSource (Source (OperandXReg 0))
fun_ <- readSource (Source (OperandXReg 1))
args <- readSource (Source (OperandXReg 2))
case (emod_, fun_) of
(EAtom emod, EAtom fun) | isList args -> do
liftIO $ spawn3 ctx emod fun args
return ()
ioFormat1 :: PM ()
ioFormat1 = do
str <- readSource (Source (OperandXReg 0))
case isList str of
-- TODO: this is wrong and lame
True -> liftIO $ putStr ("io:format/1 says: " ++ fixup [ Char.chr (fromIntegral c) | EInteger c <- fromErlangList str ])
False -> error "io:format/1 says: not a string/list"
where
fixup ('~':'n':xs) = '\n' : fixup xs
fixup (x:xs) = x : fixup xs
fixup [] = []
whenJust :: Monad m => Maybe a -> (a -> m ()) -> m ()
whenJust Nothing _ = return ()
whenJust (Just x) f = f x
data ErrorType
= ExcError !ErrorKind
| ExcThrown
| ExcExit
deriving (Show)
data ErrorKind
= JustError
| BasicError
| BadMatch
| CaseClause
| TryClause
| BadFun
| BadArity
| IfClause
| FunctionClause
deriving (Show)
fault :: ETerm -> ErrorType -> PM (Maybe a)
fault errorTerm0 kind0 = do
st <- stackTrace
catches <- getsProcess pCatches
let (errorTerm', kind) = case (catches, kind0) of
([], ExcThrown) -> (ETuple [(EAtom AT.am_nocatch), errorTerm0], ExcError BasicError)
_ -> (errorTerm0, kind0)
errorTerm = expandErrorTerm errorTerm' kind
case catches of
[] -> do
at <- getsProcess pAtomTable
liftIO $ putStrLn (renderETerm at errorTerm)
liftIO $ print kind
error "fault: should kill process"
(c:_cs) -> do
modifyProcess (\p -> p { pStack = reverse . take (catchCallStackLength c) . reverse $ pStack p
, pYreg = reverse . take (catchActiveYRegs c) . reverse $ pYreg p })
let st' = ETuple [errorTerm, st]
writeDestination (Destination (OperandXReg 0)) ENonValue
writeDestination (Destination (OperandXReg 1)) (EAtom (exceptionAtom kind))
writeDestination (Destination (OperandXReg 2)) errorTerm
writeDestination (Destination (OperandXReg 3)) st' --approx...
modifyProcess (\p -> p { pStackTrace = Just st' })
gotoModIp (catchModule c) (catchIp c)
return Nothing
expandErrorTerm :: ETerm -> ErrorType -> ETerm
expandErrorTerm t err =
case err of
ExcThrown -> t
ExcExit -> t
ExcError BasicError -> t
ExcError BadMatch -> ETuple [EAtom AT.am_badmatch, t]
ExcError CaseClause -> ETuple [EAtom AT.am_case_clause, t]
ExcError TryClause -> ETuple [EAtom AT.am_try_clause, t]
ExcError BadFun -> ETuple [EAtom AT.am_badfun, t]
ExcError BadArity -> ETuple [EAtom AT.am_badarity, t]
ExcError _ -> t
exceptionAtom :: ErrorType -> AtomNo
exceptionAtom (ExcError _) = AT.am_error
exceptionAtom ExcExit = AT.am_exit
exceptionAtom ExcThrown = AT.am_throw
erlangGetStacktrace0 :: PM ()
erlangGetStacktrace0 = do
st <- getsProcess pStackTrace
let term = case st of
Nothing -> ENil
Just st' -> st'
writeDestination (Destination (OperandXReg 0)) term
handleOp KReturn
return ()
stackTrace :: PM ETerm
stackTrace = do
stack <- getsProcess pStack
allModules <- getsProcess pAllModules
lst <- forM stack $ \(StackFrame modName ip) -> do
let Just emod = lookup modName allModules
let code = emodCode emod
let Just (stackFrame@(emod, fun, ar)) = ipToFunction code ip
return $ ETuple [EAtom emod, EAtom fun, EInteger (fromIntegral ar)]
return (toErlangList lst)
ipToFunction :: Code -> Int -> Maybe (AtomNo, AtomNo, Int32)
ipToFunction _ (-1) = Nothing
ipToFunction code n =
case opAtIp code n of
FuncInfo emod fun arity -> Just (emod, fun, arity)
_ -> ipToFunction code (n-1)
renderETerm :: AtomTable -> ETerm -> String
renderETerm at eterm = go at eterm
where
go _ ENonValue = "the-non-value"
go _ (EInteger n) = show n
go at (ETuple lst) = concat ("{" : intersperse "," (map (go at) lst) ++ ["}"])
go at (EList hd tl) = "[" ++ concat (intersperse "," (map (go at) (fromList hd tl))) ++ "]"
go _ (EString str) = show str
go _ ENil = "nil"
go _ (EBinary _) = "<<bin>>"
go at (EAtom no) = showByteString (AT.lookupByCode at no) []
go _ (EFun {..}) = showByteString funMod . showString ":" . showByteString funName . showString "/" . shows etfunArity $ []
showAtomName :: String -> String
showAtomName name
| any Char.isSpace name = quote name
| Just c <- listToMaybe name, Char.isUpper c = quote name
| otherwise = name
quote :: String -> String
quote name = "'" ++ name ++ "'"
fromList :: ETerm -> ETerm -> [ETerm]
fromList hd ENil = [hd]
fromList hd (EList hd' tl) = hd : fromList hd' tl
continue :: PM (Maybe a)
continue = modifyProcess (\p -> p { pIp = pIp p + 1 }) >> return Nothing
gotoModIp :: AtomNo -> Int -> PM ()
gotoModIp modName ip = do
p <- getProcess
emod <- case lookup modName (pAllModules p) of
Just emod -> return emod
Nothing -> error $ "no such module; " ++ show modName
modifyProcess (\p -> p { pEModule = emod, pIp = ip })
gotoModFunArity :: AtomNo -> AtomNo -> Arity -> PM (Maybe ETerm)
gotoModFunArity mod fun ar = do
erl <- lookupModFunArity mod fun ar
case erl of
Just (emod, ip) -> gotoModIp (emodModNameAtom emod) ip >> return Nothing
Nothing -> do -- can be a bif
case lookup (mod, fun, ar) bifs of
Just func -> func >> handleOp KReturn
Nothing -> do -- TODO: module:fun/ar not found! create erlang error.
at <- getsProcess pAtomTable
error $ showString "function " . showMFA at mod fun ar . showString " not found" $ []
lookupModFunArity :: AtomNo -> AtomNo -> Arity -> PM (Maybe (EModule, Int))
lookupModFunArity modName funName funArity = do
p <- getProcess
case [ (emod, ip)
| emod <- maybeToList (lookup modName (pAllModules p))
, (fun', arity, label) <- emodExports emod
, fun' == funName
, arity == funArity
, ip <- maybeToList (lookup label (emodLabelToIp emod)) ] of
[res] -> return (Just res)
_ -> return Nothing
readSource :: Source -> PM ETerm
readSource (Source (OperandInt no)) = return $ EInteger (fromIntegral no)
readSource (Source (OperandXReg n)) =
getsProcess $ \p -> pXreg p !! (fromIntegral n)
readSource (Source (OperandYReg n)) =
getsProcess $ \p -> pYreg p !! (fromIntegral n)
readSource (Source (OperandTableLiteral no)) = do
p <- getProcess
let Literal x = emodLiteralTable (pEModule p) !! (fromIntegral no)
return $ extTermToETerm x
readSource (Source (OperandAtom atomNo)) = return $! EAtom atomNo
readSource (Source OperandNil) = return ENil
readSource (Source src) = error $ "readSource " ++ show src
writeDestination :: Destination -> ETerm -> PM ()
writeDestination dest !value =
case dest of
(Destination (OperandXReg n)) -> modifyProcess (\p -> p { pXreg = updateList (pXreg p) (fromIntegral n) })
(Destination (OperandYReg n)) -> modifyProcess (\p -> p { pYreg = updateList (pYreg p) (fromIntegral n) })
_ -> error ("writeDest " ++ show dest ++ ", value=" ++ show value)
where
updateList list pos =
prefix ++ fill ++ value : drop (pos+1) list
where
prefix = take pos list
fill | length prefix < pos = replicate (pos - length prefix) ENil
| otherwise = []
popCatch :: PM CatchContext
popCatch = do
ccs <- getsProcess pCatches
case ccs of
(c:cs) -> modifyProcess (\p -> p { pCatches = cs }) >> return c
[] -> error "popCatch: no catchcontexts to pop"
addStackTrace :: ETerm -> ETerm -> PM ETerm
addStackTrace value exc = do
where_ <- buildStackTrace exc
return (ETuple [value, where_])
buildStackTrace :: ETerm -> PM ETerm
buildStackTrace exc = return exc
step :: PM (Maybe ETerm)
step = do
p <- getProcess
let op = opAtIp (emodCode (pEModule p)) (pIp p)
handleOp op
handleOp :: Op -> PM (Maybe ETerm)
handleOp op0 = do
p <- getProcess
let thisModuleName = emodModNameAtom (pEModule p)
sameModule ip = StackFrame thisModuleName ip
-- liftIO $ print op0
case op0 of
Label _ -> continue
Line _ -> continue
TestHeap _ _ -> continue
Trim n _ -> deallocateY n >> continue
Deallocate n -> deallocateY n >> continue
Call _ (OperandLabl label) -> do
let jumpIp = fromJust $ lookup label (emodLabelToIp (pEModule p))
returnIp = pIp p + 1
updateStack (sameModule returnIp:)
gotoIp jumpIp
ret
CallOnly _ label -> gotoLabel label >> ret
CallFun arityAndReg -> do
-- Fun fact; the value arityAndReg says both where the function is stored
-- as well as its arity.
efun <- readSource (Source (OperandXReg arityAndReg))
case efun of
EFun {} -> do
let jumpIp = funIp efun
returnIp = pIp p + 1
functionArity = etfunArity efun
freeVars = funFree efun
x_regs | length freeVars > 0 =
-- [ ... function arguments ...
-- , ... free variables ...
-- , ... function gets moved here ...
-- , ... rest of X registers ... ]
take (fromIntegral functionArity) (pXreg p) ++
freeVars ++ [efun] ++ drop (fromIntegral functionArity + length freeVars + 1) (pXreg p)
| otherwise = pXreg p
if (functionArity /= arityAndReg)
then fault (ETuple [efun, toErlangList (take (fromIntegral functionArity) (pXreg p))]) (ExcError BadArity)
else do
updateStack (sameModule returnIp:)
gotoIp jumpIp
setXRegs x_regs
ret
_ -> fault efun (ExcError BadFun)
CallExt _arity ix -> do
let (modName, funName, funArity) = (emodImports (pEModule p)) V.! (fromIntegral ix)
returnIp = pIp p + 1
updateStack (sameModule returnIp:)
gotoModFunArity modName funName funArity
CallExtOnly _arity ix -> do
let (modName, funName, funArity) = (emodImports (pEModule p)) V.! (fromIntegral ix)
gotoModFunArity modName funName funArity
AllocateZero noYregs _ -> do
modifyProcess (\p -> p { pYreg = replicate (fromIntegral noYregs) (EInteger 0) ++ (pYreg p) })
continue
Allocate noYregs _ -> do
modifyProcess (\p -> p { pYreg = replicate (fromIntegral noYregs) ENil ++ (pYreg p) })
continue
IsLt label src1 src2 -> do
EInteger value1 <- readSource src1
EInteger value2 <- readSource src2
let trueIp = pIp p + 1
falseIp <- lookupIp label
gotoIp (if value1 < value2 then trueIp else falseIp)
return Nothing
IsEqExact label src1 src2 -> do
value1 <- readSource src1
value2 <- readSource src2
let trueIp = pIp p + 1
falseIp <- lookupIp label
gotoIp (if isEtermEq value1 value2 then trueIp else falseIp)
return Nothing
IsEq label src1 src2 -> handleOp (IsEqExact label src1 src2) -- todo: fix
IsInteger lbl src -> do
value <- readSource src
ip <- case value of
EInteger _ -> return (pIp p + 1)
_ -> lookupIp lbl
gotoIp ip
return Nothing
IsAtom lblIfFalse src -> do
value <- readSource src
if isAtom value
then continue
else gotoLabel lblIfFalse >> ret
SelectVal src lbl (SelectList lst) -> do
val <- readSource src
let newLbl [] = lbl
newLbl ((op, branch_lbl):xs)
| isEtermEq val (operandToETerm op) = branch_lbl
| otherwise = newLbl xs
newIp <- lookupIp (newLbl lst)
gotoIp newIp
ret
FuncInfo _ _ _ -> fault ENil (ExcError FunctionClause)
Move src dest -> do
value <- readSource src
writeDestination dest value
continue
PutList src1 src2 dest -> do
val1 <- readSource src1
val2 <- readSource src2
let lst = EList val1 val2
writeDestination dest lst
continue
PutTuple arity dest -> do
-- The 'arity' number of following instructions will be 'Put Source' describing where to find
-- the values to put into the tuple.
vals <- replicateM (fromIntegral arity) $ do
continue
op <- getOp
case op of
Put src -> readSource src
_ -> error "PutTuple; unexpected instruction"
writeDestination dest (ETuple vals)
continue
Put _src -> error "Put; I expected to be part of a PutTuple!"
GcBif2 _ _ n op1 op2 dest -> do
let op = case emodImports (pEModule p) V.! (fromIntegral n) of
imp | imp == (AT.am_erlang, AT.am_sign_plus, Arity 2) -> bif_plus
| imp == (AT.am_erlang, AT.am_sign_minus, Arity 2) -> bif_minus
| imp == (AT.am_erlang, AT.am_sign_mult, Arity 2) -> bif_mult
bif_binop op op1 op2 dest
continue
MakeFun2 no -> do
let funs = emodFunctions (pEModule p)
fun = funs!!(fromIntegral no)
numFree = funFreeVars fun
free = take (fromIntegral numFree) (pXreg p)
arity = funArity fun - numFree
funIp <- lookupIp (OperandLabl (funLabel fun))
let f = EFun
{ funIp = funIp
, funMod = emodName (pEModule p)
, funFree = free
, etfunArity = arity
, funName = AT.lookupByCode (pAtomTable p) (funAtom fun)
}
writeDestination (Destination (OperandXReg 0)) f
continue
KReturn
| null (pStack p) -> return $ Just ((pXreg p) !! 0)
| otherwise -> do
let (jumpIp:newStack) = pStack p
p' = case jumpIp of
StackFrame newMod ip
| newMod == thisModuleName -> p { pStack = newStack, pIp = ip }
| otherwise -> p { pEModule = fromJust (lookup newMod (pAllModules p))
, pStack = newStack
, pIp = ip }
modifyProcess (const p')
ret
Catch (YReg dest) catchLbl -> do
returnIp <- lookupIp catchLbl
let catchContext =
CatchContext
{ catchModule = emodModNameAtom (pEModule p)
, catchIp = returnIp
, catchCallStackLength = length (pStack p)
, catchActiveYRegs = length (pYreg p)
}
writeDestination (Destination (OperandYReg dest)) (EString "catch label!")
updateCatches (catchContext:)
continue
Try y l -> handleOp (Catch y l)
CatchEnd (YReg catchSrc) -> do
popCatch
-- TODO: shrink yregs?
writeDestination (Destination (OperandYReg catchSrc)) ENil
r <- readSource (Source (OperandXReg 0))
when (isNonValue r) $ do
x1 <- readSource (Source (OperandXReg 1))
if (x1 == EAtom AT.am_throw)
then writeDestination (Destination (OperandXReg 0)) =<< readSource (Source (OperandXReg 2))
else do
when (x1 == EAtom AT.am_error) $ do
Just st <- getsProcess pStackTrace
writeDestination (Destination (OperandXReg 2)) st
x2 <- readSource (Source (OperandXReg 2))
writeDestination (Destination (OperandXReg 0))
(ETuple [EAtom AT.am_EXIT, x2])
continue
TryEnd dst -> do
popCatch
writeDestination dst ENil
r <- readSource (Source (OperandXReg 0))
when (isNonValue r) $ do
readSource (Source (OperandXReg 1)) >>= writeDestination (Destination (OperandXReg 0))
readSource (Source (OperandXReg 2)) >>= writeDestination (Destination (OperandXReg 1))
readSource (Source (OperandXReg 3)) >>= writeDestination (Destination (OperandXReg 2))
continue
TryCase dst -> handleOp (TryEnd dst)
{- Faults -}
CaseEnd nonMatchingClauseSrc -> do -- a case expression has ended without a match.
t <- readSource nonMatchingClauseSrc
fault t (ExcError CaseClause)
IfEnd ->
fault ENil (ExcError IfClause)
_ -> error (show op0)
where
getOp = getsProcess $ \p -> opAtIp (emodCode (pEModule p)) (pIp p)
deallocateY n = modifyProcess (\p -> p { pYreg = drop (fromIntegral n) (pYreg p) })
updateStack f = modifyProcess (\p -> p { pStack = f (pStack p)})
updateCatches f = modifyProcess (\p -> p { pCatches = f (pCatches p) })
setXRegs x_regs = modifyProcess (\p -> p { pXreg = x_regs})
bif_binop f op1 op2 dest = do
value1 <- readSource op1
value2 <- readSource op2
writeDestination dest (f value1 value2)
bif_plus (EInteger x) (EInteger y) = EInteger (x+y)
bif_plus x y = error (show x ++ " + " ++ show y)
bif_minus (EInteger x) (EInteger y) = EInteger (x-y)
bif_minus x y = error (show x ++ " - " ++ show y)
bif_mult (EInteger x) (EInteger y) = EInteger (x*y)
bif_mult x y = error (show x ++ " * " ++ show y)
lookupIp (OperandLabl label) = do
p <- getProcess
case lookup label (emodLabelToIp (pEModule p)) of
Nothing -> error $ "tried to lookup label that does not exist: " ++ show label
Just ip -> return ip
gotoLabel label = gotoIp =<< lookupIp label
gotoIp ip = modifyProcess (\p -> p { pIp = ip })
ret = return Nothing