aboutsummaryrefslogtreecommitdiff
path: root/ldo.c
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 /ldo.c
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.
Diffstat (limited to 'ldo.c')
-rw-r--r--ldo.c68
1 files changed, 46 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