1
+ // Complexity of state:
2
+ //
3
+ // get: O(1)
4
+ // set: O(1)
5
+ // capture: O(1)
6
+ // restore: O(|write operations since capture|)
7
+ const Mem = null
8
+
9
+ function Arena ( ) {
10
+ const s = {
11
+ root : { value : Mem } ,
12
+ generation : 0 ,
13
+ fresh : ( v ) => {
14
+ const r = {
15
+ value : v ,
16
+ generation : s . generation ,
17
+ store : s ,
18
+ set : ( v ) => {
19
+ const s = r . store
20
+ const r_gen = r . generation
21
+ const s_gen = s . generation
22
+
23
+ if ( r_gen == s_gen ) {
24
+ r . value = v ;
25
+ } else {
26
+ const root = { value : Mem }
27
+ // update store
28
+ s . root . value = { ref : r , value : r . value , generation : r_gen , root : root }
29
+ s . root = root
30
+ r . value = v
31
+ r . generation = s_gen
32
+ }
33
+ }
34
+ } ;
35
+ return r
36
+ } ,
37
+ // not implemented
38
+ newRegion : ( ) => s
39
+ } ;
40
+ return s
41
+ }
1
42
2
- // Common Runtime
3
- // --------------
4
- function Cell ( init , region ) {
5
- const cell = {
6
- value : init ,
7
- backup : function ( ) {
8
- const _backup = cell . value ;
9
- // restore function (has a STRONG reference to `this`)
10
- return ( ) => { cell . value = _backup ; return cell }
11
- }
43
+ const global = {
44
+ fresh : ( v ) => {
45
+ const r = {
46
+ value : v ,
47
+ set : ( v ) => { r . value = v }
48
+ } ;
49
+ return r
12
50
}
13
- return cell ;
14
51
}
15
52
16
- const global = {
17
- fresh : Cell
53
+ function snapshot ( s ) {
54
+ const snap = { store : s , root : s . root , generation : s . generation }
55
+ s . generation = s . generation + 1
56
+ return snap
18
57
}
19
58
20
- function Arena ( _region ) {
21
- const region = _region ;
22
- return {
23
- fresh : function ( init ) {
24
- const cell = Cell ( init ) ;
25
- // region keeps track what to backup, but we do not need to backup unreachable cells
26
- region . push ( cell ) // new WeakRef(cell))
27
- return cell ;
28
- } ,
29
- region : _region ,
30
- newRegion : function ( ) {
31
- // a region aggregates weak references
32
- const nested = Arena ( [ ] )
33
- // this doesn't work yet, since Arena.backup doesn't return a thunk
34
- region . push ( nested ) //new WeakRef(nested))
35
- return nested ;
36
- } ,
37
- backup : function ( ) {
38
- const _backup = [ ]
39
- let nextIndex = 0 ;
40
- for ( const ref of region ) {
41
- const cell = ref //.deref()
42
- // only backup live cells
43
- if ( cell ) {
44
- _backup [ nextIndex ] = cell . backup ( )
45
- nextIndex ++
46
- }
47
- }
48
- function restore ( ) {
49
- const region = [ ]
50
- let nextIndex = 0 ;
51
- for ( const restoreCell of _backup ) {
52
- region [ nextIndex ] = restoreCell ( ) // new WeakRef(restoreCell())
53
- nextIndex ++
54
- }
55
- return Arena ( region )
56
- }
57
- return restore ;
58
- }
59
- }
59
+ function reroot ( n ) {
60
+ if ( n . value === Mem ) return ;
61
+
62
+ const diff = n . value
63
+ const r = diff . ref
64
+ const v = diff . value
65
+ const g = diff . generation
66
+ const n2 = diff . root
67
+ reroot ( n2 )
68
+ n . value = Mem
69
+ n2 . value = { ref : r , value : r . value , generation : r . generation , root : n }
70
+ r . value = v
71
+ r . generation = g
60
72
}
61
73
74
+ function restore ( store , snap ) {
75
+ // linear in the number of modifications...
76
+ reroot ( snap . root )
77
+ store . root = snap . root
78
+ store . generation = snap . generation + 1
79
+ }
62
80
81
+ // Common Runtime
82
+ // --------------
63
83
let _prompt = 1 ;
64
84
65
85
const TOPLEVEL_K = ( x , ks ) => { throw { computationIsDone : true , result : x } }
66
- const TOPLEVEL_KS = { prompt : 0 , arena : Arena ( [ ] ) , rest : null }
86
+ const TOPLEVEL_KS = { prompt : 0 , arena : Arena ( ) , rest : null }
67
87
68
88
function THUNK ( f ) {
69
89
f . thunk = true
@@ -80,37 +100,29 @@ function CAPTURE(body) {
80
100
81
101
const RETURN = ( x , ks ) => ks . rest . stack ( x , ks . rest )
82
102
83
- // const r = ks.arena.newRegion(); body
84
- // const x = r.alloc(init); body
85
-
86
103
// HANDLE(ks, ks, (p, ks, k) => { STMT })
87
104
function RESET ( prog , ks , k ) {
88
105
const prompt = _prompt ++ ;
89
106
const rest = { stack : k , prompt : ks . prompt , arena : ks . arena , rest : ks . rest }
90
107
return prog ( prompt , { prompt, arena : Arena ( [ ] ) , rest } , RETURN )
91
108
}
92
109
93
- function DEALLOC ( ks ) {
94
- const arena = ks . arena
95
- if ( ! ! arena ) {
96
- arena . length = arena . length - 1
97
- }
98
- }
99
-
100
110
function SHIFT ( p , body , ks , k ) {
101
111
102
112
// TODO avoid constructing this object
103
113
let meta = { stack : k , prompt : ks . prompt , arena : ks . arena , rest : ks . rest }
104
114
let cont = null
105
115
106
116
while ( ! ! meta && meta . prompt !== p ) {
107
- cont = { stack : meta . stack , prompt : meta . prompt , backup : meta . arena . backup ( ) , rest : cont }
117
+ let store = meta . arena
118
+ cont = { stack : meta . stack , prompt : meta . prompt , arena : store , backup : snapshot ( store ) , rest : cont }
108
119
meta = meta . rest
109
120
}
110
121
if ( ! meta ) { throw `Prompt not found ${ p } ` }
111
122
112
123
// package the prompt itself
113
- cont = { stack : meta . stack , prompt : meta . prompt , backup : meta . arena . backup ( ) , rest : cont }
124
+ let store = meta . arena
125
+ cont = { stack : meta . stack , prompt : meta . prompt , arena : store , backup : snapshot ( store ) , rest : cont }
114
126
meta = meta . rest
115
127
116
128
const k1 = meta . stack
@@ -123,7 +135,8 @@ function RESUME(cont, c, ks, k) {
123
135
let meta = { stack : k , prompt : ks . prompt , arena : ks . arena , rest : ks . rest }
124
136
let toRewind = cont
125
137
while ( ! ! toRewind ) {
126
- meta = { stack : toRewind . stack , prompt : toRewind . prompt , arena : toRewind . backup ( ) , rest : meta }
138
+ restore ( toRewind . arena , toRewind . backup )
139
+ meta = { stack : toRewind . stack , prompt : toRewind . prompt , arena : toRewind . arena , rest : meta }
127
140
toRewind = toRewind . rest
128
141
}
129
142
0 commit comments