diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-03-30 14:49:18 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2021-03-30 14:49:18 -0300 |
commit | 36de01d9885562444ae2e2a3e0b7e01b3fb8743b (patch) | |
tree | 7aed386cc8d13e3b2a960404d2cf605d8090d571 | |
parent | 7fbe2158089898f09d741e991737f282e514ffaa (diff) | |
download | lua-github-36de01d9885562444ae2e2a3e0b7e01b3fb8743b.tar.gz |
Changes in cache for function constants
In 'lcode.c', when adding constants to the list of constants of a
function, integers represent themselves in the cache and floats
with integral values get a small delta to avoid collision with
integers. (This change avoids creating artificial addresses; the old
implementation converted integers to pointers to index the cache.)
-rw-r--r-- | lcode.c | 34 | ||||
-rw-r--r-- | testes/code.lua | 14 |
2 files changed, 40 insertions, 8 deletions
@@ -10,6 +10,7 @@ #include "lprefix.h" +#include <float.h> #include <limits.h> #include <math.h> #include <stdlib.h> @@ -580,24 +581,41 @@ static int stringK (FuncState *fs, TString *s) { /* ** Add an integer to list of constants and return its index. -** Integers use userdata as keys to avoid collision with floats with -** same value; conversion to 'void*' is used only for hashing, so there -** are no "precision" problems. */ static int luaK_intK (FuncState *fs, lua_Integer n) { - TValue k, o; - setpvalue(&k, cast_voidp(cast_sizet(n))); + TValue o; setivalue(&o, n); - return addk(fs, &k, &o); + return addk(fs, &o, &o); /* use integer itself as key */ } /* -** Add a float to list of constants and return its index. +** Add a float to list of constants and return its index. Floats +** with integral values need a different key, to avoid collision +** with actual integers. To that, we add to the number its smaller +** power-of-two fraction that is still significant in its scale. +** For doubles, that would be 1/2^52. +** (This method is not bulletproof: there may be another float +** with that value, and for floats larger than 2^53 the result is +** still an integer. At worst, this only wastes an entry with +** a duplicate.) */ static int luaK_numberK (FuncState *fs, lua_Number r) { TValue o; + lua_Integer ik; setfltvalue(&o, r); - return addk(fs, &o, &o); /* use number itself as key */ + if (!luaV_flttointeger(r, &ik, F2Ieq)) /* not an integral value? */ + return addk(fs, &o, &o); /* use number itself as key */ + else { /* must build an alternative key */ + const int nbm = l_floatatt(MANT_DIG); + const lua_Number q = l_mathop(ldexp)(1.0, -nbm + 1); + const lua_Number k = (ik == 0) ? q : r + r*q; /* new key */ + TValue kv; + setfltvalue(&kv, k); + /* result is not an integral value, unless value is too large */ + lua_assert(!luaV_flttointeger(k, &ik, F2Ieq) || + l_mathop(fabs)(r) >= l_mathop(1e6)); + return addk(fs, &kv, &o); + } } diff --git a/testes/code.lua b/testes/code.lua index 4e00309f..543743fc 100644 --- a/testes/code.lua +++ b/testes/code.lua @@ -69,6 +69,20 @@ foo = function (f, a) checkKlist(foo, {100000, 100000.0, -100000, -100000.0}) +-- floats x integers +foo = function (t, a) + t[a] = 1; t[a] = 1.0 + t[a] = 1; t[a] = 1.0 + t[a] = 2; t[a] = 2.0 + t[a] = 0; t[a] = 0.0 + t[a] = 1; t[a] = 1.0 + t[a] = 2; t[a] = 2.0 + t[a] = 0; t[a] = 0.0 +end + +checkKlist(foo, {1, 1.0, 2, 2.0, 0, 0.0}) + + -- testing opcodes -- check that 'f' opcodes match '...' |