aboutsummaryrefslogtreecommitdiff
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-ee645472ebe153e2c6669c84a632297a8110bdb6.tar.gz
lua-ee645472ebe153e2c6669c84a632297a8110bdb6.tar.bz2
lua-ee645472ebe153e2c6669c84a632297a8110bdb6.zip
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) {
157** Stack reallocation 157** Stack reallocation
158** =================================================================== 158** ===================================================================
159*/ 159*/
160static void correctstack (lua_State *L, StkId oldstack, StkId newstack) { 160
161
162/*
163** Change all pointers to the stack into offsets.
164*/
165static void relstack (lua_State *L) {
166 CallInfo *ci;
167 UpVal *up;
168 L->top.offset = savestack(L, L->top.p);
169 L->tbclist.offset = savestack(L, L->tbclist.p);
170 for (up = L->openupval; up != NULL; up = up->u.open.next)
171 up->v.offset = savestack(L, uplevel(up));
172 for (ci = L->ci; ci != NULL; ci = ci->previous) {
173 ci->top.offset = savestack(L, ci->top.p);
174 ci->func.offset = savestack(L, ci->func.p);
175 }
176}
177
178
179/*
180** Change back all offsets into pointers.
181*/
182static void correctstack (lua_State *L) {
161 CallInfo *ci; 183 CallInfo *ci;
162 UpVal *up; 184 UpVal *up;
163 L->top.p = (L->top.p - oldstack) + newstack; 185 L->top.p = restorestack(L, L->top.offset);
164 L->tbclist.p = (L->tbclist.p - oldstack) + newstack; 186 L->tbclist.p = restorestack(L, L->tbclist.offset);
165 for (up = L->openupval; up != NULL; up = up->u.open.next) 187 for (up = L->openupval; up != NULL; up = up->u.open.next)
166 up->v.p = s2v((uplevel(up) - oldstack) + newstack); 188 up->v.p = s2v(restorestack(L, up->v.offset));
167 for (ci = L->ci; ci != NULL; ci = ci->previous) { 189 for (ci = L->ci; ci != NULL; ci = ci->previous) {
168 ci->top.p = (ci->top.p - oldstack) + newstack; 190 ci->top.p = restorestack(L, ci->top.offset);
169 ci->func.p = (ci->func.p - oldstack) + newstack; 191 ci->func.p = restorestack(L, ci->func.offset);
170 if (isLua(ci)) 192 if (isLua(ci))
171 ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */ 193 ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
172 } 194 }
@@ -177,36 +199,38 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
177#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) 199#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
178 200
179/* 201/*
180** Reallocate the stack to a new size, correcting all pointers into 202** Reallocate the stack to a new size, correcting all pointers into it.
181** it. (There are pointers to a stack from its upvalues, from its list 203** In ISO C, any pointer use after the pointer has been deallocated is
182** of call infos, plus a few individual pointers.) The reallocation is 204** undefined behavior. So, before the reallocation, all pointers are
183** done in two steps (allocation + free) because the correction must be 205** changed to offsets, and after the reallocation they are changed back
184** done while both addresses (the old stack and the new one) are valid. 206** to pointers. As during the reallocation the pointers are invalid, the
185** (In ISO C, any pointer use after the pointer has been deallocated is 207** reallocation cannot run emergency collections.
186** undefined behavior.) 208**
187** In case of allocation error, raise an error or return false according 209** In case of allocation error, raise an error or return false according
188** to 'raiseerror'. 210** to 'raiseerror'.
189*/ 211*/
190int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { 212int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
191 int oldsize = stacksize(L); 213 int oldsize = stacksize(L);
192 int i; 214 int i;
193 StkId newstack = luaM_reallocvector(L, NULL, 0, 215 StkId newstack;
194 newsize + EXTRA_STACK, StackValue); 216 int oldgcstop = G(L)->gcstopem;
195 lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); 217 lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
218 relstack(L); /* change pointers to offsets */
219 G(L)->gcstopem = 1; /* stop emergency collection */
220 newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
221 newsize + EXTRA_STACK, StackValue);
222 G(L)->gcstopem = oldgcstop; /* restore emergency collection */
196 if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ 223 if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
224 correctstack(L); /* change offsets back to pointers */
197 if (raiseerror) 225 if (raiseerror)
198 luaM_error(L); 226 luaM_error(L);
199 else return 0; /* do not raise an error */ 227 else return 0; /* do not raise an error */
200 } 228 }
201 /* number of elements to be copied to the new stack */
202 i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
203 memcpy(newstack, L->stack.p, i * sizeof(StackValue));
204 for (; i < newsize + EXTRA_STACK; i++)
205 setnilvalue(s2v(newstack + i)); /* erase new segment */
206 correctstack(L, L->stack.p, newstack);
207 luaM_freearray(L, L->stack.p, oldsize + EXTRA_STACK);
208 L->stack.p = newstack; 229 L->stack.p = newstack;
230 correctstack(L); /* change offsets back to pointers */
209 L->stack_last.p = L->stack.p + newsize; 231 L->stack_last.p = L->stack.p + newsize;
232 for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
233 setnilvalue(s2v(newstack + i)); /* erase new segment */
210 return 1; 234 return 1;
211} 235}
212 236
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 {
158typedef StackValue *StkId; 158typedef StackValue *StkId;
159 159
160 160
161/*
162** When reallocating the stack, change all pointers to the stack into
163** proper offsets.
164*/
161typedef union { 165typedef union {
162 StkId p; /* actual pointer */ 166 StkId p; /* actual pointer */
167 ptrdiff_t offset; /* used while the stack is being reallocated */
163} StkIdRel; 168} StkIdRel;
164 169
165 170
@@ -626,6 +631,7 @@ typedef struct UpVal {
626 lu_byte tbc; /* true if it represents a to-be-closed variable */ 631 lu_byte tbc; /* true if it represents a to-be-closed variable */
627 union { 632 union {
628 TValue *p; /* points to stack or to its own value */ 633 TValue *p; /* points to stack or to its own value */
634 ptrdiff_t offset; /* used while the stack is being reallocated */
629 } v; 635 } v;
630 union { 636 union {
631 struct { /* (when open) */ 637 struct { /* (when open) */