2
0
Эх сурвалжийг харах

revamp of fast track for table access (table set uses the same
macros as table get + new macro for integer keys)

Roberto Ierusalimschy 8 жил өмнө
parent
commit
7647d5d13d
3 өөрчлөгдсөн 81 нэмэгдсэн , 94 устгасан
  1. 26 15
      lapi.c
  2. 36 51
      lvm.c
  3. 19 28
      lvm.h

+ 26 - 15
lapi.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 2.264 2017/04/20 18:22:44 roberto Exp roberto $
+** $Id: lapi.c,v 2.265 2017/04/24 16:59:26 roberto Exp roberto $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
@@ -609,10 +609,15 @@ LUA_API int lua_getglobal (lua_State *L, const char *name) {
 
 
 LUA_API int lua_gettable (lua_State *L, int idx) {
+  const TValue *slot;
   StkId t;
   lua_lock(L);
   t = index2addr(L, idx);
-  luaV_gettable(L, t, L->top - 1, L->top - 1);
+  if (luaV_fastget(L, t, L->top - 1, slot, luaH_get)) {
+    setobj2s(L, L->top - 1, slot);
+  }
+  else
+    luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
   lua_unlock(L);
   return ttnov(L->top - 1);
 }
@@ -629,15 +634,15 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
   const TValue *slot;
   lua_lock(L);
   t = index2addr(L, idx);
-  if (luaV_fastget(L, t, n, slot, luaH_getint)) {
+  if (luaV_fastgeti(L, t, n, slot)) {
     setobj2s(L, L->top, slot);
-    api_incr_top(L);
   }
   else {
-    setivalue(L->top, n);
-    api_incr_top(L);
-    luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
+    TValue aux;
+    setivalue(&aux, n);
+    luaV_finishget(L, t, &aux, L->top, slot);
   }
+  api_incr_top(L);
   lua_unlock(L);
   return ttnov(L->top - 1);
 }
@@ -743,8 +748,10 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
   const TValue *slot;
   TString *str = luaS_new(L, k);
   api_checknelems(L, 1);
-  if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
+  if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
+    luaV_finishfastset(L, t, slot, L->top - 1);
     L->top--;  /* pop value */
+  }
   else {
     setsvalue2s(L, L->top, str);  /* push 'str' (to make it a TValue) */
     api_incr_top(L);
@@ -764,10 +771,14 @@ LUA_API void lua_setglobal (lua_State *L, const char *name) {
 
 LUA_API void lua_settable (lua_State *L, int idx) {
   StkId t;
+  const TValue *slot;
   lua_lock(L);
   api_checknelems(L, 2);
   t = index2addr(L, idx);
-  luaV_settable(L, t, L->top - 2, L->top - 1);
+  if (luaV_fastget(L, t, L->top - 2, slot, luaH_get))
+    luaV_finishfastset(L, t, slot, L->top - 1);
+  else
+    luaV_finishset(L, t, L->top - 2, L->top - 1, slot);
   L->top -= 2;  /* pop index and value */
   lua_unlock(L);
 }
@@ -785,14 +796,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
   lua_lock(L);
   api_checknelems(L, 1);
   t = index2addr(L, idx);
-  if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
-    L->top--;  /* pop value */
+  if (luaV_fastgeti(L, t, n, slot))
+    luaV_finishfastset(L, t, slot, L->top - 1);
   else {
-    setivalue(L->top, n);
-    api_incr_top(L);
-    luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
-    L->top -= 2;  /* pop value and key */
+    TValue aux;
+    setivalue(&aux, n);
+    luaV_finishset(L, t, &aux, L->top - 1, slot);
   }
+  L->top--;  /* pop value */
   lua_unlock(L);
 }
 

+ 36 - 51
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.278 2017/05/08 16:08:01 roberto Exp roberto $
+** $Id: lvm.c,v 2.279 2017/05/10 17:32:19 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -182,7 +182,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
       return;
     }
     t = tm;  /* else try to access 'tm[key]' */
-    if (luaV_fastget(L,t,key,slot,luaH_get)) {  /* fast track? */
+    if (luaV_fastget(L, t, key, slot, luaH_get)) {  /* fast track? */
       setobj2s(L, val, slot);  /* done */
       return;
     }
@@ -196,7 +196,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
 ** Finish a table assignment 't[key] = val'.
 ** If 'slot' is NULL, 't' is not a table.  Otherwise, 'slot' points
 ** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
-** entry.  (The value at 'slot' must be nil, otherwise 'luaV_fastset'
+** entry.  (The value at 'slot' must be nil, otherwise 'luaV_fastget'
 ** would have done the job.)
 */
 void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
@@ -229,9 +229,11 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
       return;
     }
     t = tm;  /* else repeat assignment over 'tm' */
-    if (luaV_fastset(L, t, key, slot, luaH_get, val))
+    if (luaV_fastget(L, t, key, slot, luaH_get)) {
+      luaV_finishfastset(L, t, slot, val);
       return;  /* done */
-    /* else loop */
+    }
+    /* else 'return luaV_finishset(L, t, key, val, slot)' (loop) */
   }
   luaG_runerror(L, "'__newindex' chain too long; possible loop");
 }
@@ -791,35 +793,6 @@ void luaV_finishOp (lua_State *L) {
 #define vmbreak		break
 
 
-/*
-** copy of 'luaV_gettable', but protecting the call to potential
-** metamethod (which can reallocate the stack)
-*/
-#define gettableProtected(L,t,k,v)  { const TValue *slot; \
-  if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
-  else Protect(luaV_finishget(L,t,k,v,slot)); }
-
-
-/* same for 'luaV_settable' */
-#define settableProtected(L,t,k,v) { const TValue *slot; \
-  if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
-    Protect(luaV_finishset(L,t,k,v,slot)); }
-
-
-/*
-** Predicate for integer fast track in GET/SETTABLE.
-** (Strings are usually constant and therefore coded with
-** GET/SETFIELD). Check that index is an integer, "table" is
-** a table, index is in the array part, and value is not nil
-** (otherwise it will need metamethods). Use 'n' and 't' for
-** for caching the integer and table values.
-*/
-#define fastintindex(tbl,idx,t,n)  \
-        (ttisinteger(idx) && ttistable(tbl) && \
-            (n = l_castS2U(ivalue(idx)) - 1u, t = hvalue(tbl), \
-             n < t->sizearray) && !ttisnil(&t->array[n]))
-
-
 void luaV_execute (lua_State *L) {
   CallInfo *ci = L->ci;
   LClosure *cl;
@@ -899,21 +872,24 @@ void luaV_execute (lua_State *L) {
         vmbreak;
       }
       vmcase(OP_GETTABLE) {
+        const TValue *slot;
         StkId rb = RB(i);
         TValue *rc = RC(i);
-        Table *t; lua_Unsigned n;
-        if (fastintindex(rb, rc, t, n)) {
-          setobj2s(L, ra, &t->array[n]);
+        lua_Unsigned n;
+        if (ttisinteger(rc)  /* fast track for integers? */
+            ? (n = ivalue(rc), luaV_fastgeti(L, rb, n, slot))
+            : luaV_fastget(L, rb, rc, slot, luaH_get)) {
+          setobj2s(L, ra, slot);
         }
         else
-          gettableProtected(L, rb, rc, ra);
+          Protect(luaV_finishget(L, rb, rc, ra, slot));
         vmbreak;
       }
       vmcase(OP_GETI) {
         const TValue *slot;
         StkId rb = RB(i);
         int c = GETARG_C(i);
-        if (luaV_fastget(L, rb, c, slot, luaH_getint)) {
+        if (luaV_fastgeti(L, rb, c, slot)) {
           setobj2s(L, ra, slot);
         }
         else {
@@ -940,26 +916,32 @@ void luaV_execute (lua_State *L) {
         TValue *rb = KB(i);
         TValue *rc = RKC(i);
         TString *key = tsvalue(rb);  /* key must be a string */
-        if (!luaV_fastset(L, upval, key, slot, luaH_getstr, rc))
+        if (luaV_fastget(L, upval, key, slot, luaH_getstr))
+          luaV_finishfastset(L, upval, slot, rc);
+        else
           Protect(luaV_finishset(L, upval, rb, rc, slot));
         vmbreak;
       }
       vmcase(OP_SETTABLE) {
-        TValue *rb = RB(i);
-        TValue *rc = RKC(i);
-        Table *t; lua_Unsigned n;
-        if (fastintindex(ra, rb, t, n)) {
-          setobj2t(L, &t->array[n], rc);
-        }
+        const TValue *slot;
+        TValue *rb = RB(i);  /* key (table is in 'ra') */
+        TValue *rc = RKC(i);  /* value */
+        lua_Unsigned n;
+        if (ttisinteger(rb)  /* fast track for integers? */
+            ? (n = ivalue(rb), luaV_fastgeti(L, ra, n, slot))
+            : luaV_fastget(L, ra, rb, slot, luaH_get))
+          luaV_finishfastset(L, ra, slot, rc);
         else
-          settableProtected(L, ra, rb, rc);
+          Protect(luaV_finishset(L, ra, rb, rc, slot));
         vmbreak;
       }
       vmcase(OP_SETI) {
         const TValue *slot;
         int c = GETARG_B(i);
         TValue *rc = RKC(i);
-        if (!luaV_fastset(L, ra, c, slot, luaH_getint, rc)) {
+        if (luaV_fastgeti(L, ra, c, slot))
+          luaV_finishfastset(L, ra, slot, rc);
+        else {
           TValue key;
           setivalue(&key, c);
           Protect(luaV_finishset(L, ra, &key, rc, slot));
@@ -971,7 +953,9 @@ void luaV_execute (lua_State *L) {
         TValue *rb = KB(i);
         TValue *rc = RKC(i);
         TString *key = tsvalue(rb);  /* key must be a string */
-        if (!luaV_fastset(L, ra, key, slot, luaH_getstr, rc))
+        if (luaV_fastget(L, ra, key, slot, luaH_getstr))
+          luaV_finishfastset(L, ra, slot, rc);
+        else
           Protect(luaV_finishset(L, ra, rb, rc, slot));
         vmbreak;
       }
@@ -1427,8 +1411,9 @@ void luaV_execute (lua_State *L) {
         if (last > h->sizearray)  /* needs more space? */
           luaH_resizearray(L, h, last);  /* preallocate it at once */
         for (; n > 0; n--) {
-          TValue *val = ra+n;
-          luaH_setint(L, h, last--, val);
+          TValue *val = ra + n;
+          setobj2t(L, &h->array[last - 1], val);
+          last--;
           luaC_barrierback(L, h, val);
         }
         L->top = ci->top;  /* correct top (in case of previous open call) */

+ 19 - 28
lvm.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp roberto $
+** $Id: lvm.h,v 2.41 2016/12/22 13:08:50 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -50,10 +50,10 @@
 
 /*
 ** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
-** return 1 with 'slot' pointing to 't[k]' (final result).  Otherwise,
-** return 0 (meaning it will have to check metamethod) with 'slot'
-** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
-** 'f' is the raw get function to use.
+** return 1 with 'slot' pointing to 't[k]' (position of final result).
+** Otherwise, return 0 (meaning it will have to check metamethod)
+** with 'slot' pointing to a nil 't[k]' (if 't' is a table) or NULL
+** (otherwise). 'f' is the raw get function to use.
 */
 #define luaV_fastget(L,t,k,slot,f) \
   (!ttistable(t)  \
@@ -61,35 +61,26 @@
    : (slot = f(hvalue(t), k),  /* else, do raw access */  \
       !ttisnil(slot)))  /* result not nil? */
 
+
 /*
-** standard implementation for 'gettable'
+** Special case of 'luaV_fastget' for integers, inlining the fast case
+** of 'luaH_getint'.
 */
-#define luaV_gettable(L,t,k,v) { const TValue *slot; \
-  if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
-  else luaV_finishget(L,t,k,v,slot); }
+#define luaV_fastgeti(L,t,k,slot) \
+  (!ttistable(t)  \
+   ? (slot = NULL, 0)  /* not a table; 'slot' is NULL and result is 0 */  \
+   : (slot = (l_castS2U(k) - 1u < hvalue(t)->sizearray) \
+              ? &hvalue(t)->array[k - 1] : luaH_getint(hvalue(t), k), \
+      !ttisnil(slot)))  /* result not nil? */
 
 
 /*
-** Fast track for set table. If 't' is a table and 't[k]' is not nil,
-** call GC barrier, do a raw 't[k]=v', and return true; otherwise,
-** return false with 'slot' equal to NULL (if 't' is not a table) or
-** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro
-** returns true, there is no need to 'invalidateTMcache', because the
-** call is not creating a new entry.
+** Finish a fast set operation (when fast get succeeds). In that case,
+** 'slot' points to the place to put the value. 
 */
-#define luaV_fastset(L,t,k,slot,f,v) \
-  (!ttistable(t) \
-   ? (slot = NULL, 0) \
-   : (slot = f(hvalue(t), k), \
-     ttisnil(slot) ? 0 \
-     : (luaC_barrierback(L, hvalue(t), v), \
-        setobj2t(L, cast(TValue *,slot), v), \
-        1)))
-
-
-#define luaV_settable(L,t,k,v) { const TValue *slot; \
-  if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
-    luaV_finishset(L,t,k,v,slot); }
+#define luaV_finishfastset(L,t,slot,v) \
+    (setobj2t(L, cast(TValue *,slot), v), luaC_barrierback(L, hvalue(t), v))
+