diff --git a/lgc.h b/lgc.h index b972472f..f571fd2b 100644 --- a/lgc.h +++ b/lgc.h @@ -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) */ diff --git a/lobject.h b/lobject.h index 16202230..a9d45785 100644 --- a/lobject.h +++ b/lobject.h @@ -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 { diff --git a/ltable.c b/ltable.c index d7eb69a2..5a0d066f 100644 --- a/ltable.c +++ b/ltable.c @@ -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); diff --git a/ltable.h b/ltable.h index ebd7f8ec..c0060f4b 100644 --- a/ltable.h +++ b/ltable.h @@ -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 */ diff --git a/ltm.h b/ltm.h index 99b545e7..73b833c6 100644 --- a/ltm.h +++ b/ltm.h @@ -45,6 +45,15 @@ typedef enum { } TMS; +/* +** 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')