/
callcc.c
144 lines (136 loc) · 3.73 KB
/
callcc.c
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
//
// callcc.c
// creation and calling of continuations
//
// NOTE: these hacks make use of the frame pointer, so they must
// be compiled -fno-omit-frame-pointer!
//
// (c) 2008 why the lucky stiff, the freelance professor
//
#include <stdio.h>
#include "p2.h"
#include "internal.h"
PN potion_continuation_yield(Potion *P, PN cl, PN self) {
struct PNCont *cc = (struct PNCont *)self;
PN *start, *end, *sp1 = P->mem->cstack;
#if POTION_STACK_DIR > 0
start = (PN *)cc->stack[0];
end = (PN *)cc->stack[1];
#else
start = (PN *)cc->stack[1];
end = (PN *)cc->stack[0];
#endif
if ((PN)sp1 != cc->stack[0]) {
fprintf(stderr, "** TODO: continuations which switch stacks must be rewritten. (%p != %p)\n",
sp1, (void *)(cc->stack[0]));
return PN_NIL;
}
//
// move stack pointer, fill in stack, resume
//
cc->stack[3] = (PN)cc;
#if POTION_X86 == POTION_JIT_TARGET
#if __WORDSIZE == 64
__asm__ ("mov 0x8(%2), %%rsp;"
"mov 0x10(%2), %%rbp;"
"mov %2, %%rbx;"
"add $0x48, %2;"
"loop:"
"mov (%2), %%rax;"
"add $0x8, %0;"
"mov %%rax, (%0);"
"add $0x8, %2;"
"cmp %0, %1;"
"jne loop;"
"mov 0x18(%%rbx), %%rax;"
"movq $0x0, 0x18(%%rbx);"
"mov 0x28(%%rbx), %%r12;"
"mov 0x30(%%rbx), %%r13;"
"mov 0x38(%%rbx), %%r14;"
"mov 0x40(%%rbx), %%r15;"
"mov 0x20(%%rbx), %%rbx;"
"leave; ret"
:/* no output */
:"r"(start), "r"(end), "r"(cc->stack)
:"%rax", "%rsp", "%rbx"
);
#else
__asm__ ("mov 0x4(%2), %%esp;"
"mov 0x8(%2), %%ebp;"
"mov %2, %%esi;"
"add $0x1c, %2;"
"loop:"
"mov (%2), %%eax;"
"add $0x4, %0;"
"mov %%eax, (%0);"
"add $0x4, %2;"
"cmp %0, %1;"
"jne loop;"
"mov 0xc(%%esi), %%eax;"
"mov 0x14(%%esi), %%edi;"
"mov 0x18(%%esi), %%ebx;"
"mov 0x10(%%esi), %%esi;"
"leave; ret"
:/* no output */
:"r"(start), "r"(end), "r"(cc->stack)
:"%eax", "%esp", /*"%ebp",*/ "%esi"
);
#endif
#else
fprintf(stderr, "** TODO: callcc/yield does not work outside of X86 yet.\n");
#endif
return self;
}
ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS // still stack-underflow at 130
PN potion_callcc(Potion *P, PN cl, PN self) {
struct PNCont *cc;
PN_SIZE n;
PN *start, *end, *sp1 = P->mem->cstack, *sp2, *sp3;
POTION_ESP(&sp2);
POTION_EBP(&sp3);
#if POTION_STACK_DIR > 0
n = sp2 - sp1;
start = sp1;
end = sp2;
#else
n = sp1 - sp2 + 1;
start = sp2;
end = sp1;
#endif
cc = PN_ALLOC_N(PN_TCONT, struct PNCont, sizeof(PN) * (n + 3 + PN_SAVED_REGS));
cc->len = n + 3;
cc->stack[0] = (PN)sp1;
cc->stack[1] = (PN)sp2;
cc->stack[2] = (PN)sp3;
cc->stack[3] = PN_NIL;
#if POTION_X86 == POTION_JIT_TARGET
#if __WORDSIZE == 64
__asm__ ("mov %%rbx, 0x20(%0);"
"mov %%r12, 0x28(%0);"
"mov %%r13, 0x30(%0);"
"mov %%r14, 0x38(%0);"
"mov %%r15, 0x40(%0);"::"r"(cc->stack));
#else
__asm__ ("mov %%esi, 0x10(%0);"
"mov %%edi, 0x14(%0);"
"mov %%ebx, 0x18(%0)"::"r"(cc->stack));
#endif
#endif
// avoid wrong asan stack underflow, caught in memcpy
#if defined(__clang__) && defined(__SANITIZE_ADDRESS__)
{
PN *s = start + 1;
PN *d = cc->stack + 4 + PN_SAVED_REGS;
for (int i=0; i < n - 1; i++) {
*d++ = *s++;
}
}
#else
PN_MEMCPY_N((char *)(cc->stack + 4 + PN_SAVED_REGS), start + 1, PN, n - 1);
#endif
return (PN)cc;
}
void potion_cont_init(Potion *P) {
PN cnt_vt = PN_VTABLE(PN_TCONT);
potion_type_call_is(cnt_vt, PN_FUNC(potion_continuation_yield, 0));
}