summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2022-10-31 15:06:20 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2022-10-31 15:06:20 -0300
commitee645472ebe153e2c6669c84a632297a8110bdb6 (patch)
tree13444ccb5fd4bfb04bc62e2c6b035d97eb979e8f
parent413a393e6222482f46599e138bebac162610a572 (diff)
downloadlua-github-ee645472ebe153e2c6669c84a632297a8110bdb6.tar.gz
Stack reallocation done with a single realloc
To avoid the need of both the old and the new stack addresses valid at the same time, to correct the pointers to the stack, these pointers are changed to offsets before the reallocation and then changed back to pointers after the reallocation.
-rw-r--r--ldo.c68
-rw-r--r--lobject.h6
2 files changed, 52 insertions, 22 deletions
diff --git a/ldo.c b/ldo.c
index d45c74da..c30cde76 100644
--- a/ldo.c
+++ b/ldo.c
@@ -157,16 +157,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
** Stack reallocation
** ===================================================================
*/
-static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
+
+
+/*
+** Change all pointers to the stack into offsets.
+*/
+static void relstack (lua_State *L) {
+ CallInfo *ci;
+ UpVal *up;
+ L->top.offset = savestack(L, L->top.p);
+ L->tbclist.offset = savestack(L, L->tbclist.p);
+ for (up = L->openupval; up != NULL; up = up->u.open.next)
+ up->v.offset = savestack(L, uplevel(up));
+ for (ci = L->ci; ci != NULL; ci = ci->previous) {
+ ci->top.offset = savestack(L, ci->top.p);
+ ci->func.offset = savestack(L, ci->func.p);
+ }
+}
+
+
+/*
+** Change back all offsets into pointers.
+*/
+static void correctstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
- L->top.p = (L->top.p - oldstack) + newstack;
- L->tbclist.p = (L->tbclist.p - oldstack) + newstack;
+ L->top.p = restorestack(L, L->top.offset);
+ L->tbclist.p = restorestack(L, L->tbclist.offset);
for (up = L->openupval; up != NULL; up = up->u.open.next)
- up->v.p = s2v((uplevel(up) - oldstack) + newstack);
+ up->v.p = s2v(restorestack(L, up->v.offset));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
- ci->top.p = (ci->top.p - oldstack) + newstack;
- ci->func.p = (ci->func.p - oldstack) + newstack;
+ ci->top.p = restorestack(L, ci->top.offset);
+ ci->func.p = restorestack(L, ci->func.offset);
if (isLua(ci))
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
}
@@ -177,36 +199,38 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
/*
-** Reallocate the stack to a new size, correcting all pointers into
-** it. (There are pointers to a stack from its upvalues, from its list
-** of call infos, plus a few individual pointers.) The reallocation is
-** done in two steps (allocation + free) because the correction must be
-** done while both addresses (the old stack and the new one) are valid.
-** (In ISO C, any pointer use after the pointer has been deallocated is
-** undefined behavior.)
+** Reallocate the stack to a new size, correcting all pointers into it.
+** In ISO C, any pointer use after the pointer has been deallocated is
+** undefined behavior. So, before the reallocation, all pointers are
+** changed to offsets, and after the reallocation they are changed back
+** to pointers. As during the reallocation the pointers are invalid, the
+** reallocation cannot run emergency collections.
+**
** In case of allocation error, raise an error or return false according
** to 'raiseerror'.
*/
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int oldsize = stacksize(L);
int i;
- StkId newstack = luaM_reallocvector(L, NULL, 0,
- newsize + EXTRA_STACK, StackValue);
+ StkId newstack;
+ int oldgcstop = G(L)->gcstopem;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
+ relstack(L); /* change pointers to offsets */
+ G(L)->gcstopem = 1; /* stop emergency collection */
+ newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
+ newsize + EXTRA_STACK, StackValue);
+ G(L)->gcstopem = oldgcstop; /* restore emergency collection */
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
+ correctstack(L); /* change offsets back to pointers */
if (raiseerror)
luaM_error(L);
else return 0; /* do not raise an error */
}
- /* number of elements to be copied to the new stack */
- i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
- memcpy(newstack, L->stack.p, i * sizeof(StackValue));
- for (; i < newsize + EXTRA_STACK; i++)
- setnilvalue(s2v(newstack + i)); /* erase new segment */
- correctstack(L, L->stack.p, newstack);
- luaM_freearray(L, L->stack.p, oldsize + EXTRA_STACK);
L->stack.p = newstack;
+ correctstack(L); /* change offsets back to pointers */
L->stack_last.p = L->stack.p + newsize;
+ for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
+ setnilvalue(s2v(newstack + i)); /* erase new segment */
return 1;
}
diff --git a/lobject.h b/lobject.h
index 7af7bd89..e7f58cbd 100644
--- a/lobject.h
+++ b/lobject.h
@@ -158,8 +158,13 @@ typedef union StackValue {
typedef StackValue *StkId;
+/*
+** When reallocating the stack, change all pointers to the stack into
+** proper offsets.
+*/
typedef union {
StkId p; /* actual pointer */
+ ptrdiff_t offset; /* used while the stack is being reallocated */
} StkIdRel;
@@ -626,6 +631,7 @@ typedef struct UpVal {
lu_byte tbc; /* true if it represents a to-be-closed variable */
union {
TValue *p; /* points to stack or to its own value */
+ ptrdiff_t offset; /* used while the stack is being reallocated */
} v;
union {
struct { /* (when open) */