diff options
Diffstat (limited to '')
-rw-r--r-- | src/lj_serialize.c | 83 |
1 files changed, 68 insertions, 15 deletions
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 | } |