aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/LuaJIT-1.1.7/src/lcoco.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/LuaJIT-1.1.7/src/lcoco.c')
-rw-r--r--libraries/LuaJIT-1.1.7/src/lcoco.c693
1 files changed, 0 insertions, 693 deletions
diff --git a/libraries/LuaJIT-1.1.7/src/lcoco.c b/libraries/LuaJIT-1.1.7/src/lcoco.c
deleted file mode 100644
index c3acc68..0000000
--- a/libraries/LuaJIT-1.1.7/src/lcoco.c
+++ /dev/null
@@ -1,693 +0,0 @@
1/*
2** Copyright (C) 2004-2011 Mike Pall. All rights reserved.
3**
4** Permission is hereby granted, free of charge, to any person obtaining
5** a copy of this software and associated documentation files (the
6** "Software"), to deal in the Software without restriction, including
7** without limitation the rights to use, copy, modify, merge, publish,
8** distribute, sublicense, and/or sell copies of the Software, and to
9** permit persons to whom the Software is furnished to do so, subject to
10** the following conditions:
11**
12** The above copyright notice and this permission notice shall be
13** included in all copies or substantial portions of the Software.
14**
15** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22**
23** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
24*/
25
26/* Coco -- True C coroutines for Lua. http://luajit.org/coco.html */
27#ifndef COCO_DISABLE
28
29#define lcoco_c
30#define LUA_CORE
31
32#include "lua.h"
33
34#include "lobject.h"
35#include "lstate.h"
36#include "ldo.h"
37#include "lvm.h"
38#include "lgc.h"
39
40
41/*
42** Define this if you want to run Coco with valgrind. You will get random
43** errors about accessing memory from newly allocated C stacks if you don't.
44** You need at least valgrind 3.0 for this to work.
45**
46** This macro evaluates to a no-op if not run with valgrind. I.e. you can
47** use the same binary for regular runs, too (without a performance loss).
48*/
49#ifdef USE_VALGRIND
50#include <valgrind/valgrind.h>
51#define STACK_REG(coco, p, sz) (coco)->vgid = VALGRIND_STACK_REGISTER(p, p+sz);
52#define STACK_DEREG(coco) VALGRIND_STACK_DEREGISTER((coco)->vgid);
53#define STACK_VGID unsigned int vgid;
54#else
55#define STACK_REG(coco, p, sz)
56#define STACK_DEREG(id)
57#define STACK_VGID
58#endif
59
60/* ------------------------------------------------------------------------ */
61
62/* Use Windows Fibers. */
63#if defined(COCO_USE_FIBERS)
64
65#define _WIN32_WINNT 0x0400
66#include <windows.h>
67
68#define COCO_MAIN_DECL CALLBACK
69
70typedef LPFIBER_START_ROUTINE coco_MainFunc;
71
72#define COCO_NEW(OL, NL, cstacksize, mainfunc) \
73 if ((L2COCO(NL)->fib = CreateFiber(cstacksize, mainfunc, NL)) == NULL) \
74 luaD_throw(OL, LUA_ERRMEM);
75
76#define COCO_FREE(L) \
77 DeleteFiber(L2COCO(L)->fib); \
78 L2COCO(L)->fib = NULL;
79
80/* See: http://blogs.msdn.com/oldnewthing/archive/2004/12/31/344799.aspx */
81#define COCO_JUMPIN(coco) \
82 { void *cur = GetCurrentFiber(); \
83 coco->back = (cur == NULL || cur == (void *)0x1e00) ? \
84 ConvertThreadToFiber(NULL) : cur; } \
85 SwitchToFiber(coco->fib);
86
87#define COCO_JUMPOUT(coco) \
88 SwitchToFiber(coco->back);
89
90/* CreateFiber() defaults to STACKSIZE from the Windows module .def file. */
91#define COCO_DEFAULT_CSTACKSIZE 0
92
93/* ------------------------------------------------------------------------ */
94
95#else /* !COCO_USE_FIBERS */
96
97#ifndef COCO_USE_UCONTEXT
98
99/* Try inline asm first. */
100#if __GNUC__ >= 3 && !defined(COCO_USE_SETJMP)
101
102#if defined(__i386) || defined(__i386__)
103
104#ifdef __PIC__
105typedef void *coco_ctx[4]; /* eip, esp, ebp, ebx */
106static inline void coco_switch(coco_ctx from, coco_ctx to)
107{
108 __asm__ __volatile__ (
109 "call 1f\n" "1:\tpopl %%eax\n\t" "addl $(2f-1b),%%eax\n\t"
110 "movl %%eax, (%0)\n\t" "movl %%esp, 4(%0)\n\t"
111 "movl %%ebp, 8(%0)\n\t" "movl %%ebx, 12(%0)\n\t"
112 "movl 12(%1), %%ebx\n\t" "movl 8(%1), %%ebp\n\t"
113 "movl 4(%1), %%esp\n\t" "jmp *(%1)\n" "2:\n"
114 : "+S" (from), "+D" (to) : : "eax", "ecx", "edx", "memory", "cc");
115}
116#else
117typedef void *coco_ctx[3]; /* eip, esp, ebp */
118static inline void coco_switch(coco_ctx from, coco_ctx to)
119{
120 __asm__ __volatile__ (
121 "movl $1f, (%0)\n\t" "movl %%esp, 4(%0)\n\t" "movl %%ebp, 8(%0)\n\t"
122 "movl 8(%1), %%ebp\n\t" "movl 4(%1), %%esp\n\t" "jmp *(%1)\n" "1:\n"
123 : "+S" (from), "+D" (to) : : "eax", "ebx", "ecx", "edx", "memory", "cc");
124}
125#endif
126
127#define COCO_CTX coco_ctx
128#define COCO_SWITCH(from, to) coco_switch(from, to);
129#define COCO_MAKECTX(coco, buf, func, stack, a0) \
130 buf[0] = (void *)(func); \
131 buf[1] = (void *)(stack); \
132 buf[2] = (void *)0; \
133 stack[0] = 0xdeadc0c0; /* Dummy return address. */ \
134 coco->arg0 = (size_t)(a0);
135#define COCO_STATE_HEAD size_t arg0;
136
137#elif defined(__x86_64__)
138
139static void coco_wrap_main(void)
140{
141 __asm__ __volatile__ ("\tmovq %r13, %rdi\n\tjmpq *%r12\n");
142}
143
144typedef void *coco_ctx[8]; /* rip, rsp, rbp, rbx, r12, r13, r14, r15 */
145static inline void coco_switch(coco_ctx from, coco_ctx to)
146{
147 __asm__ __volatile__ (
148 "leaq 1f(%%rip), %%rax\n\t"
149 "movq %%rax, (%0)\n\t" "movq %%rsp, 8(%0)\n\t" "movq %%rbp, 16(%0)\n\t"
150 "movq %%rbx, 24(%0)\n\t" "movq %%r12, 32(%0)\n\t" "movq %%r13, 40(%0)\n\t"
151 "movq %%r14, 48(%0)\n\t" "movq %%r15, 56(%0)\n\t"
152 "movq 56(%1), %%r15\n\t" "movq 48(%1), %%r14\n\t" "movq 40(%1), %%r13\n\t"
153 "movq 32(%1), %%r12\n\t" "movq 24(%1), %%rbx\n\t" "movq 16(%1), %%rbp\n\t"
154 "movq 8(%1), %%rsp\n\t" "jmpq *(%1)\n" "1:\n"
155 : "+S" (from), "+D" (to) :
156 : "rax", "rcx", "rdx", "r8", "r9", "r10", "r11", "memory", "cc");
157}
158
159#define COCO_CTX coco_ctx
160#define COCO_SWITCH(from, to) coco_switch(from, to);
161#define COCO_MAKECTX(coco, buf, func, stack, a0) \
162 buf[0] = (void *)(coco_wrap_main); \
163 buf[1] = (void *)(stack); \
164 buf[2] = (void *)0; \
165 buf[3] = (void *)0; \
166 buf[4] = (void *)(func); \
167 buf[5] = (void *)(a0); \
168 buf[6] = (void *)0; \
169 buf[7] = (void *)0; \
170 stack[0] = 0xdeadc0c0deadc0c0; /* Dummy return address. */ \
171
172#elif __mips && _MIPS_SIM == _MIPS_SIM_ABI32 && !defined(__mips_eabi)
173
174/* No way to avoid the function prologue with inline assembler. So use this: */
175static const unsigned int coco_switch[] = {
176#ifdef __mips_soft_float
177#define COCO_STACKSAVE -10
178 0x27bdffd8, /* addiu sp, sp, -(10*4) */
179#else
180#define COCO_STACKSAVE -22
181 0x27bdffa8, /* addiu sp, sp, -(10*4+6*8) */
182 /* sdc1 {$f20-$f30}, offset(sp) */
183 0xf7be0050, 0xf7bc0048, 0xf7ba0040, 0xf7b80038, 0xf7b60030, 0xf7b40028,
184#endif
185 /* sw {gp,s0-s8}, offset(sp) */
186 0xafbe0024, 0xafb70020, 0xafb6001c, 0xafb50018, 0xafb40014, 0xafb30010,
187 0xafb2000c, 0xafb10008, 0xafb00004, 0xafbc0000,
188 /* sw sp, 4(a0); sw ra, 0(a0); lw ra, 0(a1); lw sp, 4(a1); move t9, ra */
189 0xac9d0004, 0xac9f0000, 0x8cbf0000, 0x8cbd0004, 0x03e0c821,
190 /* lw caller-saved-reg, offset(sp) */
191 0x8fbe0024, 0x8fb70020, 0x8fb6001c, 0x8fb50018, 0x8fb40014, 0x8fb30010,
192 0x8fb2000c, 0x8fb10008, 0x8fb00004, 0x8fbc0000,
193#ifdef __mips_soft_float
194 0x03e00008, 0x27bd0028 /* jr ra; addiu sp, sp, 10*4 */
195#else
196 /* ldc1 {$f20-$f30}, offset(sp) */
197 0xd7be0050, 0xd7bc0048, 0xd7ba0040, 0xd7b80038, 0xd7b60030, 0xd7b40028,
198 0x03e00008, 0x27bd0058 /* jr ra; addiu sp, sp, 10*4+6*8 */
199#endif
200};
201
202typedef void *coco_ctx[2]; /* ra, sp */
203#define COCO_CTX coco_ctx
204#define COCO_SWITCH(from, to) \
205 ((void (*)(coco_ctx, coco_ctx))coco_switch)(from, to);
206#define COCO_MAKECTX(coco, buf, func, stack, a0) \
207 buf[0] = (void *)(func); \
208 buf[1] = (void *)&stack[COCO_STACKSAVE]; \
209 stack[4] = (size_t)(a0); /* Assumes o32 ABI. */
210#define COCO_STACKADJUST 8
211#define COCO_MAIN_PARAM int _a, int _b, int _c, int _d, lua_State *L
212
213#elif defined(__sparc__)
214
215typedef void *coco_ctx[4];
216#define COCO_CTX coco_ctx
217#define COCO_SWITCH(from, to) coco_switch(from, to);
218#define COCO_STACKADJUST 24
219
220#if defined(__LP64__)
221#define COCO_STACKBIAS (2047UL)
222#define COCO_PTR2SP(stack) (((unsigned long)stack)-COCO_STACKBIAS)
223static inline void coco_switch(coco_ctx from, coco_ctx to)
224{
225 void *__stack[16] __attribute__((aligned (16)));
226 unsigned long __tmp_sp = COCO_PTR2SP(__stack);
227 __asm__ __volatile__
228 (/* Flush register window(s) to stack and save the previous stack
229 pointer to capture the current registers, %l0-%l7 and %i0-%i7. */
230 "ta 3\n\t"
231 "stx %%sp,[%0+8]\n\t"
232 /* Move to a temporary stack. If the register window is flushed
233 for some reason (e.g. context switch), not the next stack
234 but the temporary stack should be used so as not to break
235 neither the previous nor next stack */
236 "mov %2,%%sp\n\t"
237 "sethi %%hh(1f),%%g1\n\t" /* i.e. setx 1f,%%g1 */
238 "or %%g1,%%hm(1f),%%g1\n\t"
239 "sethi %%lm(1f),%%g2\n\t"
240 "or %%g2,%%lo(1f),%%g2\n\t"
241 "sllx %%g1,32,%%g1\n\t"
242 "or %%g1,%%g2,%%g1\n\t"
243 "stx %%g1,[%0]\n\t"
244 /* Restore registers from stack. DO NOT load the next stack
245 pointer directly to %sp. The register window can be possibly
246 flushed and restored asynchronous (e.g. context switch). */
247 "mov %1,%%o1\n\t"
248 "ldx [%%o1+8],%%o2\n\t"
249 "ldx [%%o2+%3],%%l0\n\t"
250 "ldx [%%o2+%3+8],%%l1\n\t"
251 "ldx [%%o2+%3+0x10],%%l2\n\t"
252 "ldx [%%o2+%3+0x18],%%l3\n\t"
253 "ldx [%%o2+%3+0x20],%%l4\n\t"
254 "ldx [%%o2+%3+0x28],%%l5\n\t"
255 "ldx [%%o2+%3+0x30],%%l6\n\t"
256 "ldx [%%o2+%3+0x38],%%l7\n\t"
257 "ldx [%%o2+%3+0x40],%%i0\n\t"
258 "ldx [%%o2+%3+0x48],%%i1\n\t"
259 "ldx [%%o2+%3+0x50],%%i2\n\t"
260 "ldx [%%o2+%3+0x58],%%i3\n\t"
261 "ldx [%%o2+%3+0x60],%%i4\n\t"
262 "ldx [%%o2+%3+0x68],%%i5\n\t"
263 "ldx [%%o2+%3+0x70],%%i6\n\t"
264 "ldx [%%o2+%3+0x78],%%i7\n\t"
265 /* Move to the next stack with the consistent registers atomically */
266 "mov %%o2,%%sp\n\t"
267 "ldx [%%o1],%%o2\n\t"
268 /* Since %o0-%o7 are marked as clobbered, values are safely overwritten
269 across the inline assembly. %o0-%o7 will have meaningless values
270 after leaving the inline assembly. The only exception is %o0, which
271 serves as an argument to coco_main */
272 "ldx [%%o1+16],%%o0\n\t"
273 "jmpl %%o2,%%g0\n\t"
274 "nop\n\t"
275 "1:\n"
276 /* An assumption is made here; no input operand is assigned to %g1
277 nor %g2. It's the case for the currently avilable gcc's */
278 : : "r"(from),"r"(to),"r"(__tmp_sp),"i"(COCO_STACKBIAS)
279 : "g1","g2","o0","o1","o2","o3","o4","o5","o7","memory","cc");
280}
281
282#define COCO_MAKECTX(coco, buf, func, stack, a0) \
283 buf[0] = (void *)(func); \
284 buf[1] = (void *)COCO_PTR2SP(&(stack)[0]); \
285 buf[2] = (void *)(a0); \
286 stack[0] = 0; \
287 stack[1] = 0; \
288 stack[2] = 0; \
289 stack[3] = 0; \
290 stack[4] = 0; \
291 stack[5] = 0; \
292 stack[6] = 0; \
293 stack[7] = 0; \
294 stack[8] = 0; \
295 stack[9] = 0; \
296 stack[10] = 0; \
297 stack[11] = 0; \
298 stack[12] = 0; \
299 stack[13] = 0; \
300 stack[14] = COCO_PTR2SP(&(stack)[COCO_STACKADJUST]); \
301 stack[15] = 0xdeadc0c0deadc0c0; /* Dummy return address. */ \
302
303#else
304static inline void coco_switch(coco_ctx from, coco_ctx to)
305{
306 void *__tmp_stack[16] __attribute__((aligned (16)));
307 __asm__ __volatile__
308 ("ta 3\n\t"
309 "st %%sp,[%0+4]\n\t"
310 "mov %2,%%sp\n\t"
311 "set 1f,%%g1\n\t"
312 "st %%g1,[%0]\n\t"
313 "mov %1,%%o1\n\t"
314 "ld [%%o1+4],%%o2\n\t"
315 "ldd [%%o2],%%l0\n\t"
316 "ldd [%%o2+8],%%l2\n\t"
317 "ldd [%%o2+0x10],%%l4\n\t"
318 "ldd [%%o2+0x18],%%l6\n\t"
319 "ldd [%%o2+0x20],%%i0\n\t"
320 "ldd [%%o2+0x28],%%i2\n\t"
321 "ldd [%%o2+0x30],%%i4\n\t"
322 "ldd [%%o2+0x38],%%i6\n\t"
323 "mov %%o2,%%sp\n\t"
324 "ld [%%o1],%%o2\n\t"
325 "ld [%%o1+8],%%o0\n\t"
326 "jmpl %%o2,%%g0\n\t"
327 "nop\n\t"
328 "1:\n"
329 : : "r"(from),"r"(to),"r"(__tmp_stack)
330 : "g1","o0","o1","o2","o3","o4","o5","o7","memory","cc");
331}
332
333#define COCO_MAKECTX(coco, buf, func, stack, a0) \
334 buf[0] = (void *)(func); \
335 buf[1] = (void *)(stack); \
336 buf[2] = (void *)(a0); \
337 stack[0] = 0; \
338 stack[1] = 0; \
339 stack[2] = 0; \
340 stack[3] = 0; \
341 stack[4] = 0; \
342 stack[5] = 0; \
343 stack[6] = 0; \
344 stack[7] = 0; \
345 stack[8] = 0; \
346 stack[9] = 0; \
347 stack[10] = 0; \
348 stack[11] = 0; \
349 stack[12] = 0; \
350 stack[13] = 0; \
351 stack[14] = (size_t)&stack[COCO_STACKADJUST]; \
352 stack[15] = 0xdeadc0c0; /* Dummy return address. */ \
353
354#endif /* !define(__LP64__) */
355
356#endif /* arch check */
357
358#endif /* !(__GNUC__ >= 3 && !defined(COCO_USE_SETJMP)) */
359
360/* Try _setjmp/_longjmp with a patched jump buffer. */
361#ifndef COCO_MAKECTX
362#include <setjmp.h>
363
364/* Check for supported CPU+OS combinations. */
365#if defined(__i386) || defined(__i386__)
366
367#define COCO_STATE_HEAD size_t arg0;
368#define COCO_SETJMP_X86(coco, stack, a0) \
369 stack[COCO_STACKADJUST-1] = 0xdeadc0c0; /* Dummy return address. */ \
370 coco->arg0 = (size_t)(a0);
371
372#if __GLIBC__ == 2 && defined(JB_SP) /* x86-linux-glibc2 */
373#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
374 buf->__jmpbuf[JB_PC] = (int)(func); \
375 buf->__jmpbuf[JB_SP] = (int)(stack); \
376 buf->__jmpbuf[JB_BP] = 0; \
377 COCO_SETJMP_X86(coco, stack, a0)
378#elif defined(__linux__) && defined(_I386_JMP_BUF_H) /* x86-linux-libc5 */
379#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
380 buf->__pc = (func); \
381 buf->__sp = (stack); \
382 buf->__bp = NULL; \
383 COCO_SETJMP_X86(coco, stack, a0)
384#elif defined(__FreeBSD__) /* x86-FreeBSD */
385#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
386 buf->_jb[0] = (long)(func); \
387 buf->_jb[2] = (long)(stack); \
388 buf->_jb[3] = 0; /* ebp */ \
389 COCO_SETJMP_X86(coco, stack, a0)
390#define COCO_STACKADJUST 2
391#elif defined(__NetBSD__) || defined(__OpenBSD__) /* x86-NetBSD, x86-OpenBSD */
392#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
393 buf[0] = (long)(func); \
394 buf[2] = (long)(stack); \
395 buf[3] = 0; /* ebp */ \
396 COCO_SETJMP_X86(coco, stack, a0)
397#define COCO_STACKADJUST 2
398#elif defined(__solaris__) && _JBLEN == 10 /* x86-solaris */
399#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
400 buf[5] = (int)(func); \
401 buf[4] = (int)(stack); \
402 buf[3] = 0; \
403 COCO_SETJMP_X86(coco, stack, a0)
404#elif defined(__MACH__) && defined(_BSD_I386_SETJMP_H) /* x86-macosx */
405#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
406 buf[12] = (int)(func); \
407 buf[9] = (int)(stack); \
408 buf[8] = 0; /* ebp */ \
409 COCO_SETJMP_X86(coco, stack, a0)
410#endif
411
412#elif defined(__x86_64__) || defined(__x86_64)
413
414#define COCO_STATE_HEAD size_t arg0;
415
416#define COCO_MAIN_PARAM \
417 int _a, int _b, int _c, int _d, int _e, int _f, lua_State *L
418
419#if defined(__solaris__) && _JBLEN == 8 /* x64-solaris */
420#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
421 buf[7] = (long)(func); \
422 buf[6] = (long)(stack); \
423 buf[5] = 0; \
424 stack[0] = 0xdeadc0c0; /* Dummy return address. */ \
425 coco->arg0 = (size_t)(a0);
426#endif
427
428#elif defined(PPC) || defined(__ppc__) || defined(__PPC__) || \
429 defined(__powerpc__) || defined(__POWERPC__) || defined(_ARCH_PPC)
430
431#define COCO_STACKADJUST 16
432#define COCO_MAIN_PARAM \
433 int _a, int _b, int _c, int _d, int _e, int _f, int _g, int _h, lua_State *L
434
435#if defined(__MACH__) && defined(_BSD_PPC_SETJMP_H_) /* ppc32-macosx */
436#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
437 buf[21] = (int)(func); \
438 buf[0] = (int)(stack); \
439 stack[6+8] = (size_t)(a0);
440#endif
441
442#elif (defined(MIPS) || defined(MIPSEL) || defined(__mips)) && \
443 _MIPS_SIM == _MIPS_SIM_ABI32 && !defined(__mips_eabi)
444
445/* Stack layout for o32 ABI. */
446#define COCO_STACKADJUST 8
447#define COCO_MAIN_PARAM int _a, int _b, int _c, int _d, lua_State *L
448
449#if __GLIBC__ == 2 || defined(__UCLIBC__) /* mips32-linux-glibc2 */
450#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
451 buf->__jmpbuf->__pc = (func); /* = t9 in _longjmp. Reqd. for -mabicalls. */ \
452 buf->__jmpbuf->__sp = (stack); \
453 buf->__jmpbuf->__fp = (void *)0; \
454 stack[4] = (size_t)(a0);
455#endif
456
457#elif defined(__arm__) || defined(__ARM__)
458
459#if __GLIBC__ == 2 || defined(__UCLIBC__) /* arm-linux-glibc2 */
460#ifndef __JMP_BUF_SP
461#define __JMP_BUF_SP ((sizeof(__jmp_buf)/sizeof(int))-2)
462#endif
463#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
464 buf->__jmpbuf[__JMP_BUF_SP+1] = (int)(func); /* pc */ \
465 buf->__jmpbuf[__JMP_BUF_SP] = (int)(stack); /* sp */ \
466 buf->__jmpbuf[__JMP_BUF_SP-1] = 0; /* fp */ \
467 stack[0] = (size_t)(a0);
468#define COCO_STACKADJUST 2
469#define COCO_MAIN_PARAM int _a, int _b, int _c, int _d, lua_State *L
470#endif
471
472#endif /* arch check */
473
474#ifdef COCO_PATCHCTX
475#define COCO_CTX jmp_buf
476#define COCO_MAKECTX(coco, buf, func, stack, a0) \
477 _setjmp(buf); COCO_PATCHCTX(coco, buf, func, stack, a0)
478#define COCO_SWITCH(from, to) if (!_setjmp(from)) _longjmp(to, 1);
479#endif
480
481#endif /* !defined(COCO_MAKECTX) */
482
483#endif /* !defined(COCO_USE_UCONTEXT) */
484
485/* ------------------------------------------------------------------------ */
486
487/* Use inline asm or _setjmp/_longjmp if available. */
488#ifdef COCO_MAKECTX
489
490#ifndef COCO_STACKADJUST
491#define COCO_STACKADJUST 1
492#endif
493
494#define COCO_FILL(coco, NL, mainfunc) \
495{ /* Include the return address to get proper stack alignment. */ \
496 size_t *stackptr = &((size_t *)coco)[-COCO_STACKADJUST]; \
497 COCO_MAKECTX(coco, coco->ctx, mainfunc, stackptr, NL) \
498}
499
500/* ------------------------------------------------------------------------ */
501
502/* Else fallback to ucontext. Slower, because it saves/restores signals. */
503#else /* !defined(COCO_MAKECTX) */
504
505#include <ucontext.h>
506
507#define COCO_CTX ucontext_t
508
509/* Ugly workaround for makecontext() deficiencies on 64 bit CPUs. */
510/* Note that WIN64 (which is LLP64) never comes here. See above. */
511#if defined(__LP64__) || defined(_LP64) || INT_MAX != LONG_MAX
512/* 64 bit CPU: split the pointer into two 32 bit ints. */
513#define COCO_MAIN_PARAM unsigned int lo, unsigned int hi
514#define COCO_MAIN_GETL \
515 lua_State *L = (lua_State *)((((unsigned long)hi)<<32)+(unsigned long)lo);
516#define COCO_MAKECTX(coco, NL, mainfunc) \
517 makecontext(&coco->ctx, mainfunc, 2, \
518 (int)(ptrdiff_t)NL, (int)((ptrdiff_t)NL>>32));
519#else
520/* 32 bit CPU: a pointer fits into an int. */
521#define COCO_MAKECTX(coco, NL, mainfunc) \
522 makecontext(&coco->ctx, mainfunc, 1, (int)NL);
523#endif
524
525#define COCO_FILL(coco, NL, mainfunc) \
526 getcontext(&coco->ctx); \
527 coco->ctx.uc_link = NULL; /* We never exit from coco_main. */ \
528 coco->ctx.uc_stack.ss_sp = coco->allocptr; \
529 coco->ctx.uc_stack.ss_size = (char *)coco - (char *)(coco->allocptr); \
530 COCO_MAKECTX(coco, NL, mainfunc)
531
532#define COCO_SWITCH(from, to) swapcontext(&(from), &(to));
533
534#endif /* !defined(COCO_MAKECTX) */
535
536
537/* Common code for inline asm/setjmp/ucontext to allocate/free the stack. */
538
539struct coco_State {
540#ifdef COCO_STATE_HEAD
541 COCO_STATE_HEAD
542#endif
543 COCO_CTX ctx; /* Own context. */
544 COCO_CTX back; /* Context to switch back to. */
545 void *allocptr; /* Pointer to allocated memory. */
546 int allocsize; /* Size of allocated memory. */
547 int nargs; /* Number of arguments to pass. */
548 STACK_VGID /* Optional valgrind stack id. See above. */
549};
550
551typedef void (*coco_MainFunc)(void);
552
553/* Put the Coco state at the end and align it downwards. */
554#define ALIGNED_END(p, s, t) \
555 ((t *)(((char *)0) + ((((char *)(p)-(char *)0)+(s)-sizeof(t)) & -16)))
556
557/* TODO: use mmap. */
558#define COCO_NEW(OL, NL, cstacksize, mainfunc) \
559{ \
560 void *ptr = luaM_malloc(OL, cstacksize); \
561 coco_State *coco = ALIGNED_END(ptr, cstacksize, coco_State); \
562 STACK_REG(coco, ptr, cstacksize) \
563 coco->allocptr = ptr; \
564 coco->allocsize = cstacksize; \
565 COCO_FILL(coco, NL, mainfunc) \
566 L2COCO(NL) = coco; \
567}
568
569#define COCO_FREE(L) \
570 STACK_DEREG(L2COCO(L)) \
571 luaM_freemem(L, L2COCO(L)->allocptr, L2COCO(L)->allocsize); \
572 L2COCO(L) = NULL;
573
574#define COCO_JUMPIN(coco) COCO_SWITCH(coco->back, coco->ctx)
575#define COCO_JUMPOUT(coco) COCO_SWITCH(coco->ctx, coco->back)
576
577#endif /* !COCO_USE_FIBERS */
578
579/* ------------------------------------------------------------------------ */
580
581#ifndef COCO_MIN_CSTACKSIZE
582#define COCO_MIN_CSTACKSIZE (32768+4096)
583#endif
584
585/* Don't use multiples of 64K to avoid D-cache aliasing conflicts. */
586#ifndef COCO_DEFAULT_CSTACKSIZE
587#define COCO_DEFAULT_CSTACKSIZE (65536-4096)
588#endif
589
590static int defaultcstacksize = COCO_DEFAULT_CSTACKSIZE;
591
592/* Start the Lua or C function. */
593static void coco_start(lua_State *L, void *ud)
594{
595 if (luaD_precall(L, (StkId)ud, LUA_MULTRET) == PCRLUA)
596 luaV_execute(L, L->ci - L->base_ci);
597}
598
599#ifndef COCO_MAIN_PARAM
600#define COCO_MAIN_PARAM lua_State *L
601#endif
602
603#ifndef COCO_MAIN_DECL
604#define COCO_MAIN_DECL
605#endif
606
607/* Toplevel function for the new coroutine stack. Never exits. */
608static void COCO_MAIN_DECL coco_main(COCO_MAIN_PARAM)
609{
610#ifdef COCO_MAIN_GETL
611 COCO_MAIN_GETL
612#endif
613 coco_State *coco = L2COCO(L);
614 for (;;) {
615 L->status = luaD_rawrunprotected(L, coco_start, L->top - (coco->nargs+1));
616 if (L->status != 0) luaD_seterrorobj(L, L->status, L->top);
617 COCO_JUMPOUT(coco)
618 }
619}
620
621/* Add a C stack to a coroutine. */
622lua_State *lua_newcthread(lua_State *OL, int cstacksize)
623{
624 lua_State *NL = lua_newthread(OL);
625
626 if (cstacksize < 0)
627 return NL;
628 if (cstacksize == 0)
629 cstacksize = defaultcstacksize;
630 else if (cstacksize < COCO_MIN_CSTACKSIZE)
631 cstacksize = COCO_MIN_CSTACKSIZE;
632 cstacksize &= -16;
633
634 COCO_NEW(OL, NL, cstacksize, ((coco_MainFunc)(coco_main)))
635
636 return NL;
637}
638
639/* Free the C stack of a coroutine. Called from lstate.c. */
640void luaCOCO_free(lua_State *L)
641{
642 COCO_FREE(L)
643}
644
645/* Resume a coroutine with a C stack. Called from ldo.c. */
646int luaCOCO_resume(lua_State *L, int nargs)
647{
648 coco_State *coco = L2COCO(L);
649 coco->nargs = nargs;
650 COCO_JUMPIN(coco)
651#ifndef COCO_DISABLE_EARLY_FREE
652 if (L->status != LUA_YIELD) {
653 COCO_FREE(L)
654 }
655#endif
656 return L->status;
657}
658
659/* Yield from a coroutine with a C stack. Called from ldo.c. */
660int luaCOCO_yield(lua_State *L)
661{
662 coco_State *coco = L2COCO(L);
663 L->status = LUA_YIELD;
664 COCO_JUMPOUT(coco)
665 L->status = 0;
666 {
667 StkId base = L->top - coco->nargs;
668 StkId rbase = L->base;
669 if (rbase < base) { /* Need to move args down? */
670 while (base < L->top)
671 setobjs2s(L, rbase++, base++);
672 L->top = rbase;
673 }
674 }
675 L->base = L->ci->base; /* Restore invariant. */
676 return coco->nargs;
677}
678
679/* Get/set the default C stack size. */
680int luaCOCO_cstacksize(int cstacksize)
681{
682 int oldsz = defaultcstacksize;
683 if (cstacksize >= 0) {
684 if (cstacksize == 0)
685 cstacksize = COCO_DEFAULT_CSTACKSIZE;
686 else if (cstacksize < COCO_MIN_CSTACKSIZE)
687 cstacksize = COCO_MIN_CSTACKSIZE;
688 defaultcstacksize = cstacksize;
689 }
690 return oldsz;
691}
692
693#endif