diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-08-07 11:21:44 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-08-07 11:21:44 -0300 |
| commit | 7c3cb71fa48fbe84d9d9c664eb646446fb80898b (patch) | |
| tree | 43d2b2282853b882877e42a0b8ec7467c9bb0e9e | |
| parent | 68109afcdb59a7eeb75bacf055abce3e56a53645 (diff) | |
| download | lua-github-7c3cb71fa48fbe84d9d9c664eb646446fb80898b.tar.gz | |
Free bit 7 of GC 'marked' field
Tables were using this bit to indicate their array sizes were real
('isrealasize'), but this bit can be useful for tests. Instead, they
can use bit 7 of their 'flag' field for that purpose. (There are only
six fast-access metamethods.) This 'flag' field only exists in tables,
so this use does not affect other types.
| -rw-r--r-- | lgc.h | 3 | ||||
| -rw-r--r-- | lobject.h | 6 | ||||
| -rw-r--r-- | ltable.c | 2 | ||||
| -rw-r--r-- | ltable.h | 7 | ||||
| -rw-r--r-- | ltm.h | 9 | ||||
| -rw-r--r-- | testes/events.lua | 11 |
6 files changed, 31 insertions, 7 deletions
@@ -69,8 +69,7 @@ /* ** Layout for bit use in 'marked' field. First three bits are -** used for object "age" in generational mode. Last bit is free -** to be used by respective objects. +** used for object "age" in generational mode. */ #define WHITE0BIT 3 /* object is white (type 0) */ #define WHITE1BIT 4 /* object is white (type 1) */ @@ -704,9 +704,9 @@ typedef union Node { */ #define BITRAS (1 << 7) -#define isrealasize(t) (!((t)->marked & BITRAS)) -#define setrealasize(t) ((t)->marked &= cast_byte(~BITRAS)) -#define setnorealasize(t) ((t)->marked |= BITRAS) +#define isrealasize(t) (!((t)->flags & BITRAS)) +#define setrealasize(t) ((t)->flags &= cast_byte(~BITRAS)) +#define setnorealasize(t) ((t)->flags |= BITRAS) typedef struct Table { @@ -583,7 +583,7 @@ Table *luaH_new (lua_State *L) { GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table)); Table *t = gco2t(o); t->metatable = NULL; - t->flags = cast_byte(~0); + t->flags = cast_byte(maskflags); /* table has no metamethod fields */ t->array = NULL; t->alimit = 0; setnodevector(L, t, 0); @@ -15,7 +15,12 @@ #define gnext(n) ((n)->u.next) -#define invalidateTMcache(t) ((t)->flags = 0) +/* +** Clear all bits of fast-access metamethods, which means that the table +** may have any of these metamethods. (First access that fails after the +** clearing will set the bit again.) +*/ +#define invalidateTMcache(t) ((t)->flags &= ~maskflags) /* true when 't' is using 'dummynode' as its hash part */ @@ -46,6 +46,15 @@ typedef enum { /* +** Mask with 1 in all fast-access methods. A 1 in any of these bits +** in the flag of a (meta)table means the metatable does not have the +** corresponding metamethod field. (Bit 7 of the flag is used for +** 'isrealasize'.) +*/ +#define maskflags (~(~0u << (TM_EQ + 1))) + + +/* ** Test whether there is no tagmethod. ** (Because tagmethods use raw accesses, the result may be an "empty" nil.) */ diff --git a/testes/events.lua b/testes/events.lua index 8a01330e..17a73664 100644 --- a/testes/events.lua +++ b/testes/events.lua @@ -305,6 +305,17 @@ t[Set{1,3,5}] = 1 assert(t[Set{1,3,5}] == undef) +do -- test invalidating flags + local mt = {__eq = true} + local a = setmetatable({10}, mt) + local b = setmetatable({10}, mt) + mt.__eq = nil + assert(a ~= b) -- no metamethod + mt.__eq = function (x,y) return x[1] == y[1] end + assert(a == b) -- must use metamethod now +end + + if not T then (Message or print)('\n >>> testC not active: skipping tests for \z userdata <<<\n') |
