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.
diff --git a/lgc.h b/lgc.h
index b972472..f571fd2 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 1620223..a9d4578 100644
--- a/lobject.h
+++ b/lobject.h
@@ -704,9 +704,9 @@
*/
#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 d7eb69a..5a0d066 100644
--- a/ltable.c
+++ b/ltable.c
@@ -583,7 +583,7 @@
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 ebd7f8e..c0060f4 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 99b545e..73b833c 100644
--- a/ltm.h
+++ b/ltm.h
@@ -46,6 +46,15 @@
/*
+** 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 8a01330..17a7366 100644
--- a/testes/events.lua
+++ b/testes/events.lua
@@ -305,6 +305,17 @@
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')