aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--loadlib.c4
-rw-r--r--lobject.h1
-rw-r--r--lstring.c46
-rw-r--r--lstring.h3
-rw-r--r--ltable.c82
-rw-r--r--ltests.c6
-rw-r--r--lvm.c106
-rw-r--r--manual/manual.of12
-rw-r--r--testes/attrib.lua28
9 files changed, 168 insertions, 120 deletions
diff --git a/loadlib.c b/loadlib.c
index 2cd95ca3..8d2e68e2 100644
--- a/loadlib.c
+++ b/loadlib.c
@@ -345,8 +345,8 @@ static void *freelib (void *ud, void *ptr, size_t osize, size_t nsize) {
345** Create a library string that, when deallocated, will unload 'plib' 345** Create a library string that, when deallocated, will unload 'plib'
346*/ 346*/
347static void createlibstr (lua_State *L, void *plib) { 347static void createlibstr (lua_State *L, void *plib) {
348 static const char dummy[] = /* common long body for all library strings */ 348 /* common content for all library strings */
349 "01234567890123456789012345678901234567890123456789"; 349 static const char dummy[] = "01234567890";
350 lua_pushexternalstring(L, dummy, sizeof(dummy) - 1, freelib, plib); 350 lua_pushexternalstring(L, dummy, sizeof(dummy) - 1, freelib, plib);
351} 351}
352 352
diff --git a/lobject.h b/lobject.h
index bc2f69ab..cc3dd370 100644
--- a/lobject.h
+++ b/lobject.h
@@ -418,6 +418,7 @@ typedef struct TString {
418 418
419 419
420#define strisshr(ts) ((ts)->shrlen >= 0) 420#define strisshr(ts) ((ts)->shrlen >= 0)
421#define isextstr(ts) (ttislngstring(ts) && tsvalue(ts)->shrlen != LSTRREG)
421 422
422 423
423/* 424/*
diff --git a/lstring.c b/lstring.c
index b5c8f89f..17c6fd8f 100644
--- a/lstring.c
+++ b/lstring.c
@@ -39,14 +39,14 @@
39 39
40 40
41/* 41/*
42** equality for long strings 42** generic equality for strings
43*/ 43*/
44int luaS_eqlngstr (TString *a, TString *b) { 44int luaS_eqstr (TString *a, TString *b) {
45 size_t len = a->u.lnglen; 45 size_t len1, len2;
46 lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR); 46 const char *s1 = getlstr(a, len1);
47 return (a == b) || /* same instance or... */ 47 const char *s2 = getlstr(b, len2);
48 ((len == b->u.lnglen) && /* equal length and ... */ 48 return ((len1 == len2) && /* equal length and ... */
49 (memcmp(getlngstr(a), getlngstr(b), len) == 0)); /* equal contents */ 49 (memcmp(s1, s2, len1) == 0)); /* equal contents */
50} 50}
51 51
52 52
@@ -315,28 +315,9 @@ static void f_newext (lua_State *L, void *ud) {
315} 315}
316 316
317 317
318static void f_pintern (lua_State *L, void *ud) {
319 struct NewExt *ne = cast(struct NewExt *, ud);
320 ne->ts = internshrstr(L, ne->s, ne->len);
321}
322
323
324TString *luaS_newextlstr (lua_State *L, 318TString *luaS_newextlstr (lua_State *L,
325 const char *s, size_t len, lua_Alloc falloc, void *ud) { 319 const char *s, size_t len, lua_Alloc falloc, void *ud) {
326 struct NewExt ne; 320 struct NewExt ne;
327 if (len <= LUAI_MAXSHORTLEN) { /* short string? */
328 ne.s = s; ne.len = len;
329 if (!falloc)
330 f_pintern(L, &ne); /* just internalize string */
331 else {
332 TStatus status = luaD_rawrunprotected(L, f_pintern, &ne);
333 (*falloc)(ud, cast_voidp(s), len + 1, 0); /* free external string */
334 if (status != LUA_OK) /* memory error? */
335 luaM_error(L); /* re-raise memory error */
336 }
337 return ne.ts;
338 }
339 /* "normal" case: long strings */
340 if (!falloc) { 321 if (!falloc) {
341 ne.kind = LSTRFIX; 322 ne.kind = LSTRFIX;
342 f_newext(L, &ne); /* just create header */ 323 f_newext(L, &ne); /* just create header */
@@ -357,3 +338,16 @@ TString *luaS_newextlstr (lua_State *L,
357} 338}
358 339
359 340
341/*
342** Normalize an external string: If it is short, internalize it.
343*/
344TString *luaS_normstr (lua_State *L, TString *ts) {
345 size_t len = ts->u.lnglen;
346 if (len > LUAI_MAXSHORTLEN)
347 return ts; /* long string; keep the original */
348 else {
349 const char *str = getlngstr(ts);
350 return internshrstr(L, str, len);
351 }
352}
353
diff --git a/lstring.h b/lstring.h
index 1751e043..2eac222b 100644
--- a/lstring.h
+++ b/lstring.h
@@ -56,7 +56,7 @@
56 56
57LUAI_FUNC unsigned luaS_hash (const char *str, size_t l, unsigned seed); 57LUAI_FUNC unsigned luaS_hash (const char *str, size_t l, unsigned seed);
58LUAI_FUNC unsigned luaS_hashlongstr (TString *ts); 58LUAI_FUNC unsigned luaS_hashlongstr (TString *ts);
59LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); 59LUAI_FUNC int luaS_eqstr (TString *a, TString *b);
60LUAI_FUNC void luaS_resize (lua_State *L, int newsize); 60LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
61LUAI_FUNC void luaS_clearcache (global_State *g); 61LUAI_FUNC void luaS_clearcache (global_State *g);
62LUAI_FUNC void luaS_init (lua_State *L); 62LUAI_FUNC void luaS_init (lua_State *L);
@@ -69,5 +69,6 @@ LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
69LUAI_FUNC TString *luaS_newextlstr (lua_State *L, 69LUAI_FUNC TString *luaS_newextlstr (lua_State *L,
70 const char *s, size_t len, lua_Alloc falloc, void *ud); 70 const char *s, size_t len, lua_Alloc falloc, void *ud);
71LUAI_FUNC size_t luaS_sizelngstr (size_t len, int kind); 71LUAI_FUNC size_t luaS_sizelngstr (size_t len, int kind);
72LUAI_FUNC TString *luaS_normstr (lua_State *L, TString *ts);
72 73
73#endif 74#endif
diff --git a/ltable.c b/ltable.c
index 0b3ec176..1bea7aff 100644
--- a/ltable.c
+++ b/ltable.c
@@ -234,41 +234,51 @@ l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) {
234** Check whether key 'k1' is equal to the key in node 'n2'. This 234** Check whether key 'k1' is equal to the key in node 'n2'. This
235** equality is raw, so there are no metamethods. Floats with integer 235** equality is raw, so there are no metamethods. Floats with integer
236** values have been normalized, so integers cannot be equal to 236** values have been normalized, so integers cannot be equal to
237** floats. It is assumed that 'eqshrstr' is simply pointer equality, so 237** floats. It is assumed that 'eqshrstr' is simply pointer equality,
238** that short strings are handled in the default case. 238** so that short strings are handled in the default case. The flag
239** A true 'deadok' means to accept dead keys as equal to their original 239** 'deadok' means to accept dead keys as equal to their original values.
240** values. All dead keys are compared in the default case, by pointer 240** (Only collectable objects can produce dead keys.) Note that dead
241** identity. (Only collectable objects can produce dead keys.) Note that 241** long strings are also compared by identity. Once a key is dead,
242** dead long strings are also compared by identity. 242** its corresponding value may be collected, and then another value
243** Once a key is dead, its corresponding value may be collected, and 243** can be created with the same address. If this other value is given
244** then another value can be created with the same address. If this 244** to 'next', 'equalkey' will signal a false positive. In a regular
245** other value is given to 'next', 'equalkey' will signal a false 245** traversal, this situation should never happen, as all keys given to
246** positive. In a regular traversal, this situation should never happen, 246** 'next' came from the table itself, and therefore could not have been
247** as all keys given to 'next' came from the table itself, and therefore 247** collected. Outside a regular traversal, we have garbage in, garbage
248** could not have been collected. Outside a regular traversal, we 248** out. What is relevant is that this false positive does not break
249** have garbage in, garbage out. What is relevant is that this false 249** anything. (In particular, 'next' will return some other valid item
250** positive does not break anything. (In particular, 'next' will return 250** on the table or nil.)
251** some other valid item on the table or nil.)
252*/ 251*/
253static int equalkey (const TValue *k1, const Node *n2, int deadok) { 252static int equalkey (const TValue *k1, const Node *n2, int deadok) {
254 if ((rawtt(k1) != keytt(n2)) && /* not the same variants? */ 253 if (rawtt(k1) != keytt(n2)) { /* not the same variants? */
255 !(deadok && keyisdead(n2) && iscollectable(k1))) 254 if (keyisshrstr(n2) && ttislngstring(k1)) {
256 return 0; /* cannot be same key */ 255 /* an external string can be equal to a short-string key */
257 switch (keytt(n2)) { 256 return luaS_eqstr(tsvalue(k1), keystrval(n2));
258 case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: 257 }
259 return 1; 258 else if (deadok && keyisdead(n2) && iscollectable(k1)) {
260 case LUA_VNUMINT: 259 /* a collectable value can be equal to a dead key */
261 return (ivalue(k1) == keyival(n2));
262 case LUA_VNUMFLT:
263 return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2)));
264 case LUA_VLIGHTUSERDATA:
265 return pvalue(k1) == pvalueraw(keyval(n2));
266 case LUA_VLCF:
267 return fvalue(k1) == fvalueraw(keyval(n2));
268 case ctb(LUA_VLNGSTR):
269 return luaS_eqlngstr(tsvalue(k1), keystrval(n2));
270 default:
271 return gcvalue(k1) == gcvalueraw(keyval(n2)); 260 return gcvalue(k1) == gcvalueraw(keyval(n2));
261 }
262 else
263 return 0; /* otherwise, different variants cannot be equal */
264 }
265 else { /* equal variants */
266 switch (keytt(n2)) {
267 case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
268 return 1;
269 case LUA_VNUMINT:
270 return (ivalue(k1) == keyival(n2));
271 case LUA_VNUMFLT:
272 return luai_numeq(fltvalue(k1), fltvalueraw(keyval(n2)));
273 case LUA_VLIGHTUSERDATA:
274 return pvalue(k1) == pvalueraw(keyval(n2));
275 case LUA_VLCF:
276 return fvalue(k1) == fvalueraw(keyval(n2));
277 case ctb(LUA_VLNGSTR):
278 return luaS_eqstr(tsvalue(k1), keystrval(n2));
279 default:
280 return gcvalue(k1) == gcvalueraw(keyval(n2));
281 }
272 } 282 }
273} 283}
274 284
@@ -1158,6 +1168,14 @@ void luaH_finishset (lua_State *L, Table *t, const TValue *key,
1158 else if (l_unlikely(luai_numisnan(f))) 1168 else if (l_unlikely(luai_numisnan(f)))
1159 luaG_runerror(L, "table index is NaN"); 1169 luaG_runerror(L, "table index is NaN");
1160 } 1170 }
1171 else if (isextstr(key)) { /* external string? */
1172 /* If string is short, must internalize it to be used as table key */
1173 TString *ts = luaS_normstr(L, tsvalue(key));
1174 setsvalue2s(L, L->top.p++, ts); /* anchor 'ts' (EXTRA_STACK) */
1175 luaH_newkey(L, t, s2v(L->top.p - 1), value);
1176 L->top.p--;
1177 return;
1178 }
1161 luaH_newkey(L, t, key, value); 1179 luaH_newkey(L, t, key, value);
1162 } 1180 }
1163 else if (hres > 0) { /* regular Node? */ 1181 else if (hres > 0) { /* regular Node? */
diff --git a/ltests.c b/ltests.c
index e7bc66dd..d92cd6c5 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1066,8 +1066,12 @@ static int tracegc (lua_State *L) {
1066 1066
1067static int hash_query (lua_State *L) { 1067static int hash_query (lua_State *L) {
1068 if (lua_isnone(L, 2)) { 1068 if (lua_isnone(L, 2)) {
1069 TString *ts;
1069 luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected"); 1070 luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected");
1070 lua_pushinteger(L, cast_int(tsvalue(obj_at(L, 1))->hash)); 1071 ts = tsvalue(obj_at(L, 1));
1072 if (ts->tt == LUA_VLNGSTR)
1073 luaS_hashlongstr(ts); /* make sure long string has a hash */
1074 lua_pushinteger(L, cast_int(ts->hash));
1071 } 1075 }
1072 else { 1076 else {
1073 TValue *o = obj_at(L, 1); 1077 TValue *o = obj_at(L, 1);
diff --git a/lvm.c b/lvm.c
index 97dfe5ee..74566888 100644
--- a/lvm.c
+++ b/lvm.c
@@ -573,52 +573,74 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
573*/ 573*/
574int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { 574int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
575 const TValue *tm; 575 const TValue *tm;
576 if (ttypetag(t1) != ttypetag(t2)) { /* not the same variant? */ 576 if (ttype(t1) != ttype(t2)) /* not the same type? */
577 if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER) 577 return 0;
578 return 0; /* only numbers can be equal with different variants */ 578 else if (ttypetag(t1) != ttypetag(t2)) {
579 else { /* two numbers with different variants */ 579 switch (ttypetag(t1)) {
580 /* One of them is an integer. If the other does not have an 580 case LUA_VNUMINT: { /* integer == float? */
581 integer value, they cannot be equal; otherwise, compare their 581 /* integer and float can only be equal if float has an integer
582 integer values. */ 582 value equal to the integer */
583 lua_Integer i1, i2; 583 lua_Integer i2;
584 return (luaV_tointegerns(t1, &i1, F2Ieq) && 584 return (luaV_flttointeger(fltvalue(t2), &i2, F2Ieq) &&
585 luaV_tointegerns(t2, &i2, F2Ieq) && 585 ivalue(t1) == i2);
586 i1 == i2); 586 }
587 case LUA_VNUMFLT: { /* float == integer? */
588 lua_Integer i1; /* see comment in previous case */
589 return (luaV_flttointeger(fltvalue(t1), &i1, F2Ieq) &&
590 i1 == ivalue(t2));
591 }
592 case LUA_VSHRSTR: case LUA_VLNGSTR: {
593 /* compare two strings with different variants: they can be
594 equal when one string is a short string and the other is
595 an external string */
596 return luaS_eqstr(tsvalue(t1), tsvalue(t2));
597 }
598 default:
599 /* only numbers (integer/float) and strings (long/short) can have
600 equal values with different variants */
601 return 0;
587 } 602 }
588 } 603 }
589 /* values have same type and same variant */ 604 else { /* equal variants */
590 switch (ttypetag(t1)) { 605 switch (ttypetag(t1)) {
591 case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE: return 1; 606 case LUA_VNIL: case LUA_VFALSE: case LUA_VTRUE:
592 case LUA_VNUMINT: return (ivalue(t1) == ivalue(t2)); 607 return 1;
593 case LUA_VNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); 608 case LUA_VNUMINT:
594 case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); 609 return (ivalue(t1) == ivalue(t2));
595 case LUA_VLCF: return fvalue(t1) == fvalue(t2); 610 case LUA_VNUMFLT:
596 case LUA_VSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); 611 return (fltvalue(t1) == fltvalue(t2));
597 case LUA_VLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); 612 case LUA_VLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
598 case LUA_VUSERDATA: { 613 case LUA_VSHRSTR:
599 if (uvalue(t1) == uvalue(t2)) return 1; 614 return eqshrstr(tsvalue(t1), tsvalue(t2));
600 else if (L == NULL) return 0; 615 case LUA_VLNGSTR:
601 tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); 616 return luaS_eqstr(tsvalue(t1), tsvalue(t2));
602 if (tm == NULL) 617 case LUA_VUSERDATA: {
603 tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); 618 if (uvalue(t1) == uvalue(t2)) return 1;
604 break; /* will try TM */ 619 else if (L == NULL) return 0;
620 tm = fasttm(L, uvalue(t1)->metatable, TM_EQ);
621 if (tm == NULL)
622 tm = fasttm(L, uvalue(t2)->metatable, TM_EQ);
623 break; /* will try TM */
624 }
625 case LUA_VTABLE: {
626 if (hvalue(t1) == hvalue(t2)) return 1;
627 else if (L == NULL) return 0;
628 tm = fasttm(L, hvalue(t1)->metatable, TM_EQ);
629 if (tm == NULL)
630 tm = fasttm(L, hvalue(t2)->metatable, TM_EQ);
631 break; /* will try TM */
632 }
633 case LUA_VLCF:
634 return (fvalue(t1) == fvalue(t2));
635 default: /* functions and threads */
636 return (gcvalue(t1) == gcvalue(t2));
605 } 637 }
606 case LUA_VTABLE: { 638 if (tm == NULL) /* no TM? */
607 if (hvalue(t1) == hvalue(t2)) return 1; 639 return 0; /* objects are different */
608 else if (L == NULL) return 0; 640 else {
609 tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); 641 int tag = luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
610 if (tm == NULL) 642 return !tagisfalse(tag);
611 tm = fasttm(L, hvalue(t2)->metatable, TM_EQ);
612 break; /* will try TM */
613 } 643 }
614 default:
615 return gcvalue(t1) == gcvalue(t2);
616 }
617 if (tm == NULL) /* no TM? */
618 return 0; /* objects are different */
619 else {
620 int tag = luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
621 return !tagisfalse(tag);
622 } 644 }
623} 645}
624 646
diff --git a/manual/manual.of b/manual/manual.of
index 8f90f942..b2765774 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -2419,8 +2419,8 @@ for instance @T{foo(e1, e2, e3)} @see{functioncall}.}
2419@item{A multiple assignment, 2419@item{A multiple assignment,
2420for instance @T{a , b, c = e1, e2, e3} @see{assignment}.} 2420for instance @T{a , b, c = e1, e2, e3} @see{assignment}.}
2421 2421
2422@item{A local declaration, 2422@item{A local or global declaration,
2423for instance @T{local a , b, c = e1, e2, e3} @see{localvar}.} 2423which is a special case of multiple assignment.}
2424 2424
2425@item{The initial values in a generic @rw{for} loop, 2425@item{The initial values in a generic @rw{for} loop,
2426for instance @T{for k in e1, e2, e3 do ... end} @see{for}.} 2426for instance @T{for k in e1, e2, e3 do ... end} @see{for}.}
@@ -2431,8 +2431,7 @@ the list of values from the list of expressions
2431must be @emph{adjusted} to a specific length: 2431must be @emph{adjusted} to a specific length:
2432the number of parameters in a call to a non-variadic function 2432the number of parameters in a call to a non-variadic function
2433@see{func-def}, 2433@see{func-def},
2434the number of variables in a multiple assignment or 2434the number of variables in a multiple assignment or a declaration,
2435a local declaration,
2436and exactly four values for a generic @rw{for} loop. 2435and exactly four values for a generic @rw{for} loop.
2437The @def{adjustment} follows these rules: 2436The @def{adjustment} follows these rules:
2438If there are more values than needed, 2437If there are more values than needed,
@@ -4075,11 +4074,6 @@ the string @id{s} as the block,
4075the length plus one (to account for the ending zero) as the old size, 4074the length plus one (to account for the ending zero) as the old size,
4076and 0 as the new size. 4075and 0 as the new size.
4077 4076
4078Lua always @x{internalizes} strings with lengths up to 40 characters.
4079So, for strings in that range,
4080this function will immediately internalize the string
4081and call @id{falloc} to free the buffer.
4082
4083Even when using an external buffer, 4077Even when using an external buffer,
4084Lua still has to allocate a header for the string. 4078Lua still has to allocate a header for the string.
4085In case of a memory-allocation error, 4079In case of a memory-allocation error,
diff --git a/testes/attrib.lua b/testes/attrib.lua
index 8a3462ea..f4156086 100644
--- a/testes/attrib.lua
+++ b/testes/attrib.lua
@@ -300,12 +300,6 @@ else
300 assert(_ENV.x == "lib2-v2" and _ENV.y == DC"lib2-v2") 300 assert(_ENV.x == "lib2-v2" and _ENV.y == DC"lib2-v2")
301 assert(lib2.id("x") == true) -- a different "id" implementation 301 assert(lib2.id("x") == true) -- a different "id" implementation
302 302
303 for _, len in ipairs{0, 10, 39, 40, 41, 1000} do
304 local str = string.rep("a", len)
305 local str1 = lib2.newstr(str)
306 assert(str == str1)
307 end
308
309 -- test C submodules 303 -- test C submodules
310 local fs, ext = require"lib1.sub" 304 local fs, ext = require"lib1.sub"
311 assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1") 305 assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
@@ -314,11 +308,11 @@ else
314 _ENV.x, _ENV.y = nil 308 _ENV.x, _ENV.y = nil
315end 309end
316 310
311
317_ENV = _G 312_ENV = _G
318 313
319 314
320-- testing preload 315-- testing preload
321
322do 316do
323 local p = package 317 local p = package
324 package = {} 318 package = {}
@@ -337,6 +331,26 @@ do
337 assert(type(package.path) == "string") 331 assert(type(package.path) == "string")
338end 332end
339 333
334
335do print("testing external strings")
336 package.cpath = DC"?"
337 local lib2 = require"lib2-v2"
338 local t = {}
339 for _, len in ipairs{0, 10, 39, 40, 41, 1000} do
340 local str = string.rep("a", len)
341 local str1 = lib2.newstr(str)
342 assert(str == str1)
343 assert(not T or T.hash(str) == T.hash(str1))
344 t[str1] = 20; assert(t[str] == 20 and t[str1] == 20)
345 t[str] = 10; assert(t[str1] == 10)
346 local tt = {[str1] = str1}
347 assert(next(tt) == str1 and next(tt, str1) == nil)
348 assert(tt[str] == str)
349 local str2 = lib2.newstr(str1)
350 assert(str == str2 and t[str2] == 10 and tt[str2] == str)
351 end
352end
353
340print('+') 354print('+')
341 355
342end --] 356end --]