diff options
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 | ||