@@ -34,8 +34,9 @@ typedef enum {
VNONRELOC, /* expression has its value in a fixed register;
info = result register */
VLOCAL, /* local variable; var.ridx = local register;
var.vidx = index in 'actvar.arr' */
var.vidx = relative index in 'actvar.arr' */
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
VCONST, /* compile-time constant; info = absolute index in 'actvar.arr' */
VINDEXED, /* indexed variable;
ind.t = table register;
ind.idx = key's R index */
@@ -81,19 +82,25 @@ typedef struct expdesc {
} expdesc;


/* kinds of variables */
#define VDKREG 0 /* regular */
#define RDKCONST 1 /* constant */
#define RDKTOCLOSE 2 /* to-be-closed */
#define RDKCTC 3 /* compile-time constant */

/* description of an active local variable */
typedef struct Vardesc {
TValuefields; /* constant value (if it is a compile-time constant) */
lu_byte ro; /* true if variable is 'const' */
lu_byte sidx; /* index of the variable in the stack */
short pidx; /* index of the variable in the Proto's 'locvars' array */
TString *name; /* variable name */
typedef union Vardesc {
struct {
TValuefields; /* constant value (if it is a compile-time constant) */
lu_byte kind;
lu_byte sidx; /* index of the variable in the stack */
short pidx; /* index of the variable in the Proto's 'locvars' array */
TString *name; /* variable name */
} vd;
TValue k; /* constant value (if any) */
} Vardesc;


/* check whether Vardesc is in the stack (not a compile-time constant) */
#define vdinstack(vd) (ttisnil(vd))


/* description of pending goto statements and label statements */
typedef struct Labeldesc {
@@ -198,12 +198,11 @@ static void LoadUpvalues (LoadState *S, Proto *f) {
n = LoadInt(S);
f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
f->sizeupvalues = n;
for (i = 0; i < n; i++)
f->upvalues[i].name = NULL;
for (i = 0; i < n; i++) {
f->upvalues[i].name = NULL;
f->upvalues[i].instack = LoadByte(S);
f->upvalues[i].idx = LoadByte(S);
f->upvalues[i].ro = LoadByte(S);
f->upvalues[i].kind = LoadByte(S);
}
}

@@ -223,7 +223,7 @@ In Lua, the global variable @Lid{_G} is initialized with this same value.
so changing its value will affect only your own code.)

When Lua loads a chunk,
the default value for its @id{_ENV} upvalue
the default value for its @id{_ENV} variable
is the global environment @seeF{load}.
Therefore, by default,
free names in Lua code refer to entries in the global environment
@@ -233,7 +233,7 @@ and some functions there operate on that environment.
You can use @Lid{load} (or @Lid{loadfile})
to load a chunk with a different environment.
(In C, you have to load the chunk and then change the value
of its first upvalue.)
of its first upvalue; see @See{lua_setupvalue}.)

}

@@ -1224,7 +1224,7 @@ As such, chunks can define local variables,
receive arguments, and return values.
Moreover, such anonymous function is compiled as in the
scope of an external local variable called @id{_ENV} @see{globalenv}.
The resulting function always has @id{_ENV} as its only upvalue,
The resulting function always has @id{_ENV} as its only external variable,
even if it does not use that variable.

A chunk can be stored in a file or in a string inside the host program.
@@ -2241,8 +2241,8 @@ and so the second @id{x} refers to the outside variable.
Because of the @x{lexical scoping} rules,
local variables can be freely accessed by functions
defined inside their scope.
A local variable used by an inner function is called
an @def{upvalue}, or @emphx{external local variable},
A local variable used by an inner function is called an @def{upvalue}
(or @emphx{external local variable}, or simply @emphx{external variable})
inside the inner function.

Notice that each execution of a @Rw{local} statement
@@ -4765,11 +4765,7 @@ and returns its name.
Returns @id{NULL} (and pushes nothing)
when the index @id{n} is greater than the number of upvalues.

For @N{C functions}, this function uses the empty string @T{""}
as a name for all upvalues.
(For Lua functions,
upvalues are the external local variables that the function uses,
and that are consequently included in its closure.)
See @Lid{debug.getupvalue} for more information about upvalues.

}

@@ -8485,6 +8481,8 @@ The first parameter or local variable has @N{index 1}, and so on,
following the order that they are declared in the code,
counting only the variables that are active
in the current scope of the function.
Compile-time constants may not appear in this listing,
if they were optimized away by the compiler.
Negative indices refer to vararg arguments;
@num{-1} is the first vararg argument.
The function returns @nil if there is no variable with the given index,
@@ -8520,8 +8518,15 @@ This function returns the name and the value of the upvalue
with index @id{up} of the function @id{f}.
The function returns @nil if there is no upvalue with the given index.

Variable names starting with @Char{(} (open parenthesis) @C{)}
represent variables with no known names
(For Lua functions,
upvalues are the external local variables that the function uses,
and that are consequently included in its closure.)

For @N{C functions}, this function uses the empty string @T{""}
as a name for all upvalues.

Variable name @Char{?} (interrogation mark)
represents variables with no known names
(variables from chunks saved without debug information).

}
@@ -8626,6 +8631,8 @@ The function returns @nil if there is no upvalue
with the given index.
Otherwise, it returns the name of the upvalue.

See @Lid{debug.getupvalue} for more information about upvalues.

}

@LibEntry{debug.setuservalue (udata, value, n)|
@@ -7,6 +7,22 @@ if T==nil then
end
print "testing code generation and optimizations"

-- to test constant propagation
local <const> k0 = 0
local <const> k1 = 1
local <const> k3 = 3
local <const> k6 = k3 + (k3 << k0)
local <const> kFF0 = 0xFF0
local <const> k3_78 = 3.78
local <const> x, <const> k3_78_4 = 10, k3_78 / 4
assert(x == 10)

local <const> kx = "x"

local <const> kTrue = true
local <const> kFalse = false

local <const> kNil = nil

-- this code gave an error for the code checker
do
@@ -27,12 +43,12 @@ end

local function foo ()
local a
a = 3;
a = k3;
a = 0; a = 0.0; a = -7 + 7
a = 3.78/4; a = 3.78/4
a = -3.78/4; a = 3.78/4; a = -3.78/4
a = k3_78/4; a = k3_78_4
a = -k3_78/4; a = k3_78/4; a = -3.78/4
a = -3.79/4; a = 0.0; a = -0;
a = 3; a = 3.0; a = 3; a = 3.0
a = k3; a = 3.0; a = 3; a = 3.0
end

checkKlist(foo, {3.78/4, -3.78/4, -3.79/4})
@@ -86,10 +102,11 @@ end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN')

-- sequence of LOADNILs
check(function ()
local <const> kNil = nil
local a,b,c
local d; local e;
local f,g,h;
d = nil; d=nil; b=nil; a=nil; c=nil;
d = nil; d=nil; b=nil; a=kNil; c=nil;
end, 'LOADNIL', 'RETURN0')

check(function ()
@@ -109,7 +126,7 @@ check (function (a,b,c) return a end, 'RETURN1')


-- infinite loops
check(function () while true do local a = -1 end end,
check(function () while kTrue do local a = -1 end end,
'LOADI', 'JMP', 'RETURN0')

check(function () while 1 do local a = -1 end end,
@@ -125,9 +142,9 @@ check(function (a,b,c,d) return a..b..c..d end,

-- not
check(function () return not not nil end, 'LOADBOOL', 'RETURN1')
check(function () return not not false end, 'LOADBOOL', 'RETURN1')
check(function () return not not kFalse end, 'LOADBOOL', 'RETURN1')
check(function () return not not true end, 'LOADBOOL', 'RETURN1')
check(function () return not not 1 end, 'LOADBOOL', 'RETURN1')
check(function () return not not k3 end, 'LOADBOOL', 'RETURN1')

-- direct access to locals
check(function ()
@@ -144,16 +161,18 @@ end,
-- direct access to constants
check(function ()
local a,b
a.x = 3.2
local c = kNil
a[kx] = 3.2
a.x = b
a[b] = 'x'
end,
'LOADNIL', 'SETFIELD', 'SETFIELD', 'SETTABLE', 'RETURN0')

-- "get/set table" with numeric indices
check(function (a)
local <const> k255 = 255
a[1] = a[100]
a[255] = a[256]
a[k255] = a[256]
a[256] = 5
end,
'GETI', 'SETI',
@@ -170,7 +189,7 @@ end,

check(function ()
local a,b
a[true] = false
a[kTrue] = false
end,
'LOADNIL', 'LOADBOOL', 'SETTABLE', 'RETURN0')

@@ -238,45 +257,47 @@ local function checkF (func, val)
end

checkF(function () return 0.0 end, 0.0)
checkI(function () return 0 end, 0)
checkI(function () return -0//1 end, 0)
checkI(function () return k0 end, 0)
checkI(function () return -k0//1 end, 0)
checkK(function () return 3^-1 end, 1/3)
checkK(function () return (1 + 1)^(50 + 50) end, 2^100)
checkK(function () return (-2)^(31 - 2) end, -0x20000000 + 0.0)
checkF(function () return (-3^0 + 5) // 3.0 end, 1.0)
checkI(function () return -3 % 5 end, 2)
checkF(function () return (-k3^0 + 5) // 3.0 end, 1.0)
checkI(function () return -k3 % 5 end, 2)
checkF(function () return -((2.0^8 + -(-1)) % 8)/2 * 4 - 3 end, -5.0)
checkF(function () return -((2^8 + -(-1)) % 8)//2 * 4 - 3 end, -7.0)
checkI(function () return 0xF0.0 | 0xCC.0 ~ 0xAA & 0xFD end, 0xF4)
checkI(function () return ~(~0xFF0 | 0xFF0) end, 0)
checkI(function () return ~(~kFF0 | kFF0) end, 0)
checkI(function () return ~~-1024.0 end, -1024)
checkI(function () return ((100 << 6) << -4) >> 2 end, 100)
checkI(function () return ((100 << k6) << -4) >> 2 end, 100)

-- borders around MAXARG_sBx ((((1 << 17) - 1) >> 1) == 65535)
local a = 17; local sbx = ((1 << a) - 1) >> 1 -- avoid folding
checkI(function () return 65535 end, sbx)
checkI(function () return -65535 end, -sbx)
checkI(function () return 65536 end, sbx + 1)
checkK(function () return 65537 end, sbx + 2)
checkK(function () return -65536 end, -(sbx + 1))
local <const> border = 65535
checkI(function () return border end, sbx)
checkI(function () return -border end, -sbx)
checkI(function () return border + 1 end, sbx + 1)
checkK(function () return border + 2 end, sbx + 2)
checkK(function () return -(border + 1) end, -(sbx + 1))

checkF(function () return 65535.0 end, sbx + 0.0)
checkF(function () return -65535.0 end, -sbx + 0.0)
checkF(function () return 65536.0 end, (sbx + 1.0))
checkK(function () return 65537.0 end, (sbx + 2.0))
checkK(function () return -65536.0 end, -(sbx + 1.0))
local <const> border = 65535.0
checkF(function () return border end, sbx + 0.0)
checkF(function () return -border end, -sbx + 0.0)
checkF(function () return border + 1 end, (sbx + 1.0))
checkK(function () return border + 2 end, (sbx + 2.0))
checkK(function () return -(border + 1) end, -(sbx + 1.0))


-- immediate operands
checkR(function (x) return x + 1 end, 10, 11, 'ADDI', 'RETURN1')
checkR(function (x) return x + k1 end, 10, 11, 'ADDI', 'RETURN1')
checkR(function (x) return 128 + x end, 0.0, 128.0, 'ADDI', 'RETURN1')
checkR(function (x) return x * -127 end, -1.0, 127.0, 'MULI', 'RETURN1')
checkR(function (x) return 20 * x end, 2, 40, 'MULI', 'RETURN1')
checkR(function (x) return x ^ -2 end, 2, 0.25, 'POWI', 'RETURN1')
checkR(function (x) return x / 40 end, 40, 1.0, 'DIVI', 'RETURN1')
checkR(function (x) return x // 1 end, 10.0, 10.0, 'IDIVI', 'RETURN1')
checkR(function (x) return x % (100 - 10) end, 91, 1, 'MODI', 'RETURN1')
checkR(function (x) return 1 << x end, 3, 8, 'SHLI', 'RETURN1')
checkR(function (x) return k1 << x end, 3, 8, 'SHLI', 'RETURN1')
checkR(function (x) return x << 2 end, 10, 40, 'SHRI', 'RETURN1')
checkR(function (x) return x >> 2 end, 8, 2, 'SHRI', 'RETURN1')
checkR(function (x) return x & 1 end, 9, 1, 'BANDK', 'RETURN1')
@@ -295,7 +316,7 @@ checkR(function (x) return x % (100.0 - 10) end, 91, 1.0, 'MODK', 'RETURN1')

-- no foldings (and immediate operands)
check(function () return -0.0 end, 'LOADF', 'UNM', 'RETURN1')
check(function () return 3/0 end, 'LOADI', 'DIVI', 'RETURN1')
check(function () return k3/0 end, 'LOADI', 'DIVI', 'RETURN1')
check(function () return 0%0 end, 'LOADI', 'MODI', 'RETURN1')
check(function () return -4//0 end, 'LOADI', 'IDIVI', 'RETURN1')
check(function (x) return x >> 2.0 end, 'LOADF', 'SHR', 'RETURN1')
@@ -335,7 +356,7 @@ end,

do -- tests for table access in upvalues
local t
check(function () t.x = t.y end, 'GETTABUP', 'SETTABUP')
check(function () t[kx] = t.y end, 'GETTABUP', 'SETTABUP')
check(function (a) t[a()] = t[a()] end,
'MOVE', 'CALL', 'GETUPVAL', 'MOVE', 'CALL',
'GETUPVAL', 'GETTABLE', 'SETTABLE')
@@ -379,6 +400,12 @@ function (a)
end
)

checkequal(function () return 6 or true or nil end,
function () return k6 or kTrue or kNil end)

checkequal(function () return 6 and true or nil end,
function () return k6 and kTrue or kNil end)


print 'OK'

@@ -287,7 +287,7 @@ a,b = F(nil)==nil; assert(a == true and b == nil)
------------------------------------------------------------------

-- sometimes will be 0, sometimes will not...
_ENV.GLOB1 = math.floor(os.time()) % 2
_ENV.GLOB1 = math.random(0, 1)

-- basic expressions with their respective values
local basiccases = {
@@ -298,6 +298,26 @@ local basiccases = {
{"(0==_ENV.GLOB1)", 0 == _ENV.GLOB1},
}

local prog

if _ENV.GLOB1 == 0 then
basiccases[2][1] = "F" -- constant false

prog = [[
local <const> F = false
if %s then IX = true end
return %s
]]
else
basiccases[4][1] = "k10" -- constant 10

prog = [[
local <const> k10 = 10
if %s then IX = true end
return %s
]]
end

print('testing short-circuit optimizations (' .. _ENV.GLOB1 .. ')')


@@ -337,8 +357,6 @@ cases[1] = basiccases
for i = 2, level do cases[i] = createcases(i) end
print("+")

local prog = [[if %s then IX = true end; return %s]]

local i = 0
for n = 1, level do
for _, v in pairs(cases[n]) do
@@ -324,7 +324,7 @@ do

-- errors due to non-closable values
local function foo ()
local <toclose> x = 34
local <toclose> x = {}
end
local stat, msg = pcall(foo)
assert(not stat and string.find(msg, "variable 'x'"))
@@ -270,7 +270,7 @@ else
end

do
local NaN = 0/0
local <const> NaN = 0/0
assert(not (NaN < 0))
assert(not (NaN > minint))
assert(not (NaN <= -9))
@@ -767,25 +767,27 @@ assert(a == '10' and b == '20')

do
print("testing -0 and NaN")
local mz, z = -0.0, 0.0
local <const> mz = -0.0
local <const> z = 0.0
assert(mz == z)
assert(1/mz < 0 and 0 < 1/z)
local a = {[mz] = 1}
assert(a[z] == 1 and a[mz] == 1)
a[z] = 2
assert(a[z] == 2 and a[mz] == 2)
local inf = math.huge * 2 + 1
mz, z = -1/inf, 1/inf
local <const> mz = -1/inf
local <const> z = 1/inf
assert(mz == z)
assert(1/mz < 0 and 0 < 1/z)
local NaN = inf - inf
local <const> NaN = inf - inf
assert(NaN ~= NaN)
assert(not (NaN < NaN))
assert(not (NaN <= NaN))
assert(not (NaN > NaN))
assert(not (NaN >= NaN))
assert(not (0 < NaN) and not (NaN < 0))
local NaN1 = 0/0
local <const> NaN1 = 0/0
assert(NaN ~= NaN1 and not (NaN <= NaN1) and not (NaN1 <= NaN))
local a = {}
assert(not pcall(rawset, a, NaN, 1))
@@ -814,8 +816,8 @@ end
-- the first call after seed 1007 should return 0x7a7040a5a323c9d6
do
-- all computations assume at most 32-bit integers
local h = 0x7a7040a5 -- higher half
local l = 0xa323c9d6 -- lower half
local <const> h = 0x7a7040a5 -- higher half
local <const> l = 0xa323c9d6 -- lower half

math.randomseed(1007)
-- get the low 'intbits' of the 64-bit expected result