diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2015-01-16 14:54:37 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2015-01-16 14:54:37 -0200 |
commit | 7e2015a46df7976bddee313b994742e49e420714 (patch) | |
tree | 0b2db30f1214a478ccb3664d165c8a431f0d5850 | |
parent | 5b01cb39b5ec36c544152351c35c43149d9bbfec (diff) | |
download | lua-7e2015a46df7976bddee313b994742e49e420714.tar.gz lua-7e2015a46df7976bddee313b994742e49e420714.tar.bz2 lua-7e2015a46df7976bddee313b994742e49e420714.zip |
size of short strings stored in a single byte, to reduce the size
of struct 'TString'
-rw-r--r-- | lapi.c | 10 | ||||
-rw-r--r-- | ldump.c | 4 | ||||
-rw-r--r-- | lgc.c | 15 | ||||
-rw-r--r-- | lobject.h | 15 | ||||
-rw-r--r-- | lstring.c | 27 | ||||
-rw-r--r-- | lstring.h | 3 | ||||
-rw-r--r-- | ltable.c | 4 | ||||
-rw-r--r-- | ltests.c | 4 | ||||
-rw-r--r-- | lvm.c | 32 |
9 files changed, 69 insertions, 45 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lapi.c,v 2.243 2014/11/12 13:28:54 roberto Exp roberto $ | 2 | ** $Id: lapi.c,v 2.244 2014/12/26 14:43:45 roberto Exp roberto $ |
3 | ** Lua API | 3 | ** Lua API |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -382,15 +382,17 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { | |||
382 | luaO_tostring(L, o); | 382 | luaO_tostring(L, o); |
383 | lua_unlock(L); | 383 | lua_unlock(L); |
384 | } | 384 | } |
385 | if (len != NULL) *len = tsvalue(o)->len; | 385 | if (len != NULL) |
386 | *len = vslen(o); | ||
386 | return svalue(o); | 387 | return svalue(o); |
387 | } | 388 | } |
388 | 389 | ||
389 | 390 | ||
390 | LUA_API size_t lua_rawlen (lua_State *L, int idx) { | 391 | LUA_API size_t lua_rawlen (lua_State *L, int idx) { |
391 | StkId o = index2addr(L, idx); | 392 | StkId o = index2addr(L, idx); |
392 | switch (ttnov(o)) { | 393 | switch (ttype(o)) { |
393 | case LUA_TSTRING: return tsvalue(o)->len; | 394 | case LUA_TSHRSTR: return tsvalue(o)->shrlen; |
395 | case LUA_TLNGSTR: return tsvalue(o)->u.lnglen; | ||
394 | case LUA_TUSERDATA: return uvalue(o)->len; | 396 | case LUA_TUSERDATA: return uvalue(o)->len; |
395 | case LUA_TTABLE: return luaH_getn(hvalue(o)); | 397 | case LUA_TTABLE: return luaH_getn(hvalue(o)); |
396 | default: return 0; | 398 | default: return 0; |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldump.c,v 2.33 2014/07/18 13:36:14 roberto Exp roberto $ | 2 | ** $Id: ldump.c,v 2.34 2014/11/02 19:19:04 roberto Exp roberto $ |
3 | ** save precompiled Lua chunks | 3 | ** save precompiled Lua chunks |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -74,7 +74,7 @@ static void DumpString (const TString *s, DumpState *D) { | |||
74 | if (s == NULL) | 74 | if (s == NULL) |
75 | DumpByte(0, D); | 75 | DumpByte(0, D); |
76 | else { | 76 | else { |
77 | size_t size = s->len + 1; /* include trailing '\0' */ | 77 | size_t size = tsslen(s) + 1; /* include trailing '\0' */ |
78 | if (size < 0xFF) | 78 | if (size < 0xFF) |
79 | DumpByte(cast_int(size), D); | 79 | DumpByte(cast_int(size), D); |
80 | else { | 80 | else { |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.200 2014/11/02 19:19:04 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.201 2014/12/20 13:58:15 roberto Exp roberto $ |
3 | ** Garbage Collector | 3 | ** Garbage Collector |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -226,10 +226,14 @@ static void reallymarkobject (global_State *g, GCObject *o) { | |||
226 | reentry: | 226 | reentry: |
227 | white2gray(o); | 227 | white2gray(o); |
228 | switch (o->tt) { | 228 | switch (o->tt) { |
229 | case LUA_TSHRSTR: | 229 | case LUA_TSHRSTR: { |
230 | gray2black(o); | ||
231 | g->GCmemtrav += sizelstring(gco2ts(o)->shrlen); | ||
232 | break; | ||
233 | } | ||
230 | case LUA_TLNGSTR: { | 234 | case LUA_TLNGSTR: { |
231 | gray2black(o); | 235 | gray2black(o); |
232 | g->GCmemtrav += sizestring(gco2ts(o)); | 236 | g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen); |
233 | break; | 237 | break; |
234 | } | 238 | } |
235 | case LUA_TUSERDATA: { | 239 | case LUA_TUSERDATA: { |
@@ -689,9 +693,10 @@ static void freeobj (lua_State *L, GCObject *o) { | |||
689 | case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; | 693 | case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; |
690 | case LUA_TSHRSTR: | 694 | case LUA_TSHRSTR: |
691 | luaS_remove(L, gco2ts(o)); /* remove it from hash table */ | 695 | luaS_remove(L, gco2ts(o)); /* remove it from hash table */ |
692 | /* go through */ | 696 | luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen)); |
697 | break; | ||
693 | case LUA_TLNGSTR: { | 698 | case LUA_TLNGSTR: { |
694 | luaM_freemem(L, o, sizestring(gco2ts(o))); | 699 | luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen)); |
695 | break; | 700 | break; |
696 | } | 701 | } |
697 | default: lua_assert(0); | 702 | default: lua_assert(0); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lobject.h,v 2.105 2014/12/19 13:36:32 roberto Exp roberto $ | 2 | ** $Id: lobject.h,v 2.106 2015/01/05 13:52:37 roberto Exp roberto $ |
3 | ** Type definitions for Lua objects | 3 | ** Type definitions for Lua objects |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -303,9 +303,12 @@ typedef TValue *StkId; /* index to stack elements */ | |||
303 | typedef struct TString { | 303 | typedef struct TString { |
304 | CommonHeader; | 304 | CommonHeader; |
305 | lu_byte extra; /* reserved words for short strings; "has hash" for longs */ | 305 | lu_byte extra; /* reserved words for short strings; "has hash" for longs */ |
306 | lu_byte shrlen; /* length for short strings */ | ||
306 | unsigned int hash; | 307 | unsigned int hash; |
307 | size_t len; /* number of characters in string */ | 308 | union { |
308 | struct TString *hnext; /* linked list for hash table */ | 309 | size_t lnglen; /* length for long strings */ |
310 | struct TString *hnext; /* linked list for hash table */ | ||
311 | } u; | ||
309 | } TString; | 312 | } TString; |
310 | 313 | ||
311 | 314 | ||
@@ -329,6 +332,12 @@ typedef union UTString { | |||
329 | /* get the actual string (array of bytes) from a Lua value */ | 332 | /* get the actual string (array of bytes) from a Lua value */ |
330 | #define svalue(o) getstr(tsvalue(o)) | 333 | #define svalue(o) getstr(tsvalue(o)) |
331 | 334 | ||
335 | /* get string length from 'TString *s' */ | ||
336 | #define tsslen(s) ((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen) | ||
337 | |||
338 | /* get string length from 'TValue *o' */ | ||
339 | #define vslen(o) tsslen(tsvalue(o)) | ||
340 | |||
332 | 341 | ||
333 | /* | 342 | /* |
334 | ** Header for userdata; memory area follows the end of this structure | 343 | ** Header for userdata; memory area follows the end of this structure |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstring.c,v 2.44 2014/07/21 16:02:10 roberto Exp roberto $ | 2 | ** $Id: lstring.c,v 2.45 2014/11/02 19:19:04 roberto Exp roberto $ |
3 | ** String table (keeps all strings handled by Lua) | 3 | ** String table (keeps all strings handled by Lua) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -36,10 +36,10 @@ | |||
36 | ** equality for long strings | 36 | ** equality for long strings |
37 | */ | 37 | */ |
38 | int luaS_eqlngstr (TString *a, TString *b) { | 38 | int luaS_eqlngstr (TString *a, TString *b) { |
39 | size_t len = a->len; | 39 | size_t len = a->u.lnglen; |
40 | lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); | 40 | lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); |
41 | return (a == b) || /* same instance or... */ | 41 | return (a == b) || /* same instance or... */ |
42 | ((len == b->len) && /* equal length and ... */ | 42 | ((len == b->u.lnglen) && /* equal length and ... */ |
43 | (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ | 43 | (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ |
44 | } | 44 | } |
45 | 45 | ||
@@ -69,9 +69,9 @@ void luaS_resize (lua_State *L, int newsize) { | |||
69 | TString *p = tb->hash[i]; | 69 | TString *p = tb->hash[i]; |
70 | tb->hash[i] = NULL; | 70 | tb->hash[i] = NULL; |
71 | while (p) { /* for each node in the list */ | 71 | while (p) { /* for each node in the list */ |
72 | TString *hnext = p->hnext; /* save next */ | 72 | TString *hnext = p->u.hnext; /* save next */ |
73 | unsigned int h = lmod(p->hash, newsize); /* new position */ | 73 | unsigned int h = lmod(p->hash, newsize); /* new position */ |
74 | p->hnext = tb->hash[h]; /* chain it */ | 74 | p->u.hnext = tb->hash[h]; /* chain it */ |
75 | tb->hash[h] = p; | 75 | tb->hash[h] = p; |
76 | p = hnext; | 76 | p = hnext; |
77 | } | 77 | } |
@@ -97,7 +97,6 @@ static TString *createstrobj (lua_State *L, const char *str, size_t l, | |||
97 | totalsize = sizelstring(l); | 97 | totalsize = sizelstring(l); |
98 | o = luaC_newobj(L, tag, totalsize); | 98 | o = luaC_newobj(L, tag, totalsize); |
99 | ts = gco2ts(o); | 99 | ts = gco2ts(o); |
100 | ts->len = l; | ||
101 | ts->hash = h; | 100 | ts->hash = h; |
102 | ts->extra = 0; | 101 | ts->extra = 0; |
103 | memcpy(getaddrstr(ts), str, l * sizeof(char)); | 102 | memcpy(getaddrstr(ts), str, l * sizeof(char)); |
@@ -110,8 +109,8 @@ void luaS_remove (lua_State *L, TString *ts) { | |||
110 | stringtable *tb = &G(L)->strt; | 109 | stringtable *tb = &G(L)->strt; |
111 | TString **p = &tb->hash[lmod(ts->hash, tb->size)]; | 110 | TString **p = &tb->hash[lmod(ts->hash, tb->size)]; |
112 | while (*p != ts) /* find previous element */ | 111 | while (*p != ts) /* find previous element */ |
113 | p = &(*p)->hnext; | 112 | p = &(*p)->u.hnext; |
114 | *p = (*p)->hnext; /* remove element from its list */ | 113 | *p = (*p)->u.hnext; /* remove element from its list */ |
115 | tb->nuse--; | 114 | tb->nuse--; |
116 | } | 115 | } |
117 | 116 | ||
@@ -124,8 +123,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { | |||
124 | global_State *g = G(L); | 123 | global_State *g = G(L); |
125 | unsigned int h = luaS_hash(str, l, g->seed); | 124 | unsigned int h = luaS_hash(str, l, g->seed); |
126 | TString **list = &g->strt.hash[lmod(h, g->strt.size)]; | 125 | TString **list = &g->strt.hash[lmod(h, g->strt.size)]; |
127 | for (ts = *list; ts != NULL; ts = ts->hnext) { | 126 | for (ts = *list; ts != NULL; ts = ts->u.hnext) { |
128 | if (l == ts->len && | 127 | if (l == ts->shrlen && |
129 | (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { | 128 | (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { |
130 | /* found! */ | 129 | /* found! */ |
131 | if (isdead(g, ts)) /* dead (but not collected yet)? */ | 130 | if (isdead(g, ts)) /* dead (but not collected yet)? */ |
@@ -138,7 +137,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { | |||
138 | list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ | 137 | list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ |
139 | } | 138 | } |
140 | ts = createstrobj(L, str, l, LUA_TSHRSTR, h); | 139 | ts = createstrobj(L, str, l, LUA_TSHRSTR, h); |
141 | ts->hnext = *list; | 140 | ts->shrlen = cast_byte(l); |
141 | ts->u.hnext = *list; | ||
142 | *list = ts; | 142 | *list = ts; |
143 | g->strt.nuse++; | 143 | g->strt.nuse++; |
144 | return ts; | 144 | return ts; |
@@ -152,9 +152,12 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { | |||
152 | if (l <= LUAI_MAXSHORTLEN) /* short string? */ | 152 | if (l <= LUAI_MAXSHORTLEN) /* short string? */ |
153 | return internshrstr(L, str, l); | 153 | return internshrstr(L, str, l); |
154 | else { | 154 | else { |
155 | TString *ts; | ||
155 | if (l + 1 > (MAX_SIZE - sizeof(TString))/sizeof(char)) | 156 | if (l + 1 > (MAX_SIZE - sizeof(TString))/sizeof(char)) |
156 | luaM_toobig(L); | 157 | luaM_toobig(L); |
157 | return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed); | 158 | ts = createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed); |
159 | ts->u.lnglen = l; | ||
160 | return ts; | ||
158 | } | 161 | } |
159 | } | 162 | } |
160 | 163 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstring.h,v 1.54 2014/03/19 18:51:42 roberto Exp roberto $ | 2 | ** $Id: lstring.h,v 1.56 2014/07/18 14:46:47 roberto Exp roberto $ |
3 | ** String table (keep all strings handled by Lua) | 3 | ** String table (keep all strings handled by Lua) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -13,7 +13,6 @@ | |||
13 | 13 | ||
14 | 14 | ||
15 | #define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) | 15 | #define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) |
16 | #define sizestring(s) sizelstring((s)->len) | ||
17 | 16 | ||
18 | #define sizeludata(l) (sizeof(union UUdata) + (l)) | 17 | #define sizeludata(l) (sizeof(union UUdata) + (l)) |
19 | #define sizeudata(u) sizeludata((u)->len) | 18 | #define sizeudata(u) sizeludata((u)->len) |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltable.c,v 2.99 2014/11/02 19:19:04 roberto Exp roberto $ | 2 | ** $Id: ltable.c,v 2.100 2015/01/05 13:52:37 roberto Exp roberto $ |
3 | ** Lua tables (hash) | 3 | ** Lua tables (hash) |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -127,7 +127,7 @@ static Node *mainposition (const Table *t, const TValue *key) { | |||
127 | case LUA_TLNGSTR: { | 127 | case LUA_TLNGSTR: { |
128 | TString *s = tsvalue(key); | 128 | TString *s = tsvalue(key); |
129 | if (s->extra == 0) { /* no hash? */ | 129 | if (s->extra == 0) { /* no hash? */ |
130 | s->hash = luaS_hash(getstr(s), s->len, s->hash); | 130 | s->hash = luaS_hash(getstr(s), s->u.lnglen, s->hash); |
131 | s->extra = 1; /* now it has its hash */ | 131 | s->extra = 1; /* now it has its hash */ |
132 | } | 132 | } |
133 | return hashstr(t, tsvalue(key)); | 133 | return hashstr(t, tsvalue(key)); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltests.c,v 2.200 2014/12/10 11:30:51 roberto Exp roberto $ | 2 | ** $Id: ltests.c,v 2.201 2014/12/18 12:13:42 roberto Exp roberto $ |
3 | ** Internal Module for Debugging of the Lua Implementation | 3 | ** Internal Module for Debugging of the Lua Implementation |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -724,7 +724,7 @@ static int string_query (lua_State *L) { | |||
724 | else if (s < tb->size) { | 724 | else if (s < tb->size) { |
725 | TString *ts; | 725 | TString *ts; |
726 | int n = 0; | 726 | int n = 0; |
727 | for (ts = tb->hash[s]; ts != NULL; ts = ts->hnext) { | 727 | for (ts = tb->hash[s]; ts != NULL; ts = ts->u.hnext) { |
728 | setsvalue2s(L, L->top, ts); | 728 | setsvalue2s(L, L->top, ts); |
729 | api_incr_top(L); | 729 | api_incr_top(L); |
730 | n++; | 730 | n++; |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 2.231 2014/12/19 13:36:32 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.232 2014/12/27 20:30:38 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -73,7 +73,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) { | |||
73 | return 1; | 73 | return 1; |
74 | } | 74 | } |
75 | else if (cvt2num(obj) && /* string convertible to number? */ | 75 | else if (cvt2num(obj) && /* string convertible to number? */ |
76 | luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) { | 76 | luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { |
77 | *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ | 77 | *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ |
78 | return 1; | 78 | return 1; |
79 | } | 79 | } |
@@ -106,7 +106,7 @@ static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) { | |||
106 | return 1; | 106 | return 1; |
107 | } | 107 | } |
108 | else if (cvt2num(obj) && | 108 | else if (cvt2num(obj) && |
109 | luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) { | 109 | luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { |
110 | obj = &v; | 110 | obj = &v; |
111 | goto again; /* convert result from 'luaO_str2num' to an integer */ | 111 | goto again; /* convert result from 'luaO_str2num' to an integer */ |
112 | } | 112 | } |
@@ -239,9 +239,9 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { | |||
239 | */ | 239 | */ |
240 | static int l_strcmp (const TString *ls, const TString *rs) { | 240 | static int l_strcmp (const TString *ls, const TString *rs) { |
241 | const char *l = getstr(ls); | 241 | const char *l = getstr(ls); |
242 | size_t ll = ls->len; | 242 | size_t ll = tsslen(ls); |
243 | const char *r = getstr(rs); | 243 | const char *r = getstr(rs); |
244 | size_t lr = rs->len; | 244 | size_t lr = tsslen(rs); |
245 | for (;;) { /* for each segment */ | 245 | for (;;) { /* for each segment */ |
246 | int temp = strcoll(l, r); | 246 | int temp = strcoll(l, r); |
247 | if (temp != 0) /* not equal? */ | 247 | if (temp != 0) /* not equal? */ |
@@ -354,6 +354,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { | |||
354 | #define tostring(L,o) \ | 354 | #define tostring(L,o) \ |
355 | (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) | 355 | (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) |
356 | 356 | ||
357 | #define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) | ||
358 | |||
357 | /* | 359 | /* |
358 | ** Main operation for concatenation: concat 'total' values in the stack, | 360 | ** Main operation for concatenation: concat 'total' values in the stack, |
359 | ** from 'L->top - total' up to 'L->top - 1'. | 361 | ** from 'L->top - total' up to 'L->top - 1'. |
@@ -365,19 +367,19 @@ void luaV_concat (lua_State *L, int total) { | |||
365 | int n = 2; /* number of elements handled in this pass (at least 2) */ | 367 | int n = 2; /* number of elements handled in this pass (at least 2) */ |
366 | if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1)) | 368 | if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1)) |
367 | luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT); | 369 | luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT); |
368 | else if (tsvalue(top-1)->len == 0) /* second operand is empty? */ | 370 | else if (isemptystr(top - 1)) /* second operand is empty? */ |
369 | cast_void(tostring(L, top - 2)); /* result is first operand */ | 371 | cast_void(tostring(L, top - 2)); /* result is first operand */ |
370 | else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) { | 372 | else if (isemptystr(top - 2)) { /* first operand is an empty string? */ |
371 | setobjs2s(L, top - 2, top - 1); /* result is second op. */ | 373 | setobjs2s(L, top - 2, top - 1); /* result is second op. */ |
372 | } | 374 | } |
373 | else { | 375 | else { |
374 | /* at least two non-empty string values; get as many as possible */ | 376 | /* at least two non-empty string values; get as many as possible */ |
375 | size_t tl = tsvalue(top-1)->len; | 377 | size_t tl = vslen(top - 1); |
376 | char *buffer; | 378 | char *buffer; |
377 | int i; | 379 | int i; |
378 | /* collect total length */ | 380 | /* collect total length */ |
379 | for (i = 1; i < total && tostring(L, top-i-1); i++) { | 381 | for (i = 1; i < total && tostring(L, top-i-1); i++) { |
380 | size_t l = tsvalue(top-i-1)->len; | 382 | size_t l = vslen(top - i - 1); |
381 | if (l >= (MAX_SIZE/sizeof(char)) - tl) | 383 | if (l >= (MAX_SIZE/sizeof(char)) - tl) |
382 | luaG_runerror(L, "string length overflow"); | 384 | luaG_runerror(L, "string length overflow"); |
383 | tl += l; | 385 | tl += l; |
@@ -386,7 +388,7 @@ void luaV_concat (lua_State *L, int total) { | |||
386 | tl = 0; | 388 | tl = 0; |
387 | n = i; | 389 | n = i; |
388 | do { /* copy all strings to buffer */ | 390 | do { /* copy all strings to buffer */ |
389 | size_t l = tsvalue(top-i)->len; | 391 | size_t l = vslen(top - i); |
390 | memcpy(buffer+tl, svalue(top-i), l * sizeof(char)); | 392 | memcpy(buffer+tl, svalue(top-i), l * sizeof(char)); |
391 | tl += l; | 393 | tl += l; |
392 | } while (--i > 0); | 394 | } while (--i > 0); |
@@ -403,7 +405,7 @@ void luaV_concat (lua_State *L, int total) { | |||
403 | */ | 405 | */ |
404 | void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { | 406 | void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { |
405 | const TValue *tm; | 407 | const TValue *tm; |
406 | switch (ttnov(rb)) { | 408 | switch (ttype(rb)) { |
407 | case LUA_TTABLE: { | 409 | case LUA_TTABLE: { |
408 | Table *h = hvalue(rb); | 410 | Table *h = hvalue(rb); |
409 | tm = fasttm(L, h->metatable, TM_LEN); | 411 | tm = fasttm(L, h->metatable, TM_LEN); |
@@ -411,8 +413,12 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { | |||
411 | setivalue(ra, luaH_getn(h)); /* else primitive len */ | 413 | setivalue(ra, luaH_getn(h)); /* else primitive len */ |
412 | return; | 414 | return; |
413 | } | 415 | } |
414 | case LUA_TSTRING: { | 416 | case LUA_TSHRSTR: { |
415 | setivalue(ra, tsvalue(rb)->len); | 417 | setivalue(ra, tsvalue(rb)->shrlen); |
418 | return; | ||
419 | } | ||
420 | case LUA_TLNGSTR: { | ||
421 | setivalue(ra, tsvalue(rb)->u.lnglen); | ||
416 | return; | 422 | return; |
417 | } | 423 | } |
418 | default: { /* try metamethod */ | 424 | default: { /* try metamethod */ |