diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-10-31 15:06:20 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2022-10-31 15:06:20 -0300 |
commit | ee645472ebe153e2c6669c84a632297a8110bdb6 (patch) | |
tree | 13444ccb5fd4bfb04bc62e2c6b035d97eb979e8f /ldo.c | |
parent | 413a393e6222482f46599e138bebac162610a572 (diff) | |
download | lua-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.c | 68 |
1 files changed, 46 insertions, 22 deletions
@@ -157,16 +157,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { | |||
157 | ** Stack reallocation | 157 | ** Stack reallocation |
158 | ** =================================================================== | 158 | ** =================================================================== |
159 | */ | 159 | */ |
160 | static void correctstack (lua_State *L, StkId oldstack, StkId newstack) { | 160 | |
161 | |||
162 | /* | ||
163 | ** Change all pointers to the stack into offsets. | ||
164 | */ | ||
165 | static 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 | */ | ||
182 | static 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 | */ |
190 | int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { | 212 | int 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 | ||