aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-01-15 11:31:49 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-01-15 11:31:49 -0300
commit17e0c29d9b435392016b707309ed51409b0aea12 (patch)
treec7178cf68fac2f1f9c3b22ce50be29b67f416cc0
parent8eb0abc9db4d47db5192bed18565e3d1aa53566d (diff)
downloadlua-17e0c29d9b435392016b707309ed51409b0aea12.tar.gz
lua-17e0c29d9b435392016b707309ed51409b0aea12.tar.bz2
lua-17e0c29d9b435392016b707309ed51409b0aea12.zip
Clear interface between references and predefines
The reference system has a defined way to add initial values to the table where it operates.
Diffstat (limited to '')
-rw-r--r--lauxlib.c28
-rw-r--r--lstate.c3
-rw-r--r--ltests.c28
-rw-r--r--lua.h5
-rw-r--r--manual/manual.of26
-rw-r--r--testes/api.lua37
-rw-r--r--testes/coroutine.lua8
7 files changed, 92 insertions, 43 deletions
diff --git a/lauxlib.c b/lauxlib.c
index ab3c7c93..8d23bc7d 100644
--- a/lauxlib.c
+++ b/lauxlib.c
@@ -672,13 +672,10 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
672** ======================================================= 672** =======================================================
673*/ 673*/
674 674
675/* index of free-list header (after the predefined values) */
676#define freelist (LUA_RIDX_LAST + 1)
677
678/* 675/*
679** The previously freed references form a linked list: 676** The previously freed references form a linked list: t[1] is the index
680** t[freelist] is the index of a first free index, or zero if list is 677** of a first free index, t[t[1]] is the index of the second element,
681** empty; t[t[freelist]] is the index of the second element; etc. 678** etc. A zero signals the end of the list.
682*/ 679*/
683LUALIB_API int luaL_ref (lua_State *L, int t) { 680LUALIB_API int luaL_ref (lua_State *L, int t) {
684 int ref; 681 int ref;
@@ -687,19 +684,18 @@ LUALIB_API int luaL_ref (lua_State *L, int t) {
687 return LUA_REFNIL; /* 'nil' has a unique fixed reference */ 684 return LUA_REFNIL; /* 'nil' has a unique fixed reference */
688 } 685 }
689 t = lua_absindex(L, t); 686 t = lua_absindex(L, t);
690 if (lua_rawgeti(L, t, freelist) == LUA_TNIL) { /* first access? */ 687 if (lua_rawgeti(L, t, 1) == LUA_TNUMBER) /* already initialized? */
688 ref = (int)lua_tointeger(L, -1); /* ref = t[1] */
689 else { /* first access */
690 lua_assert(!lua_toboolean(L, -1)); /* must be nil or false */
691 ref = 0; /* list is empty */ 691 ref = 0; /* list is empty */
692 lua_pushinteger(L, 0); /* initialize as an empty list */ 692 lua_pushinteger(L, 0); /* initialize as an empty list */
693 lua_rawseti(L, t, freelist); /* ref = t[freelist] = 0 */ 693 lua_rawseti(L, t, 1); /* ref = t[1] = 0 */
694 }
695 else { /* already initialized */
696 lua_assert(lua_isinteger(L, -1));
697 ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */
698 } 694 }
699 lua_pop(L, 1); /* remove element from stack */ 695 lua_pop(L, 1); /* remove element from stack */
700 if (ref != 0) { /* any free element? */ 696 if (ref != 0) { /* any free element? */
701 lua_rawgeti(L, t, ref); /* remove it from list */ 697 lua_rawgeti(L, t, ref); /* remove it from list */
702 lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ 698 lua_rawseti(L, t, 1); /* (t[1] = t[ref]) */
703 } 699 }
704 else /* no free elements */ 700 else /* no free elements */
705 ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ 701 ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */
@@ -711,11 +707,11 @@ LUALIB_API int luaL_ref (lua_State *L, int t) {
711LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { 707LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
712 if (ref >= 0) { 708 if (ref >= 0) {
713 t = lua_absindex(L, t); 709 t = lua_absindex(L, t);
714 lua_rawgeti(L, t, freelist); 710 lua_rawgeti(L, t, 1);
715 lua_assert(lua_isinteger(L, -1)); 711 lua_assert(lua_isinteger(L, -1));
716 lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ 712 lua_rawseti(L, t, ref); /* t[ref] = t[1] */
717 lua_pushinteger(L, ref); 713 lua_pushinteger(L, ref);
718 lua_rawseti(L, t, freelist); /* t[freelist] = ref */ 714 lua_rawseti(L, t, 1); /* t[1] = ref */
719 } 715 }
720} 716}
721 717
diff --git a/lstate.c b/lstate.c
index 78146bdb..9a61cd6d 100644
--- a/lstate.c
+++ b/lstate.c
@@ -189,6 +189,9 @@ static void init_registry (lua_State *L, global_State *g) {
189 Table *registry = luaH_new(L); 189 Table *registry = luaH_new(L);
190 sethvalue(L, &g->l_registry, registry); 190 sethvalue(L, &g->l_registry, registry);
191 luaH_resize(L, registry, LUA_RIDX_LAST, 0); 191 luaH_resize(L, registry, LUA_RIDX_LAST, 0);
192 /* registry[1] = false */
193 setbfvalue(&aux);
194 luaH_setint(L, registry, 1, &aux);
192 /* registry[LUA_RIDX_MAINTHREAD] = L */ 195 /* registry[LUA_RIDX_MAINTHREAD] = L */
193 setthvalue(L, &aux, L); 196 setthvalue(L, &aux, L);
194 luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &aux); 197 luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &aux);
diff --git a/ltests.c b/ltests.c
index 6eebc732..6de62e52 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1084,27 +1084,39 @@ static int string_query (lua_State *L) {
1084} 1084}
1085 1085
1086 1086
1087static int getreftable (lua_State *L) {
1088 if (lua_istable(L, 2)) /* is there a table as second argument? */
1089 return 2; /* use it as the table */
1090 else
1091 return LUA_REGISTRYINDEX; /* default is to use the register */
1092}
1093
1094
1087static int tref (lua_State *L) { 1095static int tref (lua_State *L) {
1096 int t = getreftable(L);
1088 int level = lua_gettop(L); 1097 int level = lua_gettop(L);
1089 luaL_checkany(L, 1); 1098 luaL_checkany(L, 1);
1090 lua_pushvalue(L, 1); 1099 lua_pushvalue(L, 1);
1091 lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX)); 1100 lua_pushinteger(L, luaL_ref(L, t));
1092 cast_void(level); /* to avoid warnings */ 1101 cast_void(level); /* to avoid warnings */
1093 lua_assert(lua_gettop(L) == level+1); /* +1 for result */ 1102 lua_assert(lua_gettop(L) == level+1); /* +1 for result */
1094 return 1; 1103 return 1;
1095} 1104}
1096 1105
1106
1097static int getref (lua_State *L) { 1107static int getref (lua_State *L) {
1108 int t = getreftable(L);
1098 int level = lua_gettop(L); 1109 int level = lua_gettop(L);
1099 lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkinteger(L, 1)); 1110 lua_rawgeti(L, t, luaL_checkinteger(L, 1));
1100 cast_void(level); /* to avoid warnings */ 1111 cast_void(level); /* to avoid warnings */
1101 lua_assert(lua_gettop(L) == level+1); 1112 lua_assert(lua_gettop(L) == level+1);
1102 return 1; 1113 return 1;
1103} 1114}
1104 1115
1105static int unref (lua_State *L) { 1116static int unref (lua_State *L) {
1117 int t = getreftable(L);
1106 int level = lua_gettop(L); 1118 int level = lua_gettop(L);
1107 luaL_unref(L, LUA_REGISTRYINDEX, cast_int(luaL_checkinteger(L, 1))); 1119 luaL_unref(L, t, cast_int(luaL_checkinteger(L, 1)));
1108 cast_void(level); /* to avoid warnings */ 1120 cast_void(level); /* to avoid warnings */
1109 lua_assert(lua_gettop(L) == level); 1121 lua_assert(lua_gettop(L) == level);
1110 return 0; 1122 return 0;
@@ -1373,6 +1385,16 @@ static int getnum_aux (lua_State *L, lua_State *L1, const char **pc) {
1373 (*pc)++; 1385 (*pc)++;
1374 return res; 1386 return res;
1375 } 1387 }
1388 else if (**pc == '!') {
1389 (*pc)++;
1390 if (**pc == 'G')
1391 res = LUA_RIDX_GLOBALS;
1392 else if (**pc == 'M')
1393 res = LUA_RIDX_MAINTHREAD;
1394 else lua_assert(0);
1395 (*pc)++;
1396 return res;
1397 }
1376 else if (**pc == '-') { 1398 else if (**pc == '-') {
1377 sig = -1; 1399 sig = -1;
1378 (*pc)++; 1400 (*pc)++;
diff --git a/lua.h b/lua.h
index 26b45e3e..b7508b4e 100644
--- a/lua.h
+++ b/lua.h
@@ -80,9 +80,10 @@ typedef struct lua_State lua_State;
80 80
81 81
82/* predefined values in the registry */ 82/* predefined values in the registry */
83#define LUA_RIDX_MAINTHREAD 1 83/* index 1 is reserved for the reference mechanism */
84#define LUA_RIDX_GLOBALS 2 84#define LUA_RIDX_GLOBALS 2
85#define LUA_RIDX_LAST LUA_RIDX_GLOBALS 85#define LUA_RIDX_MAINTHREAD 3
86#define LUA_RIDX_LAST 3
86 87
87 88
88/* type of numbers in Lua */ 89/* type of numbers in Lua */
diff --git a/manual/manual.of b/manual/manual.of
index ae38d7c6..64bb5473 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -2645,8 +2645,8 @@ string keys starting with an underscore followed by
2645uppercase letters are reserved for Lua. 2645uppercase letters are reserved for Lua.
2646 2646
2647The integer keys in the registry are used 2647The integer keys in the registry are used
2648by the reference mechanism @seeC{luaL_ref} 2648by the reference mechanism @seeC{luaL_ref},
2649and by some predefined values. 2649with some predefined values.
2650Therefore, integer keys in the registry 2650Therefore, integer keys in the registry
2651must not be used for other purposes. 2651must not be used for other purposes.
2652 2652
@@ -6018,11 +6018,21 @@ Creates and returns a @def{reference},
6018in the table at index @id{t}, 6018in the table at index @id{t},
6019for the object on the top of the stack (and pops the object). 6019for the object on the top of the stack (and pops the object).
6020 6020
6021A reference is a unique integer key. 6021The reference system uses the integer keys of the table.
6022As long as you do not manually add integer keys into the table @id{t}, 6022A reference is a unique integer key;
6023@Lid{luaL_ref} ensures the uniqueness of the key it returns. 6023@Lid{luaL_ref} ensures the uniqueness of the keys it returns.
6024The entry 1 is reserved for internal use.
6025Before the first use of @Lid{luaL_ref},
6026the integer keys of the table
6027should form a proper sequence (no holes),
6028and the value at entry 1 should be false:
6029@nil if the sequence is empty,
6030@false otherwise.
6031You should not manually set integer keys in the table
6032after the first use of @Lid{luaL_ref}.
6033
6024You can retrieve an object referred by the reference @id{r} 6034You can retrieve an object referred by the reference @id{r}
6025by calling @T{lua_rawgeti(L, t, r)}. 6035by calling @T{lua_rawgeti(L, t, r)} or @T{lua_geti(L, t, r)}.
6026The function @Lid{luaL_unref} frees a reference. 6036The function @Lid{luaL_unref} frees a reference.
6027 6037
6028If the object on the top of the stack is @nil, 6038If the object on the top of the stack is @nil,
@@ -6188,8 +6198,8 @@ Returns the name of the type of the value at the given index.
6188Releases the reference @id{ref} from the table at index @id{t} 6198Releases the reference @id{ref} from the table at index @id{t}
6189@seeC{luaL_ref}. 6199@seeC{luaL_ref}.
6190The entry is removed from the table, 6200The entry is removed from the table,
6191so that the referred object can be collected. 6201so that the referred object can be collected and
6192The reference @id{ref} is also freed to be used again. 6202the reference @id{ref} can be used again by @Lid{luaL_ref}.
6193 6203
6194If @id{ref} is @Lid{LUA_NOREF} or @Lid{LUA_REFNIL}, 6204If @id{ref} is @Lid{LUA_NOREF} or @Lid{LUA_REFNIL},
6195@Lid{luaL_unref} does nothing. 6205@Lid{luaL_unref} does nothing.
diff --git a/testes/api.lua b/testes/api.lua
index 85dadb69..ca4b3fb4 100644
--- a/testes/api.lua
+++ b/testes/api.lua
@@ -467,7 +467,7 @@ for i = 1,lim do
467 prog[#prog + 1] = "pushnum " .. i * 10 467 prog[#prog + 1] = "pushnum " .. i * 10
468end 468end
469 469
470prog[#prog + 1] = "rawgeti R 2" -- get global table in registry 470prog[#prog + 1] = "rawgeti R !G" -- get global table in registry
471prog[#prog + 1] = "insert " .. -(2*lim + 2) 471prog[#prog + 1] = "insert " .. -(2*lim + 2)
472 472
473for i = 1,lim do 473for i = 1,lim do
@@ -930,28 +930,30 @@ checkerr("FILE%* expected, got userdata", io.input, x)
930 930
931assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil) 931assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil)
932 932
933local d = T.ref(a); 933-- Test references in an arbitrary table
934local e = T.ref(b); 934local reftable = {}
935local f = T.ref(c); 935local d = T.ref(a, reftable);
936t = {T.getref(d), T.getref(e), T.getref(f)} 936local e = T.ref(b, reftable);
937local f = T.ref(c, reftable);
938t = {T.getref(d, reftable), T.getref(e, reftable), T.getref(f, reftable)}
937assert(t[1] == a and t[2] == b and t[3] == c) 939assert(t[1] == a and t[2] == b and t[3] == c)
938 940
939t=nil; a=nil; c=nil; 941t=nil; a=nil; c=nil;
940T.unref(e); T.unref(f) 942T.unref(e, reftable); T.unref(f, reftable)
941 943
942collectgarbage() 944collectgarbage()
943 945
944-- check that unref objects have been collected 946-- check that unref objects have been collected
945assert(#cl == 1 and cl[1] == nc) 947assert(#cl == 1 and cl[1] == nc)
946 948
947x = T.getref(d) 949x = T.getref(d, reftable)
948assert(type(x) == 'userdata' and debug.getmetatable(x) == tt) 950assert(type(x) == 'userdata' and debug.getmetatable(x) == tt)
949x =nil 951x =nil
950tt.b = b -- create cycle 952tt.b = b -- create cycle
951tt=nil -- frees tt for GC 953tt=nil -- frees tt for GC
952A = nil 954A = nil
953b = nil 955b = nil
954T.unref(d); 956T.unref(d, reftable);
955local n5 = T.newuserdata(0) 957local n5 = T.newuserdata(0)
956debug.setmetatable(n5, {__gc=F}) 958debug.setmetatable(n5, {__gc=F})
957n5 = T.udataval(n5) 959n5 = T.udataval(n5)
@@ -960,6 +962,21 @@ assert(#cl == 4)
960-- check order of collection 962-- check order of collection
961assert(cl[2] == n5 and cl[3] == nb and cl[4] == na) 963assert(cl[2] == n5 and cl[3] == nb and cl[4] == na)
962 964
965-- reuse a reference in 'reftable'
966T.unref(T.ref(23, reftable), reftable)
967
968do -- check reftable
969 local count = 0
970 local i = 1
971 while reftable[i] ~= 0 do
972 i = reftable[i] -- traverse linked list of free references
973 count = count + 1
974 end
975 -- maximum number of simultaneously locked objects was 3
976 assert(count == 3 and #reftable == 3 + 1) -- +1 for reserved [1]
977end
978
979
963collectgarbage"restart" 980collectgarbage"restart"
964 981
965 982
@@ -1363,8 +1380,8 @@ end)
1363 1380
1364-- testing threads 1381-- testing threads
1365 1382
1366-- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1) 1383-- get main thread from registry
1367local mt = T.testC("rawgeti R 1; return 1") 1384local mt = T.testC("rawgeti R !M; return 1")
1368assert(type(mt) == "thread" and coroutine.running() == mt) 1385assert(type(mt) == "thread" and coroutine.running() == mt)
1369 1386
1370 1387
diff --git a/testes/coroutine.lua b/testes/coroutine.lua
index 990da8c4..6c15db03 100644
--- a/testes/coroutine.lua
+++ b/testes/coroutine.lua
@@ -681,7 +681,7 @@ else
681 c == "ERRRUN" and d == 4) 681 c == "ERRRUN" and d == 4)
682 682
683 a, b, c, d = T.testC([[ 683 a, b, c, d = T.testC([[
684 rawgeti R 1 # get main thread 684 rawgeti R !M # get main thread
685 pushnum 10; 685 pushnum 10;
686 pushnum 20; 686 pushnum 20;
687 resume -3 2; 687 resume -3 2;
@@ -699,7 +699,7 @@ else
699 assert(T.testC(state, "newthread; isyieldable -1; remove 1; return 1")) 699 assert(T.testC(state, "newthread; isyieldable -1; remove 1; return 1"))
700 700
701 -- main thread is not yieldable 701 -- main thread is not yieldable
702 assert(not T.testC(state, "rawgeti R 1; isyieldable -1; remove 1; return 1")) 702 assert(not T.testC(state, "rawgeti R !M; isyieldable -1; remove 1; return 1"))
703 703
704 T.testC(state, "settop 0") 704 T.testC(state, "settop 0")
705 705
@@ -711,7 +711,7 @@ else
711 return 'ok']])) 711 return 'ok']]))
712 712
713 local t = table.pack(T.testC(state, [[ 713 local t = table.pack(T.testC(state, [[
714 rawgeti R 1 # get main thread 714 rawgeti R !M # get main thread
715 pushstring 'XX' 715 pushstring 'XX'
716 getglobal X # get function for body 716 getglobal X # get function for body
717 pushstring AA # arg 717 pushstring AA # arg
@@ -720,7 +720,7 @@ else
720 setglobal T # top 720 setglobal T # top
721 setglobal B # second yielded value 721 setglobal B # second yielded value
722 setglobal A # fist yielded value 722 setglobal A # fist yielded value
723 rawgeti R 1 # get main thread 723 rawgeti R !M # get main thread
724 pushnum 5 # arg (noise) 724 pushnum 5 # arg (noise)
725 resume 1 1 # after coroutine ends, previous stack is back 725 resume 1 1 # after coroutine ends, previous stack is back
726 pushstatus 726 pushstatus