Skip to content
Permalink
Browse files
port luaCoco to xtensa architecture
  • Loading branch information
zwh8800 committed May 27, 2017
1 parent 216b820 commit 1f31aa32901f07b6414c0471eb19f7bdd44d93a6
Showing 7 changed files with 336 additions and 24 deletions.
@@ -107,25 +107,20 @@ LUA_API int lua_checkstack (lua_State *L, int size) {


LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
int i;
StkId f, t;
if (from == to) return;
lua_lock(to);
api_checknelems(from, n);
api_check(from, G(from) == G(to));
api_check(from, to->ci->top - to->top >= n);
from->top -= n;
for (i = 0; i < n; i++) {
setobj2s(to, to->top++, from->top + i);
}
f = from->top;
t = to->top = to->top + n;
while (--n >= 0) setobj2s(to, --t, --f);
from->top = f;
lua_unlock(to);
}


LUA_API void lua_setlevel (lua_State *from, lua_State *to) {
to->nCcalls = from->nCcalls;
}


LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) {
lua_CFunction old;
lua_lock(L);
@@ -16,6 +16,9 @@
#include C_HEADER_STDLIB
#include "lauxlib.h"
#include "lualib.h"
#ifndef COCO_DISABLE
#include "lcoco.h"
#endif
#include "lrotable.h"


@@ -582,7 +585,6 @@ static int auxresume (lua_State *L, lua_State *co, int narg) {
return -1; /* error flag */
}
lua_xmove(L, co, narg);
lua_setlevel(L, co);
status = lua_resume(co, narg);
if (status == 0 || status == LUA_YIELD) {
int nres = lua_gettop(co);
@@ -631,10 +633,27 @@ static int luaB_auxwrap (lua_State *L) {
}


#ifndef COCO_DISABLE
static int luaB_cstacksize (lua_State *L)
{
lua_pushinteger(L, luaCOCO_cstacksize(luaL_optint(L, 1, -1)));
return 1;
}
#endif


static int luaB_cocreate (lua_State *L) {
#ifdef COCO_DISABLE
lua_State *NL = lua_newthread(L);
luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
"Lua function expected");
#else
int cstacksize = luaL_optint(L, 2, 0);
lua_State *NL = lua_newcthread(L, cstacksize);
luaL_argcheck(L, lua_isfunction(L, 1) &&
(cstacksize >= 0 ? 1 : !lua_iscfunction(L, 1)),
1, "Lua function expected");
#endif
lua_pushvalue(L, 1); /* move function to top */
lua_xmove(L, NL, 1); /* move function from L to NL */
return 1;
@@ -669,6 +688,9 @@ const LUA_REG_TYPE co_funcs[] = {
{LSTRKEY("status"), LFUNCVAL(luaB_costatus)},
{LSTRKEY("wrap"), LFUNCVAL(luaB_cowrap)},
{LSTRKEY("yield"), LFUNCVAL(luaB_yield)},
#ifndef COCO_DISABLE
{LSTRKEY("cstacksize"), LFUNCVAL(luaB_cstacksize)},
#endif
{LNILKEY, LNILVAL}
};

@@ -714,6 +736,10 @@ LUALIB_API int luaopen_base (lua_State *L) {
base_open(L);
#if LUA_OPTIMIZE_MEMORY == 0
luaL_register(L, LUA_COLIBNAME, co_funcs);
#ifndef COCO_DISABLE
lua_pushboolean(L, 1);
lua_setfield(L, -2, "coco");
#endif
return 2;
#else
return 1;
@@ -0,0 +1,72 @@
/*
** Lua/Coco glue.
** Copyright (C) 2004-2009 Mike Pall. See copyright notice in lcoco.c
*/

#ifndef lcoco_h
#define lcoco_h

#define LUACOCO_VERSION "Coco 1.1.6"
#define LUACOCO_VERSION_NUM 10106

/* Exported C API to add a C stack to a coroutine. */
LUA_API lua_State *lua_newcthread(lua_State *L, int cstacksize);

/* Internal support routines. */
LUAI_FUNC void luaCOCO_free(lua_State *L);
LUAI_FUNC int luaCOCO_resume(lua_State *L, int nargs);
LUAI_FUNC int luaCOCO_yield(lua_State *L);
LUAI_FUNC int luaCOCO_cstacksize(int cstacksize);

/* Forward declaration. */
typedef struct coco_State coco_State;

/* These are redefined below. */
#undef LUAI_EXTRASPACE
#undef luai_userstateopen
/* luai_userstateclose unused */
#undef luai_userstatethread
#undef luai_userstatefree
#undef luai_userstateresume
#undef luai_userstateyield

/* Use Windows Fibers (Win98+). */
#if defined(_WIN32)

/* Fibers allocate their own stack. The whole Coco state is in front of L. */
struct coco_State {
void *fib; /* Own fiber (if any). */
void *back; /* Fiber to switch back to. */
int nargs; /* Number of arguments to pass. */
int dummy_align;
};

#define L2COCO(L) (&((coco_State *)(L))[-1])
#define LHASCOCO(L) (L2COCO(L)->fib)
#define LUAI_EXTRASPACE sizeof(coco_State)
#define luai_userstateopen(L) L2COCO(L)->fib = NULL
#define luai_userstatethread(L,L1) L2COCO(L1)->fib = NULL
#define COCO_USE_FIBERS

#else /* !defined(_WIN32) */

/* The Coco state depends on the context switch method used. See lcoco.c. */
/* It's stored at the end of the stack. Only need a pointer in front of L. */
#define L2COCO(L) (((coco_State **)(L))[-1])
#define LHASCOCO(L) (L2COCO(L))
/* This wastes some space on 32 bit systems, but gets better alignment. */
#define LUAI_EXTRASPACE sizeof(LUAI_USER_ALIGNMENT_T)
#define luai_userstateopen(L) L2COCO(L) = NULL
#define luai_userstatethread(L,L1) L2COCO(L1) = NULL

#endif /* !defined(_WIN32) */

#define luai_userstatefree(L) if (LHASCOCO(L)) luaCOCO_free(L)
#define luai_userstateresume(L, nargs) \
if (LHASCOCO(L)) return luaCOCO_resume(L, nargs)
#define luai_userstateyield(L, nresults) \
do { if (LHASCOCO(L)) { \
L->base = L->top - (nresults); /* Protect stack slots below. */ \
return luaCOCO_yield(L); } } while (0)

#endif
@@ -0,0 +1,223 @@
/*
** Copyright (C) 2004-2009 Mike Pall. All rights reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
** "Software"), to deal in the Software without restriction, including
** without limitation the rights to use, copy, modify, merge, publish,
** distribute, sublicense, and/or sell copies of the Software, and to
** permit persons to whom the Software is furnished to do so, subject to
** the following conditions:
**
** The above copyright notice and this permission notice shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**
** [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
*/

/* Coco -- True C coroutines for Lua. http://luajit.org/coco.html */
#ifndef COCO_DISABLE

#define lcoco_c
#define LUA_CORE

#include "lua.h"

#include "lobject.h"
#include "lstate.h"
#include "ldo.h"
#include "lvm.h"
#include "lgc.h"

#define STACK_REG(coco, p, sz)
#define STACK_DEREG(id)
#define STACK_VGID

/* Try _setjmp/_longjmp with a patched jump buffer. */
#include <setjmp.h>

// buf[0] is regsiter a0(return addr), buf[1] is regsiter a1(stack ptr)
// see newlib-2.0.0/newlib/libc/machine/xtensa/setjmp.S
#define COCO_PATCHCTX(coco, buf, func, stack, a0) \
buf[0] = (int)(func); \
buf[1] = (int)(stack); \
stack[0] = (size_t)(a0);

#ifdef COCO_PATCHCTX
#define COCO_CTX jmp_buf
#define COCO_MAKECTX(coco, buf, func, stack, a0) \
setjmp(buf); COCO_PATCHCTX(coco, buf, func, stack, a0)
#define COCO_SWITCH(from, to) if (!setjmp(from)) longjmp(to, 1);
#endif

#ifndef COCO_STACKADJUST
#define COCO_STACKADJUST 1
#endif

#define COCO_FILL(coco, NL, mainfunc) \
{ /* Include the return address to get proper stack alignment. */ \
size_t *stackptr = &((size_t *)coco)[-COCO_STACKADJUST]; \
COCO_MAKECTX(coco, coco->ctx, mainfunc, stackptr, NL) \
}

/* Common code for inline asm/setjmp/ucontext to allocate/free the stack. */

struct coco_State {
#ifdef COCO_STATE_HEAD
COCO_STATE_HEAD
#endif
COCO_CTX ctx; /* Own context. */
COCO_CTX back; /* Context to switch back to. */
void *allocptr; /* Pointer to allocated memory. */
int allocsize; /* Size of allocated memory. */
int nargs; /* Number of arguments to pass. */
STACK_VGID /* Optional valgrind stack id. See above. */
};

typedef void (*coco_MainFunc)(void);

/* Put the Coco state at the end and align it downwards. */
#define ALIGNED_END(p, s, t) \
((t *)(((char *)0) + ((((char *)(p)-(char *)0)+(s)-sizeof(t)) & -16)))

#define COCO_NEW(OL, NL, cstacksize, mainfunc) \
{ \
void *ptr = luaM_malloc(OL, cstacksize); \
coco_State *coco = ALIGNED_END(ptr, cstacksize, coco_State); \
STACK_REG(coco, ptr, cstacksize) \
coco->allocptr = ptr; \
coco->allocsize = cstacksize; \
COCO_FILL(coco, NL, mainfunc) \
L2COCO(NL) = coco; \
}

#define COCO_FREE(L) \
STACK_DEREG(L2COCO(L)) \
luaM_freemem(L, L2COCO(L)->allocptr, L2COCO(L)->allocsize); \
L2COCO(L) = NULL;

#define COCO_JUMPIN(coco) COCO_SWITCH(coco->back, coco->ctx)
#define COCO_JUMPOUT(coco) COCO_SWITCH(coco->ctx, coco->back)

/* ------------------------------------------------------------------------ */

#ifndef COCO_MIN_CSTACKSIZE
#define COCO_MIN_CSTACKSIZE (2048)
#endif

/* Don't use multiples of 64K to avoid D-cache aliasing conflicts. */
#ifndef COCO_DEFAULT_CSTACKSIZE
#define COCO_DEFAULT_CSTACKSIZE (8192)
#endif

static int defaultcstacksize = COCO_DEFAULT_CSTACKSIZE;

/* Start the Lua or C function. */
static void coco_start(lua_State *L, void *ud)
{
if (luaD_precall(L, (StkId)ud, LUA_MULTRET) == PCRLUA)
luaV_execute(L, L->ci - L->base_ci);
}

// _a to _f for register file a2 to a7, thus L is where a1(stack ptr) point to
#define COCO_MAIN_PARAM int _a, int _b, int _c, int _d, int _e, int _f, lua_State *L

#ifndef COCO_MAIN_DECL
#define COCO_MAIN_DECL
#endif

/* Toplevel function for the new coroutine stack. Never exits. */
static void COCO_MAIN_DECL coco_main(COCO_MAIN_PARAM)
{
#ifdef COCO_MAIN_GETL
COCO_MAIN_GETL
#endif
coco_State *coco = L2COCO(L);
for (;;) {
L->status = luaD_rawrunprotected(L, coco_start, L->top - (coco->nargs+1));
if (L->status != 0) luaD_seterrorobj(L, L->status, L->top);
COCO_JUMPOUT(coco)
}
}

/* Add a C stack to a coroutine. */
lua_State *lua_newcthread(lua_State *OL, int cstacksize)
{
lua_State *NL = lua_newthread(OL);

if (cstacksize < 0)
return NL;
if (cstacksize == 0)
cstacksize = defaultcstacksize;
else if (cstacksize < COCO_MIN_CSTACKSIZE)
cstacksize = COCO_MIN_CSTACKSIZE;
cstacksize &= -16;

COCO_NEW(OL, NL, cstacksize, ((coco_MainFunc)(coco_main)))

return NL;
}

/* Free the C stack of a coroutine. Called from lstate.c. */
void luaCOCO_free(lua_State *L)
{
COCO_FREE(L)
}

/* Resume a coroutine with a C stack. Called from ldo.c. */
int luaCOCO_resume(lua_State *L, int nargs)
{
coco_State *coco = L2COCO(L);
coco->nargs = nargs;
COCO_JUMPIN(coco)
#ifndef COCO_DISABLE_EARLY_FREE
if (L->status != LUA_YIELD) {
COCO_FREE(L)
}
#endif
return L->status;
}

/* Yield from a coroutine with a C stack. Called from ldo.c. */
int luaCOCO_yield(lua_State *L)
{
coco_State *coco = L2COCO(L);
L->status = LUA_YIELD;
COCO_JUMPOUT(coco)
L->status = 0;
{
StkId base = L->top - coco->nargs;
StkId rbase = L->base;
if (rbase < base) { /* Need to move args down? */
while (base < L->top)
setobjs2s(L, rbase++, base++);
L->top = rbase;
}
}
L->base = L->ci->base; /* Restore invariant. */
return coco->nargs;
}

/* Get/set the default C stack size. */
int luaCOCO_cstacksize(int cstacksize)
{
int oldsz = defaultcstacksize;
if (cstacksize >= 0) {
if (cstacksize == 0)
cstacksize = COCO_DEFAULT_CSTACKSIZE;
else if (cstacksize < COCO_MIN_CSTACKSIZE)
cstacksize = COCO_MIN_CSTACKSIZE;
defaultcstacksize = cstacksize;
}
return oldsz;
}

#endif

0 comments on commit 1f31aa3

Please sign in to comment.