diff options
| author | Mike Pall <mike> | 2021-08-12 21:10:13 +0200 |
|---|---|---|
| committer | Mike Pall <mike> | 2021-08-12 21:27:58 +0200 |
| commit | 15ed84bd499b3ecdba9f431f2d24696a313227e4 (patch) | |
| tree | 637662b1edce646fec939e8bf75685a09e374656 | |
| parent | 983d66b8c5032b421e0f5fe8d39e9930bceb7031 (diff) | |
| download | luajit-15ed84bd499b3ecdba9f431f2d24696a313227e4.tar.gz luajit-15ed84bd499b3ecdba9f431f2d24696a313227e4.tar.bz2 luajit-15ed84bd499b3ecdba9f431f2d24696a313227e4.zip | |
String buffers, part 4a: Add metatable serialization dictionary.
Sponsored by fmad.io.
| -rw-r--r-- | doc/ext_buffer.html | 45 | ||||
| -rw-r--r-- | src/lib_buffer.c | 17 | ||||
| -rw-r--r-- | src/lj_buf.h | 3 | ||||
| -rw-r--r-- | src/lj_gc.c | 6 | ||||
| -rw-r--r-- | src/lj_serialize.c | 83 | ||||
| -rw-r--r-- | src/lj_serialize.h | 3 |
6 files changed, 116 insertions, 41 deletions
diff --git a/doc/ext_buffer.html b/doc/ext_buffer.html index 2443fc90..63c2efe3 100644 --- a/doc/ext_buffer.html +++ b/doc/ext_buffer.html | |||
| @@ -127,7 +127,7 @@ space. | |||
| 127 | <p> | 127 | <p> |
| 128 | Buffers operate like a FIFO (first-in first-out) data structure. Data | 128 | Buffers operate like a FIFO (first-in first-out) data structure. Data |
| 129 | can be appended (written) to the end of the buffer and consumed (read) | 129 | can be appended (written) to the end of the buffer and consumed (read) |
| 130 | from the front of the buffer. These operations can be freely mixed. | 130 | from the front of the buffer. These operations may be freely mixed. |
| 131 | </p> | 131 | </p> |
| 132 | <p> | 132 | <p> |
| 133 | The buffer space that holds the characters is managed automatically | 133 | The buffer space that holds the characters is managed automatically |
| @@ -199,7 +199,7 @@ may be reused. | |||
| 199 | <h3 id="buffer_free"><tt>buf = buf:free()</tt></h3> | 199 | <h3 id="buffer_free"><tt>buf = buf:free()</tt></h3> |
| 200 | <p> | 200 | <p> |
| 201 | The buffer space of the buffer object is freed. The object itself | 201 | The buffer space of the buffer object is freed. The object itself |
| 202 | remains intact, empty and it may be reused. | 202 | remains intact, empty and may be reused. |
| 203 | </p> | 203 | </p> |
| 204 | <p> | 204 | <p> |
| 205 | Note: you normally don't need to use this method. The garbage collector | 205 | Note: you normally don't need to use this method. The garbage collector |
| @@ -404,8 +404,8 @@ speed is mostly constrained by object creation cost. | |||
| 404 | </p> | 404 | </p> |
| 405 | <p> | 405 | <p> |
| 406 | The serializer handles most Lua types, common FFI number types and | 406 | The serializer handles most Lua types, common FFI number types and |
| 407 | nested structures. Functions, thread objects, other FFI cdata, full | 407 | nested structures. Functions, thread objects, other FFI cdata and full |
| 408 | userdata and associated metatables cannot be serialized (yet). | 408 | userdata cannot be serialized (yet). |
| 409 | </p> | 409 | </p> |
| 410 | <p> | 410 | <p> |
| 411 | The encoder serializes nested structures as trees. Multiple references | 411 | The encoder serializes nested structures as trees. Multiple references |
| @@ -461,21 +461,31 @@ commonly occur as table keys of objects you are serializing. These keys | |||
| 461 | are compactly encoded as indexes during serialization. A well chosen | 461 | are compactly encoded as indexes during serialization. A well chosen |
| 462 | dictionary saves space and improves serialization performance. | 462 | dictionary saves space and improves serialization performance. |
| 463 | </li> | 463 | </li> |
| 464 | <li> | ||
| 465 | <tt>metatable</tt> is a Lua table holding a <b>dictionary of metatables</b> | ||
| 466 | for the table objects you are serializing. | ||
| 467 | </li> | ||
| 464 | </ul> | 468 | </ul> |
| 465 | <p> | 469 | <p> |
| 466 | <tt>dict</tt> needs to be an array of strings, starting at index 1 and | 470 | <tt>dict</tt> needs to be an array of strings and <tt>metatable</tt> needs |
| 467 | without holes (no <tt>nil</tt> inbetween). The table is anchored in the | 471 | to be an array of tables. Both starting at index 1 and without holes (no |
| 468 | buffer object and internally modified into a two-way index (don't do | 472 | <tt>nil</tt> inbetween). The tables are anchored in the buffer object and |
| 469 | this yourself, just pass a plain array). The table must not be modified | 473 | internally modified into a two-way index (don't do this yourself, just pass |
| 470 | after it has been passed to <tt>buffer.new()</tt>. | 474 | a plain array). The tables must not be modified after they have been passed |
| 475 | to <tt>buffer.new()</tt>. | ||
| 476 | </p> | ||
| 477 | <p> | ||
| 478 | The <tt>dict</tt> and <tt>metatable</tt> tables used by the encoder and | ||
| 479 | decoder must be the same. Put the most common entries at the front. Extend | ||
| 480 | at the end to ensure backwards-compatibility — older encodings can | ||
| 481 | then still be read. You may also set some indexes to <tt>false</tt> to | ||
| 482 | explicitly drop backwards-compatibility. Old encodings that use these | ||
| 483 | indexes will throw an error when decoded. | ||
| 471 | </p> | 484 | </p> |
| 472 | <p> | 485 | <p> |
| 473 | The <tt>dict</tt> tables used by the encoder and decoder must be the | 486 | Metatables that are not found in the <tt>metatable</tt> dictionary are |
| 474 | same. Put the most common entries at the front. Extend at the end to | 487 | ignored when encoding. Decoding returns a table with a <tt>nil</tt> |
| 475 | ensure backwards-compatibility — older encodings can then still be | 488 | metatable. |
| 476 | read. You may also set some indexes to <tt>false</tt> to explicitly drop | ||
| 477 | backwards-compatibility. Old encodings that use these indexes will throw | ||
| 478 | an error when decoded. | ||
| 479 | </p> | 489 | </p> |
| 480 | <p> | 490 | <p> |
| 481 | Note: parsing and preparation of the options table is somewhat | 491 | Note: parsing and preparation of the options table is somewhat |
| @@ -564,7 +574,7 @@ suffix. | |||
| 564 | <pre> | 574 | <pre> |
| 565 | object → nil | false | true | 575 | object → nil | false | true |
| 566 | | null | lightud32 | lightud64 | 576 | | null | lightud32 | lightud64 |
| 567 | | int | num | tab | 577 | | int | num | tab | tab_mt |
| 568 | | int64 | uint64 | complex | 578 | | int64 | uint64 | complex |
| 569 | | string | 579 | | string |
| 570 | 580 | ||
| @@ -585,13 +595,14 @@ tab → 0x08 // Empty table | |||
| 585 | | 0x0b a.U a*object h.U h*{object object} // Mixed | 595 | | 0x0b a.U a*object h.U h*{object object} // Mixed |
| 586 | | 0x0c a.U (a-1)*object // 1-based array | 596 | | 0x0c a.U (a-1)*object // 1-based array |
| 587 | | 0x0d a.U (a-1)*object h.U h*{object object} // Mixed | 597 | | 0x0d a.U (a-1)*object h.U h*{object object} // Mixed |
| 598 | tab_mt → 0x0e (index-1).U tab // Metatable dict entry | ||
| 588 | 599 | ||
| 589 | int64 → 0x10 int.L // FFI int64_t | 600 | int64 → 0x10 int.L // FFI int64_t |
| 590 | uint64 → 0x11 uint.L // FFI uint64_t | 601 | uint64 → 0x11 uint.L // FFI uint64_t |
| 591 | complex → 0x12 re.L im.L // FFI complex | 602 | complex → 0x12 re.L im.L // FFI complex |
| 592 | 603 | ||
| 593 | string → (0x20+len).U len*char.B | 604 | string → (0x20+len).U len*char.B |
| 594 | | 0x0f (index-1).U // Dict entry | 605 | | 0x0f (index-1).U // String dict entry |
| 595 | 606 | ||
| 596 | .B = 8 bit | 607 | .B = 8 bit |
| 597 | .I = 32 bit little-endian | 608 | .I = 32 bit little-endian |
diff --git a/src/lib_buffer.c b/src/lib_buffer.c index ae065759..2e364861 100644 --- a/src/lib_buffer.c +++ b/src/lib_buffer.c | |||
| @@ -288,7 +288,7 @@ LJLIB_CF(buffer_new) | |||
| 288 | { | 288 | { |
| 289 | MSize sz = 0; | 289 | MSize sz = 0; |
| 290 | int targ = 1; | 290 | int targ = 1; |
| 291 | GCtab *env, *dict = NULL; | 291 | GCtab *env, *dict_str = NULL, *dict_mt = NULL; |
| 292 | GCudata *ud; | 292 | GCudata *ud; |
| 293 | SBufExt *sbx; | 293 | SBufExt *sbx; |
| 294 | if (L->base < L->top && !tvistab(L->base)) { | 294 | if (L->base < L->top && !tvistab(L->base)) { |
| @@ -298,10 +298,16 @@ LJLIB_CF(buffer_new) | |||
| 298 | } | 298 | } |
| 299 | if (L->base+targ-1 < L->top) { | 299 | if (L->base+targ-1 < L->top) { |
| 300 | GCtab *options = lj_lib_checktab(L, targ); | 300 | GCtab *options = lj_lib_checktab(L, targ); |
| 301 | cTValue *opt_dict = lj_tab_getstr(options, lj_str_newlit(L, "dict")); | 301 | cTValue *opt_dict, *opt_mt; |
| 302 | opt_dict = lj_tab_getstr(options, lj_str_newlit(L, "dict")); | ||
| 302 | if (opt_dict && tvistab(opt_dict)) { | 303 | if (opt_dict && tvistab(opt_dict)) { |
| 303 | dict = tabV(opt_dict); | 304 | dict_str = tabV(opt_dict); |
| 304 | lj_serialize_dict_prep(L, dict); | 305 | lj_serialize_dict_prep_str(L, dict_str); |
| 306 | } | ||
| 307 | opt_mt = lj_tab_getstr(options, lj_str_newlit(L, "metatable")); | ||
| 308 | if (opt_mt && tvistab(opt_mt)) { | ||
| 309 | dict_mt = tabV(opt_mt); | ||
| 310 | lj_serialize_dict_prep_mt(L, dict_mt); | ||
| 305 | } | 311 | } |
| 306 | } | 312 | } |
| 307 | env = tabref(curr_func(L)->c.env); | 313 | env = tabref(curr_func(L)->c.env); |
| @@ -312,7 +318,8 @@ LJLIB_CF(buffer_new) | |||
| 312 | setudataV(L, L->top++, ud); | 318 | setudataV(L, L->top++, ud); |
| 313 | sbx = (SBufExt *)uddata(ud); | 319 | sbx = (SBufExt *)uddata(ud); |
| 314 | lj_bufx_init(L, sbx); | 320 | lj_bufx_init(L, sbx); |
| 315 | setgcref(sbx->dict, obj2gco(dict)); | 321 | setgcref(sbx->dict_str, obj2gco(dict_str)); |
| 322 | setgcref(sbx->dict_mt, obj2gco(dict_mt)); | ||
| 316 | if (sz > 0) lj_buf_need2((SBuf *)sbx, sz); | 323 | if (sz > 0) lj_buf_need2((SBuf *)sbx, sz); |
| 317 | return 1; | 324 | return 1; |
| 318 | } | 325 | } |
diff --git a/src/lj_buf.h b/src/lj_buf.h index 4ace2685..e2ac922e 100644 --- a/src/lj_buf.h +++ b/src/lj_buf.h | |||
| @@ -27,7 +27,8 @@ typedef struct SBufExt { | |||
| 27 | MRef bsb; /* Borrowed string buffer. */ | 27 | MRef bsb; /* Borrowed string buffer. */ |
| 28 | }; | 28 | }; |
| 29 | char *r; /* Read pointer. */ | 29 | char *r; /* Read pointer. */ |
| 30 | GCRef dict; /* Serialization string dictionary table. */ | 30 | GCRef dict_str; /* Serialization string dictionary table. */ |
| 31 | GCRef dict_mt; /* Serialization metatable dictionary table. */ | ||
| 31 | int depth; /* Remaining recursion depth. */ | 32 | int depth; /* Remaining recursion depth. */ |
| 32 | } SBufExt; | 33 | } SBufExt; |
| 33 | 34 | ||
diff --git a/src/lj_gc.c b/src/lj_gc.c index 646a27b2..5a238542 100644 --- a/src/lj_gc.c +++ b/src/lj_gc.c | |||
| @@ -69,8 +69,10 @@ static void gc_mark(global_State *g, GCobj *o) | |||
| 69 | SBufExt *sbx = (SBufExt *)uddata(gco2ud(o)); | 69 | SBufExt *sbx = (SBufExt *)uddata(gco2ud(o)); |
| 70 | if (sbufiscow(sbx) && gcref(sbx->cowref)) | 70 | if (sbufiscow(sbx) && gcref(sbx->cowref)) |
| 71 | gc_markobj(g, gcref(sbx->cowref)); | 71 | gc_markobj(g, gcref(sbx->cowref)); |
| 72 | if (gcref(sbx->dict)) | 72 | if (gcref(sbx->dict_str)) |
| 73 | gc_markobj(g, gcref(sbx->dict)); | 73 | gc_markobj(g, gcref(sbx->dict_str)); |
| 74 | if (gcref(sbx->dict_mt)) | ||
| 75 | gc_markobj(g, gcref(sbx->dict_mt)); | ||
| 74 | } | 76 | } |
| 75 | } else if (LJ_UNLIKELY(gct == ~LJ_TUPVAL)) { | 77 | } else if (LJ_UNLIKELY(gct == ~LJ_TUPVAL)) { |
| 76 | GCupval *uv = gco2uv(o); | 78 | GCupval *uv = gco2uv(o); |
diff --git a/src/lj_serialize.c b/src/lj_serialize.c index 70ff4796..e12e3668 100644 --- a/src/lj_serialize.c +++ b/src/lj_serialize.c | |||
| @@ -34,8 +34,8 @@ enum { | |||
| 34 | SER_TAG_INT, | 34 | SER_TAG_INT, |
| 35 | SER_TAG_NUM, | 35 | SER_TAG_NUM, |
| 36 | SER_TAG_TAB, /* 0x08 */ | 36 | SER_TAG_TAB, /* 0x08 */ |
| 37 | SER_TAG_0x0e = SER_TAG_TAB+6, | 37 | SER_TAG_DICT_MT = SER_TAG_TAB+6, |
| 38 | SER_TAG_DICT, | 38 | SER_TAG_DICT_STR, |
| 39 | SER_TAG_INT64, /* 0x10 */ | 39 | SER_TAG_INT64, /* 0x10 */ |
| 40 | SER_TAG_UINT64, | 40 | SER_TAG_UINT64, |
| 41 | SER_TAG_COMPLEX, | 41 | SER_TAG_COMPLEX, |
| @@ -124,7 +124,7 @@ static LJ_AINLINE char *serialize_ru124(char *r, char *w, uint32_t *pv) | |||
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | /* Prepare string dictionary for use (once). */ | 126 | /* Prepare string dictionary for use (once). */ |
| 127 | void LJ_FASTCALL lj_serialize_dict_prep(lua_State *L, GCtab *dict) | 127 | void LJ_FASTCALL lj_serialize_dict_prep_str(lua_State *L, GCtab *dict) |
| 128 | { | 128 | { |
| 129 | if (!dict->hmask) { /* No hash part means not prepared, yet. */ | 129 | if (!dict->hmask) { /* No hash part means not prepared, yet. */ |
| 130 | MSize i, len = lj_tab_len(dict); | 130 | MSize i, len = lj_tab_len(dict); |
| @@ -143,6 +143,26 @@ void LJ_FASTCALL lj_serialize_dict_prep(lua_State *L, GCtab *dict) | |||
| 143 | } | 143 | } |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | /* Prepare metatable dictionary for use (once). */ | ||
| 147 | void LJ_FASTCALL lj_serialize_dict_prep_mt(lua_State *L, GCtab *dict) | ||
| 148 | { | ||
| 149 | if (!dict->hmask) { /* No hash part means not prepared, yet. */ | ||
| 150 | MSize i, len = lj_tab_len(dict); | ||
| 151 | if (!len) return; | ||
| 152 | lj_tab_resize(L, dict, dict->asize, hsize2hbits(len)); | ||
| 153 | for (i = 1; i <= len && i < dict->asize; i++) { | ||
| 154 | cTValue *o = arrayslot(dict, i); | ||
| 155 | if (tvistab(o)) { | ||
| 156 | if (tvisnil(lj_tab_get(L, dict, o))) { /* Ignore dups. */ | ||
| 157 | lj_tab_newkey(L, dict, o)->u64 = (uint64_t)(i-1); | ||
| 158 | } | ||
| 159 | } else if (!tvisfalse(o)) { | ||
| 160 | lj_err_caller(L, LJ_ERR_BUFFER_BADOPT); | ||
| 161 | } | ||
| 162 | } | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 146 | /* -- Internal serializer ------------------------------------------------- */ | 166 | /* -- Internal serializer ------------------------------------------------- */ |
| 147 | 167 | ||
| 148 | /* Put serialized object into buffer. */ | 168 | /* Put serialized object into buffer. */ |
| @@ -185,6 +205,22 @@ static char *serialize_put(char *w, SBufExt *sbx, cTValue *o) | |||
| 185 | for (i = 0; i <= hmask; i++) | 205 | for (i = 0; i <= hmask; i++) |
| 186 | nhash += !tvisnil(&node[i].val); | 206 | nhash += !tvisnil(&node[i].val); |
| 187 | } | 207 | } |
| 208 | /* Write metatable index. */ | ||
| 209 | if (LJ_UNLIKELY(tabref(sbx->dict_mt)) && tabref(t->metatable)) { | ||
| 210 | TValue mto; | ||
| 211 | Node *n; | ||
| 212 | settabV(sbufL(sbx), &mto, tabref(t->metatable)); | ||
| 213 | n = hashgcref(tabref(sbx->dict_mt), mto.gcr); | ||
| 214 | do { | ||
| 215 | if (n->key.u64 == mto.u64) { | ||
| 216 | uint32_t idx = n->val.u32.lo; | ||
| 217 | w = serialize_more(w, sbx, 1+5); | ||
| 218 | *w++ = SER_TAG_DICT_MT; | ||
| 219 | w = serialize_wu124(w, idx); | ||
| 220 | break; | ||
| 221 | } | ||
| 222 | } while ((n = nextnode(n))); | ||
| 223 | } | ||
| 188 | /* Write number of array slots and hash slots. */ | 224 | /* Write number of array slots and hash slots. */ |
| 189 | w = serialize_more(w, sbx, 1+2*5); | 225 | w = serialize_more(w, sbx, 1+2*5); |
| 190 | *w++ = (char)(SER_TAG_TAB + (nhash ? 1 : 0) + (narray ? one : 0)); | 226 | *w++ = (char)(SER_TAG_TAB + (nhash ? 1 : 0) + (narray ? one : 0)); |
| @@ -197,19 +233,19 @@ static char *serialize_put(char *w, SBufExt *sbx, cTValue *o) | |||
| 197 | } | 233 | } |
| 198 | if (nhash) { /* Write hash entries. */ | 234 | if (nhash) { /* Write hash entries. */ |
| 199 | const Node *node = noderef(t->node) + t->hmask; | 235 | const Node *node = noderef(t->node) + t->hmask; |
| 200 | GCtab *dict = tabref(sbx->dict); | 236 | GCtab *dict_str = tabref(sbx->dict_str); |
| 201 | if (LJ_UNLIKELY(dict)) { | 237 | if (LJ_UNLIKELY(dict_str)) { |
| 202 | for (;; node--) | 238 | for (;; node--) |
| 203 | if (!tvisnil(&node->val)) { | 239 | if (!tvisnil(&node->val)) { |
| 204 | if (LJ_LIKELY(tvisstr(&node->key))) { | 240 | if (LJ_LIKELY(tvisstr(&node->key))) { |
| 205 | /* Inlined lj_tab_getstr is 30% faster. */ | 241 | /* Inlined lj_tab_getstr is 30% faster. */ |
| 206 | const GCstr *str = strV(&node->key); | 242 | const GCstr *str = strV(&node->key); |
| 207 | Node *n = hashstr(dict, str); | 243 | Node *n = hashstr(dict_str, str); |
| 208 | do { | 244 | do { |
| 209 | if (tvisstr(&n->key) && strV(&n->key) == str) { | 245 | if (tvisstr(&n->key) && strV(&n->key) == str) { |
| 210 | uint32_t idx = n->val.u32.lo; | 246 | uint32_t idx = n->val.u32.lo; |
| 211 | w = serialize_more(w, sbx, 1+5); | 247 | w = serialize_more(w, sbx, 1+5); |
| 212 | *w++ = SER_TAG_DICT; | 248 | *w++ = SER_TAG_DICT_STR; |
| 213 | w = serialize_wu124(w, idx); | 249 | w = serialize_wu124(w, idx); |
| 214 | break; | 250 | break; |
| 215 | } | 251 | } |
| @@ -322,19 +358,32 @@ static char *serialize_get(char *r, SBufExt *sbx, TValue *o) | |||
| 322 | if (!tvisnum(o)) setnanV(o); | 358 | if (!tvisnum(o)) setnanV(o); |
| 323 | } else if (tp <= SER_TAG_TRUE) { | 359 | } else if (tp <= SER_TAG_TRUE) { |
| 324 | setpriV(o, ~tp); | 360 | setpriV(o, ~tp); |
| 325 | } else if (tp == SER_TAG_DICT) { | 361 | } else if (tp == SER_TAG_DICT_STR) { |
| 326 | GCtab *dict; | 362 | GCtab *dict_str; |
| 327 | uint32_t idx; | 363 | uint32_t idx; |
| 328 | r = serialize_ru124(r, w, &idx); | 364 | r = serialize_ru124(r, w, &idx); |
| 329 | idx++; | 365 | idx++; |
| 330 | dict = tabref(sbx->dict); | 366 | dict_str = tabref(sbx->dict_str); |
| 331 | if (dict && idx < dict->asize && tvisstr(arrayslot(dict, idx))) | 367 | if (dict_str && idx < dict_str->asize && tvisstr(arrayslot(dict_str, idx))) |
| 332 | copyTV(sbufL(sbx), o, arrayslot(dict, idx)); | 368 | copyTV(sbufL(sbx), o, arrayslot(dict_str, idx)); |
| 333 | else | 369 | else |
| 334 | lj_err_callerv(sbufL(sbx), LJ_ERR_BUFFER_BADDICTX, idx); | 370 | lj_err_callerv(sbufL(sbx), LJ_ERR_BUFFER_BADDICTX, idx); |
| 335 | } else if (tp >= SER_TAG_TAB && tp < SER_TAG_TAB+6) { | 371 | } else if (tp >= SER_TAG_TAB && tp <= SER_TAG_DICT_MT) { |
| 336 | uint32_t narray = 0, nhash = 0; | 372 | uint32_t narray = 0, nhash = 0; |
| 337 | GCtab *t; | 373 | GCtab *t, *mt = NULL; |
| 374 | if (tp == SER_TAG_DICT_MT) { | ||
| 375 | GCtab *dict_mt; | ||
| 376 | uint32_t idx; | ||
| 377 | r = serialize_ru124(r, w, &idx); if (LJ_UNLIKELY(!r)) goto eob; | ||
| 378 | idx++; | ||
| 379 | dict_mt = tabref(sbx->dict_mt); | ||
| 380 | if (dict_mt && idx < dict_mt->asize && tvistab(arrayslot(dict_mt, idx))) | ||
| 381 | mt = tabV(arrayslot(dict_mt, idx)); | ||
| 382 | else | ||
| 383 | lj_err_callerv(sbufL(sbx), LJ_ERR_BUFFER_BADDICTX, idx); | ||
| 384 | r = serialize_ru124(r, w, &tp); if (LJ_UNLIKELY(!r)) goto eob; | ||
| 385 | if (!(tp >= SER_TAG_TAB && tp < SER_TAG_DICT_MT)) goto badtag; | ||
| 386 | } | ||
| 338 | if (tp >= SER_TAG_TAB+2) { | 387 | if (tp >= SER_TAG_TAB+2) { |
| 339 | r = serialize_ru124(r, w, &narray); if (LJ_UNLIKELY(!r)) goto eob; | 388 | r = serialize_ru124(r, w, &narray); if (LJ_UNLIKELY(!r)) goto eob; |
| 340 | } | 389 | } |
| @@ -342,6 +391,8 @@ static char *serialize_get(char *r, SBufExt *sbx, TValue *o) | |||
| 342 | r = serialize_ru124(r, w, &nhash); if (LJ_UNLIKELY(!r)) goto eob; | 391 | r = serialize_ru124(r, w, &nhash); if (LJ_UNLIKELY(!r)) goto eob; |
| 343 | } | 392 | } |
| 344 | t = lj_tab_new(sbufL(sbx), narray, hsize2hbits(nhash)); | 393 | t = lj_tab_new(sbufL(sbx), narray, hsize2hbits(nhash)); |
| 394 | /* NOBARRIER: The table is new (marked white). */ | ||
| 395 | setgcref(t->metatable, obj2gco(mt)); | ||
| 345 | settabV(sbufL(sbx), o, t); | 396 | settabV(sbufL(sbx), o, t); |
| 346 | if (narray) { | 397 | if (narray) { |
| 347 | TValue *oa = tvref(t->array) + (tp >= SER_TAG_TAB+4); | 398 | TValue *oa = tvref(t->array) + (tp >= SER_TAG_TAB+4); |
| @@ -395,6 +446,7 @@ static char *serialize_get(char *r, SBufExt *sbx, TValue *o) | |||
| 395 | setrawlightudV(o, (void *)ud); | 446 | setrawlightudV(o, (void *)ud); |
| 396 | #endif | 447 | #endif |
| 397 | } else { | 448 | } else { |
| 449 | badtag: | ||
| 398 | lj_err_callerv(sbufL(sbx), LJ_ERR_BUFFER_BADDEC, tp); | 450 | lj_err_callerv(sbufL(sbx), LJ_ERR_BUFFER_BADDEC, tp); |
| 399 | } | 451 | } |
| 400 | return r; | 452 | return r; |
| @@ -460,10 +512,11 @@ LJ_FUNC MSize LJ_FASTCALL lj_serialize_peektype(SBufExt *sbx) | |||
| 460 | case SER_TAG_NUM: return IRT_NUM; | 512 | case SER_TAG_NUM: return IRT_NUM; |
| 461 | case SER_TAG_TAB: case SER_TAG_TAB+1: case SER_TAG_TAB+2: | 513 | case SER_TAG_TAB: case SER_TAG_TAB+1: case SER_TAG_TAB+2: |
| 462 | case SER_TAG_TAB+3: case SER_TAG_TAB+4: case SER_TAG_TAB+5: | 514 | case SER_TAG_TAB+3: case SER_TAG_TAB+4: case SER_TAG_TAB+5: |
| 515 | case SER_TAG_DICT_MT: | ||
| 463 | return IRT_TAB; | 516 | return IRT_TAB; |
| 464 | case SER_TAG_INT64: case SER_TAG_UINT64: case SER_TAG_COMPLEX: | 517 | case SER_TAG_INT64: case SER_TAG_UINT64: case SER_TAG_COMPLEX: |
| 465 | return IRT_CDATA; | 518 | return IRT_CDATA; |
| 466 | case SER_TAG_DICT: | 519 | case SER_TAG_DICT_STR: |
| 467 | default: | 520 | default: |
| 468 | return IRT_STR; | 521 | return IRT_STR; |
| 469 | } | 522 | } |
diff --git a/src/lj_serialize.h b/src/lj_serialize.h index 9bd780ca..1fda23eb 100644 --- a/src/lj_serialize.h +++ b/src/lj_serialize.h | |||
| @@ -13,7 +13,8 @@ | |||
| 13 | 13 | ||
| 14 | #define LJ_SERIALIZE_DEPTH 100 /* Default depth. */ | 14 | #define LJ_SERIALIZE_DEPTH 100 /* Default depth. */ |
| 15 | 15 | ||
| 16 | LJ_FUNC void LJ_FASTCALL lj_serialize_dict_prep(lua_State *L, GCtab *dict); | 16 | LJ_FUNC void LJ_FASTCALL lj_serialize_dict_prep_str(lua_State *L, GCtab *dict); |
| 17 | LJ_FUNC void LJ_FASTCALL lj_serialize_dict_prep_mt(lua_State *L, GCtab *dict); | ||
| 17 | LJ_FUNC SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o); | 18 | LJ_FUNC SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o); |
| 18 | LJ_FUNC char * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o); | 19 | LJ_FUNC char * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o); |
| 19 | LJ_FUNC GCstr * LJ_FASTCALL lj_serialize_encode(lua_State *L, cTValue *o); | 20 | LJ_FUNC GCstr * LJ_FASTCALL lj_serialize_encode(lua_State *L, cTValue *o); |
