-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathmemory-racket.rkt
217 lines (171 loc) · 6.47 KB
/
memory-racket.rkt
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
#lang racket
(require "special.rkt" "ops-racket.rkt")
(provide memory-racket%)
;; Mask method which should only be public for object of memory-racket%
(define-local-member-name lookup-init)
(define memory-racket%
(class* special% (equal<%> printable<%>)
(super-new)
(init-field [get-fresh-val #f]
[init (make-hash)]
[update (make-hash)]
;; If this memory object is for interpreting specification program,
;; don't initialize ref.
;; Otherwise, initailize ref with memory object output from specification program.
[ref #f]) ;; TODO: do we ever use ref?
(public load store clone correctness-cost
;; for backward interpret
del lookup-update
get-update-addr-val get-update-addr-with-val get-addr-with-val get-available-addr
get-live-mask)
(define/public (custom-print port depth)
(print `(memory% init: ,init update: ,update) port depth))
(define/public (custom-write port)
(write `(memory% init: ,init update: ,update) port))
(define/public (custom-display port)
(display `(memory% init: ,init update: ,update) port))
(define/public (equal-to? other recur)
(and (is-a? other memory-racket%)
(equal? update (get-field update other))))
(define/public (equal-hash-code-of hash-code)
(hash-code update))
(define/public (equal-secondary-hash-code-of hash-code)
(hash-code update))
;; Clone a new memory object with the same init and update.
;; Use this method to clone new memory for every program interpretation.
(define (clone [ref #f])
(new memory-racket% [ref ref] [init init]
[update (make-hash (hash->list update))] [get-fresh-val get-fresh-val]))
(define/public (clone-init)
(new memory-racket% [ref ref] [init init]))
;; (if (hash-empty? update)
;; this
;; (new memory-racket% [ref ref] [init init])))
(define (correctness-cost other diff-cost bit)
(define cost 0)
(for ([pair (hash->list update)])
(let* ([addr (car pair)]
[val (cdr pair)]
[other-val (or (send other lookup-update addr)
(send other lookup-init addr))])
(set! cost (+ cost
(if other-val
(diff-cost val other-val)
bit)))))
cost)
(define (get-live-mask) (> (hash-count update) 0))
;;;;;;;;;;;;;;;;;;;; get addr & val ;;;;;;;;;;;;;;;;;;;;;
(define (get-update-addr-val)
(hash->list update))
(define (get-update-addr-with-val val)
(map car (filter (lambda (x) (= (cdr x) val)) (hash->list update))))
(define (get-addr-with-val val)
;;(pretty-display `(val ,val))
(append
(map car (filter (lambda (x) (= (cdr x) val)) (hash->list update)))
(map car (filter (lambda (x)
(and (= (cdr x) val)
(not (hash-has-key? update (car x)))))
(hash->list init)))))
(define (get-available-addr ref)
(remove*
(hash-keys update)
(hash-keys (get-field update ref))))
;;;;;;;;;;;;;;;;;;;; lookup & update ;;;;;;;;;;;;;;;;;;;;
(define (lookup storage addr)
(and (hash-has-key? storage addr)
(hash-ref storage addr)))
(define/public (lookup-init addr) (lookup init addr))
(define (lookup-update addr) (lookup update addr))
(define (modify storage addr val)
(hash-set! storage addr val))
(define (init-new-val addr)
(define val (get-fresh-val))
(hash-set! init addr val)
val)
;;;;;;;;;;;;;;;;;;;; del ;;;;;;;;;;;;;;;;;;;;
(define (del addr)
(hash-remove! update addr))
;;;;;;;;;;;;;;;;;;;; load ;;;;;;;;;;;;;;;;;;;;
(define (load-spec addr)
;;(pretty-display `(load-spec ,init ,(lookup init addr)))
(or (lookup update addr)
(lookup init addr)
(init-new-val addr)))
;;(assert #f "load illegal address (spec)")))
(define (load-cand addr ref-mem)
(or (lookup update addr)
(send ref-mem lookup-init addr)
(assert #f "load illegal address (candidate)")))
(define (load addr)
(if ref
(load-cand addr ref)
(load-spec addr)))
;;;;;;;;;;;;;;;;;;;; store ;;;;;;;;;;;;;;;;;;;;
(define (store-spec addr val)
(modify update addr val))
(define (store-cand addr val mem-ref)
;; legal to update if that address is used for spec.
(cond
[(send mem-ref lookup-update addr)
(store-spec addr val)]
[else (assert #f "store illegal address")]))
(define (store addr val)
(if ref
(store-cand addr val ref)
(store-spec addr val)))
))
(define (test1)
(define mem (new memory-racket%))
(send mem load 9) ;; expect error here
)
(define (test2)
;; test correctness-cost
(define (diff-cost x y) (if (= x y) 0 1))
(define mem (new memory-racket% [init (make-hash '((9 . 99) (6 . 66)))]))
(define mem2 (send mem clone mem))
(send mem load 9)
(send mem load 6)
(send mem store 2 222)
(send mem store 3 333)
(send mem2 load 9)
(send mem2 load 6)
(send mem2 store 2 111)
(assert (= (send mem correctness-cost mem2 diff-cost 10) 11))
(pretty-display "test 2: passed")
)
(define (test3)
;; test clone del lookup-update
(define mem (new memory-racket% [init (make-hash '((9 . 99) (6 . 66)))]))
(send mem store 2 222)
(send mem store 3 333)
(define mem2 (send mem clone))
(send mem2 del 3)
(assert (= 222 (send mem2 lookup-update 2)))
(assert (equal? #f (send mem2 lookup-update 3)))
(assert (= 333 (send mem lookup-update 3)))
(pretty-display "test 3: passed")
)
(define (test4)
(define state1 (vector 1 (new memory-racket% [update (make-hash '((9 . 99) (6 . 66)))])))
(define state2 (vector 1 (new memory-racket% [update (make-hash '((9 . 99) (6 . 66)))])))
(assert (equal? state1 state2))
(define my-hash (make-hash))
(hash-set! my-hash state1 1234)
(assert (= 1234 (hash-ref my-hash state2)))
(pretty-display "test 4: passed")
)
(define (test-all)
(test2)
(test3)
(test4))
(define (test-performance)
(define q (new memory-racket%))
(for/list ([i 1000000])
(send q clone-init)))
#|
(define t1 (current-milliseconds))
(define ans (test-performance))
(define t2 (current-milliseconds))
(- t2 t1)
|#