@@ -0,0 +1,139 @@
1+module Effect.Memory
2+
3+import Effects
4+import Control.IOExcept
5+
6+%access public
7+
8+abstract
9+data MemoryChunk : Nat -> Type where
10+ CH : Ptr -> (size : Nat) -> MemoryChunk size
11+
12+abstract
13+data RawMemory : Effect where
14+ Allocate : (n : Nat) ->
15+ RawMemory () (MemoryChunk n) ()
16+ Free : RawMemory (MemoryChunk n) () ()
17+ Peek : (offset : Nat) ->
18+ (size : Nat) ->
19+ so (offset + size <= n) ->
20+ RawMemory (MemoryChunk n) (MemoryChunk n) (Vect Bits8 size)
21+ Poke : (offset : Nat) ->
22+ (Vect Bits8 size) ->
23+ so (offset + size <= n) ->
24+ RawMemory (MemoryChunk n) (MemoryChunk n) ()
25+ Move : (src : MemoryChunk m) ->
26+ (dest_offset : Nat) ->
27+ (src_offset : Nat) ->
28+ (size : Nat) ->
29+ so (dest_offset + size <= n) ->
30+ so (src_offset + size <= m) ->
31+ RawMemory (MemoryChunk n) (MemoryChunk n) ()
32+ GetRawPtr : RawMemory (MemoryChunk n) (MemoryChunk n) (MemoryChunk n)
33+
34+private
35+do_malloc : Nat -> IOExcept String Ptr
36+do_malloc size with (fromInteger (cast size) == size)
37+ | True = do ptr <- ioe_lift $ mkForeign (FFun "malloc" [FInt] FPtr) (cast size)
38+ fail <- ioe_lift $ nullPtr ptr
39+ if fail then ioe_fail "Cannot allocate memory"
40+ else return ptr
41+ | False = ioe_fail "The target architecture does not support adressing enough memory"
42+
43+private
44+do_free : Ptr -> IO ()
45+do_free ptr = mkForeign (FFun "free" [FPtr] FUnit) ptr
46+
47+private
48+do_memmove : Ptr -> Ptr -> Nat -> Nat -> Nat -> IO ()
49+do_memmove dest src dest_offset src_offset size
50+ = mkForeign (FFun "idris_memmove" [FPtr, FPtr, FInt, FInt, FInt] FUnit)
51+ dest src (cast dest_offset) (cast src_offset) (cast size)
52+
53+private
54+do_peek : Ptr -> Nat -> (size : Nat) -> IO (Vect Bits8 size)
55+do_peek _ _ O = return (Prelude.Vect.Nil)
56+do_peek ptr offset (S n)
57+ = do b <- mkForeign (FFun "idris_peek" [FPtr, FInt] FInt) ptr (cast offset)
58+ bs <- do_peek ptr (S offset) n
59+ Prelude.Monad.return (Prelude.Vect.(::) (prim__intToB8 b) bs)
60+
61+do_poke : Ptr -> Nat -> Vect Bits8 size -> IO ()
62+do_poke _ _ [] = return ()
63+do_poke ptr offset (b::bs)
64+ = do mkForeign (FFun "idris_poke" [FPtr, FInt, FAny Bits8] FUnit) ptr (cast offset) b
65+ do_poke ptr (S offset) bs
66+
67+instance Handler RawMemory (IOExcept String) where
68+ handle () (Allocate n) k
69+ = do ptr <- do_malloc n
70+ k (CH ptr n) ()
71+ handle (CH ptr n) (Free) k
72+ = ioe_lift (do_free ptr) $> k () ()
73+ handle (CH ptr n) (Peek offset size _) k
74+ = do res <- ioe_lift (do_peek ptr offset size)
75+ k (CH ptr n) res
76+ handle (CH ptr n) (Poke offset content _) k
77+ = do ioe_lift (do_poke ptr offset content)
78+ k (CH ptr n) ()
79+ handle (CH dest_ptr n) (Move (CH src_ptr m) dest_offset src_offset size _ _) k
80+ = do ioe_lift (do_memmove dest_ptr src_ptr dest_offset src_offset size)
81+ k (CH dest_ptr n) ()
82+ handle (CH ptr n) (GetRawPtr) k
83+ = k (CH ptr n) (CH ptr n)
84+
85+RAW_MEMORY : Type -> EFFECT
86+RAW_MEMORY t = MkEff t RawMemory
87+
88+allocate : (n : Nat) -> EffM m [RAW_MEMORY ()] [RAW_MEMORY (MemoryChunk n)] ()
89+allocate size = Allocate size
90+
91+free : EffM m [RAW_MEMORY (MemoryChunk n)] [RAW_MEMORY ()] ()
92+free = Free
93+
94+peek : {n : Nat} ->
95+ (offset : Nat) ->
96+ (size : Nat) ->
97+ so (offset + size <= n) ->
98+ Eff m [RAW_MEMORY (MemoryChunk n)] (Vect Bits8 size)
99+peek offset size prf = Peek offset size prf
100+
101+poke : {n : Nat} ->
102+ (offset : Nat) ->
103+ Vect Bits8 size ->
104+ so (offset + size <= n) ->
105+ Eff m [RAW_MEMORY (MemoryChunk n)] ()
106+poke offset content prf = Poke offset content prf
107+
108+private
109+getRawPtr : Eff m [RAW_MEMORY (MemoryChunk n)] (MemoryChunk n)
110+getRawPtr = GetRawPtr
111+
112+private
113+move' : {dst_size : Nat} ->
114+ {src_size : Nat} ->
115+ (src_ptr : MemoryChunk src_size) ->
116+ (dst_offset : Nat) ->
117+ (src_offset : Nat) ->
118+ (size : Nat) ->
119+ so (dst_offset + size <= dst_size) ->
120+ so (src_offset + size <= src_size) ->
121+ Eff m [RAW_MEMORY (MemoryChunk dst_size)] ()
122+move' src_ptr dst_offset src_offset size dst_bounds src_bounds
123+ = Move src_ptr dst_offset src_offset size dst_bounds src_bounds
124+
125+data MoveDescriptor = Dst | Src
126+
127+move : {dst_size : Nat} ->
128+ {src_size : Nat} ->
129+ (dst_offset : Nat) ->
130+ (src_offset : Nat) ->
131+ (size : Nat) ->
132+ so (dst_offset + size <= dst_size) ->
133+ so (src_offset + size <= src_size) ->
134+ Eff m [ Dst ::: RAW_MEMORY (MemoryChunk dst_size)
135+ , Src ::: RAW_MEMORY (MemoryChunk src_size)] ()
136+move dst_offset src_offset size dst_bounds src_bounds
137+ = do src_ptr <- Src :- getRawPtr
138+ Dst :- move' src_ptr dst_offset src_offset size dst_bounds src_bounds
139+ return ()