potion  0.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
callcc.c
Go to the documentation of this file.
1 //
4 // NOTE: these hacks make use of the frame pointer, so they must
5 // be compiled -fno-omit-frame-pointer!
6 //
7 // (c) 2008 why the lucky stiff, the freelance professor
8 //
9 #include <stdio.h>
10 #include "potion.h"
11 #include "internal.h"
12 
19  struct PNCont *cc = (struct PNCont *)self;
20  PN *start, *end, *sp1 = P->mem->cstack;
21 #if POTION_STACK_DIR > 0
22  start = (PN *)cc->stack[0];
23  end = (PN *)cc->stack[1];
24 #else
25  start = (PN *)cc->stack[1];
26  end = (PN *)cc->stack[0];
27 #endif
28 
29  if ((PN)sp1 != cc->stack[0]) {
30  fprintf(stderr, "** TODO: continuations which switch stacks must be rewritten. (%p != %p)\n",
31  sp1, (void *)(cc->stack[0]));
32  return PN_NIL;
33  }
34  DBG_vt("\nyield: start=%p, end=%p, cc=%p\n", start, end, cc->stack);
35 
36  //
37  // move stack pointer, fill in stack, resume
38  cc->stack[3] = (PN)cc;
39 #if POTION_X86 == POTION_JIT_TARGET
40 #if PN_SIZE_T == 8
41  __asm__ ("mov 0x8(%2), %%rsp;"
42  "mov 0x10(%2), %%rbp;"
43  "mov %2, %%rbx;"
44  "add $0x48, %2;"
45  "loop:"
46  "mov (%2), %%rax;"
47  "add $0x8, %0;"
48  "mov %%rax, (%0);"
49  "add $0x8, %2;"
50  "cmp %0, %1;"
51  "jne loop;"
52  "mov 0x18(%%rbx), %%rax;"
53  "movq $0x0, 0x18(%%rbx);"
54  "mov 0x28(%%rbx), %%r12;"
55  "mov 0x30(%%rbx), %%r13;"
56  "mov 0x38(%%rbx), %%r14;"
57  "mov 0x40(%%rbx), %%r15;"
58  "mov 0x20(%%rbx), %%rbx;"
59  "leave; ret"
60  :/* no output */
61  :"r"(start), "r"(end), "r"(cc->stack)
62  :"%rax", "%rsp", "%rbx"
63  );
64 #else
65  __asm__ ("mov 0x4(%2), %%esp;"
66  "mov 0x8(%2), %%ebp;"
67  "mov %2, %%esi;"
68  "add $0x1c, %2;"
69  "loop:"
70  "mov (%2), %%eax;"
71  "add $0x4, %0;"
72  "mov %%eax, (%0);"
73  "add $0x4, %2;"
74  "cmp %0, %1;"
75  "jne loop;"
76  "mov 0xc(%%esi), %%eax;"
77  "mov 0x14(%%esi), %%edi;"
78  "mov 0x18(%%esi), %%ebx;"
79  "mov 0x10(%%esi), %%esi;"
80  "leave; ret"
81  :/* no output */
82  :"r"(start), "r"(end), "r"(cc->stack)
83  :"%eax", "%esp", /*"%ebp",*/ "%esi"
84  );
85  //DBG_vt("yield => start=%p, end=%p, cc=%p\n", start, end, cc->stack);
86 #endif
87 #else
88  fprintf(stderr, "** TODO: callcc/yield does not work outside of X86 yet.\n");
89 #endif
90 #ifdef DEBUG
91  if (!P->strings || !P->lobby || !P->mem)
92  potion_fatal("fatal: yield stack underflow\n");
93 #endif
94  return self;
95 }
96 
102 PN potion_callcc(Potion *P, PN cl, PN self) {
103  struct PNCont *cc;
104  long n;
105  PN *start, *sp1 = P->mem->cstack, *sp2, *sp3;
106 #if defined(DEBUG) && (PN_SIZE_T == 8)
107  if ((_PN)sp1 & 0xF) {
108  fprintf(stderr,"P->mem->cstack=0x%lx ", (_PN)sp1);
109  potion_fatal("stack not 16byte aligned");
110  }
111 #endif
112  POTION_ESP(&sp2); // usually P
113  POTION_EBP(&sp3);
114 #if POTION_STACK_DIR > 0
115  n = sp2 - sp1;
116  start = sp1;
117 #else
118  n = sp1 - sp2 + 1;
119  start = sp2;
120 #endif
121 
122  if (n < 0) {
123  DBG_vt("\ncallcc: n=%ld, start=%p, end=%p, cc=%p\n", n, start, sp2, sp1);
124  potion_fatal("invalid stack direction");
125  return 0;
126  }
127  cc = PN_ALLOC_N(PN_TCONT, struct PNCont, sizeof(PN) * (n + 3 + PN_SAVED_REGS));
128  cc->len = n + 3;
129  cc->stack[0] = (PN)sp1;
130  cc->stack[1] = (PN)sp2;
131  cc->stack[2] = (PN)sp3;
132  cc->stack[3] = PN_NIL;
133  DBG_vt("\ncallcc: start=%p, end=%p, cc=%p\n", start, sp2, cc->stack);
134 #if POTION_X86 == POTION_JIT_TARGET
135 #if PN_SIZE_T == 8
136  __asm__ ("mov %%rbx, 0x20(%0);"
137  "mov %%r12, 0x28(%0);"
138  "mov %%r13, 0x30(%0);"
139  "mov %%r14, 0x38(%0);"
140  "mov %%r15, 0x40(%0);"::"r"(cc->stack));
141 #else
142  __asm__ ("mov %%esi, 0x10(%0);"
143  "mov %%edi, 0x14(%0);"
144  "mov %%ebx, 0x18(%0)"::"r"(cc->stack));
145 #endif
146 #endif
147 
148 // avoid wrong asan stack underflow, caught in memcpy
149 #if defined(__clang__) && defined(__SANITIZE_ADDRESS__)
150  {
151  PN *s = start + 1;
152  PN *d = cc->stack + 4 + PN_SAVED_REGS;
153  for (int i=0; i < n - 1; i++) {
154  *d++ = *s++;
155  }
156  }
157 #else
158  PN_MEMCPY_N((char *)(cc->stack + 4 + PN_SAVED_REGS), start + 1, PN, n - 1);
159 #endif
160 // stack-buffer-underflow sanity check, should not overwrite P
161 #ifdef DEBUG
162  if (!P->strings || !P->lobby || !P->mem)
163  potion_fatal("fatal: callcc stack underflow\n");
164 #endif
165  return (PN)cc;
166 }
167 
168 // callcc is the "here" method of lobby
170  PN cnt_vt = PN_VTABLE(PN_TCONT);
172 }
#define DBG_vt(...)
Definition: potion.h:246
PN potion_continuation_yield(Potion *P, PN cl, PN self)
Definition: callcc.c:18
#define PN_ALLOC_N(V, T, C)
Definition: internal.h:13
unsigned long _PN
Definition: potion.h:78
void potion_cont_init(Potion *P)
Definition: callcc.c:169
#define PN_TCONT
Definition: potion.h:129
struct PNMemory * mem
allocator/gc
Definition: potion.h:651
void potion_type_call_is(PN vt, PN cl)
sets the default call method of the PNVtable
Definition: objmodel.c:225
void * cstack
machine stack start
Definition: potion.h:676
#define PN_SAVED_REGS
Definition: internal.h:108
a continuation saves the stack and all stack pointers.
Definition: potion.h:510
PN lobby
root namespace
Definition: potion.h:648
#define ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
Definition: potion.h:65
#define PN_MEMCPY_N(X, Y, T, N)
Definition: internal.h:22
#define POTION_ESP(p)
Definition: internal.h:115
non-API internal parts
ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS PN potion_callcc(Potion *P, PN cl, PN self)
Definition: callcc.c:102
the global interpreter state P. currently singleton (not threads yet)
Definition: potion.h:644
The potion API.
PN_SIZE len
Definition: potion.h:512
PN stack[]
Definition: potion.h:513
volatile _PN PN
Definition: potion.h:81
#define PN_NIL
Definition: potion.h:139
#define POTION_EBP(p)
Definition: internal.h:118
#define PN_FUNC(f, s)
Definition: potion.h:219
struct PNTable * strings
table of all strings
Definition: potion.h:647
void potion_fatal(char *message)
Definition: internal.c:282
#define PN_VTABLE(t)
Definition: potion.h:136