This commit is contained in:
Roberto I
2025-08-09 15:08:53 -03:00
parent 8fddca81e7
commit 5b179eaf6a
5 changed files with 51 additions and 28 deletions

29
lcode.c
View File

@@ -565,20 +565,20 @@ static int k2proto (FuncState *fs, TValue *key, TValue *v) {
TValue val; TValue val;
Proto *f = fs->f; Proto *f = fs->f;
int tag = luaH_get(fs->kcache, key, &val); /* query scanner table */ int tag = luaH_get(fs->kcache, key, &val); /* query scanner table */
int k;
if (!tagisempty(tag)) { /* is there an index there? */ if (!tagisempty(tag)) { /* is there an index there? */
k = cast_int(ivalue(&val)); int k = cast_int(ivalue(&val));
/* collisions can happen only for float keys */ /* collisions can happen only for float keys */
lua_assert(ttisfloat(key) || luaV_rawequalobj(&f->k[k], v)); lua_assert(ttisfloat(key) || luaV_rawequalobj(&f->k[k], v));
return k; /* reuse index */ return k; /* reuse index */
} }
/* constant not found; create a new entry */ else { /* constant not found; create a new entry */
k = addk(fs, f, v); int k = addk(fs, f, v);
/* cache it for reuse; numerical value does not need GC barrier; /* cache it for reuse; numerical value does not need GC barrier;
table is not a metatable, so it does not need to invalidate cache */ table is not a metatable, so it does not need to invalidate cache */
setivalue(&val, k); setivalue(&val, k);
luaH_set(fs->ls->L, fs->kcache, key, &val); luaH_set(fs->ls->L, fs->kcache, key, &val);
return k; return k;
}
} }
@@ -604,13 +604,14 @@ static int luaK_intK (FuncState *fs, lua_Integer n) {
/* /*
** Add a float to list of constants and return its index. Floats ** Add a float to list of constants and return its index. Floats
** with integral values need a different key, to avoid collision ** with integral values need a different key, to avoid collision
** with actual integers. To that, we add to the number its smaller ** with actual integers. To that end, we add to the number its smaller
** power-of-two fraction that is still significant in its scale. ** power-of-two fraction that is still significant in its scale.
** For doubles, that would be 1/2^52. ** (For doubles, the fraction would be 2^-52).
** This method is not bulletproof: different numbers may generate the ** This method is not bulletproof: different numbers may generate the
** same key (e.g., very large numbers will overflow to 'inf') and for ** same key (e.g., very large numbers will overflow to 'inf') and for
** floats larger than 2^53 the result is still an integer. At worst, ** floats larger than 2^53 the result is still an integer. For those
** this only wastes an entry with a duplicate. ** cases, just generate a new entry. At worst, this only wastes an entry
** with a duplicate.
*/ */
static int luaK_numberK (FuncState *fs, lua_Number r) { static int luaK_numberK (FuncState *fs, lua_Number r) {
TValue o, kv; TValue o, kv;
@@ -625,7 +626,7 @@ static int luaK_numberK (FuncState *fs, lua_Number r) {
const lua_Number k = r * (1 + q); /* key */ const lua_Number k = r * (1 + q); /* key */
lua_Integer ik; lua_Integer ik;
setfltvalue(&kv, k); /* key as a TValue */ setfltvalue(&kv, k); /* key as a TValue */
if (!luaV_flttointeger(k, &ik, F2Ieq)) { /* not an integral value? */ if (!luaV_flttointeger(k, &ik, F2Ieq)) { /* not an integer value? */
int n = k2proto(fs, &kv, &o); /* use key */ int n = k2proto(fs, &kv, &o); /* use key */
if (luaV_rawequalobj(&fs->f->k[n], &o)) /* correct value? */ if (luaV_rawequalobj(&fs->f->k[n], &o)) /* correct value? */
return n; return n;

View File

@@ -1827,7 +1827,7 @@ static lu_byte getglobalattribute (LexState *ls, lu_byte df) {
switch (kind) { switch (kind) {
case RDKTOCLOSE: case RDKTOCLOSE:
luaK_semerror(ls, "global variables cannot be to-be-closed"); luaK_semerror(ls, "global variables cannot be to-be-closed");
break; /* to avoid warnings */ return kind; /* to avoid warnings */
case RDKCONST: case RDKCONST:
return GDKCONST; /* adjust kind for global variable */ return GDKCONST; /* adjust kind for global variable */
default: default:

View File

@@ -156,7 +156,7 @@ static Node *hashint (const Table *t, lua_Integer i) {
** The main computation should be just ** The main computation should be just
** n = frexp(n, &i); return (n * INT_MAX) + i ** n = frexp(n, &i); return (n * INT_MAX) + i
** but there are some numerical subtleties. ** but there are some numerical subtleties.
** In a two-complement representation, INT_MAX does not has an exact ** In a two-complement representation, INT_MAX may not have an exact
** representation as a float, but INT_MIN does; because the absolute ** representation as a float, but INT_MIN does; because the absolute
** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the ** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the
** absolute value of the product 'frexp * -INT_MIN' is smaller or equal ** absolute value of the product 'frexp * -INT_MIN' is smaller or equal

View File

@@ -127,7 +127,8 @@ strings can contain any 8-bit value,
including @x{embedded zeros} (@Char{\0}). including @x{embedded zeros} (@Char{\0}).
Lua is also encoding-agnostic; Lua is also encoding-agnostic;
it makes no assumptions about the contents of a string. it makes no assumptions about the contents of a string.
The length of any string in Lua must fit in a Lua integer. The length of any string in Lua must fit in a Lua integer,
and the string plus a small header must fit in @id{size_t}.
Lua can call (and manipulate) functions written in Lua and Lua can call (and manipulate) functions written in Lua and
functions written in C @see{functioncall}. functions written in C @see{functioncall}.
@@ -1555,7 +1556,8 @@ It has the following syntax:
exp @bnfter{,} exp @bnfopt{@bnfter{,} exp} @Rw{do} block @Rw{end}} exp @bnfter{,} exp @bnfopt{@bnfter{,} exp} @Rw{do} block @Rw{end}}
} }
The given identifier (@bnfNter{Name}) defines the control variable, The given identifier (@bnfNter{Name}) defines the control variable,
which is a new read-only variable local to the loop body (@emph{block}). which is a new read-only (@id{const}) variable local to the loop body
(@emph{block}).
The loop starts by evaluating once the three control expressions. The loop starts by evaluating once the three control expressions.
Their values are called respectively Their values are called respectively
@@ -1610,7 +1612,7 @@ works as follows.
The names @rep{var_i} declare loop variables local to the loop body. The names @rep{var_i} declare loop variables local to the loop body.
The first of these variables is the @emph{control variable}, The first of these variables is the @emph{control variable},
which is a read-only variable. which is a read-only (@id{const}) variable.
The loop starts by evaluating @rep{explist} The loop starts by evaluating @rep{explist}
to produce four values: to produce four values:
@@ -4083,7 +4085,7 @@ Lua will call @id{falloc} before raising the error.
@APIEntry{const char *lua_pushfstring (lua_State *L, const char *fmt, ...);| @APIEntry{const char *lua_pushfstring (lua_State *L, const char *fmt, ...);|
@apii{0,1,m} @apii{0,1,v}
Pushes onto the stack a formatted string Pushes onto the stack a formatted string
and returns a pointer to this string @see{constchar}. and returns a pointer to this string @see{constchar}.
@@ -4103,6 +4105,9 @@ A conversion specifier (and its corresponding extra argument) can be
Every occurrence of @Char{%} in the string @id{fmt} Every occurrence of @Char{%} in the string @id{fmt}
must form a valid conversion specifier. must form a valid conversion specifier.
Besides memory allocation errors,
this function may raise an error if the resulting string is too large.
} }
@APIEntry{void lua_pushglobaltable (lua_State *L);| @APIEntry{void lua_pushglobaltable (lua_State *L);|
@@ -4135,7 +4140,7 @@ light userdata with the same @N{C address}.
} }
@APIEntry{const char *lua_pushliteral (lua_State *L, const char *s);| @APIEntry{const char *lua_pushliteral (lua_State *L, const char *s);|
@apii{0,1,m} @apii{0,1,v}
This macro is equivalent to @Lid{lua_pushstring}, This macro is equivalent to @Lid{lua_pushstring},
but should be used only when @id{s} is a literal string. but should be used only when @id{s} is a literal string.
@@ -4144,7 +4149,7 @@ but should be used only when @id{s} is a literal string.
} }
@APIEntry{const char *lua_pushlstring (lua_State *L, const char *s, size_t len);| @APIEntry{const char *lua_pushlstring (lua_State *L, const char *s, size_t len);|
@apii{0,1,m} @apii{0,1,v}
Pushes the string pointed to by @id{s} with size @id{len} Pushes the string pointed to by @id{s} with size @id{len}
onto the stack. onto the stack.
@@ -4156,6 +4161,9 @@ including @x{embedded zeros}.
Returns a pointer to the internal copy of the string @see{constchar}. Returns a pointer to the internal copy of the string @see{constchar}.
Besides memory allocation errors,
this function may raise an error if the string is too large.
} }
@APIEntry{void lua_pushnil (lua_State *L);| @APIEntry{void lua_pushnil (lua_State *L);|
@@ -5015,8 +5023,8 @@ then @id{name} is set to @id{NULL}.
@item{@id{namewhat}| @item{@id{namewhat}|
explains the @T{name} field. explains the @T{name} field.
The value of @T{namewhat} can be The value of @T{namewhat} can be
@T{"global"}, @T{"local"}, @T{"method"}, @T{"global"}, @T{"local"}, @T{"upvalue"},
@T{"field"}, @T{"upvalue"}, or @T{""} (the empty string), @T{"field"}, @T{""} (the empty string), plus some other options,
according to how the function was called. according to how the function was called.
(Lua uses the empty string when no other option seems to apply.) (Lua uses the empty string when no other option seems to apply.)
} }
@@ -6571,7 +6579,7 @@ The call always returns the previous value of the parameter.
If the call does not give a new value, If the call does not give a new value,
the value is left unchanged. the value is left unchanged.
Lua rounds these values before storing them; Lua stores these values in a compressed format,
so, the value returned as the previous value may not be so, the value returned as the previous value may not be
exactly the last value set. exactly the last value set.
} }
@@ -6585,10 +6593,10 @@ This function should not be called by a finalizer.
} }
@LibEntry{dofile ([filename])| @LibEntry{dofile ([filename])|
Opens the named file and executes its content as a Lua chunk. Opens the named file and executes its content as a Lua chunk,
returning all values returned by the chunk.
When called without arguments, When called without arguments,
@id{dofile} executes the content of the standard input (@id{stdin}). @id{dofile} executes the content of the standard input (@id{stdin}).
Returns all values returned by the chunk.
In case of errors, @id{dofile} propagates the error In case of errors, @id{dofile} propagates the error
to its caller. to its caller.
(That is, @id{dofile} does not run in protected mode.) (That is, @id{dofile} does not run in protected mode.)
@@ -6960,7 +6968,7 @@ in case of error
(either the original error that stopped the coroutine or (either the original error that stopped the coroutine or
errors in closing methods), errors in closing methods),
this function returns @false plus the error object; this function returns @false plus the error object;
otherwise ir returns @true. otherwise it returns @true.
} }

View File

@@ -176,6 +176,20 @@ do print"testing stop-the-world collection"
assert(collectgarbage("param", "stepsize") == step) assert(collectgarbage("param", "stepsize") == step)
end end
if T then -- test GC parameter codification
for _, percentage in ipairs{5, 10, 12, 20, 50, 100, 200, 500} do
local param = T.codeparam(percentage) -- codify percentage
for _, value in ipairs{1, 2, 10, 100, 257, 1023, 6500, 100000} do
local exact = value*percentage // 100
local aprox = T.applyparam(param, value) -- apply percentage
-- difference is at most 10% (+1 compensates difference due to
-- rounding to integers)
assert(math.abs(aprox - exact) <= exact/10 + 1)
end
end
end
collectgarbage(oldmode) collectgarbage(oldmode)
print('OK') print('OK')