Browse Source

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.
Roberto Ierusalimschy 5 years ago
parent
commit
7c3cb71fa4
6 changed files with 31 additions and 7 deletions
  1. 1 2
      lgc.h
  2. 3 3
      lobject.h
  3. 1 1
      ltable.c
  4. 6 1
      ltable.h
  5. 9 0
      ltm.h
  6. 11 0
      testes/events.lua

+ 1 - 2
lgc.h

@@ -69,8 +69,7 @@
 
 
 /*
 /*
 ** Layout for bit use in 'marked' field. First three bits are
 ** 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 WHITE0BIT	3  /* object is white (type 0) */
 #define WHITE1BIT	4  /* object is white (type 1) */
 #define WHITE1BIT	4  /* object is white (type 1) */

+ 3 - 3
lobject.h

@@ -704,9 +704,9 @@ typedef union Node {
 */
 */
 
 
 #define BITRAS		(1 << 7)
 #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 {
 typedef struct Table {

+ 1 - 1
ltable.c

@@ -583,7 +583,7 @@ Table *luaH_new (lua_State *L) {
   GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table));
   GCObject *o = luaC_newobj(L, LUA_VTABLE, sizeof(Table));
   Table *t = gco2t(o);
   Table *t = gco2t(o);
   t->metatable = NULL;
   t->metatable = NULL;
-  t->flags = cast_byte(~0);
+  t->flags = cast_byte(maskflags);  /* table has no metamethod fields */
   t->array = NULL;
   t->array = NULL;
   t->alimit = 0;
   t->alimit = 0;
   setnodevector(L, t, 0);
   setnodevector(L, t, 0);

+ 6 - 1
ltable.h

@@ -15,7 +15,12 @@
 #define gnext(n)	((n)->u.next)
 #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 */
 /* true when 't' is using 'dummynode' as its hash part */

+ 9 - 0
ltm.h

@@ -45,6 +45,15 @@ typedef enum {
 } TMS;
 } 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.
 ** Test whether there is no tagmethod.
 ** (Because tagmethods use raw accesses, the result may be an "empty" nil.)
 ** (Because tagmethods use raw accesses, the result may be an "empty" nil.)

+ 11 - 0
testes/events.lua

@@ -305,6 +305,17 @@ t[Set{1,3,5}] = 1
 assert(t[Set{1,3,5}] == undef)
 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
 if not T then
   (Message or print)('\n >>> testC not active: skipping tests for \z
   (Message or print)('\n >>> testC not active: skipping tests for \z
 userdata <<<\n')
 userdata <<<\n')