aboutsummaryrefslogtreecommitdiff
path: root/src/lj_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_api.c')
-rw-r--r--src/lj_api.c372
1 files changed, 237 insertions, 135 deletions
diff --git a/src/lj_api.c b/src/lj_api.c
index 1a34a774..f1cfebbc 100644
--- a/src/lj_api.c
+++ b/src/lj_api.c
@@ -24,11 +24,12 @@
24#include "lj_trace.h" 24#include "lj_trace.h"
25#include "lj_vm.h" 25#include "lj_vm.h"
26#include "lj_strscan.h" 26#include "lj_strscan.h"
27#include "lj_strfmt.h"
27 28
28/* -- Common helper functions --------------------------------------------- */ 29/* -- Common helper functions --------------------------------------------- */
29 30
30#define api_checknelems(L, n) api_check(L, (n) <= (L->top - L->base)) 31#define lj_checkapi_slot(idx) \
31#define api_checkvalidindex(L, i) api_check(L, (i) != niltv(L)) 32 lj_checkapi((idx) <= (L->top - L->base), "stack slot %d out of range", (idx))
32 33
33static TValue *index2adr(lua_State *L, int idx) 34static TValue *index2adr(lua_State *L, int idx)
34{ 35{
@@ -36,7 +37,8 @@ static TValue *index2adr(lua_State *L, int idx)
36 TValue *o = L->base + (idx - 1); 37 TValue *o = L->base + (idx - 1);
37 return o < L->top ? o : niltv(L); 38 return o < L->top ? o : niltv(L);
38 } else if (idx > LUA_REGISTRYINDEX) { 39 } else if (idx > LUA_REGISTRYINDEX) {
39 api_check(L, idx != 0 && -idx <= L->top - L->base); 40 lj_checkapi(idx != 0 && -idx <= L->top - L->base,
41 "bad stack slot %d", idx);
40 return L->top + idx; 42 return L->top + idx;
41 } else if (idx == LUA_GLOBALSINDEX) { 43 } else if (idx == LUA_GLOBALSINDEX) {
42 TValue *o = &G(L)->tmptv; 44 TValue *o = &G(L)->tmptv;
@@ -46,7 +48,8 @@ static TValue *index2adr(lua_State *L, int idx)
46 return registry(L); 48 return registry(L);
47 } else { 49 } else {
48 GCfunc *fn = curr_func(L); 50 GCfunc *fn = curr_func(L);
49 api_check(L, fn->c.gct == ~LJ_TFUNC && !isluafunc(fn)); 51 lj_checkapi(fn->c.gct == ~LJ_TFUNC && !isluafunc(fn),
52 "calling frame is not a C function");
50 if (idx == LUA_ENVIRONINDEX) { 53 if (idx == LUA_ENVIRONINDEX) {
51 TValue *o = &G(L)->tmptv; 54 TValue *o = &G(L)->tmptv;
52 settabV(L, o, tabref(fn->c.env)); 55 settabV(L, o, tabref(fn->c.env));
@@ -58,13 +61,27 @@ static TValue *index2adr(lua_State *L, int idx)
58 } 61 }
59} 62}
60 63
61static TValue *stkindex2adr(lua_State *L, int idx) 64static LJ_AINLINE TValue *index2adr_check(lua_State *L, int idx)
65{
66 TValue *o = index2adr(L, idx);
67 lj_checkapi(o != niltv(L), "invalid stack slot %d", idx);
68 return o;
69}
70
71static TValue *index2adr_stack(lua_State *L, int idx)
62{ 72{
63 if (idx > 0) { 73 if (idx > 0) {
64 TValue *o = L->base + (idx - 1); 74 TValue *o = L->base + (idx - 1);
75 if (o < L->top) {
76 return o;
77 } else {
78 lj_checkapi(0, "invalid stack slot %d", idx);
79 return niltv(L);
80 }
65 return o < L->top ? o : niltv(L); 81 return o < L->top ? o : niltv(L);
66 } else { 82 } else {
67 api_check(L, idx != 0 && -idx <= L->top - L->base); 83 lj_checkapi(idx != 0 && -idx <= L->top - L->base,
84 "invalid stack slot %d", idx);
68 return L->top + idx; 85 return L->top + idx;
69 } 86 }
70} 87}
@@ -98,17 +115,24 @@ LUALIB_API void luaL_checkstack(lua_State *L, int size, const char *msg)
98 lj_err_callerv(L, LJ_ERR_STKOVM, msg); 115 lj_err_callerv(L, LJ_ERR_STKOVM, msg);
99} 116}
100 117
101LUA_API void lua_xmove(lua_State *from, lua_State *to, int n) 118LUA_API void lua_xmove(lua_State *L, lua_State *to, int n)
102{ 119{
103 TValue *f, *t; 120 TValue *f, *t;
104 if (from == to) return; 121 if (L == to) return;
105 api_checknelems(from, n); 122 lj_checkapi_slot(n);
106 api_check(from, G(from) == G(to)); 123 lj_checkapi(G(L) == G(to), "move across global states");
107 lj_state_checkstack(to, (MSize)n); 124 lj_state_checkstack(to, (MSize)n);
108 f = from->top; 125 f = L->top;
109 t = to->top = to->top + n; 126 t = to->top = to->top + n;
110 while (--n >= 0) copyTV(to, --t, --f); 127 while (--n >= 0) copyTV(to, --t, --f);
111 from->top = f; 128 L->top = f;
129}
130
131LUA_API const lua_Number *lua_version(lua_State *L)
132{
133 static const lua_Number version = LUA_VERSION_NUM;
134 UNUSED(L);
135 return &version;
112} 136}
113 137
114/* -- Stack manipulation -------------------------------------------------- */ 138/* -- Stack manipulation -------------------------------------------------- */
@@ -121,7 +145,7 @@ LUA_API int lua_gettop(lua_State *L)
121LUA_API void lua_settop(lua_State *L, int idx) 145LUA_API void lua_settop(lua_State *L, int idx)
122{ 146{
123 if (idx >= 0) { 147 if (idx >= 0) {
124 api_check(L, idx <= tvref(L->maxstack) - L->base); 148 lj_checkapi(idx <= tvref(L->maxstack) - L->base, "bad stack slot %d", idx);
125 if (L->base + idx > L->top) { 149 if (L->base + idx > L->top) {
126 if (L->base + idx >= tvref(L->maxstack)) 150 if (L->base + idx >= tvref(L->maxstack))
127 lj_state_growstack(L, (MSize)idx - (MSize)(L->top - L->base)); 151 lj_state_growstack(L, (MSize)idx - (MSize)(L->top - L->base));
@@ -130,51 +154,58 @@ LUA_API void lua_settop(lua_State *L, int idx)
130 L->top = L->base + idx; 154 L->top = L->base + idx;
131 } 155 }
132 } else { 156 } else {
133 api_check(L, -(idx+1) <= (L->top - L->base)); 157 lj_checkapi(-(idx+1) <= (L->top - L->base), "bad stack slot %d", idx);
134 L->top += idx+1; /* Shrinks top (idx < 0). */ 158 L->top += idx+1; /* Shrinks top (idx < 0). */
135 } 159 }
136} 160}
137 161
138LUA_API void lua_remove(lua_State *L, int idx) 162LUA_API void lua_remove(lua_State *L, int idx)
139{ 163{
140 TValue *p = stkindex2adr(L, idx); 164 TValue *p = index2adr_stack(L, idx);
141 api_checkvalidindex(L, p);
142 while (++p < L->top) copyTV(L, p-1, p); 165 while (++p < L->top) copyTV(L, p-1, p);
143 L->top--; 166 L->top--;
144} 167}
145 168
146LUA_API void lua_insert(lua_State *L, int idx) 169LUA_API void lua_insert(lua_State *L, int idx)
147{ 170{
148 TValue *q, *p = stkindex2adr(L, idx); 171 TValue *q, *p = index2adr_stack(L, idx);
149 api_checkvalidindex(L, p);
150 for (q = L->top; q > p; q--) copyTV(L, q, q-1); 172 for (q = L->top; q > p; q--) copyTV(L, q, q-1);
151 copyTV(L, p, L->top); 173 copyTV(L, p, L->top);
152} 174}
153 175
154LUA_API void lua_replace(lua_State *L, int idx) 176static void copy_slot(lua_State *L, TValue *f, int idx)
155{ 177{
156 api_checknelems(L, 1);
157 if (idx == LUA_GLOBALSINDEX) { 178 if (idx == LUA_GLOBALSINDEX) {
158 api_check(L, tvistab(L->top-1)); 179 lj_checkapi(tvistab(f), "stack slot %d is not a table", idx);
159 /* NOBARRIER: A thread (i.e. L) is never black. */ 180 /* NOBARRIER: A thread (i.e. L) is never black. */
160 setgcref(L->env, obj2gco(tabV(L->top-1))); 181 setgcref(L->env, obj2gco(tabV(f)));
161 } else if (idx == LUA_ENVIRONINDEX) { 182 } else if (idx == LUA_ENVIRONINDEX) {
162 GCfunc *fn = curr_func(L); 183 GCfunc *fn = curr_func(L);
163 if (fn->c.gct != ~LJ_TFUNC) 184 if (fn->c.gct != ~LJ_TFUNC)
164 lj_err_msg(L, LJ_ERR_NOENV); 185 lj_err_msg(L, LJ_ERR_NOENV);
165 api_check(L, tvistab(L->top-1)); 186 lj_checkapi(tvistab(f), "stack slot %d is not a table", idx);
166 setgcref(fn->c.env, obj2gco(tabV(L->top-1))); 187 setgcref(fn->c.env, obj2gco(tabV(f)));
167 lj_gc_barrier(L, fn, L->top-1); 188 lj_gc_barrier(L, fn, f);
168 } else { 189 } else {
169 TValue *o = index2adr(L, idx); 190 TValue *o = index2adr_check(L, idx);
170 api_checkvalidindex(L, o); 191 copyTV(L, o, f);
171 copyTV(L, o, L->top-1);
172 if (idx < LUA_GLOBALSINDEX) /* Need a barrier for upvalues. */ 192 if (idx < LUA_GLOBALSINDEX) /* Need a barrier for upvalues. */
173 lj_gc_barrier(L, curr_func(L), L->top-1); 193 lj_gc_barrier(L, curr_func(L), f);
174 } 194 }
195}
196
197LUA_API void lua_replace(lua_State *L, int idx)
198{
199 lj_checkapi_slot(1);
200 copy_slot(L, L->top - 1, idx);
175 L->top--; 201 L->top--;
176} 202}
177 203
204LUA_API void lua_copy(lua_State *L, int fromidx, int toidx)
205{
206 copy_slot(L, index2adr(L, fromidx), toidx);
207}
208
178LUA_API void lua_pushvalue(lua_State *L, int idx) 209LUA_API void lua_pushvalue(lua_State *L, int idx)
179{ 210{
180 copyTV(L, L->top, index2adr(L, idx)); 211 copyTV(L, L->top, index2adr(L, idx));
@@ -188,7 +219,7 @@ LUA_API int lua_type(lua_State *L, int idx)
188 cTValue *o = index2adr(L, idx); 219 cTValue *o = index2adr(L, idx);
189 if (tvisnumber(o)) { 220 if (tvisnumber(o)) {
190 return LUA_TNUMBER; 221 return LUA_TNUMBER;
191#if LJ_64 222#if LJ_64 && !LJ_GC64
192 } else if (tvislightud(o)) { 223 } else if (tvislightud(o)) {
193 return LUA_TLIGHTUSERDATA; 224 return LUA_TLIGHTUSERDATA;
194#endif 225#endif
@@ -201,7 +232,7 @@ LUA_API int lua_type(lua_State *L, int idx)
201#else 232#else
202 int tt = (int)(((t < 8 ? 0x98042110u : 0x75a06u) >> 4*(t&7)) & 15u); 233 int tt = (int)(((t < 8 ? 0x98042110u : 0x75a06u) >> 4*(t&7)) & 15u);
203#endif 234#endif
204 lua_assert(tt != LUA_TNIL || tvisnil(o)); 235 lj_assertL(tt != LUA_TNIL || tvisnil(o), "bad tag conversion");
205 return tt; 236 return tt;
206 } 237 }
207} 238}
@@ -268,7 +299,7 @@ LUA_API int lua_equal(lua_State *L, int idx1, int idx2)
268 return 0; 299 return 0;
269 } else if (tvispri(o1)) { 300 } else if (tvispri(o1)) {
270 return o1 != niltv(L) && o2 != niltv(L); 301 return o1 != niltv(L) && o2 != niltv(L);
271#if LJ_64 302#if LJ_64 && !LJ_GC64
272 } else if (tvislightud(o1)) { 303 } else if (tvislightud(o1)) {
273 return o1->u64 == o2->u64; 304 return o1->u64 == o2->u64;
274#endif 305#endif
@@ -283,8 +314,8 @@ LUA_API int lua_equal(lua_State *L, int idx1, int idx2)
283 } else { 314 } else {
284 L->top = base+2; 315 L->top = base+2;
285 lj_vm_call(L, base, 1+1); 316 lj_vm_call(L, base, 1+1);
286 L->top -= 2; 317 L->top -= 2+LJ_FR2;
287 return tvistruecond(L->top+1); 318 return tvistruecond(L->top+1+LJ_FR2);
288 } 319 }
289 } 320 }
290} 321}
@@ -306,8 +337,8 @@ LUA_API int lua_lessthan(lua_State *L, int idx1, int idx2)
306 } else { 337 } else {
307 L->top = base+2; 338 L->top = base+2;
308 lj_vm_call(L, base, 1+1); 339 lj_vm_call(L, base, 1+1);
309 L->top -= 2; 340 L->top -= 2+LJ_FR2;
310 return tvistruecond(L->top+1); 341 return tvistruecond(L->top+1+LJ_FR2);
311 } 342 }
312 } 343 }
313} 344}
@@ -324,6 +355,22 @@ LUA_API lua_Number lua_tonumber(lua_State *L, int idx)
324 return 0; 355 return 0;
325} 356}
326 357
358LUA_API lua_Number lua_tonumberx(lua_State *L, int idx, int *ok)
359{
360 cTValue *o = index2adr(L, idx);
361 TValue tmp;
362 if (LJ_LIKELY(tvisnumber(o))) {
363 if (ok) *ok = 1;
364 return numberVnum(o);
365 } else if (tvisstr(o) && lj_strscan_num(strV(o), &tmp)) {
366 if (ok) *ok = 1;
367 return numV(&tmp);
368 } else {
369 if (ok) *ok = 0;
370 return 0;
371 }
372}
373
327LUALIB_API lua_Number luaL_checknumber(lua_State *L, int idx) 374LUALIB_API lua_Number luaL_checknumber(lua_State *L, int idx)
328{ 375{
329 cTValue *o = index2adr(L, idx); 376 cTValue *o = index2adr(L, idx);
@@ -361,9 +408,38 @@ LUA_API lua_Integer lua_tointeger(lua_State *L, int idx)
361 if (!(tvisstr(o) && lj_strscan_number(strV(o), &tmp))) 408 if (!(tvisstr(o) && lj_strscan_number(strV(o), &tmp)))
362 return 0; 409 return 0;
363 if (tvisint(&tmp)) 410 if (tvisint(&tmp))
364 return (lua_Integer)intV(&tmp); 411 return intV(&tmp);
412 n = numV(&tmp);
413 }
414#if LJ_64
415 return (lua_Integer)n;
416#else
417 return lj_num2int(n);
418#endif
419}
420
421LUA_API lua_Integer lua_tointegerx(lua_State *L, int idx, int *ok)
422{
423 cTValue *o = index2adr(L, idx);
424 TValue tmp;
425 lua_Number n;
426 if (LJ_LIKELY(tvisint(o))) {
427 if (ok) *ok = 1;
428 return intV(o);
429 } else if (LJ_LIKELY(tvisnum(o))) {
430 n = numV(o);
431 } else {
432 if (!(tvisstr(o) && lj_strscan_number(strV(o), &tmp))) {
433 if (ok) *ok = 0;
434 return 0;
435 }
436 if (tvisint(&tmp)) {
437 if (ok) *ok = 1;
438 return intV(&tmp);
439 }
365 n = numV(&tmp); 440 n = numV(&tmp);
366 } 441 }
442 if (ok) *ok = 1;
367#if LJ_64 443#if LJ_64
368 return (lua_Integer)n; 444 return (lua_Integer)n;
369#else 445#else
@@ -434,7 +510,7 @@ LUA_API const char *lua_tolstring(lua_State *L, int idx, size_t *len)
434 } else if (tvisnumber(o)) { 510 } else if (tvisnumber(o)) {
435 lj_gc_check(L); 511 lj_gc_check(L);
436 o = index2adr(L, idx); /* GC may move the stack. */ 512 o = index2adr(L, idx); /* GC may move the stack. */
437 s = lj_str_fromnumber(L, o); 513 s = lj_strfmt_number(L, o);
438 setstrV(L, o, s); 514 setstrV(L, o, s);
439 } else { 515 } else {
440 if (len != NULL) *len = 0; 516 if (len != NULL) *len = 0;
@@ -453,7 +529,7 @@ LUALIB_API const char *luaL_checklstring(lua_State *L, int idx, size_t *len)
453 } else if (tvisnumber(o)) { 529 } else if (tvisnumber(o)) {
454 lj_gc_check(L); 530 lj_gc_check(L);
455 o = index2adr(L, idx); /* GC may move the stack. */ 531 o = index2adr(L, idx); /* GC may move the stack. */
456 s = lj_str_fromnumber(L, o); 532 s = lj_strfmt_number(L, o);
457 setstrV(L, o, s); 533 setstrV(L, o, s);
458 } else { 534 } else {
459 lj_err_argt(L, idx, LUA_TSTRING); 535 lj_err_argt(L, idx, LUA_TSTRING);
@@ -475,7 +551,7 @@ LUALIB_API const char *luaL_optlstring(lua_State *L, int idx,
475 } else if (tvisnumber(o)) { 551 } else if (tvisnumber(o)) {
476 lj_gc_check(L); 552 lj_gc_check(L);
477 o = index2adr(L, idx); /* GC may move the stack. */ 553 o = index2adr(L, idx); /* GC may move the stack. */
478 s = lj_str_fromnumber(L, o); 554 s = lj_strfmt_number(L, o);
479 setstrV(L, o, s); 555 setstrV(L, o, s);
480 } else { 556 } else {
481 lj_err_argt(L, idx, LUA_TSTRING); 557 lj_err_argt(L, idx, LUA_TSTRING);
@@ -507,7 +583,7 @@ LUA_API size_t lua_objlen(lua_State *L, int idx)
507 } else if (tvisudata(o)) { 583 } else if (tvisudata(o)) {
508 return udataV(o)->len; 584 return udataV(o)->len;
509 } else if (tvisnumber(o)) { 585 } else if (tvisnumber(o)) {
510 GCstr *s = lj_str_fromnumber(L, o); 586 GCstr *s = lj_strfmt_number(L, o);
511 setstrV(L, o, s); 587 setstrV(L, o, s);
512 return s->len; 588 return s->len;
513 } else { 589 } else {
@@ -545,17 +621,7 @@ LUA_API lua_State *lua_tothread(lua_State *L, int idx)
545 621
546LUA_API const void *lua_topointer(lua_State *L, int idx) 622LUA_API const void *lua_topointer(lua_State *L, int idx)
547{ 623{
548 cTValue *o = index2adr(L, idx); 624 return lj_obj_ptr(index2adr(L, idx));
549 if (tvisudata(o))
550 return uddata(udataV(o));
551 else if (tvislightud(o))
552 return lightudV(o);
553 else if (tviscdata(o))
554 return cdataptr(cdataV(o));
555 else if (tvisgcv(o))
556 return gcV(o);
557 else
558 return NULL;
559} 625}
560 626
561/* -- Stack setters (object creation) ------------------------------------- */ 627/* -- Stack setters (object creation) ------------------------------------- */
@@ -606,7 +672,7 @@ LUA_API const char *lua_pushvfstring(lua_State *L, const char *fmt,
606 va_list argp) 672 va_list argp)
607{ 673{
608 lj_gc_check(L); 674 lj_gc_check(L);
609 return lj_str_pushvf(L, fmt, argp); 675 return lj_strfmt_pushvf(L, fmt, argp);
610} 676}
611 677
612LUA_API const char *lua_pushfstring(lua_State *L, const char *fmt, ...) 678LUA_API const char *lua_pushfstring(lua_State *L, const char *fmt, ...)
@@ -615,7 +681,7 @@ LUA_API const char *lua_pushfstring(lua_State *L, const char *fmt, ...)
615 va_list argp; 681 va_list argp;
616 lj_gc_check(L); 682 lj_gc_check(L);
617 va_start(argp, fmt); 683 va_start(argp, fmt);
618 ret = lj_str_pushvf(L, fmt, argp); 684 ret = lj_strfmt_pushvf(L, fmt, argp);
619 va_end(argp); 685 va_end(argp);
620 return ret; 686 return ret;
621} 687}
@@ -624,14 +690,14 @@ LUA_API void lua_pushcclosure(lua_State *L, lua_CFunction f, int n)
624{ 690{
625 GCfunc *fn; 691 GCfunc *fn;
626 lj_gc_check(L); 692 lj_gc_check(L);
627 api_checknelems(L, n); 693 lj_checkapi_slot(n);
628 fn = lj_func_newC(L, (MSize)n, getcurrenv(L)); 694 fn = lj_func_newC(L, (MSize)n, getcurrenv(L));
629 fn->c.f = f; 695 fn->c.f = f;
630 L->top -= n; 696 L->top -= n;
631 while (n--) 697 while (n--)
632 copyTV(L, &fn->c.upvalue[n], L->top+n); 698 copyTV(L, &fn->c.upvalue[n], L->top+n);
633 setfuncV(L, L->top, fn); 699 setfuncV(L, L->top, fn);
634 lua_assert(iswhite(obj2gco(fn))); 700 lj_assertL(iswhite(obj2gco(fn)), "new GC object is not white");
635 incr_top(L); 701 incr_top(L);
636} 702}
637 703
@@ -649,10 +715,8 @@ LUA_API void lua_pushlightuserdata(lua_State *L, void *p)
649 715
650LUA_API void lua_createtable(lua_State *L, int narray, int nrec) 716LUA_API void lua_createtable(lua_State *L, int narray, int nrec)
651{ 717{
652 GCtab *t;
653 lj_gc_check(L); 718 lj_gc_check(L);
654 t = lj_tab_new(L, (uint32_t)(narray > 0 ? narray+1 : 0), hsize2hbits(nrec)); 719 settabV(L, L->top, lj_tab_new_ah(L, narray, nrec));
655 settabV(L, L->top, t);
656 incr_top(L); 720 incr_top(L);
657} 721}
658 722
@@ -703,7 +767,7 @@ LUA_API void *lua_newuserdata(lua_State *L, size_t size)
703 767
704LUA_API void lua_concat(lua_State *L, int n) 768LUA_API void lua_concat(lua_State *L, int n)
705{ 769{
706 api_checknelems(L, n); 770 lj_checkapi_slot(n);
707 if (n >= 2) { 771 if (n >= 2) {
708 n--; 772 n--;
709 do { 773 do {
@@ -715,8 +779,8 @@ LUA_API void lua_concat(lua_State *L, int n)
715 n -= (int)(L->top - top); 779 n -= (int)(L->top - top);
716 L->top = top+2; 780 L->top = top+2;
717 lj_vm_call(L, top, 1+1); 781 lj_vm_call(L, top, 1+1);
718 L->top--; 782 L->top -= 1+LJ_FR2;
719 copyTV(L, L->top-1, L->top); 783 copyTV(L, L->top-1, L->top+LJ_FR2);
720 } while (--n > 0); 784 } while (--n > 0);
721 } else if (n == 0) { /* Push empty string. */ 785 } else if (n == 0) { /* Push empty string. */
722 setstrV(L, L->top, &G(L)->strempty); 786 setstrV(L, L->top, &G(L)->strempty);
@@ -729,30 +793,28 @@ LUA_API void lua_concat(lua_State *L, int n)
729 793
730LUA_API void lua_gettable(lua_State *L, int idx) 794LUA_API void lua_gettable(lua_State *L, int idx)
731{ 795{
732 cTValue *v, *t = index2adr(L, idx); 796 cTValue *t = index2adr_check(L, idx);
733 api_checkvalidindex(L, t); 797 cTValue *v = lj_meta_tget(L, t, L->top-1);
734 v = lj_meta_tget(L, t, L->top-1);
735 if (v == NULL) { 798 if (v == NULL) {
736 L->top += 2; 799 L->top += 2;
737 lj_vm_call(L, L->top-2, 1+1); 800 lj_vm_call(L, L->top-2, 1+1);
738 L->top -= 2; 801 L->top -= 2+LJ_FR2;
739 v = L->top+1; 802 v = L->top+1+LJ_FR2;
740 } 803 }
741 copyTV(L, L->top-1, v); 804 copyTV(L, L->top-1, v);
742} 805}
743 806
744LUA_API void lua_getfield(lua_State *L, int idx, const char *k) 807LUA_API void lua_getfield(lua_State *L, int idx, const char *k)
745{ 808{
746 cTValue *v, *t = index2adr(L, idx); 809 cTValue *v, *t = index2adr_check(L, idx);
747 TValue key; 810 TValue key;
748 api_checkvalidindex(L, t);
749 setstrV(L, &key, lj_str_newz(L, k)); 811 setstrV(L, &key, lj_str_newz(L, k));
750 v = lj_meta_tget(L, t, &key); 812 v = lj_meta_tget(L, t, &key);
751 if (v == NULL) { 813 if (v == NULL) {
752 L->top += 2; 814 L->top += 2;
753 lj_vm_call(L, L->top-2, 1+1); 815 lj_vm_call(L, L->top-2, 1+1);
754 L->top -= 2; 816 L->top -= 2+LJ_FR2;
755 v = L->top+1; 817 v = L->top+1+LJ_FR2;
756 } 818 }
757 copyTV(L, L->top, v); 819 copyTV(L, L->top, v);
758 incr_top(L); 820 incr_top(L);
@@ -761,14 +823,14 @@ LUA_API void lua_getfield(lua_State *L, int idx, const char *k)
761LUA_API void lua_rawget(lua_State *L, int idx) 823LUA_API void lua_rawget(lua_State *L, int idx)
762{ 824{
763 cTValue *t = index2adr(L, idx); 825 cTValue *t = index2adr(L, idx);
764 api_check(L, tvistab(t)); 826 lj_checkapi(tvistab(t), "stack slot %d is not a table", idx);
765 copyTV(L, L->top-1, lj_tab_get(L, tabV(t), L->top-1)); 827 copyTV(L, L->top-1, lj_tab_get(L, tabV(t), L->top-1));
766} 828}
767 829
768LUA_API void lua_rawgeti(lua_State *L, int idx, int n) 830LUA_API void lua_rawgeti(lua_State *L, int idx, int n)
769{ 831{
770 cTValue *v, *t = index2adr(L, idx); 832 cTValue *v, *t = index2adr(L, idx);
771 api_check(L, tvistab(t)); 833 lj_checkapi(tvistab(t), "stack slot %d is not a table", idx);
772 v = lj_tab_getint(tabV(t), n); 834 v = lj_tab_getint(tabV(t), n);
773 if (v) { 835 if (v) {
774 copyTV(L, L->top, v); 836 copyTV(L, L->top, v);
@@ -810,8 +872,7 @@ LUALIB_API int luaL_getmetafield(lua_State *L, int idx, const char *field)
810 872
811LUA_API void lua_getfenv(lua_State *L, int idx) 873LUA_API void lua_getfenv(lua_State *L, int idx)
812{ 874{
813 cTValue *o = index2adr(L, idx); 875 cTValue *o = index2adr_check(L, idx);
814 api_checkvalidindex(L, o);
815 if (tvisfunc(o)) { 876 if (tvisfunc(o)) {
816 settabV(L, L->top, tabref(funcV(o)->c.env)); 877 settabV(L, L->top, tabref(funcV(o)->c.env));
817 } else if (tvisudata(o)) { 878 } else if (tvisudata(o)) {
@@ -828,7 +889,7 @@ LUA_API int lua_next(lua_State *L, int idx)
828{ 889{
829 cTValue *t = index2adr(L, idx); 890 cTValue *t = index2adr(L, idx);
830 int more; 891 int more;
831 api_check(L, tvistab(t)); 892 lj_checkapi(tvistab(t), "stack slot %d is not a table", idx);
832 more = lj_tab_next(L, tabV(t), L->top-1); 893 more = lj_tab_next(L, tabV(t), L->top-1);
833 if (more) { 894 if (more) {
834 incr_top(L); /* Return new key and value slot. */ 895 incr_top(L); /* Return new key and value slot. */
@@ -854,7 +915,7 @@ LUA_API void *lua_upvalueid(lua_State *L, int idx, int n)
854{ 915{
855 GCfunc *fn = funcV(index2adr(L, idx)); 916 GCfunc *fn = funcV(index2adr(L, idx));
856 n--; 917 n--;
857 api_check(L, (uint32_t)n < fn->l.nupvalues); 918 lj_checkapi((uint32_t)n < fn->l.nupvalues, "bad upvalue %d", n);
858 return isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) : 919 return isluafunc(fn) ? (void *)gcref(fn->l.uvptr[n]) :
859 (void *)&fn->c.upvalue[n]; 920 (void *)&fn->c.upvalue[n];
860} 921}
@@ -864,13 +925,15 @@ LUA_API void lua_upvaluejoin(lua_State *L, int idx1, int n1, int idx2, int n2)
864 GCfunc *fn1 = funcV(index2adr(L, idx1)); 925 GCfunc *fn1 = funcV(index2adr(L, idx1));
865 GCfunc *fn2 = funcV(index2adr(L, idx2)); 926 GCfunc *fn2 = funcV(index2adr(L, idx2));
866 n1--; n2--; 927 n1--; n2--;
867 api_check(L, isluafunc(fn1) && (uint32_t)n1 < fn1->l.nupvalues); 928 lj_checkapi(isluafunc(fn1), "stack slot %d is not a Lua function", idx1);
868 api_check(L, isluafunc(fn2) && (uint32_t)n2 < fn2->l.nupvalues); 929 lj_checkapi(isluafunc(fn2), "stack slot %d is not a Lua function", idx2);
930 lj_checkapi((uint32_t)n1 < fn1->l.nupvalues, "bad upvalue %d", n1+1);
931 lj_checkapi((uint32_t)n2 < fn2->l.nupvalues, "bad upvalue %d", n2+1);
869 setgcrefr(fn1->l.uvptr[n1], fn2->l.uvptr[n2]); 932 setgcrefr(fn1->l.uvptr[n1], fn2->l.uvptr[n2]);
870 lj_gc_objbarrier(L, fn1, gcref(fn1->l.uvptr[n1])); 933 lj_gc_objbarrier(L, fn1, gcref(fn1->l.uvptr[n1]));
871} 934}
872 935
873LUALIB_API void *luaL_checkudata(lua_State *L, int idx, const char *tname) 936LUALIB_API void *luaL_testudata(lua_State *L, int idx, const char *tname)
874{ 937{
875 cTValue *o = index2adr(L, idx); 938 cTValue *o = index2adr(L, idx);
876 if (tvisudata(o)) { 939 if (tvisudata(o)) {
@@ -879,8 +942,14 @@ LUALIB_API void *luaL_checkudata(lua_State *L, int idx, const char *tname)
879 if (tv && tvistab(tv) && tabV(tv) == tabref(ud->metatable)) 942 if (tv && tvistab(tv) && tabV(tv) == tabref(ud->metatable))
880 return uddata(ud); 943 return uddata(ud);
881 } 944 }
882 lj_err_argtype(L, idx, tname); 945 return NULL; /* value is not a userdata with a metatable */
883 return NULL; /* unreachable */ 946}
947
948LUALIB_API void *luaL_checkudata(lua_State *L, int idx, const char *tname)
949{
950 void *p = luaL_testudata(L, idx, tname);
951 if (!p) lj_err_argtype(L, idx, tname);
952 return p;
884} 953}
885 954
886/* -- Object setters ------------------------------------------------------ */ 955/* -- Object setters ------------------------------------------------------ */
@@ -888,19 +957,19 @@ LUALIB_API void *luaL_checkudata(lua_State *L, int idx, const char *tname)
888LUA_API void lua_settable(lua_State *L, int idx) 957LUA_API void lua_settable(lua_State *L, int idx)
889{ 958{
890 TValue *o; 959 TValue *o;
891 cTValue *t = index2adr(L, idx); 960 cTValue *t = index2adr_check(L, idx);
892 api_checknelems(L, 2); 961 lj_checkapi_slot(2);
893 api_checkvalidindex(L, t);
894 o = lj_meta_tset(L, t, L->top-2); 962 o = lj_meta_tset(L, t, L->top-2);
895 if (o) { 963 if (o) {
896 /* NOBARRIER: lj_meta_tset ensures the table is not black. */ 964 /* NOBARRIER: lj_meta_tset ensures the table is not black. */
897 copyTV(L, o, L->top-1);
898 L->top -= 2; 965 L->top -= 2;
966 copyTV(L, o, L->top+1);
899 } else { 967 } else {
900 L->top += 3; 968 TValue *base = L->top;
901 copyTV(L, L->top-1, L->top-6); 969 copyTV(L, base+2, base-3-2*LJ_FR2);
902 lj_vm_call(L, L->top-3, 0+1); 970 L->top = base+3;
903 L->top -= 3; 971 lj_vm_call(L, base, 0+1);
972 L->top -= 3+LJ_FR2;
904 } 973 }
905} 974}
906 975
@@ -908,20 +977,19 @@ LUA_API void lua_setfield(lua_State *L, int idx, const char *k)
908{ 977{
909 TValue *o; 978 TValue *o;
910 TValue key; 979 TValue key;
911 cTValue *t = index2adr(L, idx); 980 cTValue *t = index2adr_check(L, idx);
912 api_checknelems(L, 1); 981 lj_checkapi_slot(1);
913 api_checkvalidindex(L, t);
914 setstrV(L, &key, lj_str_newz(L, k)); 982 setstrV(L, &key, lj_str_newz(L, k));
915 o = lj_meta_tset(L, t, &key); 983 o = lj_meta_tset(L, t, &key);
916 if (o) { 984 if (o) {
917 L->top--;
918 /* NOBARRIER: lj_meta_tset ensures the table is not black. */ 985 /* NOBARRIER: lj_meta_tset ensures the table is not black. */
919 copyTV(L, o, L->top); 986 copyTV(L, o, --L->top);
920 } else { 987 } else {
921 L->top += 3; 988 TValue *base = L->top;
922 copyTV(L, L->top-1, L->top-6); 989 copyTV(L, base+2, base-3-2*LJ_FR2);
923 lj_vm_call(L, L->top-3, 0+1); 990 L->top = base+3;
924 L->top -= 2; 991 lj_vm_call(L, base, 0+1);
992 L->top -= 2+LJ_FR2;
925 } 993 }
926} 994}
927 995
@@ -929,7 +997,7 @@ LUA_API void lua_rawset(lua_State *L, int idx)
929{ 997{
930 GCtab *t = tabV(index2adr(L, idx)); 998 GCtab *t = tabV(index2adr(L, idx));
931 TValue *dst, *key; 999 TValue *dst, *key;
932 api_checknelems(L, 2); 1000 lj_checkapi_slot(2);
933 key = L->top-2; 1001 key = L->top-2;
934 dst = lj_tab_set(L, t, key); 1002 dst = lj_tab_set(L, t, key);
935 copyTV(L, dst, key+1); 1003 copyTV(L, dst, key+1);
@@ -941,7 +1009,7 @@ LUA_API void lua_rawseti(lua_State *L, int idx, int n)
941{ 1009{
942 GCtab *t = tabV(index2adr(L, idx)); 1010 GCtab *t = tabV(index2adr(L, idx));
943 TValue *dst, *src; 1011 TValue *dst, *src;
944 api_checknelems(L, 1); 1012 lj_checkapi_slot(1);
945 dst = lj_tab_setint(L, t, n); 1013 dst = lj_tab_setint(L, t, n);
946 src = L->top-1; 1014 src = L->top-1;
947 copyTV(L, dst, src); 1015 copyTV(L, dst, src);
@@ -953,13 +1021,12 @@ LUA_API int lua_setmetatable(lua_State *L, int idx)
953{ 1021{
954 global_State *g; 1022 global_State *g;
955 GCtab *mt; 1023 GCtab *mt;
956 cTValue *o = index2adr(L, idx); 1024 cTValue *o = index2adr_check(L, idx);
957 api_checknelems(L, 1); 1025 lj_checkapi_slot(1);
958 api_checkvalidindex(L, o);
959 if (tvisnil(L->top-1)) { 1026 if (tvisnil(L->top-1)) {
960 mt = NULL; 1027 mt = NULL;
961 } else { 1028 } else {
962 api_check(L, tvistab(L->top-1)); 1029 lj_checkapi(tvistab(L->top-1), "top stack slot is not a table");
963 mt = tabV(L->top-1); 1030 mt = tabV(L->top-1);
964 } 1031 }
965 g = G(L); 1032 g = G(L);
@@ -988,13 +1055,18 @@ LUA_API int lua_setmetatable(lua_State *L, int idx)
988 return 1; 1055 return 1;
989} 1056}
990 1057
1058LUALIB_API void luaL_setmetatable(lua_State *L, const char *tname)
1059{
1060 lua_getfield(L, LUA_REGISTRYINDEX, tname);
1061 lua_setmetatable(L, -2);
1062}
1063
991LUA_API int lua_setfenv(lua_State *L, int idx) 1064LUA_API int lua_setfenv(lua_State *L, int idx)
992{ 1065{
993 cTValue *o = index2adr(L, idx); 1066 cTValue *o = index2adr_check(L, idx);
994 GCtab *t; 1067 GCtab *t;
995 api_checknelems(L, 1); 1068 lj_checkapi_slot(1);
996 api_checkvalidindex(L, o); 1069 lj_checkapi(tvistab(L->top-1), "top stack slot is not a table");
997 api_check(L, tvistab(L->top-1));
998 t = tabV(L->top-1); 1070 t = tabV(L->top-1);
999 if (tvisfunc(o)) { 1071 if (tvisfunc(o)) {
1000 setgcref(funcV(o)->c.env, obj2gco(t)); 1072 setgcref(funcV(o)->c.env, obj2gco(t));
@@ -1017,7 +1089,7 @@ LUA_API const char *lua_setupvalue(lua_State *L, int idx, int n)
1017 TValue *val; 1089 TValue *val;
1018 GCobj *o; 1090 GCobj *o;
1019 const char *name; 1091 const char *name;
1020 api_checknelems(L, 1); 1092 lj_checkapi_slot(1);
1021 name = lj_debug_uvnamev(f, (uint32_t)(n-1), &val, &o); 1093 name = lj_debug_uvnamev(f, (uint32_t)(n-1), &val, &o);
1022 if (name) { 1094 if (name) {
1023 L->top--; 1095 L->top--;
@@ -1029,11 +1101,25 @@ LUA_API const char *lua_setupvalue(lua_State *L, int idx, int n)
1029 1101
1030/* -- Calls --------------------------------------------------------------- */ 1102/* -- Calls --------------------------------------------------------------- */
1031 1103
1104#if LJ_FR2
1105static TValue *api_call_base(lua_State *L, int nargs)
1106{
1107 TValue *o = L->top, *base = o - nargs;
1108 L->top = o+1;
1109 for (; o > base; o--) copyTV(L, o, o-1);
1110 setnilV(o);
1111 return o+1;
1112}
1113#else
1114#define api_call_base(L, nargs) (L->top - (nargs))
1115#endif
1116
1032LUA_API void lua_call(lua_State *L, int nargs, int nresults) 1117LUA_API void lua_call(lua_State *L, int nargs, int nresults)
1033{ 1118{
1034 api_check(L, L->status == 0 || L->status == LUA_ERRERR); 1119 lj_checkapi(L->status == LUA_OK || L->status == LUA_ERRERR,
1035 api_checknelems(L, nargs+1); 1120 "thread called in wrong state %d", L->status);
1036 lj_vm_call(L, L->top - nargs, nresults+1); 1121 lj_checkapi_slot(nargs+1);
1122 lj_vm_call(L, api_call_base(L, nargs), nresults+1);
1037} 1123}
1038 1124
1039LUA_API int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc) 1125LUA_API int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc)
@@ -1042,16 +1128,16 @@ LUA_API int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc)
1042 uint8_t oldh = hook_save(g); 1128 uint8_t oldh = hook_save(g);
1043 ptrdiff_t ef; 1129 ptrdiff_t ef;
1044 int status; 1130 int status;
1045 api_check(L, L->status == 0 || L->status == LUA_ERRERR); 1131 lj_checkapi(L->status == LUA_OK || L->status == LUA_ERRERR,
1046 api_checknelems(L, nargs+1); 1132 "thread called in wrong state %d", L->status);
1133 lj_checkapi_slot(nargs+1);
1047 if (errfunc == 0) { 1134 if (errfunc == 0) {
1048 ef = 0; 1135 ef = 0;
1049 } else { 1136 } else {
1050 cTValue *o = stkindex2adr(L, errfunc); 1137 cTValue *o = index2adr_stack(L, errfunc);
1051 api_checkvalidindex(L, o);
1052 ef = savestack(L, o); 1138 ef = savestack(L, o);
1053 } 1139 }
1054 status = lj_vm_pcall(L, L->top - nargs, nresults+1, ef); 1140 status = lj_vm_pcall(L, api_call_base(L, nargs), nresults+1, ef);
1055 if (status) hook_restore(g, oldh); 1141 if (status) hook_restore(g, oldh);
1056 return status; 1142 return status;
1057} 1143}
@@ -1059,12 +1145,14 @@ LUA_API int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc)
1059static TValue *cpcall(lua_State *L, lua_CFunction func, void *ud) 1145static TValue *cpcall(lua_State *L, lua_CFunction func, void *ud)
1060{ 1146{
1061 GCfunc *fn = lj_func_newC(L, 0, getcurrenv(L)); 1147 GCfunc *fn = lj_func_newC(L, 0, getcurrenv(L));
1148 TValue *top = L->top;
1062 fn->c.f = func; 1149 fn->c.f = func;
1063 setfuncV(L, L->top, fn); 1150 setfuncV(L, top++, fn);
1064 setlightudV(L->top+1, checklightudptr(L, ud)); 1151 if (LJ_FR2) setnilV(top++);
1152 setlightudV(top++, checklightudptr(L, ud));
1065 cframe_nres(L->cframe) = 1+0; /* Zero results. */ 1153 cframe_nres(L->cframe) = 1+0; /* Zero results. */
1066 L->top += 2; 1154 L->top = top;
1067 return L->top-1; /* Now call the newly allocated C function. */ 1155 return top-1; /* Now call the newly allocated C function. */
1068} 1156}
1069 1157
1070LUA_API int lua_cpcall(lua_State *L, lua_CFunction func, void *ud) 1158LUA_API int lua_cpcall(lua_State *L, lua_CFunction func, void *ud)
@@ -1072,7 +1160,8 @@ LUA_API int lua_cpcall(lua_State *L, lua_CFunction func, void *ud)
1072 global_State *g = G(L); 1160 global_State *g = G(L);
1073 uint8_t oldh = hook_save(g); 1161 uint8_t oldh = hook_save(g);
1074 int status; 1162 int status;
1075 api_check(L, L->status == 0 || L->status == LUA_ERRERR); 1163 lj_checkapi(L->status == LUA_OK || L->status == LUA_ERRERR,
1164 "thread called in wrong state %d", L->status);
1076 status = lj_vm_cpcall(L, func, ud, cpcall); 1165 status = lj_vm_cpcall(L, func, ud, cpcall);
1077 if (status) hook_restore(g, oldh); 1166 if (status) hook_restore(g, oldh);
1078 return status; 1167 return status;
@@ -1081,10 +1170,11 @@ LUA_API int lua_cpcall(lua_State *L, lua_CFunction func, void *ud)
1081LUALIB_API int luaL_callmeta(lua_State *L, int idx, const char *field) 1170LUALIB_API int luaL_callmeta(lua_State *L, int idx, const char *field)
1082{ 1171{
1083 if (luaL_getmetafield(L, idx, field)) { 1172 if (luaL_getmetafield(L, idx, field)) {
1084 TValue *base = L->top--; 1173 TValue *top = L->top--;
1085 copyTV(L, base, index2adr(L, idx)); 1174 if (LJ_FR2) setnilV(top++);
1086 L->top = base+1; 1175 copyTV(L, top++, index2adr(L, idx));
1087 lj_vm_call(L, base, 1+1); 1176 L->top = top;
1177 lj_vm_call(L, top-1, 1+1);
1088 return 1; 1178 return 1;
1089 } 1179 }
1090 return 0; 1180 return 0;
@@ -1092,6 +1182,11 @@ LUALIB_API int luaL_callmeta(lua_State *L, int idx, const char *field)
1092 1182
1093/* -- Coroutine yield and resume ------------------------------------------ */ 1183/* -- Coroutine yield and resume ------------------------------------------ */
1094 1184
1185LUA_API int lua_isyieldable(lua_State *L)
1186{
1187 return cframe_canyield(L->cframe);
1188}
1189
1095LUA_API int lua_yield(lua_State *L, int nresults) 1190LUA_API int lua_yield(lua_State *L, int nresults)
1096{ 1191{
1097 void *cf = L->cframe; 1192 void *cf = L->cframe;
@@ -1111,12 +1206,14 @@ LUA_API int lua_yield(lua_State *L, int nresults)
1111 } else { /* Yield from hook: add a pseudo-frame. */ 1206 } else { /* Yield from hook: add a pseudo-frame. */
1112 TValue *top = L->top; 1207 TValue *top = L->top;
1113 hook_leave(g); 1208 hook_leave(g);
1114 top->u64 = cframe_multres(cf); 1209 (top++)->u64 = cframe_multres(cf);
1115 setcont(top+1, lj_cont_hook); 1210 setcont(top, lj_cont_hook);
1116 setframe_pc(top+1, cframe_pc(cf)-1); 1211 if (LJ_FR2) top++;
1117 setframe_gc(top+2, obj2gco(L)); 1212 setframe_pc(top, cframe_pc(cf)-1);
1118 setframe_ftsz(top+2, (int)((char *)(top+3)-(char *)L->base)+FRAME_CONT); 1213 if (LJ_FR2) top++;
1119 L->top = L->base = top+3; 1214 setframe_gc(top, obj2gco(L), LJ_TTHREAD);
1215 setframe_ftsz(top, ((char *)(top+1)-(char *)L->base)+FRAME_CONT);
1216 L->top = L->base = top+1;
1120#if LJ_TARGET_X64 1217#if LJ_TARGET_X64
1121 lj_err_throw(L, LUA_YIELD); 1218 lj_err_throw(L, LUA_YIELD);
1122#else 1219#else
@@ -1133,7 +1230,9 @@ LUA_API int lua_yield(lua_State *L, int nresults)
1133LUA_API int lua_resume(lua_State *L, int nargs) 1230LUA_API int lua_resume(lua_State *L, int nargs)
1134{ 1231{
1135 if (L->cframe == NULL && L->status <= LUA_YIELD) 1232 if (L->cframe == NULL && L->status <= LUA_YIELD)
1136 return lj_vm_resume(L, L->top - nargs, 0, 0); 1233 return lj_vm_resume(L,
1234 L->status == LUA_OK ? api_call_base(L, nargs) : L->top - nargs,
1235 0, 0);
1137 L->top = L->base; 1236 L->top = L->base;
1138 setstrV(L, L->top, lj_err_str(L, LJ_ERR_COSUSP)); 1237 setstrV(L, L->top, lj_err_str(L, LJ_ERR_COSUSP));
1139 incr_top(L); 1238 incr_top(L);
@@ -1163,7 +1262,7 @@ LUA_API int lua_gc(lua_State *L, int what, int data)
1163 res = (int)(g->gc.total & 0x3ff); 1262 res = (int)(g->gc.total & 0x3ff);
1164 break; 1263 break;
1165 case LUA_GCSTEP: { 1264 case LUA_GCSTEP: {
1166 MSize a = (MSize)data << 10; 1265 GCSize a = (GCSize)data << 10;
1167 g->gc.threshold = (a <= g->gc.total) ? (g->gc.total - a) : 0; 1266 g->gc.threshold = (a <= g->gc.total) ? (g->gc.total - a) : 0;
1168 while (g->gc.total >= g->gc.threshold) 1267 while (g->gc.total >= g->gc.threshold)
1169 if (lj_gc_step(L) > 0) { 1268 if (lj_gc_step(L) > 0) {
@@ -1180,6 +1279,9 @@ LUA_API int lua_gc(lua_State *L, int what, int data)
1180 res = (int)(g->gc.stepmul); 1279 res = (int)(g->gc.stepmul);
1181 g->gc.stepmul = (MSize)data; 1280 g->gc.stepmul = (MSize)data;
1182 break; 1281 break;
1282 case LUA_GCISRUNNING:
1283 res = (g->gc.threshold != LJ_MAX_MEM);
1284 break;
1183 default: 1285 default:
1184 res = -1; /* Invalid option. */ 1286 res = -1; /* Invalid option. */
1185 } 1287 }