Coveralls logob
Coveralls logo
  • Home
  • Features
  • Pricing
  • Docs
  • Sign In

tarantool / tarantool / 753380157

15 Apr 2021 - 21:05 coverage increased (+0.01%) to 83.493%
753380157

push

github-ci

Roman Khabibov
serializer: serialize recursive structures

56037 of 109408 branches covered (51.22%)

79138 of 94784 relevant lines covered (83.49%)

1585873.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.81
/src/lua/utils.c
1
/*
2
 * Copyright 2010-2015, Tarantool AUTHORS, please see AUTHORS file.
3
 *
4
 * Redistribution and use in source and binary forms, with or
5
 * without modification, are permitted provided that the following
6
 * conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above
9
 *    copyright notice, this list of conditions and the
10
 *    following disclaimer.
11
 *
12
 * 2. Redistributions in binary form must reproduce the above
13
 *    copyright notice, this list of conditions and the following
14
 *    disclaimer in the documentation and/or other materials
15
 *    provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
 * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
25
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
#include "lua/utils.h"
32
#include <lj_trace.h>
33

34
#include <assert.h>
35
#include <errno.h>
36

37
#include <trivia/util.h>
38
#include <diag.h>
39
#include <fiber.h>
40

41
#include "serializer_opts.h"
42

43
int luaL_nil_ref = LUA_REFNIL;
44
int luaL_map_metatable_ref = LUA_REFNIL;
45
int luaL_array_metatable_ref = LUA_REFNIL;
46

47
static int luaT_newthread_ref = LUA_NOREF;
48

49
static uint32_t CTID_STRUCT_IBUF;
50
static uint32_t CTID_STRUCT_IBUF_PTR;
51
static uint32_t CTID_CHAR_PTR;
52
static uint32_t CTID_CONST_CHAR_PTR;
53
static uint32_t CTID_UUID;
54
uint32_t CTID_DECIMAL;
55

56

57
void *
58
luaL_pushcdata(struct lua_State *L, uint32_t ctypeid)
6,051,497×
59
{
60
        /*
61
         * ctypeid is actually has CTypeID type.
62
         * CTypeId is defined somewhere inside luajit's internal
63
         * headers.
64
         */
65
        assert(sizeof(ctypeid) == sizeof(CTypeID));
66

67
        /* Code below is based on ffi_new() from luajit/src/lib_ffi.c */
68

69
        /* Get information about ctype */
70
        CTSize size;
71
        CTState *cts = ctype_cts(L);
6,051,497×
72
        CTInfo info = lj_ctype_info(cts, ctypeid, &size);
Branches [[0, 2]] missed. 6,051,497×
73
        assert(size != CTSIZE_INVALID);
Branches [[0, 0]] missed. 6,051,497×
74

75
        /* Allocate a new cdata */
76
        GCcdata *cd = lj_cdata_new(cts, ctypeid, size);
12,102,994×
77

78
        /* Anchor the uninitialized cdata with the stack. */
79
        TValue *o = L->top;
6,051,497×
80
        setcdataV(L, o, cd);
81
        incr_top(L);
Branches [[0, 0], [1, 3], [1, 4]] missed. 6,051,497×
82

83
        /*
84
         * lj_cconv_ct_init is omitted for non-structs because it actually
85
         * does memset()
86
         * Caveats: cdata memory is returned uninitialized
87
         */
88
        if (ctype_isstruct(info)) {
6,051,497×
89
                /* Initialize cdata. */
90
                CType *ct = ctype_raw(cts, ctypeid);
1,065×
91
                lj_cconv_ct_init(cts, ct, size, cdataptr(cd), o,
Branches [[0, 2]] missed. 1,065×
92
                                 (MSize)(L->top - o));
1,065×
93
                /* Handle ctype __gc metamethod. Use the fast lookup here. */
94
                cTValue *tv = lj_tab_getinth(cts->miscmap, -(int32_t)ctypeid);
Branches [[0, 2]] missed. 1,065×
95
                if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) {
Branches [[0, 1], [1, 3], [2, 5], [4, 10]] missed. 1,065×
96
                        GCtab *t = cts->finalizer;
1×
97
                        if (gcref(t->metatable)) {
Branches [[0, 1]] missed. 1×
98
                                /* Add to finalizer table, if still enabled. */
99
                                copyTV(L, lj_tab_set(L, t, o), tv);
Branches [[0, 2]] missed. 1×
100
                                lj_gc_anybarriert(L, t);
Branches [[0, 0]] missed. 1×
101
                                cd->marked |= LJ_GC_CDATA_FIN;
1×
102
                        }
103
                }
104
        }
105

106
        lj_gc_check(L);
Branches [[1, 4]] missed. 6,051,497×
107
        return cdataptr(cd);
6,051,497×
108
}
109

110
struct tt_uuid *
111
luaL_pushuuid(struct lua_State *L)
14×
112
{
113
        return luaL_pushcdata(L, CTID_UUID);
14×
114
}
115

116
int
117
luaL_iscdata(struct lua_State *L, int idx)
18×
118
{
119
        return lua_type(L, idx) == LUA_TCDATA;
18×
120
}
121

122
void *
123
luaL_checkcdata(struct lua_State *L, int idx, uint32_t *ctypeid)
7,413,191×
124
{
125
        /* Calculate absolute value in the stack. */
126
        if (idx < 0)
7,413,191×
127
                idx = lua_gettop(L) + idx + 1;
70,602×
128

129
        if (lua_type(L, idx) != LUA_TCDATA) {
7,413,191×
130
                *ctypeid = 0;
3×
131
                luaL_error(L, "expected cdata as %d argument", idx);
3×
132
                return NULL;
!
133
        }
134

135
        GCcdata *cd = cdataV(L->base + idx - 1);
7,413,188×
136
        *ctypeid = cd->ctypeid;
7,413,188×
137
        return (void *)cdataptr(cd);
7,413,188×
138
}
139

140
uint32_t
141
luaL_ctypeid(struct lua_State *L, const char *ctypename)
28,491×
142
{
143
        int idx = lua_gettop(L);
Branches [[0, 2]] missed. 28,491×
144
        /* This function calls ffi.typeof to determine CDataType */
145

146
        /* Get ffi.typeof function */
147
        luaL_loadstring(L, "return require('ffi').typeof");
Branches [[0, 2]] missed. 28,491×
148
        lua_call(L, 0, 1);
Branches [[0, 2]] missed. 28,491×
149
        /* FFI must exist */
150
        assert(lua_gettop(L) == idx + 1 && lua_isfunction(L, idx + 1));
Branches [[0, 2], [1, 4], [2, 7], [3, 8]] missed. 28,491×
151
        /* Push the first argument to ffi.typeof */
152
        lua_pushstring(L, ctypename);
Branches [[0, 2]] missed. 28,491×
153
        /* Call ffi.typeof() */
154
        lua_call(L, 1, 1);
Branches [[0, 2]] missed. 28,491×
155
        /* Returned type must be LUA_TCDATA with CTID_CTYPEID */
156
        uint32_t ctypetypeid;
157
        CTypeID ctypeid = *(CTypeID *)luaL_checkcdata(L, idx + 1, &ctypetypeid);
Branches [[0, 2]] missed. 28,491×
158
        assert(ctypetypeid == CTID_CTYPEID);
Branches [[0, 0]] missed. 28,491×
159

160
        lua_settop(L, idx);
Branches [[0, 2]] missed. 28,491×
161
        return ctypeid;
28,491×
162
}
163

164
uint32_t
165
luaL_metatype(struct lua_State *L, const char *ctypename,
1,899×
166
              const struct luaL_Reg *methods)
167
{
168
        /* Create a metatable for our ffi metatype. */
169
        luaL_register_type(L, ctypename, methods);
Branches [[0, 2]] missed. 1,899×
170
        int idx = lua_gettop(L);
Branches [[0, 2]] missed. 1,899×
171
        /*
172
         * Get ffi.metatype function. It is like typeof with
173
         * an additional effect of registering a metatable for
174
         * all the cdata objects of the type.
175
         */
176
        luaL_loadstring(L, "return require('ffi').metatype");
Branches [[0, 2]] missed. 1,899×
177
        lua_call(L, 0, 1);
Branches [[0, 2]] missed. 1,899×
178
        assert(lua_gettop(L) == idx + 1 && lua_isfunction(L, idx + 1));
Branches [[0, 2], [1, 4], [2, 7], [3, 8]] missed. 1,899×
179
        lua_pushstring(L, ctypename);
Branches [[0, 2]] missed. 1,899×
180
        /* Push the freshly created metatable as the second parameter. */
181
        luaL_getmetatable(L, ctypename);
Branches [[0, 2]] missed. 1,899×
182
        assert(lua_gettop(L) == idx + 3 && lua_istable(L, idx + 3));
Branches [[0, 2], [1, 4], [2, 7], [3, 8]] missed. 1,899×
183
        lua_call(L, 2, 1);
Branches [[0, 2]] missed. 1,899×
184
        uint32_t ctypetypeid;
185
        CTypeID ctypeid = *(CTypeID *)luaL_checkcdata(L, idx + 1, &ctypetypeid);
Branches [[0, 2]] missed. 1,899×
186
        assert(ctypetypeid == CTID_CTYPEID);
Branches [[0, 0]] missed. 1,899×
187

188
        lua_settop(L, idx);
Branches [[0, 2]] missed. 1,899×
189
        return ctypeid;
1,899×
190
}
191

192
int
193
luaL_cdef(struct lua_State *L, const char *what)
22,791×
194
{
195
        int idx = lua_gettop(L);
22,791×
196
        (void) idx;
197
        /* This function calls ffi.cdef  */
198

199
        /* Get ffi.typeof function */
200
        luaL_loadstring(L, "return require('ffi').cdef");
22,791×
201
        lua_call(L, 0, 1);
22,791×
202
        /* FFI must exist */
203
        assert(lua_gettop(L) == idx + 1 && lua_isfunction(L, idx + 1));
Branches [[4294967295, 2], [0, 4]] missed. 22,791×
204
        /* Push the argument to ffi.cdef */
205
        lua_pushstring(L, what);
22,791×
206
        /* Call ffi.cdef() */
207
        return lua_pcall(L, 1, 0, 0);
22,791×
208
}
209

210
void
211
luaL_setcdatagc(struct lua_State *L, int idx)
5,947,645×
212
{
213
        /* Calculate absolute value in the stack. */
214
        if (idx < 0)
Branches [[0, 1]] missed. 5,947,645×
215
                idx = lua_gettop(L) + idx + 1;
5,947,645×
216

217
        /* Code below is based on ffi_gc() from luajit/src/lib_ffi.c */
218

219
        /* Get cdata from the stack */
220
        assert(lua_type(L, idx) == LUA_TCDATA);
Branches [[0, 1]] missed. 5,947,645×
221
        GCcdata *cd = cdataV(L->base + idx - 1);
5,947,645×
222

223
        /* Get finalizer from the stack */
224
        TValue *fin = lj_lib_checkany(L, lua_gettop(L));
5,947,645×
225

226
#if !defined(NDEBUG)
227
        CTState *cts = ctype_cts(L);
5,947,645×
228
        CType *ct = ctype_raw(cts, cd->ctypeid);
11,895,290×
229
        (void) ct;
230
        assert(ctype_isptr(ct->info) || ctype_isstruct(ct->info) ||
Branches [[0, 0], [1, 2], [1, 3], [2, 4], [2, 5]] missed. 5,947,645×
231
               ctype_isrefarray(ct->info));
232
#endif /* !defined(NDEBUG) */
233

234
        /* Set finalizer */
235
        lj_cdata_setfin(L, cd, gcval(fin), itype(fin));
5,947,645×
236

237
        /* Pop finalizer */
238
        lua_pop(L, 1);
5,947,645×
239
}
5,947,645×
240

241

242
#define OPTION(type, name, defvalue) { #name, \
243
        offsetof(struct luaL_serializer, name), type, defvalue}
244
/**
245
 * Configuration options for serializers
246
 * @sa struct luaL_serializer
247
 */
248
static struct {
249
        const char *name;
250
        size_t offset; /* offset in structure */
251
        int type;
252
        int defvalue;
253
} OPTIONS[] = {
254
        OPTION(LUA_TBOOLEAN, encode_sparse_convert, 1),
255
        OPTION(LUA_TNUMBER,  encode_sparse_ratio, 2),
256
        OPTION(LUA_TNUMBER,  encode_sparse_safe, 10),
257
        OPTION(LUA_TNUMBER,  encode_max_depth, 128),
258
        OPTION(LUA_TBOOLEAN, encode_deep_as_nil, 0),
259
        OPTION(LUA_TBOOLEAN, encode_invalid_numbers, 1),
260
        OPTION(LUA_TNUMBER,  encode_number_precision, 14),
261
        OPTION(LUA_TBOOLEAN, encode_load_metatables, 1),
262
        OPTION(LUA_TBOOLEAN, encode_use_tostring, 0),
263
        OPTION(LUA_TBOOLEAN, encode_invalid_as_nil, 0),
264
        OPTION(LUA_TBOOLEAN, decode_invalid_numbers, 1),
265
        OPTION(LUA_TBOOLEAN, decode_save_metatables, 1),
266
        OPTION(LUA_TNUMBER,  decode_max_depth, 128),
267
        { NULL, 0, 0, 0},
268
};
269

270
void
271
luaL_serializer_create(struct luaL_serializer *cfg)
15,210×
272
{
273
        rlist_create(&cfg->on_update);
15,210×
274
        for (int i = 0; OPTIONS[i].name != NULL; i++) {
212,940×
275
                int *pval = (int *) ((char *) cfg + OPTIONS[i].offset);
197,730×
276
                *pval = OPTIONS[i].defvalue;
197,730×
277
        }
278
}
15,210×
279

280
void
281
luaL_serializer_copy_options(struct luaL_serializer *dst,
1,919×
282
                             const struct luaL_serializer *src)
283
{
284
        memcpy(dst, src, offsetof(struct luaL_serializer, end_of_options));
1,919×
285
}
1,919×
286

287
/**
288
 * Configure one field in @a cfg. Value of the field is kept on
289
 * Lua stack after this function, and should be popped manually.
290
 * @param L Lua stack.
291
 * @param i Index of option in OPTIONS[].
292
 * @param cfg Serializer to inherit configuration.
293
 * @retval Pointer to the value of option.
294
 * @retval NULL if option is not in the table.
295
 */
296
static int *
297
luaL_serializer_parse_option(struct lua_State *L, int i,
50,609×
298
                             struct luaL_serializer *cfg)
299
{
300
        lua_getfield(L, 2, OPTIONS[i].name);
50,609×
301
        if (lua_isnil(L, -1))
50,609×
302
                return NULL;
35,294×
303
        /*
304
         * Update struct luaL_serializer using pointer to a
305
         * configuration value (all values must be `int` for that).
306
        */
307
        int *pval = (int *) ((char *) cfg + OPTIONS[i].offset);
15,315×
308
        switch (OPTIONS[i].type) {
Branches [[0, 2]] missed. 15,315×
309
        case LUA_TBOOLEAN:
310
                *pval = lua_toboolean(L, -1);
15,278×
311
                break;
15,278×
312
        case LUA_TNUMBER:
313
                *pval = lua_tointeger(L, -1);
37×
314
                break;
37×
315
        default:
316
                unreachable();
!
317
        }
318
        return pval;
15,315×
319
}
320

321
void
322
luaL_serializer_parse_options(struct lua_State *L,
7×
323
                              struct luaL_serializer *cfg)
324
{
325
        for (int i = 0; OPTIONS[i].name != NULL; ++i) {
98×
326
                luaL_serializer_parse_option(L, i, cfg);
91×
327
                lua_pop(L, 1);
91×
328
        }
329
}
7×
330

331
/**
332
 * @brief serializer.cfg{} Lua binding for serializers.
333
 * serializer.cfg is a table that contains current configuration values from
334
 * luaL_serializer structure. serializer.cfg has overriden __call() method
335
 * to change configuration keys in internal userdata (like box.cfg{}).
336
 * Please note that direct change in serializer.cfg.key will not affect
337
 * internal state of userdata. Changes via cfg() are reflected in
338
 * both Lua cfg table, and C serializer structure.
339
 * @param L lua stack
340
 * @return 0
341
 */
342
static int
343
luaL_serializer_cfg(struct lua_State *L)
3,886×
344
{
345
        /* Serializer.cfg */
346
        luaL_checktype(L, 1, LUA_TTABLE);
3,886×
347
        /* Updated parameters. */
348
        luaL_checktype(L, 2, LUA_TTABLE);
3,886×
349
        struct luaL_serializer *cfg = luaL_checkserializer(L);
3,886×
350
        for (int i = 0; OPTIONS[i].name != NULL; ++i) {
54,404×
351
                if (luaL_serializer_parse_option(L, i, cfg) == NULL)
50,518×
352
                        lua_pop(L, 1);
35,210×
353
                else
354
                        lua_setfield(L, 1, OPTIONS[i].name);
15,308×
355
        }
356
        trigger_run(&cfg->on_update, cfg);
3,886×
357
        return 0;
3,886×
358
}
359

360
/**
361
 * @brief serializer.new() Lua binding.
362
 * @param L stack
363
 * @param reg methods to register
364
 * @param parent parent serializer to inherit configuration
365
 * @return new serializer
366
 */
367
struct luaL_serializer *
368
luaL_newserializer(struct lua_State *L, const char *modname, const luaL_Reg *reg)
15,210×
369
{
370
        luaL_checkstack(L, 1, "too many upvalues");
15,210×
371

372
        /* Create new module */
373
        lua_newtable(L);
15,210×
374

375
        /* Create new configuration */
376
        struct luaL_serializer *serializer = (struct luaL_serializer *)
15,210×
377
                        lua_newuserdata(L, sizeof(*serializer));
378
        luaL_getmetatable(L, LUAL_SERIALIZER);
15,210×
379
        lua_setmetatable(L, -2);
15,210×
380
        luaL_serializer_create(serializer);
15,210×
381

382
        for (; reg->name != NULL; reg++) {
57,066×
383
                /* push luaL_serializer as upvalue */
384
                lua_pushvalue(L, -1);
41,856×
385
                /* register method */
386
                lua_pushcclosure(L, reg->func, 1);
41,856×
387
                lua_setfield(L, -3, reg->name);
41,856×
388
        }
389

390
        /* Add cfg{} */
391
        lua_newtable(L); /* cfg */
15,210×
392
        lua_newtable(L); /* metatable */
15,210×
393
        lua_pushvalue(L, -3); /* luaL_serializer */
15,210×
394
        lua_pushcclosure(L, luaL_serializer_cfg, 1);
15,210×
395
        lua_setfield(L, -2, "__call");
15,210×
396
        lua_setmetatable(L, -2);
15,210×
397
        /* Save configuration values to serializer.cfg */
398
        for (int i = 0; OPTIONS[i].name != NULL; i++) {
212,940×
399
                int *pval = (int *) ((char *) serializer + OPTIONS[i].offset);
197,730×
400
                switch (OPTIONS[i].type) {
Branches [[0, 2]] missed. 197,730×
401
                case LUA_TBOOLEAN:
402
                        lua_pushboolean(L, *pval);
121,680×
403
                        break;
121,680×
404
                case LUA_TNUMBER:
405
                        lua_pushinteger(L, *pval);
76,050×
406
                        break;
76,050×
407
                default:
408
                        unreachable();
!
409
                }
410
                lua_setfield(L, -2, OPTIONS[i].name);
197,730×
411
        }
412
        lua_setfield(L, -3, "cfg");
15,210×
413

414
        lua_pop(L, 1);  /* remove upvalues */
15,210×
415

416
        luaL_pushnull(L);
15,210×
417
        lua_setfield(L, -2, "NULL");
15,210×
418
        lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_array_metatable_ref);
15,210×
419
        lua_setfield(L, -2, "array_mt");
15,210×
420
        lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_map_metatable_ref);
15,210×
421
        lua_setfield(L, -2, "map_mt");
15,210×
422

423
        if (modname != NULL) {
15,210×
424
                /* Register module */
425
                lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
5,698×
426
                lua_pushstring(L, modname); /* add alias */
5,698×
427
                lua_pushvalue(L, -3);
5,698×
428
                lua_settable(L, -3);
5,698×
429
                lua_pop(L, 1); /* _LOADED */
5,698×
430
        }
431

432
        return serializer;
15,210×
433
}
434

435
static int
436
lua_gettable_wrapper(lua_State *L)
51,342×
437
{
438
        lua_gettable(L, -2);
51,342×
439
        return 1;
51,290×
440
}
441

442
static void
443
lua_field_inspect_ucdata(struct lua_State *L, struct luaL_serializer *cfg,
51,342×
444
                         int serialized_objs_idx, int idx,
445
                         struct luaL_field *field)
446
{
447
        if (!cfg->encode_load_metatables)
Branches [[0, 0]] missed. 51,342×
448
                return;
!
449

450
        /*
451
         * Try to call LUAL_SERIALIZE method on udata/cdata
452
         * LuaJIT specific: lua_getfield/lua_gettable raises exception on
453
         * cdata if field doesn't exist.
454
         */
455
        int top = lua_gettop(L);
51,342×
456
        lua_pushcfunction(L, lua_gettable_wrapper);
51,342×
457
        lua_pushvalue(L, idx);
51,342×
458
        lua_pushliteral(L, LUAL_SERIALIZE);
51,342×
459
        if (lua_pcall(L, 2, 1, 0) == 0  && !lua_isnil(L, -1)) {
51,342×
460
                if (!lua_isfunction(L, -1))
Branches [[0, 1]] missed. 51,287×
461
                        luaL_error(L, "invalid " LUAL_SERIALIZE  " value");
!
462
                /* copy object itself */
463
                lua_pushvalue(L, idx);
51,287×
464
                lua_pcall(L, 1, 1, 0);
51,287×
465
                /* replace obj with the unpacked value */
466
                lua_replace(L, idx);
51,287×
467
                if (luaL_tofield(L, cfg, serialized_objs_idx, NULL, idx,
Branches [[4294967295, 1]] missed. 51,287×
468
                                 field) < 0)
469
                        luaT_error(L);
!
470
        } /* else ignore lua_gettable exceptions */
471
        lua_settop(L, top); /* remove temporary objects */
51,342×
472
}
473

474
int
475
get_anchor(struct lua_State *L, int anchortable_index,
117,269×
476
           unsigned int *anchor_number, const char **anchor)
477
{
478
        lua_pushvalue(L, -1);
117,269×
479
        lua_rawget(L, anchortable_index);
117,269×
480
        if (lua_toboolean(L, -1) == 0) {
117,269×
481
                /* This element is not referenced. */
482
                lua_pop(L, 1);
117,143×
483
                *anchor = NULL;
117,143×
484
                return 0;
117,143×
485
        }
486

487
        if (lua_isboolean(L, -1) != 0) {
126×
488
                /*
489
                 * This element is referenced more than once but
490
                 * has not been named.
491
                 */
492
                char buf[32];
493
                snprintf(buf, sizeof(buf), "%u", (*anchor_number)++);
41×
494
                lua_pop(L, 1);
Branches [[0, 2]] missed. 41×
495
                /* Generate a string anchor and push to table. */
496
                lua_pushvalue(L, -1);
Branches [[0, 2]] missed. 41×
497
                lua_pushstring(L, buf);
Branches [[0, 2]] missed. 41×
498
                *anchor = lua_tostring(L, -1);
Branches [[0, 2]] missed. 41×
499
                lua_rawset(L, anchortable_index);
Branches [[0, 2]] missed. 41×
500
                return GET_ANCHOR_NAMED_NOT;
41×
501
        } else {
502
                /* This is an aliased element. */
503
                *anchor = lua_tostring(L, -1);
85×
504
                lua_pop(L, 1);
85×
505
                return GET_ANCHOR_ALIASED;
117,269×
506
        }
507
        return GET_ANCHOR_NO_REFS;
508
}
509

510
void
511
find_references_and_serialize(struct lua_State *L, int anchortable_index,
353,870×
512
                              int serialized_objs_idx)
513
{
514
        int type = lua_type(L, -1);
353,870×
515
        if (type != LUA_TTABLE)
353,870×
516
                return;
288,075×
517
        int node_idx = lua_gettop(L);
65,795×
518

519
        /*
520
         * Check if the node is already serialized i.e. the record
521
         * is already in the map of serialized objects.
522
         */
523
        lua_pushvalue(L, node_idx);
65,795×
524
        lua_rawget(L, serialized_objs_idx);
65,795×
525
        bool srlzd = lua_isnil(L, -1) == 0;
65,795×
526
        /*
527
         * This flag indicates that the object is being serialized
528
         * in the current function call.
529
         */
530
        bool serialization = false;
65,795×
531

532
        if (!srlzd && luaL_getmetafield(L, node_idx, LUAL_SERIALIZE) != 0 &&
69,208×
533
            lua_isfunction(L, -1) != 0) {
3,413×
534
                /* Delete nil after lua_rawget() above. */
535
                lua_replace(L, -2);
63×
536
                srlzd = true;
63×
537
                serialization = true;
63×
538
                /*
539
                 * Copy object itself and call serialize function
540
                 * for it.
541
                 */
542
                lua_pushvalue(L, node_idx);
63×
543
                if (lua_pcall(L, 1, 1, 0) != 0) {
63×
544
                        diag_set(LuajitError, lua_tostring(L, -1));
Branches [[0, 2]] missed. 1×
545
                        luaT_error(L);
1×
546
                }
547
                /*
548
                 * Add the result of serialization to the
549
                 * serialized_objs map. Key is node (node_idx),
550
                 * value is the result of serialization (now on
551
                 * the top of stack).
552
                 */
553
                lua_pushvalue(L, node_idx);
62×
554
                lua_pushvalue(L, -2);
62×
555
                lua_rawset(L, serialized_objs_idx);
62×
556
        }
557

558
        if (srlzd) {
65,794×
559
                if (lua_type(L, -1) == LUA_TTABLE) {
81×
560
                        /*
561
                         * Now we will process the new node - the
562
                         * result of serialization. It is
563
                         * necessary to take it into account in
564
                         * the anchor table.
565
                         */
566
                        node_idx = lua_gettop(L);
60×
567
                } else {
568
                        lua_pop(L, 1);
21×
569
                        return;
21×
570
                }
571
        } else {
572
                if (lua_isnil(L, -1) == 0)
65,713×
573
                        /*
574
                         * Pop an extra field thrown out
575
                         * by luaL_getmetafield(), it was
576
                         * not a function.
577
                         */
578
                        lua_pop(L, 1);
3,350×
579
                /* Delete nil after lua_rawget() above. */
580
                lua_pop(L, 1);
65,713×
581
        }
582
        /*
583
         * Take an entry from the anchor table about the current
584
         * node.
585
         */
586
        lua_pushvalue(L, node_idx);
65,773×
587
        lua_rawget(L, anchortable_index);
65,773×
588
        int newval = -1;
65,773×
589
        if (lua_isnil(L, -1) == 1)
65,773×
590
                /*
591
                 * The node has not yet been encountered, it is
592
                 * bypassed for the first time.
593
                 */
594
                newval = 0;
65,688×
595
        else if (lua_toboolean(L, -1) == 0)
85×
596
                 /* The node has already met once. */
597
                newval = 1;
41×
598
        lua_pop(L, 1);
65,773×
599
        if (newval != -1) {
65,773×
600
                lua_pushvalue(L, node_idx);
65,729×
601
                lua_pushboolean(L, newval);
65,729×
602
                lua_rawset(L, anchortable_index);
65,729×
603
        }
604
        if (srlzd && !serialization) {
65,773×
605
                /*
606
                 * The node has already been serialized not in the
607
                 * current call, so there is no point in going
608
                 * further in depth and checking the leaves. Pop
609
                 * the processed sterilization result.
610
                 */
611
                lua_pop(L, 1);
17×
612
                return;
17×
613
        }
614
        if (newval)
65,756×
615
                /* The node has already met twice or more, so
616
                 * there is no point in going further in depth and
617
                 * checking the leaves.
618
                 */
619
                return;
68×
620

621
        /* Recursively process other table values. */
622
        lua_pushnil(L);
65,688×
623
        while (lua_next(L, node_idx) != 0) {
221,900×
624
                /* Find references on value. */
625
                find_references_and_serialize(L, anchortable_index,
156,213×
626
                                              serialized_objs_idx);
627
                lua_pop(L, 1);
156,212×
628
                /* Find references on key. */
629
                find_references_and_serialize(L, anchortable_index,
156,212×
630
                                              serialized_objs_idx);
631
        }
632
        if (serialization)
65,687×
633
                /*
634
                 * The loop above processed the nodes inside the
635
                 * serialization result. Pop it, so as not to
636
                 * break the integrity of the loop of the previous
637
                 * call in recursion.
638
                 */
639
                lua_pop(L, 1);
43×
640

641
        return;
65,687×
642
}
643

644
enum try_serialize_ret_code
645
{
646

647
        TRY_SERIALIZE_ERROR = -1,
648
        TRY_SERIALIZE_RES_TABLE_NOT = 0,
649
        TRY_SERIALIZE_RES_FROM_MAP,
650
        TRY_SERIALIZE_DEFAULT_TABLE,
651
};
652

653
/**
654
 * Call __serialize method of a table object by index
655
 * if the former exists or pull result of serialization (if
656
 * exists) from table with index @a serialized_objs_idx if it
657
 * isn't 0.
658
 *
659
 * If __serialize does not exist then function does nothing
660
 * and the function returns TRY_SERIALIZE_DEFAULT_TABLE;
661
 *
662
 * If __serialize exists, is a function (which doesn't
663
 * raise any error) then a result of serialization
664
 * replaces old value by the index and the function returns
665
 * TRY_SERIALIZE_RES_TABLE_NOT or TRY_SERIALIZE_DEFAULT_TABLE;
666
 *
667
 * If the serialization is a hint string (like 'array' or 'map'),
668
 * then field->type, field->size and field->compact
669
 * are set if necessary and the function returns
670
 * TRY_SERIALIZE_RES_TABLE_NOT;
671
 *
672
 * Otherwise it is an error, set diag and the funciton returns
673
 * TRY_SERIALIZE_ERROR;
674
 *
675
 * Return values:
676
 * TRY_SERIALIZE_ERROR - error occurs, diag is set, the top of
677
 * guest stack is undefined.
678
 * TRY_SERIALIZE_RES_TABLE_NOT - __serialize field is available in
679
 * the metatable, the result value is put in the origin slot,
680
 * encoding is finished.
681
 * TRY_SERIALIZE_RES_FROM_MAP - __serialize field is available in
682
 * the metatable, the result value is table from serialized
683
 * objects map.
684
 * TRY_SERIALIZE_DEFAULT_TABLE - __serialize field is not
685
 * available in the metatable, proceed with default table
686
 * encoding.
687
 */
688

689
static int
690
lua_field_try_serialize(struct lua_State *L, int serialized_objs_idx,
6,118,442×
691
                        struct luaL_serializer *cfg, int idx,
692
                        struct luaL_field *field)
693
{
694
        if (luaL_getmetafield(L, idx, LUAL_SERIALIZE) == 0)
6,118,442×
695
                return TRY_SERIALIZE_DEFAULT_TABLE;
5,927,944×
696
        if (lua_isfunction(L, -1)) {
190,498×
697
                if (serialized_objs_idx != 0) {
86×
698
                        /*
699
                         * Pop the __serialize function for the
700
                         * current node. It was already called in
701
                         * find_references_and_serialize().
702
                         */
703
                        lua_pop(L, 1);
80×
704
                        /*
705
                         * Get the result of serialization from
706
                         * the map.
707
                         */
708
                        lua_pushvalue(L, idx);
80×
709
                        lua_rawget(L, serialized_objs_idx);
80×
710
                        assert(lua_isnil(L, -1) == 0);
Branches [[4294967295, 1]] missed. 80×
711

712
                        /*
713
                         * Replace the serialized node with a new
714
                         * result, if it is a table.
715
                         */
716
                        if (lua_type(L, -1) == LUA_TTABLE) {
80×
717
                                lua_replace(L, idx);
60×
718
                                return TRY_SERIALIZE_RES_FROM_MAP;
60×
719
                        }
720
                } else {
721
                        /*
722
                         * Serializer don't use map with
723
                         * serialized objects. Copy object itself
724
                         * and call __serialize for it.
725
                         */
726
                        lua_pushvalue(L, idx);
6×
727
                        if (lua_pcall(L, 1, 1, 0) != 0) {
6×
728
                                diag_set(LuajitError, lua_tostring(L, -1));
Branches [[0, 2]] missed. 1×
729
                                return TRY_SERIALIZE_ERROR;
1×
730
                        }
731
                }
732
                if (luaL_tofield(L, cfg, serialized_objs_idx, NULL, -1,
Branches [[0, 1]] missed. 25×
733
                                 field) != 0)
734
                        return TRY_SERIALIZE_ERROR;
!
735
                lua_replace(L, idx);
25×
736
                return TRY_SERIALIZE_RES_TABLE_NOT;
25×
737
        }
738
        if (!lua_isstring(L, -1)) {
Branches [[0, 1]] missed. 190,412×
739
                diag_set(LuajitError, "invalid " LUAL_SERIALIZE " value");
Branches [[0, 2], [0, 3]] missed. !
740
                return TRY_SERIALIZE_ERROR;
!
741
        }
742
        const char *type = lua_tostring(L, -1);
190,412×
743
        if (strcmp(type, "array") == 0 || strcmp(type, "seq") == 0 ||
190,412×
744
            strcmp(type, "sequence") == 0) {
138,496×
745
                field->type = MP_ARRAY; /* Override type */
51,917×
746
                field->size = luaL_arrlen(L, idx);
51,917×
747
                /* YAML: use flow mode if __serialize == 'seq' */
748
                if (cfg->has_compact && type[3] == '\0')
101,636×
749
                        field->compact = true;
49,719×
750
        } else if (strcmp(type, "map") == 0 || strcmp(type, "mapping") == 0) {
Branches [[1, 3]] missed. 138,495×
751
                field->type = MP_MAP;   /* Override type */
138,495×
752
                field->size = luaL_maplen(L, idx);
138,495×
753
                /* YAML: use flow mode if __serialize == 'map' */
754
                if (cfg->has_compact && type[3] == '\0')
143,113×
755
                        field->compact = true;
4,618×
756
        } else {
757
                diag_set(LuajitError, "invalid " LUAL_SERIALIZE " value");
Branches [[0, 2], [0, 3]] missed. !
758
                return TRY_SERIALIZE_ERROR;
!
759
        }
760
        /* Remove value set by luaL_getmetafield. */
761
        lua_pop(L, 1);
190,412×
762
        return TRY_SERIALIZE_RES_TABLE_NOT;
190,412×
763
}
764

765
static int
766
lua_field_inspect_table(struct lua_State *L, int serialized_objs_idx,
6,118,454×
767
                        struct luaL_serializer *cfg, int idx,
768
                        struct luaL_field *field)
769
{
770
        assert(lua_type(L, idx) == LUA_TTABLE);
Branches [[0, 1]] missed. 6,118,454×
771
        uint32_t size = 0;
6,118,454×
772
        uint32_t max = 0;
6,118,454×
773

774
        if (cfg->encode_load_metatables) {
6,118,454×
775
                int top = lua_gettop(L);
6,118,442×
776
                int res = lua_field_try_serialize(L, serialized_objs_idx, cfg,
6,118,442×
777
                                                  idx, field);
778
                if (res == TRY_SERIALIZE_ERROR)
6,118,442×
779
                        return -1;
1×
780
                assert(lua_gettop(L) == top);
Branches [[0, 1]] missed. 6,118,441×
781
                (void)top;
782
                if (res == TRY_SERIALIZE_RES_TABLE_NOT ||
6,118,441×
783
                    (res == TRY_SERIALIZE_RES_FROM_MAP &&
Branches [[4294967295, 0]] missed. 60×
784
                    lua_type(L, -1) != LUA_TTABLE))
60×
785
                        return 0;
190,437×
786
                /*
787
                 * Fallthrough with res TRY_SERIALIZE_RES_FROM_MAP
788
                 * or TRY_SERIALIZE_DEFAULT_TABLE.
789
                 */
790
        }
791

792
        field->type = MP_ARRAY;
5,928,016×
793

794
        /* Calculate size and check that table can represent an array */
795
        lua_pushnil(L);
5,928,016×
796
        while (lua_next(L, idx)) {
18,018,221×
797
                size++;
12,117,678×
798
                lua_pop(L, 1); /* pop the value */
12,117,678×
799
                lua_Number k;
800
                if (lua_type(L, -1) != LUA_TNUMBER ||
12,117,678×
801
                    ((k = lua_tonumber(L, -1)) != size &&
5,311×
802
                     (k < 1 || floor(k) != k))) {
Branches [[0, 0]] missed. 5,262×
803
                        /* Finish size calculation */
804
                        while (lua_next(L, idx)) {
58,553×
805
                                size++;
31,080×
806
                                lua_pop(L, 1); /* pop the value */
31,080×
807
                        }
808
                        field->type = MP_MAP;
27,473×
809
                        field->size = size;
27,473×
810
                        return 0;
27,473×
811
                }
812
                if (k > max)
12,090,205×
813
                        max = k;
12,090,184×
814
        }
815

816
        /* Encode excessively sparse arrays as objects (if enabled) */
817
        if (cfg->encode_sparse_ratio > 0 &&
5,900,543×
818
            max > size * (uint32_t)cfg->encode_sparse_ratio &&
43×
819
            max > (uint32_t)cfg->encode_sparse_safe) {
43×
820
                if (!cfg->encode_sparse_convert) {
26×
821
                        diag_set(LuajitError, "excessively sparse array");
Branches [[0, 2]] missed. 3×
822
                        return -1;
3×
823
                }
824
                field->type = MP_MAP;
23×
825
                field->size = size;
23×
826
                return 0;
23×
827
        }
828

829
        assert(field->type == MP_ARRAY);
Branches [[0, 0]] missed. 5,900,517×
830
        field->size = max;
5,900,517×
831
        return 0;
5,900,517×
832
}
833

834
static void
835
lua_field_tostring(struct lua_State *L, struct luaL_serializer *cfg, int idx,
861×
836
                   struct luaL_field *field)
837
{
838
        int top = lua_gettop(L);
861×
839
        lua_getglobal(L, "tostring");
861×
840
        lua_pushvalue(L, idx);
861×
841
        lua_call(L, 1, 1);
861×
842
        lua_replace(L, idx);
861×
843
        lua_settop(L, top);
861×
844
        if (luaL_tofield(L, cfg, 0, NULL, idx, field) < 0)
Branches [[4294967295, 1]] missed. 861×
845
                luaT_error(L);
!
846
}
861×
847

848
int
849
luaL_tofield(struct lua_State *L, struct luaL_serializer *cfg,
17,578,377×
850
             int serialized_objs_idx, const struct serializer_opts *opts,
851
             int index, struct luaL_field *field)
852
{
853
        if (index < 0)
17,578,377×
854
                index = lua_gettop(L) + index + 1;
Branches [[0, 2]] missed. 67,768×
855

856
        double num;
857
        double intpart;
858
        size_t size;
859

860
#define CHECK_NUMBER(x) ({                                                        \
861
        if (!isfinite(x) && !cfg->encode_invalid_numbers) {                        \
862
                if (!cfg->encode_invalid_as_nil) {                                \
863
                        diag_set(LuajitError, "number must not be NaN or Inf");        \
864
                        return -1;                                                \
865
                }                                                                \
866
                field->type = MP_NIL;                                                \
867
        }})
868

869
        switch (lua_type(L, index)) {
Branches [[0, 2]] missed. 17,578,377×
870
        case LUA_TNUMBER:
871
                num = lua_tonumber(L, index);
Branches [[0, 2]] missed. 5,344,967×
872
                if (isfinite(num) && modf(num, &intpart) != 0.0) {
5,344,967×
873
                        field->type = MP_DOUBLE;
104,628×
874
                        field->dval = num;
104,628×
875
                } else if (num >= 0 && num < exp2(64)) {
5,240,339×
876
                        field->type = MP_UINT;
5,233,529×
877
                        field->ival = (uint64_t) num;
5,233,529×
878
                } else if (num >= -exp2(63) && num < exp2(63)) {
6,810×
879
                        field->type = MP_INT;
6,684×
880
                        field->ival = (int64_t) num;
6,684×
881
                } else {
882
                        field->type = MP_DOUBLE;
126×
883
                        field->dval = num;
126×
884
                        CHECK_NUMBER(num);
Branches [[2, 5], [3, 9], [4, 10], [5, 13], [5, 14], [6, 17], [7, 20], [8, 23]] missed. 17,578,494×
885
                }
886
                return 0;
5,344,958×
887
        case LUA_TCDATA:
888
        {
889
                GCcdata *cd = cdataV(L->base + index - 1);
77,521×
890
                void *cdata = (void *)cdataptr(cd);
77,521×
891

892
                int64_t ival;
893
                switch (cd->ctypeid) {
77,521×
894
                case CTID_BOOL:
895
                        field->type = MP_BOOL;
18×
896
                        field->bval = *(bool*) cdata;
18×
897
                        return 0;
18×
898
                case CTID_CCHAR:
899
                case CTID_INT8:
900
                        ival = *(int8_t *) cdata;
5×
901
                        field->type = (ival >= 0) ? MP_UINT : MP_INT;
5×
902
                        field->ival = ival;
5×
903
                        return 0;
5×
904
                case CTID_INT16:
905
                        ival = *(int16_t *) cdata;
5×
906
                        field->type = (ival >= 0) ? MP_UINT : MP_INT;
5×
907
                        field->ival = ival;
5×
908
                        return 0;
5×
909
                case CTID_INT32:
910
                        ival = *(int32_t *) cdata;
17×
911
                        field->type = (ival >= 0) ? MP_UINT : MP_INT;
17×
912
                        field->ival = ival;
17×
913
                        return 0;
17×
914
                case CTID_INT64:
915
                        ival = *(int64_t *) cdata;
202×
916
                        field->type = (ival >= 0) ? MP_UINT : MP_INT;
202×
917
                        field->ival = ival;
202×
918
                        return 0;
202×
919
                case CTID_UINT8:
920
                        field->type = MP_UINT;
2×
921
                        field->ival = *(uint8_t *) cdata;
2×
922
                        return 0;
2×
923
                case CTID_UINT16:
924
                        field->type = MP_UINT;
5×
925
                        field->ival = *(uint16_t *) cdata;
5×
926
                        return 0;
5×
927
                case CTID_UINT32:
928
                        field->type = MP_UINT;
18×
929
                        field->ival = *(uint32_t *) cdata;
18×
930
                        return 0;
18×
931
                case CTID_UINT64:
932
                        field->type = MP_UINT;
2,423×
933
                        field->ival = *(uint64_t *) cdata;
2,423×
934
                        return 0;
2,423×
935
                case CTID_FLOAT:
936
                        field->type = MP_FLOAT;
20×
937
                        field->fval = *(float *) cdata;
20×
938
                        CHECK_NUMBER(field->fval);
Branches [[0, 0], [1, 2], [1, 3], [2, 4], [2, 5], [3, 8], [3, 9], [4, 10], [4, 11], [5, 13], [5, 14], [6, 16], [6, 17], [7, 19], [7, 20], [8, 22], [8, 23]] missed. 20×
939
                        return 0;
20×
940
                case CTID_DOUBLE:
941
                        field->type = MP_DOUBLE;
90×
942
                        field->dval = *(double *) cdata;
90×
943
                        CHECK_NUMBER(field->dval);
Branches [[0, 0], [1, 2], [1, 3], [2, 4], [2, 5], [3, 8], [3, 9], [4, 10], [4, 11], [5, 13], [5, 14], [6, 16], [6, 17], [7, 19], [7, 20], [8, 22], [8, 23]] missed. 90×
944
                        return 0;
90×
945
                case CTID_P_CVOID:
946
                case CTID_P_VOID:
947
                        if (*(void **) cdata == NULL) {
Branches [[0, 1]] missed. 19,634×
948
                                field->type = MP_NIL;
19,634×
949
                                return 0;
19,634×
950
                        }
951
                        /* Fall through */
952
                default:
953
                        field->type = MP_EXT;
55,082×
954
                        if (cd->ctypeid == CTID_DECIMAL) {
55,082×
955
                                field->ext_type = MP_DECIMAL;
1,945×
956
                                field->decval = (decimal_t *) cdata;
1,945×
957
                        } else if (cd->ctypeid == CTID_UUID) {
53,137×
958
                                field->ext_type = MP_UUID;
76×
959
                                field->uuidval = (struct tt_uuid *) cdata;
76×
960
                        } else if (cd->ctypeid == CTID_CONST_STRUCT_ERROR_REF &&
53,061×
961
                                   opts != NULL &&
5×
962
                                   opts->error_marshaling_enabled) {
5×
963
                                field->ext_type = MP_ERROR;
4×
964
                        } else {
965
                                field->ext_type = MP_UNKNOWN_EXTENSION;
53,057×
966
                        }
967
                }
968
                return 0;
55,082×
969
        }
970
        case LUA_TBOOLEAN:
971
                field->type = MP_BOOL;
213,041×
972
                field->bval = lua_toboolean(L, index);
Branches [[0, 2]] missed. 213,041×
973
                return 0;
213,041×
974
        case LUA_TNIL:
975
                field->type = MP_NIL;
4,243×
976
                return 0;
4,243×
977
        case LUA_TSTRING:
978
                field->sval.data = lua_tolstring(L, index, &size);
Branches [[0, 2]] missed. 5,819,336×
979
                field->sval.len = (uint32_t) size;
5,819,336×
980
                field->type = MP_STR;
5,819,336×
981
                return 0;
5,819,336×
982
        case LUA_TTABLE:
983
        {
984
                field->compact = false;
6,118,454×
985
                return lua_field_inspect_table(L, serialized_objs_idx, cfg,
Branches [[0, 2]] missed. 6,118,454×
986
                                               index, field);
987
        }
988
        case LUA_TLIGHTUSERDATA:
989
        case LUA_TUSERDATA:
990
                field->sval.data = NULL;
20×
991
                field->sval.len = 0;
20×
992
                if (lua_touserdata(L, index) == NULL) {
Branches [[0, 2], [1, 3]] missed. 20×
993
                        field->type = MP_NIL;
!
994
                        return 0;
!
995
                }
996
                /* Fall through */
997
        default:
998
                field->type = MP_EXT;
815×
999
                field->ext_type = MP_UNKNOWN_EXTENSION;
815×
1000
        }
1001
#undef CHECK_NUMBER
1002
        return 0;
815×
1003
}
1004

1005
void
1006
luaL_convertfield(struct lua_State *L, struct luaL_serializer *cfg,
52,164×
1007
                  int serialized_objs_idx, int idx, struct luaL_field *field)
1008
{
1009
        if (idx < 0)
52,164×
1010
                idx = lua_gettop(L) + idx + 1;
283×
1011
        assert(field->type == MP_EXT && field->ext_type == MP_UNKNOWN_EXTENSION); /* must be called after tofield() */
Branches [[0, 1], [1, 2]] missed. 52,164×
1012

1013
        if (cfg->encode_load_metatables) {
52,164×
1014
                int type = lua_type(L, idx);
52,146×
1015
                if (type == LUA_TCDATA) {
52,146×
1016
                        /*
1017
                         * Don't call __serialize on primitive types
1018
                         * https://github.com/tarantool/tarantool/issues/1226
1019
                         */
1020
                        GCcdata *cd = cdataV(L->base + idx - 1);
51,340×
1021
                        if (cd->ctypeid > CTID_CTYPEID)
51,340×
1022
                                lua_field_inspect_ucdata(L, cfg,
51,340×
1023
                                                         serialized_objs_idx, idx,
1024
                                                         field);
1025
                } else if (type == LUA_TUSERDATA) {
806×
1026
                        lua_field_inspect_ucdata(L, cfg, serialized_objs_idx, idx,
11×
1027
                                                 field);
1028
                }
1029
        }
1030

1031
        if (field->type == MP_EXT && field->ext_type == MP_UNKNOWN_EXTENSION &&
Branches [[1, 3]] missed. 52,164×
1032
            cfg->encode_use_tostring)
877×
1033
                lua_field_tostring(L, cfg, idx, field);
861×
1034

1035
        if (field->type != MP_EXT || field->ext_type != MP_UNKNOWN_EXTENSION)
Branches [[1, 2]] missed. 52,164×
1036
                return;
52,148×
1037

1038
        if (cfg->encode_invalid_as_nil) {
16×
1039
                field->type = MP_NIL;
6×
1040
                return;
6×
1041
        }
1042

1043
        luaL_error(L, "unsupported Lua type '%s'",
10×
1044
                   lua_typename(L, lua_type(L, idx)));
1045
}
1046

1047
/**
1048
 * A helper to register a single type metatable.
1049
 */
1050
void
1051
luaL_register_type(struct lua_State *L, const char *type_name,
17,092×
1052
                   const struct luaL_Reg *methods)
1053
{
1054
        luaL_newmetatable(L, type_name);
17,092×
1055
        /*
1056
         * Conventionally, make the metatable point to itself
1057
         * in __index. If 'methods' contain a field for __index,
1058
         * this is a no-op.
1059
         */
1060
        lua_pushvalue(L, -1);
17,092×
1061
        lua_setfield(L, -2, "__index");
17,092×
1062
        lua_pushstring(L, type_name);
17,092×
1063
        lua_setfield(L, -2, "__metatable");
17,092×
1064
        luaL_register(L, NULL, methods);
17,092×
1065
        lua_pop(L, 1);
17,092×
1066
}
17,092×
1067

1068
void
1069
luaL_register_module(struct lua_State *L, const char *modname,
49,375×
1070
                     const struct luaL_Reg *methods)
1071
{
1072
        assert(methods != NULL && modname != NULL); /* use luaL_register instead */
Branches [[0, 1], [1, 2]] missed. 49,375×
1073
        lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
49,375×
1074
        if (strchr(modname, '.') == NULL) {
49,375×
1075
                /* root level, e.g. box */
1076
                lua_getfield(L, -1, modname); /* get package.loaded.modname */
30,384×
1077
                if (!lua_istable(L, -1)) {  /* module is not found */
30,384×
1078
                        lua_pop(L, 1);  /* remove previous result */
24,687×
1079
                        lua_newtable(L);
24,687×
1080
                        lua_pushvalue(L, -1);
24,687×
1081
                        lua_setfield(L, -3, modname);  /* _LOADED[modname] = new table */
30,384×
1082
                }
1083
        } else {
1084
                /* 1+ level, e.g. box.space */
1085
                if (luaL_findtable(L, -1, modname, 0) != NULL)
Branches [[0, 1]] missed. 18,991×
1086
                        luaL_error(L, "Failed to register library");
!
1087
        }
1088
        lua_remove(L, -2);  /* remove _LOADED table */
49,375×
1089
        luaL_register(L, NULL, methods);
49,375×
1090
}
49,375×
1091

1092
/*
1093
 * Maximum integer that doesn't lose precision on tostring() conversion.
1094
 * Lua uses sprintf("%.14g") to format its numbers, see gh-1279.
1095
 */
1096
#define DBL_INT_MAX (1e14 - 1)
1097
#define DBL_INT_MIN (-1e14 + 1)
1098

1099
void
1100
luaL_pushuint64(struct lua_State *L, uint64_t val)
1,046,445×
1101
{
1102
#if defined(LJ_DUALNUM) /* see setint64V() */
1103
        if (val <= INT32_MAX) {
1,046,445×
1104
                /* push int32_t */
1105
                lua_pushinteger(L, (int32_t) val);
1,044,447×
1106
        } else
1107
#endif /* defined(LJ_DUALNUM) */
1108
        if (val <= DBL_INT_MAX) {
1,998×
1109
                /* push double */
1110
                lua_pushnumber(L, (double) val);
39×
1111
        } else {
1112
                /* push uint64_t */
1113
                *(uint64_t *) luaL_pushcdata(L, CTID_UINT64) = val;
1,959×
1114
        }
1115
}
1,046,445×
1116

1117
void
1118
luaL_pushint64(struct lua_State *L, int64_t val)
1,267,718×
1119
{
1120
#if defined(LJ_DUALNUM) /* see setint64V() */
1121
        if (val >= INT32_MIN && val <= INT32_MAX) {
1,267,718×
1122
                /* push int32_t */
1123
                lua_pushinteger(L, (int32_t) val);
1,265,320×
1124
        } else
1125
#endif /* defined(LJ_DUALNUM) */
1126
        if (val >= DBL_INT_MIN && val <= DBL_INT_MAX) {
2,398×
1127
                /* push double */
1128
                lua_pushnumber(L, (double) val);
50×
1129
        } else {
1130
                /* push int64_t */
1131
                *(int64_t *) luaL_pushcdata(L, CTID_INT64) = val;
2,348×
1132
        }
1133
}
1,267,718×
1134

1135
static inline int
1136
luaL_convertint64(lua_State *L, int idx, bool unsignd, int64_t *result)
56,820×
1137
{
1138
        uint32_t ctypeid;
1139
        void *cdata;
1140
        /*
1141
         * This code looks mostly like luaL_tofield(), but has less
1142
         * cases and optimized for numbers.
1143
         */
1144
        switch (lua_type(L, idx)) {
Branches [[0, 2]] missed. 56,820×
1145
        case LUA_TNUMBER:
1146
                *result = lua_tonumber(L, idx);
Branches [[0, 2]] missed. 50,206×
1147
                return 0;
56,820×
1148
        case LUA_TCDATA:
1149
                cdata = luaL_checkcdata(L, idx, &ctypeid);
Branches [[0, 2]] missed. 85×
1150
                switch (ctypeid) {
Branches [[0, 0], [0, 1], [0, 2], [0, 4], [0, 5], [0, 6]] missed. 85×
1151
                case CTID_CCHAR:
1152
                case CTID_INT8:
1153
                        *result = *(int8_t *) cdata;
!
1154
                        return 0;
!
1155
                case CTID_INT16:
1156
                        *result = *(int16_t *) cdata;
!
1157
                        return 0;
!
1158
                case CTID_INT32:
1159
                        *result = *(int32_t *) cdata;
!
1160
                        return 0;
!
1161
                case CTID_INT64:
1162
                        *result = *(int64_t *) cdata;
56×
1163
                        return 0;
56×
1164
                case CTID_UINT8:
1165
                        *result = *(uint8_t *) cdata;
!
1166
                        return 0;
!
1167
                case CTID_UINT16:
1168
                        *result = *(uint16_t *) cdata;
!
1169
                        return 0;
!
1170
                case CTID_UINT32:
1171
                        *result = *(uint32_t *) cdata;
!
1172
                        return 0;
!
1173
                case CTID_UINT64:
1174
                        *result = *(uint64_t *) cdata;
27×
1175
                        return 0;
27×
1176
                }
1177
                *result = 0;
2×
1178
                return -1;
2×
1179
        case LUA_TSTRING:
1180
        {
1181
                const char *arg = luaL_checkstring(L, idx);
Branches [[0, 2]] missed. 4×
1182
                char *arge;
1183
                errno = 0;
4×
1184
                *result = (unsignd ? (long long) strtoull(arg, &arge, 10) :
4×
1185
                        strtoll(arg, &arge, 10));
1186
                if (errno == 0 && arge != arg)
Branches [[0, 2]] missed. 4×
1187
                        return 0;
4×
1188
                return 1;
2×
1189
        }
1190
        }
1191
        *result = 0;
6,525×
1192
        return -1;
6,525×
1193
}
1194

1195
uint64_t
1196
luaL_checkuint64(struct lua_State *L, int idx)
43×
1197
{
1198
        int64_t result;
1199
        if (luaL_convertint64(L, idx, true, &result) != 0) {
Branches [[0, 2], [1, 3]] missed. 43×
1200
                lua_pushfstring(L, "expected uint64_t as %d argument", idx);
Branches [[0, 1], [0, 2]] missed. !
1201
                lua_error(L);
Branches [[0, 1], [0, 2]] missed. !
1202
                return 0;
43×
1203
        }
1204
        return result;
43×
1205
}
1206

1207
int64_t
1208
luaL_checkint64(struct lua_State *L, int idx)
80×
1209
{
1210
        int64_t result;
1211
        if (luaL_convertint64(L, idx, false, &result) != 0) {
Branches [[0, 2], [1, 3]] missed. 80×
1212
                lua_pushfstring(L, "expected int64_t as %d argument", idx);
Branches [[0, 1], [0, 2]] missed. !
1213
                lua_error(L);
Branches [[0, 1], [0, 2]] missed. !
1214
                return 0;
80×
1215
        }
1216
        return result;
80×
1217
}
1218

1219
uint64_t
1220
luaL_touint64(struct lua_State *L, int idx)
21,395×
1221
{
1222
        int64_t result;
1223
        if (luaL_convertint64(L, idx, true, &result) == 0)
Branches [[0, 2]] missed. 21,395×
1224
                return result;
21,395×
1225
        return 0;
1×
1226
}
1227

1228
int64_t
1229
luaL_toint64(struct lua_State *L, int idx)
35,302×
1230
{
1231
        int64_t result;
1232
        if (luaL_convertint64(L, idx, false, &result) == 0)
Branches [[0, 2]] missed. 35,302×
1233
                return result;
35,302×
1234
        return 0;
6,528×
1235
}
1236

1237

1238
int
1239
luaT_toerror(lua_State *L)
587×
1240
{
1241
        struct error *e = luaL_iserror(L, -1);
587×
1242
        if (e != NULL) {
587×
1243
                /* Re-throw original error */
1244
                diag_set_error(&fiber()->diag, e);
427×
1245
        } else {
1246
                /* Convert Lua error to a Tarantool exception. */
1247
                diag_set(LuajitError, luaT_tolstring(L, -1, NULL));
Branches [[0, 2]] missed. 160×
1248
        }
1249
        return 1;
587×
1250
}
1251

1252
int
1253
luaT_call(struct lua_State *L, int nargs, int nreturns)
397,595×
1254
{
1255
        if (lua_pcall(L, nargs, nreturns, 0))
397,595×
1256
                return luaT_toerror(L);
584×
1257
        return 0;
387,856×
1258
}
1259

1260
int
1261
luaT_cpcall(lua_State *L, lua_CFunction func, void *ud)
26×
1262
{
1263
        if (lua_cpcall(L, func, ud))
26×
1264
                return luaT_toerror(L);
1×
1265
        return 0;
25×
1266
}
1267

1268
/**
1269
 * This function exists because lua_tostring does not use
1270
 * __tostring metamethod, and this metamethod has to be used
1271
 * if we want to print Lua userdata correctly.
1272
 */
1273
const char *
1274
luaT_tolstring(lua_State *L, int idx, size_t *len)
168×
1275
{
1276
        if (!luaL_callmeta(L, idx, "__tostring")) {
168×
1277
                switch (lua_type(L, idx)) {
167×
1278
                case LUA_TNUMBER:
1279
                case LUA_TSTRING:
1280
                        lua_pushvalue(L, idx);
163×
1281
                        break;
163×
1282
                case LUA_TBOOLEAN: {
1283
                        int val = lua_toboolean(L, idx);
2×
1284
                        lua_pushstring(L, val ? "true" : "false");
2×
1285
                        break;
2×
1286
                }
1287
                case LUA_TNIL:
1288
                        lua_pushliteral(L, "nil");
1×
1289
                        break;
1×
1290
                default:
1291
                        lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
1×
1292
                                                     lua_topointer(L, idx));
1293
                }
1294
        }
1295

1296
        return lua_tolstring(L, -1, len);
168×
1297
}
1298

1299
/* Based on ffi_meta___call() from luajit/src/lib_ffi.c. */
1300
static int
1301
luaL_cdata_iscallable(lua_State *L, int idx)
4×
1302
{
1303
        /* Calculate absolute value in the stack. */
1304
        if (idx < 0)
Branches [[0, 0]] missed. 4×
1305
                idx = lua_gettop(L) + idx + 1;
!
1306

1307
        /* Get cdata from the stack. */
1308
        assert(lua_type(L, idx) == LUA_TCDATA);
Branches [[0, 1]] missed. 4×
1309
        GCcdata *cd = cdataV(L->base + idx - 1);
4×
1310

1311
        CTState *cts = ctype_cts(L);
4×
1312
        CTypeID id = cd->ctypeid;
4×
1313
        CType *ct = ctype_raw(cts, id);
4×
1314
        if (ctype_isptr(ct->info))
4×
1315
                id = ctype_cid(ct->info);
2×
1316

1317
        /* Get ctype metamethod. */
1318
        cTValue *tv = lj_ctype_meta(cts, id, MM_call);
4×
1319

1320
        return tv != NULL;
4×
1321
}
1322

1323
int
1324
luaL_iscallable(lua_State *L, int idx)
32,992×
1325
{
1326
        /* Whether it is function. */
1327
        int res = lua_isfunction(L, idx);
32,992×
1328
        if (res == 1)
32,992×
1329
                return 1;
20,728×
1330

1331
        /* Whether it is cdata with metatype with __call field. */
1332
        if (lua_type(L, idx) == LUA_TCDATA)
12,264×
1333
                return luaL_cdata_iscallable(L, idx);
4×
1334

1335
        /* Whether it has metatable with __call field. */
1336
        res = luaL_getmetafield(L, idx, "__call");
12,260×
1337
        if (res == 1)
12,260×
1338
                lua_pop(L, 1); /* Pop __call value. */
12,253×
1339
        return res;
12,260×
1340
}
1341

1342
box_ibuf_t *
1343
luaT_toibuf(struct lua_State *L, int idx)
7,759×
1344
{
1345
        if (lua_type(L, idx) != LUA_TCDATA)
Branches [[0, 2]] missed. 7,759×
1346
                return NULL;
7,759×
1347
        uint32_t cdata_type;
1348
        void *cdata = luaL_checkcdata(L, idx, &cdata_type);
Branches [[0, 2]] missed. 7,753×
1349
        if (cdata_type == CTID_STRUCT_IBUF)
7,753×
1350
                return (box_ibuf_t *) cdata;
7,732×
1351
        if (cdata_type == CTID_STRUCT_IBUF_PTR && cdata != NULL)
Branches [[1, 3]] missed. 21×
1352
                return *(box_ibuf_t **) cdata;
14×
1353
        return NULL;
7×
1354
}
1355

1356
int
1357
luaL_checkconstchar(struct lua_State *L, int idx, const char **res,
58,851×
1358
                    uint32_t *cdata_type_p)
1359
{
1360
        if (lua_type(L, idx) != LUA_TCDATA)
Branches [[0, 2]] missed. 58,851×
1361
                return -1;
58,851×
1362
        uint32_t cdata_type;
1363
        void *cdata = luaL_checkcdata(L, idx, &cdata_type);
Branches [[0, 2]] missed. 58,847×
1364
        if (cdata_type != CTID_CHAR_PTR && cdata_type != CTID_CONST_CHAR_PTR)
58,847×
1365
                return -1;
4×
1366
        *res = cdata != NULL ? *(const char **) cdata : NULL;
Branches [[0, 1]] missed. 58,843×
1367
        *cdata_type_p = cdata_type;
58,843×
1368
        return 0;
58,843×
1369
}
1370

1371
lua_State *
1372
luaT_state(void)
1×
1373
{
1374
        return tarantool_L;
1×
1375
}
1376

1377
/* {{{ Helper functions to interact with a Lua iterator from C */
1378

1379
struct luaL_iterator {
1380
        int gen;
1381
        int param;
1382
        int state;
1383
};
1384

1385
struct luaL_iterator *
1386
luaL_iterator_new(lua_State *L, int idx)
32,986×
1387
{
1388
        struct luaL_iterator *it = malloc(sizeof(struct luaL_iterator));
32,986×
1389
        if (it == NULL) {
Branches [[0, 0]] missed. 32,986×
1390
                diag_set(OutOfMemory, sizeof(struct luaL_iterator),
Branches [[0, 2], [0, 3]] missed. !
1391
                         "malloc", "luaL_iterator");
1392
                return NULL;
!
1393
        }
1394

1395
        if (idx == 0) {
32,986×
1396
                /* gen, param, state are on top of a Lua stack. */
1397
                lua_pushvalue(L, -3); /* Popped by luaL_ref(). */
32,983×
1398
                it->gen = luaL_ref(L, LUA_REGISTRYINDEX);
32,983×
1399
                lua_pushvalue(L, -2); /* Popped by luaL_ref(). */
32,983×
1400
                it->param = luaL_ref(L, LUA_REGISTRYINDEX);
32,983×
1401
                lua_pushvalue(L, -1); /* Popped by luaL_ref(). */
32,983×
1402
                it->state = luaL_ref(L, LUA_REGISTRYINDEX);
32,983×
1403
        } else {
1404
                /*
1405
                 * {gen, param, state} table is at idx in a Lua
1406
                 * stack.
1407
                 */
1408
                lua_rawgeti(L, idx, 1); /* Popped by luaL_ref(). */
3×
1409
                it->gen = luaL_ref(L, LUA_REGISTRYINDEX);
3×
1410
                lua_rawgeti(L, idx, 2); /* Popped by luaL_ref(). */
3×
1411
                it->param = luaL_ref(L, LUA_REGISTRYINDEX);
3×
1412
                lua_rawgeti(L, idx, 3); /* Popped by luaL_ref(). */
3×
1413
                it->state = luaL_ref(L, LUA_REGISTRYINDEX);
3×
1414
        }
1415

1416
        return it;
32,986×
1417
}
1418

1419
int
1420
luaL_iterator_next(lua_State *L, struct luaL_iterator *it)
74,261×
1421
{
1422
        int frame_start = lua_gettop(L);
74,261×
1423

1424
        /* Call gen(param, state). */
1425
        lua_rawgeti(L, LUA_REGISTRYINDEX, it->gen);
74,261×
1426
        lua_rawgeti(L, LUA_REGISTRYINDEX, it->param);
74,261×
1427
        lua_rawgeti(L, LUA_REGISTRYINDEX, it->state);
74,261×
1428
        if (luaT_call(L, 2, LUA_MULTRET) != 0) {
74,261×
1429
                /*
1430
                 * Pop garbage from the call (a gen function
1431
                 * likely will not leave the stack even when raise
1432
                 * an error), pop a returned error.
1433
                 */
1434
                lua_settop(L, frame_start);
1×
1435
                return -1;
1×
1436
        }
1437
        int nresults = lua_gettop(L) - frame_start;
74,260×
1438

1439
        /*
1440
         * gen() function can either return nil when the iterator
1441
         * ends or return zero count of values.
1442
         *
1443
         * In LuaJIT pairs() returns nil, but ipairs() returns
1444
         * nothing when ends.
1445
         */
1446
        if (nresults == 0 || lua_isnil(L, frame_start + 1)) {
74,260×
1447
                lua_settop(L, frame_start);
32,968×
1448
                return 0;
32,968×
1449
        }
1450

1451
        /* Save the first result to it->state. */
1452
        luaL_unref(L, LUA_REGISTRYINDEX, it->state);
41,292×
1453
        lua_pushvalue(L, frame_start + 1); /* Popped by luaL_ref(). */
41,292×
1454
        it->state = luaL_ref(L, LUA_REGISTRYINDEX);
41,292×
1455

1456
        return nresults;
41,292×
1457
}
1458

1459
void luaL_iterator_delete(struct luaL_iterator *it)
31,854×
1460
{
1461
        luaL_unref(tarantool_L, LUA_REGISTRYINDEX, it->gen);
31,854×
1462
        luaL_unref(tarantool_L, LUA_REGISTRYINDEX, it->param);
31,854×
1463
        luaL_unref(tarantool_L, LUA_REGISTRYINDEX, it->state);
31,854×
1464
        free(it);
31,854×
1465
}
31,854×
1466

1467
/* }}} */
1468

1469
/**
1470
 * @brief A wrapper for <lua_newthread> to be called via luaT_call
1471
 * in luaT_newthread. Whether new Lua coroutine is created it is
1472
 * returned on the top of the guest stack.
1473
 * @param L is a Lua state
1474
 * @sa <lua_newthread>
1475
 */
1476
static int
1477
luaT_newthread_wrapper(struct lua_State *L)
114,103×
1478
{
1479
        (void)lua_newthread(L);
114,103×
1480
        return 1;
114,103×
1481
}
1482

1483
struct lua_State *
1484
luaT_newthread(struct lua_State *L)
114,103×
1485
{
1486
        assert(luaT_newthread_ref != LUA_NOREF);
Branches [[0, 0]] missed. 114,103×
1487
        lua_rawgeti(L, LUA_REGISTRYINDEX, luaT_newthread_ref);
114,103×
1488
        assert(lua_isfunction(L, -1));
Branches [[4294967295, 1]] missed. 114,103×
1489
        if (luaT_call(L, 0, 1) != 0)
Branches [[0, 1]] missed. 114,103×
1490
                return NULL;
!
1491
        struct lua_State *L1 = lua_tothread(L, -1);
114,103×
1492
        assert(L1 != NULL);
Branches [[4294967295, 0]] missed. 114,103×
1493
        return L1;
114,103×
1494
}
1495

1496
int
1497
tarantool_lua_utils_init(struct lua_State *L)
1,899×
1498
{
1499
        static const struct luaL_Reg serializermeta[] = {
1500
                {NULL, NULL},
1501
        };
1502

1503
        luaL_register_type(L, LUAL_SERIALIZER, serializermeta);
1,899×
1504
        /* Create NULL constant */
1505
        *(void **) luaL_pushcdata(L, CTID_P_VOID) = NULL;
1,899×
1506
        luaL_nil_ref = luaL_ref(L, LUA_REGISTRYINDEX);
1,899×
1507

1508
        lua_createtable(L, 0, 1);
1,899×
1509
        lua_pushliteral(L, "map"); /* YAML will use flow mode */
1,899×
1510
        lua_setfield(L, -2, LUAL_SERIALIZE);
1,899×
1511
        /* automatically reset hints on table change */
1512
        luaL_loadstring(L, "setmetatable((...), nil); return rawset(...)");
1,899×
1513
        lua_setfield(L, -2, "__newindex");
1,899×
1514
        luaL_map_metatable_ref = luaL_ref(L, LUA_REGISTRYINDEX);
1,899×
1515

1516
        lua_createtable(L, 0, 1);
1,899×
1517
        lua_pushliteral(L, "seq"); /* YAML will use flow mode */
1,899×
1518
        lua_setfield(L, -2, LUAL_SERIALIZE);
1,899×
1519
        /* automatically reset hints on table change */
1520
        luaL_loadstring(L, "setmetatable((...), nil); return rawset(...)");
1,899×
1521
        lua_setfield(L, -2, "__newindex");
1,899×
1522
        luaL_array_metatable_ref = luaL_ref(L, LUA_REGISTRYINDEX);
1,899×
1523

1524
        int rc = luaL_cdef(L, "struct ibuf;");
1,899×
1525
        assert(rc == 0);
Branches [[4294967295, 0]] missed. 1,899×
1526
        CTID_STRUCT_IBUF = luaL_ctypeid(L, "struct ibuf");
1,899×
1527
        assert(CTID_STRUCT_IBUF != 0);
Branches [[4294967295, 0]] missed. 1,899×
1528
        CTID_STRUCT_IBUF_PTR = luaL_ctypeid(L, "struct ibuf *");
1,899×
1529
        assert(CTID_STRUCT_IBUF_PTR != 0);
Branches [[4294967295, 0]] missed. 1,899×
1530
        CTID_CHAR_PTR = luaL_ctypeid(L, "char *");
1,899×
1531
        assert(CTID_CHAR_PTR != 0);
Branches [[4294967295, 0]] missed. 1,899×
1532
        CTID_CONST_CHAR_PTR = luaL_ctypeid(L, "const char *");
1,899×
1533
        assert(CTID_CONST_CHAR_PTR != 0);
Branches [[4294967295, 0]] missed. 1,899×
1534
        rc = luaL_cdef(L, "struct tt_uuid {"
1,899×
1535
                                  "uint32_t time_low;"
1536
                                  "uint16_t time_mid;"
1537
                                  "uint16_t time_hi_and_version;"
1538
                                  "uint8_t clock_seq_hi_and_reserved;"
1539
                                  "uint8_t clock_seq_low;"
1540
                                  "uint8_t node[6];"
1541
                          "};");
1542
        assert(rc == 0);
Branches [[4294967295, 0]] missed. 1,899×
1543
        (void) rc;
1544
        CTID_UUID = luaL_ctypeid(L, "struct tt_uuid");
1,899×
1545
        assert(CTID_UUID != 0);
Branches [[4294967295, 0]] missed. 1,899×
1546

1547
        lua_pushcfunction(L, luaT_newthread_wrapper);
1,899×
1548
        luaT_newthread_ref = luaL_ref(L, LUA_REGISTRYINDEX);
1,899×
1549
        return 0;
1,899×
1550
}
1551

1552
/*
1553
 * XXX: There is already defined <panic> macro in say.h header
1554
 * (included in diag.h). As a result the call below is misexpanded
1555
 * and compilation fails with the corresponding error. To avoid
1556
 * this error the macro is undefined since it's not used anymore
1557
 * in scope of this translation unit.
1558
 */
1559
#undef panic
1560

1561
/**
1562
 * This routine encloses the checks and actions to be done when
1563
 * the running fiber yields the execution.
1564
 * Since Tarantool fibers don't switch-over the way Lua coroutines
1565
 * do the platform ought to notify JIT engine when one lua_State
1566
 * substitutes another one. Furthermore fiber switch is forbidden
1567
 * when GC hook (i.e. __gc metamethod) is running.
1568
 */
1569
void cord_on_yield(void)
4,857,634×
1570
{
1571
        struct global_State *g = G(tarantool_L);
4,857,634×
1572
        /*
1573
         * XXX: Switching fibers while running the trace leads to
1574
         * code misbehaviour and failures, so stop its execution.
1575
         */
1576
        if (unlikely(tvref(g->jit_base))) {
4,857,634×
1577
                /*
1578
                 * XXX: mcode is executed only in scope of Lua
1579
                 * world and one can obtain the corresponding Lua
1580
                 * coroutine from the fiber storage.
1581
                 */
1582
                struct lua_State *L = fiber()->storage.lua.stack;
1×
1583
                assert(L != NULL);
Branches [[0, 0]] missed. 1×
1584
                lua_pushfstring(L, "fiber %d is switched while running the"
1×
1585
                                " compiled code (it's likely a function with"
1586
                                " a yield underneath called via LuaJIT FFI)",
1587
                                fiber()->fid);
1×
1588
                if (g->panic)
Branches [[4294967295, 1]] missed. 1×
1589
                        g->panic(L);
1×
1590
                exit(EXIT_FAILURE);
1×
1591
        }
1592
        /*
1593
         * Unconditionally abort trace recording whether fibers
1594
         * switch each other. Otherwise, further compilation may
1595
         * lead to a failure on any next compiler phase.
1596
         */
1597
        lj_trace_abort(g);
4,857,633×
1598

1599
        /*
1600
         * XXX: While running GC hook (i.e. __gc  metamethod)
1601
         * garbage collector is formally "stopped" since the
1602
         * memory penalty threshold is set to its maximum value,
1603
         * ergo incremental GC step is not triggered. Thereby,
1604
         * yielding the execution at this point leads to further
1605
         * running platform with disabled LuaJIT GC. The fiber
1606
         * doesn't get the execution back until it's ready, so
1607
         * in pessimistic scenario LuaJIT OOM might occur
1608
         * earlier. As a result fiber switch is prohibited when
1609
         * GC hook is active and the platform is forced to stop.
1610
         */
1611
        if (unlikely(g->hookmask & HOOK_GC)) {
4,857,633×
1612
                struct lua_State *L = fiber()->storage.lua.stack;
1×
1613
                assert(L != NULL);
Branches [[0, 0]] missed. 1×
1614
                lua_pushfstring(L, "fiber %d is switched while running GC"
1×
1615
                                " finalizer (i.e. __gc metamethod)",
1616
                                fiber()->fid);
1×
1617
                if (g->panic)
Branches [[4294967295, 1]] missed. 1×
1618
                        g->panic(L);
1×
1619
                exit(EXIT_FAILURE);
1×
1620
        }
1621
}
4,857,632×
Troubleshooting · Open an Issue · Sales · Support · ENTERPRISE · CAREERS · STATUS
BLOG · TWITTER · Legal & Privacy · Supported CI Services · What's a CI service? · Automated Testing

© 2022 Coveralls, Inc