-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjschemeStack.h
357 lines (307 loc) · 9.13 KB
/
jschemeStack.h
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
/*
*
* *****************************
* * The JScheme Stack *
* *****************************
*
* SP -> points to the first free slot on stack
* AP -> points to the first argument in the current stack frame
* BP -> points to the first element in the current stack frame
*
* RETVAL -> used as return value register in continuation passing style
*
*
* THE JSTACK LAYOUT:
*
* abstract layout of a stack frame:
* | ------------------------------- |
* | 11 : | <- SP
* | 10 : LOCAL N |
* | 10 : ... |
* | 10 : LOCAL 1 |
* | 10 : ARG N |
* | 10 : .... |
* | 10 : ARG 1 |
* | 4 : environment | <- AP
* | 3 : continuation / return |
* | 2 : callee |
* | 1 : (save AP) |
* | 0 : (saved BP) | <- BP
* | ------------------------------- |
*
* ***********************************************************************
* #comment:
*
* Every CALL will create a NEW stack frame. RETURN will allways leave a stack frame.
* This can be a small overhead but it simplifies the usage pattern a lot! :)
*
* 1 CALL -> RETURN most of the time
* 2 TAILCALL when reusing a stack frame ( will drop LOCALS so pass them as args if needed )
* 3 LOCALS can be created in the stack frame they are needed. Because following CALLs will
* create another stack frame LOCALS are safe in the callers stack frame.
* ***********************************************************************
*
* CALL:
* - creates a new stack frame (save oldAP, oldBP and set BP to new stack frame)
* - pushes callee
* - pushes continuation/return address
* - pushes ARG1 to ARG N
*
* TAILCALL:
* - replace calle of current stack frame with new callee
* - reuse continuation/return of current stack frame
* - set ARG1 to ARG N
* - drops locals!
*
* RETURN:
* - set RETVAL to the return value
* - calls the continuation of current stack frame
* - leaves the stack frame ( restores previous stack frame with oldBP and oldAP )
*
*
* # IF a function needs some locals it must create and manage them
*
* CREATE_LOCALS N:
* - creates n locals initilaised with js_nil
*
* LOCAL N:
* - returns the local n in the current stack frame
*
* SET_LOCAL N O:
* - sets the local n to o in the current stack frame
*
*
* initial stack:
* ----------------------------------
* | 0 : | <- SP <- AP <- BP
* ----------------------------------
*
* in CP_jREPL:
* ----------------------------------
* | 0 : | <- SP
* | 4 : #file stream | <- AP
* | 3 : NULL | (continuation/return)
* | 2 : CP_jREPL |
* | 1 : 0 | (saved AP)
* | 0 : 0 | (saved BP) <- BP
* ----------------------------------
*
* in CP_js_eval for: (define a 100)
* -> CALL( CP_js_eval, GLOBAL, expr, CP_jREPL2)
* ----------------------------------
* | 11 : | <- SP
* | 10 : cons | -> (define a 100)
* | 9 : GLOBAL: (0x7ff7fa003600) | <- AP
* | 8 : CP_jREPL2 | (continuation/return)
* | 7 : CP_js_eval |
* | 6 : 4 | (saved AP)
* | 5 : 0 | (saved BP) <- BP
* | ------------------------------- |
* | 4 : #file stream |
* | 3 : NULL |
* | 2 : CP_jREPL |
* | 1 : 0 |
* | 0 : 0 |
* ----------------------------------
*
* ...
* -> TAILCALL CP_evalCons
* -> Create LOCALS for functionsSlot, restArgs, numArgs, etc...
* ...
*
* in CP_evalCons2
* ----------------------------------
* | 17 : | <- SP
* | 16 : nil |
* | 15 : nil |
* | 14 : nil |
* | 13 : 0 | LOCAL 2: numArgs
* | 12 : cons | -> (a 100) LOCAL 1: restArgs
* | 11 : builtin (define) | LOCAL 0: THE EVALUATED FUNCTION SLOT
* | 10 : cons | -> (define a 100) THE ORIGINAL cons
* | 9 : GLOBAL: (0x7fdb74007600) | <- AP
* | 8 : CP_jREPL2 | (continuation/return)
* | 7 : CP_evalCons |
* | 6 : 4 | (saved AP)
* | 5 : 0 | (saved BP) <- BP
* | ------------------------------- |
* | 4 : #file stream |
* | 3 : NULL |
* | 2 : CP_jREPL |
* | 1 : 0 |
* | 0 : 0 |
* ----------------------------------
*
*/
extern OBJ *jStack;
extern int SP;
extern int AP;
extern int BP;
extern int stackLimit;
extern OBJ RETVAL;
static inline void
PUSH(OBJ o) {
#ifdef DEBUG
if(SP == stackLimit) {
error("stack overflow", __FILE__, __LINE__);
}
#endif
jStack[SP++] = o;
}
static inline OBJ
POP(){
#ifdef DEBUG
if(SP == 0){
error("stack underflow", __FILE__, __LINE__);
}
#endif
return jStack[--SP];
}
static inline void
POPN(int n){
SP -= n;
}
static inline OBJ
NTH_ARG(int numArgs, int index){
#ifdef DEBUG
if(SP ==0){
error("stack underflow", __FILE__, __LINE__);
}
#endif
return jStack[SP - numArgs + index];
}
static inline OBJ
ARG(int n0based ){
/*
ASSERT( ((AP + n0based) >= SP), "arg index error");
ASSERT( ((AP + n0based) >= SP), "arg index error");
*/
return jStack[AP + n0based];
}
static inline OBJ
LOCAL(int n0based ){
ASSERT( ((AP + 2 + n0based) < SP), "get local arg index error");
ASSERT( ((AP + 2 + n0based) > 0), "arg index error");
return jStack[AP + 2 + n0based];
}
static inline void
SET_LOCAL(int n0based, OBJ o){
ASSERT( ((AP + 2 + n0based) < SP), "set local arg index error");
ASSERT( ((AP + 2 + n0based) > 0), "arg index error");
jStack[AP + 2 + n0based] = o;
}
/*
* Continuation helpers
*/
static inline int
savedAP(){
ASSERT( ((BP + 1) < SP), "saved AP index error");
ASSERT( ((BP + 1) > 0), "saved AP index error");
return (int)jStack[BP+1];
}
static inline VOIDPTRFUNC
getContinuation(){
ASSERT( ((BP + 3) < SP), "CONT index error");
ASSERT( ((BP + 3) > 0), "CONT index error");
return (VOIDPTRFUNC)jStack[BP+3];
}
static inline void
CREATE_LOCALS(int n){
for(int i = 0; i < n; i++){
PUSH(js_nil);
}
}
static inline void
NEW_STACK_FRAME(){
//printf(stdout, "ENTER %d\n", numLocals);
// prepare new stackFrame
PUSH(((OBJ)(INT)BP));
BP = SP - 1;
PUSH(((OBJ)(INT)AP));
//for(int i = 0; i < numLocals; i++){
// PUSH(js_nil);
//}
}
static inline void
LEAVE_STACK_FRAME(){
//fprintf(stdout, "LEAVE\n");
AP = savedAP();
SP = BP+1;
BP = (int)(POP());
}
static inline VOIDPTRFUNC
CALL1_helper(VOIDPTRFUNC func, OBJ arg1, VOIDPTRFUNC continuation){
DEBUGCODE(PRINT_STACK->state, fprintf(stdout, "C1: %s Cont: %s\n", functionName((VOIDPTRFUNC)func), functionName((VOIDPTRFUNC)continuation)) );
NEW_STACK_FRAME();
PUSH((OBJ) func);
PUSH((OBJ)continuation);
AP = SP;
// push args
PUSH(arg1);
return func;
}
#define CALL1(func, arg1, continuation)\
{ \
return CALL1_helper((VOIDPTRFUNC)func, arg1, (VOIDPTRFUNC) continuation);\
}
static inline VOIDPTRFUNC
CALL2_helper(VOIDPTRFUNC func, OBJ arg1, OBJ arg2, VOIDPTRFUNC continuation){
DEBUGCODE(PRINT_STACK->state, fprintf(stdout, "C2: %s Cont: %s\n", functionName((VOIDPTRFUNC)func), functionName((VOIDPTRFUNC)continuation)) );
NEW_STACK_FRAME();
PUSH((OBJ) func);
PUSH((OBJ)continuation);
AP = SP;
// push args
PUSH(arg1);
PUSH(arg2);
return func;
}
#define CALL2(func, arg1, arg2, continuation)\
{ \
return CALL2_helper((VOIDPTRFUNC)func, arg1, arg2, (VOIDPTRFUNC) continuation);\
}
static inline VOIDPTRFUNC
TAILCALL1_helper(VOIDPTRFUNC func, OBJ arg1){
DEBUGCODE(PRINT_STACK->state, fprintf(stdout, "TC1: %s\n", functionName((VOIDPTRFUNC)func)) );
VOIDPTRFUNC retAddr = (VOIDPTRFUNC)(getContinuation());
jStack[AP-2] = (OBJ)func;
jStack[AP-1] = (OBJ)retAddr;
jStack[AP] = arg1;
SP = AP + 1;
return func;
}
#define TAILCALL1(func, arg1)\
{ \
return TAILCALL1_helper((VOIDPTRFUNC)func, arg1);\
}
static inline VOIDPTRFUNC
TAILCALL2_helper(VOIDPTRFUNC func, OBJ arg1, OBJ arg2){
DEBUGCODE( PRINT_STACK->state, fprintf(stdout, "TC2: %s\n", functionName((VOIDPTRFUNC)func)) );
VOIDPTRFUNC retAddr = (VOIDPTRFUNC)(getContinuation());
jStack[AP-2] = (OBJ)func;
jStack[AP-1] = (OBJ)retAddr;
jStack[AP] = arg1;
jStack[AP+1] = arg2;
SP = AP + 2;
return func;
}
#define TAILCALL2(func, arg1, arg2)\
{ \
return TAILCALL2_helper((VOIDPTRFUNC)func, arg1, arg2);\
}
static inline VOIDPTRFUNC
RETURN_helper(OBJ retVal){
RETVAL = retVal;
VOIDPTRFUNC retAddr = (VOIDPTRFUNC)(getContinuation());
LEAVE_STACK_FRAME();
//SP = AP - 1;
//AP = savedAP();
DEBUGCODE(PRINT_STACK->state, fprintf(stdout, "RETURN: ") );
DEBUGCODE(PRINT_STACK->state, js_print(stdout, retVal, 1) );
DEBUGCODE(PRINT_STACK->state, fprintf(stdout, " -> %s\n", functionName((VOIDPTRFUNC)retAddr)) );
return retAddr;
}
#define RETURN(retVal)\
{ \
return RETURN_helper(retVal);\
}