diff options
author | Li Jin <dragon-fly@qq.com> | 2020-06-22 16:50:40 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2020-06-22 16:50:40 +0800 |
commit | cd2b60b101a398cb9356d746364e70eaed1860f1 (patch) | |
tree | a1fe71b76faabc4883f16905a94164ce5c23e692 /src/lua/lstate.c | |
parent | 88c1052e700f38cf3d8ad82d469da4c487760b7e (diff) | |
download | yuescript-cd2b60b101a398cb9356d746364e70eaed1860f1.tar.gz yuescript-cd2b60b101a398cb9356d746364e70eaed1860f1.tar.bz2 yuescript-cd2b60b101a398cb9356d746364e70eaed1860f1.zip |
add support for local variable declared with attribute 'close' and 'const' for Lua 5.4.
Diffstat (limited to 'src/lua/lstate.c')
-rw-r--r-- | src/lua/lstate.c | 467 |
1 files changed, 467 insertions, 0 deletions
diff --git a/src/lua/lstate.c b/src/lua/lstate.c new file mode 100644 index 0000000..4434211 --- /dev/null +++ b/src/lua/lstate.c | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | ** $Id: lstate.c $ | ||
3 | ** Global State | ||
4 | ** See Copyright Notice in lua.h | ||
5 | */ | ||
6 | |||
7 | #define lstate_c | ||
8 | #define LUA_CORE | ||
9 | |||
10 | #include "lprefix.h" | ||
11 | |||
12 | |||
13 | #include <stddef.h> | ||
14 | #include <string.h> | ||
15 | |||
16 | #include "lua.h" | ||
17 | |||
18 | #include "lapi.h" | ||
19 | #include "ldebug.h" | ||
20 | #include "ldo.h" | ||
21 | #include "lfunc.h" | ||
22 | #include "lgc.h" | ||
23 | #include "llex.h" | ||
24 | #include "lmem.h" | ||
25 | #include "lstate.h" | ||
26 | #include "lstring.h" | ||
27 | #include "ltable.h" | ||
28 | #include "ltm.h" | ||
29 | |||
30 | |||
31 | |||
32 | /* | ||
33 | ** thread state + extra space | ||
34 | */ | ||
35 | typedef struct LX { | ||
36 | lu_byte extra_[LUA_EXTRASPACE]; | ||
37 | lua_State l; | ||
38 | } LX; | ||
39 | |||
40 | |||
41 | /* | ||
42 | ** Main thread combines a thread state and the global state | ||
43 | */ | ||
44 | typedef struct LG { | ||
45 | LX l; | ||
46 | global_State g; | ||
47 | } LG; | ||
48 | |||
49 | |||
50 | |||
51 | #define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) | ||
52 | |||
53 | |||
54 | /* | ||
55 | ** A macro to create a "random" seed when a state is created; | ||
56 | ** the seed is used to randomize string hashes. | ||
57 | */ | ||
58 | #if !defined(luai_makeseed) | ||
59 | |||
60 | #include <time.h> | ||
61 | |||
62 | /* | ||
63 | ** Compute an initial seed with some level of randomness. | ||
64 | ** Rely on Address Space Layout Randomization (if present) and | ||
65 | ** current time. | ||
66 | */ | ||
67 | #define addbuff(b,p,e) \ | ||
68 | { size_t t = cast_sizet(e); \ | ||
69 | memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } | ||
70 | |||
71 | static unsigned int luai_makeseed (lua_State *L) { | ||
72 | char buff[3 * sizeof(size_t)]; | ||
73 | unsigned int h = cast_uint(time(NULL)); | ||
74 | int p = 0; | ||
75 | addbuff(buff, p, L); /* heap variable */ | ||
76 | addbuff(buff, p, &h); /* local variable */ | ||
77 | addbuff(buff, p, &lua_newstate); /* public function */ | ||
78 | lua_assert(p == sizeof(buff)); | ||
79 | return luaS_hash(buff, p, h, 1); | ||
80 | } | ||
81 | |||
82 | #endif | ||
83 | |||
84 | |||
85 | /* | ||
86 | ** set GCdebt to a new value keeping the value (totalbytes + GCdebt) | ||
87 | ** invariant (and avoiding underflows in 'totalbytes') | ||
88 | */ | ||
89 | void luaE_setdebt (global_State *g, l_mem debt) { | ||
90 | l_mem tb = gettotalbytes(g); | ||
91 | lua_assert(tb > 0); | ||
92 | if (debt < tb - MAX_LMEM) | ||
93 | debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ | ||
94 | g->totalbytes = tb - debt; | ||
95 | g->GCdebt = debt; | ||
96 | } | ||
97 | |||
98 | |||
99 | LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) { | ||
100 | global_State *g = G(L); | ||
101 | int ccalls; | ||
102 | luaE_freeCI(L); /* release unused CIs */ | ||
103 | ccalls = getCcalls(L); | ||
104 | if (limit >= 40000) | ||
105 | return 0; /* out of bounds */ | ||
106 | limit += CSTACKERR; | ||
107 | if (L != g-> mainthread) | ||
108 | return 0; /* only main thread can change the C stack */ | ||
109 | else if (ccalls <= CSTACKERR) | ||
110 | return 0; /* handling overflow */ | ||
111 | else { | ||
112 | int diff = limit - g->Cstacklimit; | ||
113 | if (ccalls + diff <= CSTACKERR) | ||
114 | return 0; /* new limit would cause an overflow */ | ||
115 | g->Cstacklimit = limit; /* set new limit */ | ||
116 | L->nCcalls += diff; /* correct 'nCcalls' */ | ||
117 | return limit - diff - CSTACKERR; /* success; return previous limit */ | ||
118 | } | ||
119 | } | ||
120 | |||
121 | |||
122 | /* | ||
123 | ** Decrement count of "C calls" and check for overflows. In case of | ||
124 | ** a stack overflow, check appropriate error ("regular" overflow or | ||
125 | ** overflow while handling stack overflow). If 'nCcalls' is smaller | ||
126 | ** than CSTACKERR but larger than CSTACKMARK, it means it has just | ||
127 | ** entered the "overflow zone", so the function raises an overflow | ||
128 | ** error. If 'nCcalls' is smaller than CSTACKMARK (which means it is | ||
129 | ** already handling an overflow) but larger than CSTACKERRMARK, does | ||
130 | ** not report an error (to allow message handling to work). Otherwise, | ||
131 | ** report a stack overflow while handling a stack overflow (probably | ||
132 | ** caused by a repeating error in the message handling function). | ||
133 | */ | ||
134 | |||
135 | void luaE_enterCcall (lua_State *L) { | ||
136 | int ncalls = getCcalls(L); | ||
137 | L->nCcalls--; | ||
138 | if (ncalls <= CSTACKERR) { /* possible overflow? */ | ||
139 | luaE_freeCI(L); /* release unused CIs */ | ||
140 | ncalls = getCcalls(L); /* update call count */ | ||
141 | if (ncalls <= CSTACKERR) { /* still overflow? */ | ||
142 | if (ncalls <= CSTACKERRMARK) /* below error-handling zone? */ | ||
143 | luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ | ||
144 | else if (ncalls >= CSTACKMARK) { | ||
145 | /* not in error-handling zone; raise the error now */ | ||
146 | L->nCcalls = (CSTACKMARK - 1); /* enter error-handling zone */ | ||
147 | luaG_runerror(L, "C stack overflow"); | ||
148 | } | ||
149 | /* else stack is in the error-handling zone; | ||
150 | allow message handler to work */ | ||
151 | } | ||
152 | } | ||
153 | } | ||
154 | |||
155 | |||
156 | CallInfo *luaE_extendCI (lua_State *L) { | ||
157 | CallInfo *ci; | ||
158 | lua_assert(L->ci->next == NULL); | ||
159 | luaE_enterCcall(L); | ||
160 | ci = luaM_new(L, CallInfo); | ||
161 | lua_assert(L->ci->next == NULL); | ||
162 | L->ci->next = ci; | ||
163 | ci->previous = L->ci; | ||
164 | ci->next = NULL; | ||
165 | ci->u.l.trap = 0; | ||
166 | L->nci++; | ||
167 | return ci; | ||
168 | } | ||
169 | |||
170 | |||
171 | /* | ||
172 | ** free all CallInfo structures not in use by a thread | ||
173 | */ | ||
174 | void luaE_freeCI (lua_State *L) { | ||
175 | CallInfo *ci = L->ci; | ||
176 | CallInfo *next = ci->next; | ||
177 | ci->next = NULL; | ||
178 | L->nCcalls += L->nci; /* add removed elements back to 'nCcalls' */ | ||
179 | while ((ci = next) != NULL) { | ||
180 | next = ci->next; | ||
181 | luaM_free(L, ci); | ||
182 | L->nci--; | ||
183 | } | ||
184 | L->nCcalls -= L->nci; /* adjust result */ | ||
185 | } | ||
186 | |||
187 | |||
188 | /* | ||
189 | ** free half of the CallInfo structures not in use by a thread, | ||
190 | ** keeping the first one. | ||
191 | */ | ||
192 | void luaE_shrinkCI (lua_State *L) { | ||
193 | CallInfo *ci = L->ci->next; /* first free CallInfo */ | ||
194 | CallInfo *next; | ||
195 | if (ci == NULL) | ||
196 | return; /* no extra elements */ | ||
197 | L->nCcalls += L->nci; /* add removed elements back to 'nCcalls' */ | ||
198 | while ((next = ci->next) != NULL) { /* two extra elements? */ | ||
199 | CallInfo *next2 = next->next; /* next's next */ | ||
200 | ci->next = next2; /* remove next from the list */ | ||
201 | L->nci--; | ||
202 | luaM_free(L, next); /* free next */ | ||
203 | if (next2 == NULL) | ||
204 | break; /* no more elements */ | ||
205 | else { | ||
206 | next2->previous = ci; | ||
207 | ci = next2; /* continue */ | ||
208 | } | ||
209 | } | ||
210 | L->nCcalls -= L->nci; /* adjust result */ | ||
211 | } | ||
212 | |||
213 | |||
214 | static void stack_init (lua_State *L1, lua_State *L) { | ||
215 | int i; CallInfo *ci; | ||
216 | /* initialize stack array */ | ||
217 | L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, StackValue); | ||
218 | L1->stacksize = BASIC_STACK_SIZE; | ||
219 | for (i = 0; i < BASIC_STACK_SIZE; i++) | ||
220 | setnilvalue(s2v(L1->stack + i)); /* erase new stack */ | ||
221 | L1->top = L1->stack; | ||
222 | L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; | ||
223 | /* initialize first ci */ | ||
224 | ci = &L1->base_ci; | ||
225 | ci->next = ci->previous = NULL; | ||
226 | ci->callstatus = CIST_C; | ||
227 | ci->func = L1->top; | ||
228 | ci->u.c.k = NULL; | ||
229 | ci->nresults = 0; | ||
230 | setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */ | ||
231 | L1->top++; | ||
232 | ci->top = L1->top + LUA_MINSTACK; | ||
233 | L1->ci = ci; | ||
234 | } | ||
235 | |||
236 | |||
237 | static void freestack (lua_State *L) { | ||
238 | if (L->stack == NULL) | ||
239 | return; /* stack not completely built yet */ | ||
240 | L->ci = &L->base_ci; /* free the entire 'ci' list */ | ||
241 | luaE_freeCI(L); | ||
242 | lua_assert(L->nci == 0); | ||
243 | luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ | ||
244 | } | ||
245 | |||
246 | |||
247 | /* | ||
248 | ** Create registry table and its predefined values | ||
249 | */ | ||
250 | static void init_registry (lua_State *L, global_State *g) { | ||
251 | TValue temp; | ||
252 | /* create registry */ | ||
253 | Table *registry = luaH_new(L); | ||
254 | sethvalue(L, &g->l_registry, registry); | ||
255 | luaH_resize(L, registry, LUA_RIDX_LAST, 0); | ||
256 | /* registry[LUA_RIDX_MAINTHREAD] = L */ | ||
257 | setthvalue(L, &temp, L); /* temp = L */ | ||
258 | luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); | ||
259 | /* registry[LUA_RIDX_GLOBALS] = table of globals */ | ||
260 | sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ | ||
261 | luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); | ||
262 | } | ||
263 | |||
264 | |||
265 | /* | ||
266 | ** open parts of the state that may cause memory-allocation errors. | ||
267 | ** ('g->nilvalue' being a nil value flags that the state was completely | ||
268 | ** build.) | ||
269 | */ | ||
270 | static void f_luaopen (lua_State *L, void *ud) { | ||
271 | global_State *g = G(L); | ||
272 | UNUSED(ud); | ||
273 | stack_init(L, L); /* init stack */ | ||
274 | init_registry(L, g); | ||
275 | luaS_init(L); | ||
276 | luaT_init(L); | ||
277 | luaX_init(L); | ||
278 | g->gcrunning = 1; /* allow gc */ | ||
279 | setnilvalue(&g->nilvalue); | ||
280 | luai_userstateopen(L); | ||
281 | } | ||
282 | |||
283 | |||
284 | /* | ||
285 | ** preinitialize a thread with consistent values without allocating | ||
286 | ** any memory (to avoid errors) | ||
287 | */ | ||
288 | static void preinit_thread (lua_State *L, global_State *g) { | ||
289 | G(L) = g; | ||
290 | L->stack = NULL; | ||
291 | L->ci = NULL; | ||
292 | L->nci = 0; | ||
293 | L->stacksize = 0; | ||
294 | L->twups = L; /* thread has no upvalues */ | ||
295 | L->errorJmp = NULL; | ||
296 | L->hook = NULL; | ||
297 | L->hookmask = 0; | ||
298 | L->basehookcount = 0; | ||
299 | L->allowhook = 1; | ||
300 | resethookcount(L); | ||
301 | L->openupval = NULL; | ||
302 | L->status = LUA_OK; | ||
303 | L->errfunc = 0; | ||
304 | } | ||
305 | |||
306 | |||
307 | static void close_state (lua_State *L) { | ||
308 | global_State *g = G(L); | ||
309 | luaF_close(L, L->stack, CLOSEPROTECT); /* close all upvalues */ | ||
310 | luaC_freeallobjects(L); /* collect all objects */ | ||
311 | if (ttisnil(&g->nilvalue)) /* closing a fully built state? */ | ||
312 | luai_userstateclose(L); | ||
313 | luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); | ||
314 | freestack(L); | ||
315 | lua_assert(gettotalbytes(g) == sizeof(LG)); | ||
316 | (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ | ||
317 | } | ||
318 | |||
319 | |||
320 | LUA_API lua_State *lua_newthread (lua_State *L) { | ||
321 | global_State *g = G(L); | ||
322 | lua_State *L1; | ||
323 | lua_lock(L); | ||
324 | luaC_checkGC(L); | ||
325 | /* create new thread */ | ||
326 | L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; | ||
327 | L1->marked = luaC_white(g); | ||
328 | L1->tt = LUA_VTHREAD; | ||
329 | /* link it on list 'allgc' */ | ||
330 | L1->next = g->allgc; | ||
331 | g->allgc = obj2gco(L1); | ||
332 | /* anchor it on L stack */ | ||
333 | setthvalue2s(L, L->top, L1); | ||
334 | api_incr_top(L); | ||
335 | preinit_thread(L1, g); | ||
336 | L1->nCcalls = getCcalls(L); | ||
337 | L1->hookmask = L->hookmask; | ||
338 | L1->basehookcount = L->basehookcount; | ||
339 | L1->hook = L->hook; | ||
340 | resethookcount(L1); | ||
341 | /* initialize L1 extra space */ | ||
342 | memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), | ||
343 | LUA_EXTRASPACE); | ||
344 | luai_userstatethread(L, L1); | ||
345 | stack_init(L1, L); /* init stack */ | ||
346 | lua_unlock(L); | ||
347 | return L1; | ||
348 | } | ||
349 | |||
350 | |||
351 | void luaE_freethread (lua_State *L, lua_State *L1) { | ||
352 | LX *l = fromstate(L1); | ||
353 | luaF_close(L1, L1->stack, NOCLOSINGMETH); /* close all upvalues */ | ||
354 | lua_assert(L1->openupval == NULL); | ||
355 | luai_userstatefree(L, L1); | ||
356 | freestack(L1); | ||
357 | luaM_free(L, l); | ||
358 | } | ||
359 | |||
360 | |||
361 | int lua_resetthread (lua_State *L) { | ||
362 | CallInfo *ci; | ||
363 | int status; | ||
364 | lua_lock(L); | ||
365 | L->ci = ci = &L->base_ci; /* unwind CallInfo list */ | ||
366 | setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */ | ||
367 | ci->func = L->stack; | ||
368 | ci->callstatus = CIST_C; | ||
369 | status = luaF_close(L, L->stack, CLOSEPROTECT); | ||
370 | if (status != CLOSEPROTECT) /* real errors? */ | ||
371 | luaD_seterrorobj(L, status, L->stack + 1); | ||
372 | else { | ||
373 | status = LUA_OK; | ||
374 | L->top = L->stack + 1; | ||
375 | } | ||
376 | ci->top = L->top + LUA_MINSTACK; | ||
377 | L->status = status; | ||
378 | lua_unlock(L); | ||
379 | return status; | ||
380 | } | ||
381 | |||
382 | |||
383 | LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { | ||
384 | int i; | ||
385 | lua_State *L; | ||
386 | global_State *g; | ||
387 | LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); | ||
388 | if (l == NULL) return NULL; | ||
389 | L = &l->l.l; | ||
390 | g = &l->g; | ||
391 | L->tt = LUA_VTHREAD; | ||
392 | g->currentwhite = bitmask(WHITE0BIT); | ||
393 | L->marked = luaC_white(g); | ||
394 | preinit_thread(L, g); | ||
395 | g->allgc = obj2gco(L); /* by now, only object is the main thread */ | ||
396 | L->next = NULL; | ||
397 | g->Cstacklimit = L->nCcalls = LUAI_MAXCSTACK + CSTACKERR; | ||
398 | g->frealloc = f; | ||
399 | g->ud = ud; | ||
400 | g->warnf = NULL; | ||
401 | g->ud_warn = NULL; | ||
402 | g->mainthread = L; | ||
403 | g->seed = luai_makeseed(L); | ||
404 | g->gcrunning = 0; /* no GC while building state */ | ||
405 | g->strt.size = g->strt.nuse = 0; | ||
406 | g->strt.hash = NULL; | ||
407 | setnilvalue(&g->l_registry); | ||
408 | g->panic = NULL; | ||
409 | g->gcstate = GCSpause; | ||
410 | g->gckind = KGC_INC; | ||
411 | g->gcemergency = 0; | ||
412 | g->finobj = g->tobefnz = g->fixedgc = NULL; | ||
413 | g->survival = g->old = g->reallyold = NULL; | ||
414 | g->finobjsur = g->finobjold = g->finobjrold = NULL; | ||
415 | g->sweepgc = NULL; | ||
416 | g->gray = g->grayagain = NULL; | ||
417 | g->weak = g->ephemeron = g->allweak = NULL; | ||
418 | g->twups = NULL; | ||
419 | g->totalbytes = sizeof(LG); | ||
420 | g->GCdebt = 0; | ||
421 | g->lastatomic = 0; | ||
422 | setivalue(&g->nilvalue, 0); /* to signal that state is not yet built */ | ||
423 | setgcparam(g->gcpause, LUAI_GCPAUSE); | ||
424 | setgcparam(g->gcstepmul, LUAI_GCMUL); | ||
425 | g->gcstepsize = LUAI_GCSTEPSIZE; | ||
426 | setgcparam(g->genmajormul, LUAI_GENMAJORMUL); | ||
427 | g->genminormul = LUAI_GENMINORMUL; | ||
428 | for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; | ||
429 | if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { | ||
430 | /* memory allocation error: free partial state */ | ||
431 | close_state(L); | ||
432 | L = NULL; | ||
433 | } | ||
434 | return L; | ||
435 | } | ||
436 | |||
437 | |||
438 | LUA_API void lua_close (lua_State *L) { | ||
439 | L = G(L)->mainthread; /* only the main thread can be closed */ | ||
440 | lua_lock(L); | ||
441 | close_state(L); | ||
442 | } | ||
443 | |||
444 | |||
445 | void luaE_warning (lua_State *L, const char *msg, int tocont) { | ||
446 | lua_WarnFunction wf = G(L)->warnf; | ||
447 | if (wf != NULL) | ||
448 | wf(G(L)->ud_warn, msg, tocont); | ||
449 | } | ||
450 | |||
451 | |||
452 | /* | ||
453 | ** Generate a warning from an error message | ||
454 | */ | ||
455 | void luaE_warnerror (lua_State *L, const char *where) { | ||
456 | TValue *errobj = s2v(L->top - 1); /* error object */ | ||
457 | const char *msg = (ttisstring(errobj)) | ||
458 | ? svalue(errobj) | ||
459 | : "error object is not a string"; | ||
460 | /* produce warning "error in %s (%s)" (where, msg) */ | ||
461 | luaE_warning(L, "error in ", 1); | ||
462 | luaE_warning(L, where, 1); | ||
463 | luaE_warning(L, " (", 1); | ||
464 | luaE_warning(L, msg, 1); | ||
465 | luaE_warning(L, ")", 0); | ||
466 | } | ||
467 | |||