From 56cc4a879a9dc79081514ffff348e807820d363b Mon Sep 17 00:00:00 2001 From: mazze Date: Mon, 2 Sep 2013 05:00:46 +0000 Subject: [PATCH] Merged-in lua 5.2.2. git-svn-id: https://svn.aros.org/svn/aros/trunk/contrib@47953 fb15a70f-31f2-0310-bbcc-cdcc74a49acc --- development/compilers/lua/Makefile | 2 +- development/compilers/lua/README | 2 +- development/compilers/lua/doc/contents.html | 20 +- development/compilers/lua/doc/lua.css | 10 +- development/compilers/lua/doc/manual.css | 6 +- development/compilers/lua/doc/manual.html | 570 +++++++++++++++++----------- development/compilers/lua/doc/readme.html | 19 +- development/compilers/lua/src/Makefile | 4 +- development/compilers/lua/src/lapi.c | 61 +-- development/compilers/lua/src/lauxlib.c | 28 +- development/compilers/lua/src/lbaselib.c | 32 +- development/compilers/lua/src/lbitlib.c | 4 +- development/compilers/lua/src/lcode.c | 9 +- development/compilers/lua/src/lcorolib.c | 5 +- development/compilers/lua/src/ldblib.c | 19 +- development/compilers/lua/src/ldebug.c | 19 +- development/compilers/lua/src/ldo.c | 43 ++- development/compilers/lua/src/ldump.c | 5 +- development/compilers/lua/src/lfunc.c | 20 +- development/compilers/lua/src/lfunc.h | 3 +- development/compilers/lua/src/lgc.c | 504 ++++++++++++++---------- development/compilers/lua/src/lgc.h | 22 +- development/compilers/lua/src/liolib.c | 24 +- development/compilers/lua/src/llex.c | 33 +- development/compilers/lua/src/llimits.h | 21 +- development/compilers/lua/src/lmathlib.c | 70 ++-- development/compilers/lua/src/lmem.c | 16 - development/compilers/lua/src/lmem.h | 13 +- development/compilers/lua/src/loadlib.c | 95 +++-- development/compilers/lua/src/lobject.c | 18 +- development/compilers/lua/src/lobject.h | 74 ++-- development/compilers/lua/src/lopcodes.c | 1 + development/compilers/lua/src/loslib.c | 17 +- development/compilers/lua/src/lparser.c | 158 ++++---- development/compilers/lua/src/lparser.h | 4 +- development/compilers/lua/src/lstate.c | 40 +- development/compilers/lua/src/lstate.h | 20 +- development/compilers/lua/src/lstring.c | 115 ++++-- development/compilers/lua/src/lstring.h | 15 +- development/compilers/lua/src/lstrlib.c | 238 +++++++----- development/compilers/lua/src/ltable.c | 27 +- development/compilers/lua/src/ltablib.c | 18 +- development/compilers/lua/src/lua.c | 34 +- development/compilers/lua/src/lua.h | 11 +- development/compilers/lua/src/luaconf.h | 116 +++--- development/compilers/lua/src/lundump.c | 36 +- development/compilers/lua/src/lundump.h | 2 +- development/compilers/lua/src/lvm.c | 51 +-- development/compilers/lua/src/lvm.h | 3 +- development/compilers/lua/src/lzio.c | 2 +- 50 files changed, 1599 insertions(+), 1080 deletions(-) diff --git a/development/compilers/lua/Makefile b/development/compilers/lua/Makefile index ec53e1a2c..bd9515fd8 100644 --- a/development/compilers/lua/Makefile +++ b/development/compilers/lua/Makefile @@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1 # Lua version and release. V= 5.2 -R= $V.0 +R= $V.1 # Targets start here. all: $(PLAT) diff --git a/development/compilers/lua/README b/development/compilers/lua/README index 9c3846758..6e2aee6ce 100644 --- a/development/compilers/lua/README +++ b/development/compilers/lua/README @@ -1,5 +1,5 @@ -This is Lua 5.2, released on 12 Dec 2011. +This is Lua 5.2.2, released on 21 Mar 2013. For installation instructions, license details, and further information about Lua, see doc/readme.html. diff --git a/development/compilers/lua/doc/contents.html b/development/compilers/lua/doc/contents.html index 5342723f3..0ce297da1 100644 --- a/development/compilers/lua/doc/contents.html +++ b/development/compilers/lua/doc/contents.html @@ -23,7 +23,7 @@ Lua 5.2 Reference Manual

The reference manual is the official definition of the Lua language. For a complete introduction to Lua programming, see the book -Programming in Lua. +Programming in Lua.

start @@ -33,9 +33,9 @@ For a complete introduction to Lua programming, see the book index


-Copyright © 2011 Lua.org, PUC-Rio. +Copyright © 2011–2013 Lua.org, PUC-Rio. Freely available under the terms of the -Lua license. +Lua license.

Contents

@@ -149,8 +149,8 @@ Freely available under the terms of the error
getmetatable
ipairs
-loadfile
load
+loadfile
next
pairs
pcall
@@ -385,6 +385,7 @@ Freely available under the terms of the lua_pushcclosure
lua_pushcfunction
lua_pushfstring
+lua_pushglobaltable
lua_pushinteger
lua_pushlightuserdata
lua_pushliteral
@@ -393,15 +394,16 @@ Freely available under the terms of the lua_pushnumber
lua_pushstring
lua_pushthread
+lua_pushunsigned
lua_pushvalue
lua_pushvfstring
lua_rawequal
lua_rawget
lua_rawgeti
+lua_rawgetp
lua_rawlen
lua_rawset
lua_rawseti
-lua_rawgetp
lua_rawsetp
lua_register
lua_remove
@@ -460,8 +462,8 @@ Freely available under the terms of the luaL_buffinitsize
luaL_callmeta
luaL_checkany
-luaL_checkinteger
luaL_checkint
+luaL_checkinteger
luaL_checklong
luaL_checklstring
luaL_checknumber
@@ -492,8 +494,8 @@ Freely available under the terms of the luaL_newmetatable
luaL_newstate
luaL_openlibs
-luaL_optinteger
luaL_optint
+luaL_optinteger
luaL_optlong
luaL_optlstring
luaL_optnumber
@@ -521,10 +523,10 @@ Freely available under the terms of the
Last update: -Tue Nov 29 22:30:23 BRST 2011 +Tue Mar 12 11:22:18 BRT 2013 diff --git a/development/compilers/lua/doc/lua.css b/development/compilers/lua/doc/lua.css index 54708f823..240e85eb8 100644 --- a/development/compilers/lua/doc/lua.css +++ b/development/compilers/lua/doc/lua.css @@ -3,8 +3,8 @@ body { background-color: #FFFFFF ; font-family: Helvetica, Arial, sans-serif ; text-align: justify ; - margin-right: 20px ; - margin-left: 20px ; + margin-right: 30px ; + margin-left: 30px ; } h1, h2, h3, h4 { @@ -16,10 +16,10 @@ h1, h2, h3, h4 { h2 { padding-top: 0.4em ; padding-bottom: 0.4em ; - padding-left: 20px ; - padding-right: 20px ; - margin-left: -20px ; + padding-left: 1em ; + padding-right: 1em ; background-color: #E0E0FF ; + border-radius: 8px ; } h3 { diff --git a/development/compilers/lua/doc/manual.css b/development/compilers/lua/doc/manual.css index ac357a896..269bd4358 100644 --- a/development/compilers/lua/doc/manual.css +++ b/development/compilers/lua/doc/manual.css @@ -18,7 +18,9 @@ span.apii { p+h1, ul+h1 { padding-top: 0.4em ; padding-bottom: 0.4em ; - padding-left: 20px ; - margin-left: -20px ; + padding-left: 24px ; + margin-left: -24px ; background-color: #E0E0FF ; + border-radius: 8px ; } + diff --git a/development/compilers/lua/doc/manual.html b/development/compilers/lua/doc/manual.html index 360d3168b..85365363f 100644 --- a/development/compilers/lua/doc/manual.html +++ b/development/compilers/lua/doc/manual.html @@ -19,9 +19,9 @@ Lua 5.2 Reference Manual by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

-Copyright © 2011 Lua.org, PUC-Rio. +Copyright © 2011–2013 Lua.org, PUC-Rio. Freely available under the terms of the -Lua license. +Lua license.


@@ -33,7 +33,7 @@ Freely available under the terms of the

- + @@ -424,7 +424,6 @@ This should be read as

      rawget(getmetatable(obj) or {}, event)
 

- This means that the access to a metamethod does not invoke other metamethods, and access to objects with no metatables does not fail (it simply results in nil). @@ -913,6 +912,14 @@ the object memory is freed only when it becomes completely inaccessible; its finalizer will never be called twice. +

+When you close a state (see lua_close), +Lua calls the finalizers of all objects marked for finalization, +following the reverse order that they were marked. +If any finalizer marks new objects for collection during that phase, +these new objects will not be finalized. + + @@ -1206,7 +1213,7 @@ results in a newline in the string. The escape sequence '\z' skips the following span of white-space characters, including line breaks; -it is particularly useful to break and indent a long string +it is particularly useful to break and indent a long literal string into multiple lines without adding the newlines and spaces into the string contents. @@ -1234,7 +1241,7 @@ an opening long bracket of level 1 is written as [=[, and so on. A closing long bracket is defined similarly; for instance, a closing long bracket of level 4 is written as ]====]. -A long string starts with an opening long bracket of any level and +A long literal starts with an opening long bracket of any level and ends at the first closing long bracket of the same level. It can contain any text except a closing bracket of the proper level. Literals in this bracketed form can run for several lines, @@ -1247,8 +1254,7 @@ is converted to a simple newline.

-When parsing a from a string source, -any byte in a literal string not +Any byte in a literal string not explicitly affected by the previous rules represents itself. However, Lua opens files for parsing in text mode, and the system file functions may have problems with @@ -1402,6 +1408,35 @@ or write two semicolons in sequence:

+Function calls and assignments +can start with an open parenthesis. +This possibility leads to an ambiguity in Lua's grammar. +Consider the following fragment: + +

+     a = b + c
+     (print or io.write)('done')
+

+The grammar could see it in two ways: + +

+     a = b + c(print or io.write)('done')
+     
+     a = b + c; (print or io.write)('done')
+

+The current parser always sees such constructions +in the first way, +interpreting the open parenthesis +as the start of the arguments to a call. +To avoid this ambiguity, +it is a good practice to always precede with a semicolon +statements that start with a parenthesis: + +

+     ;(print or io.write)('done')
+
+ +

A block can be explicitly delimited to produce a single statement:

@@ -1420,7 +1455,7 @@ of another block (see §3.3.4).
 

3.3.2 – Chunks

-The unit of execution of Lua is called a chunk. +The unit of compilation of Lua is called a chunk. Syntactically, a chunk is simply a block: @@ -1851,7 +1886,8 @@ then no adjustment is made (unless the expression is enclosed in parentheses). In all other contexts, Lua adjusts the result list to one element, -discarding all values except the first one. +either discarding all values except the first one +or adding a single nil if there are no values.

@@ -2551,32 +2587,35 @@ works only with valid indices or acceptable indices.

A valid index is an index that refers to a -valid position within the stack, that is, -it lies between 1 and the stack top +real position within the stack, that is, +its position lies between 1 and the stack top (1 ≤ abs(index) ≤ top). -Usually, functions that need a specific stack position -(e.g., lua_remove) require valid indices. +Usually, functions that can modify the value at an index +require valid indices. + + +

+Unless otherwise noted, +any function that accepts valid indices also accepts pseudo-indices, +which represent some Lua values that are accessible to C code +but which are not in the stack. +Pseudo-indices are used to access the registry +and the upvalues of a C function (see §4.4).

Functions that do not need a specific stack position, but only a value in the stack (e.g., query functions), can be called with acceptable indices. -An acceptable index refers to a position within -the space allocated for the stack, +An acceptable index can be any valid index, +including the pseudo-indices, +but it also can be any positive index after the stack top +within the space allocated for the stack, that is, indices up to the stack size. -More formally, we define an acceptable index -as follows: - -

-     (index < 0 && abs(index) <= top) ||
-     (index > 0 && index <= stack size)
-

(Note that 0 is never an acceptable index.) -When a function is called, -its stack size is top + LUA_MINSTACK. -You can change its stack size through function lua_checkstack. +Except when noted otherwise, +functions in the API work with acceptable indices.

@@ -2590,16 +2629,8 @@ that is, without the need to check whether 3 is a valid index.

For functions that can be called with acceptable indices, any non-valid index is treated as if it -contains a value of a virtual type LUA_TNONE. - - -

-Unless otherwise noted, -any function that accepts valid indices also accepts pseudo-indices, -which represent some Lua values that are accessible to C code -but which are not in the stack. -Pseudo-indices are used to access the registry -and the upvalues of a C function (see §4.4). +contains a value of a virtual type LUA_TNONE, +which behaves like a nil value. @@ -2620,13 +2651,13 @@ accessible to the function whenever it is called. Whenever a C function is called, its upvalues are located at specific pseudo-indices. These pseudo-indices are produced by the macro -lua_upvalueindex. +lua_upvalueindex. The first value associated with a function is at position lua_upvalueindex(1), and so on. Any access to lua_upvalueindex(n), where n is greater than the number of upvalues of the current function (but not greater than 256), -produces an acceptable (but invalid) index. +produces an acceptable but invalid index. @@ -2639,7 +2670,8 @@ Lua provides a registry, a predefined table that can be used by any C code to store whatever Lua values it needs to store. The registry table is always located at pseudo-index -LUA_REGISTRYINDEX. +LUA_REGISTRYINDEX, +which is a valid index. Any C library can store data into this table, but it should take care to choose keys that are different from those used @@ -2684,8 +2716,8 @@ the global environment.

Internally, Lua uses the C longjmp facility to handle errors. -(You can also choose to use exceptions if you use C++; -see file luaconf.h.) +(You can also choose to use exceptions if you compile Lua as C++; +search for LUAI_THROW in the source code.) When Lua faces any error (such as a memory allocation error, type errors, syntax errors, and runtime errors) @@ -2820,8 +2852,7 @@ by looking only at its arguments The third field, x, tells whether the function may throw errors: '-' means the function never throws any error; -'m' means the function may throw only memory allocation errors; -'e' means the function may throw other kinds of errors; +'e' means the function may throw errors; 'v' means the function may throw an error on purpose. @@ -2922,7 +2953,7 @@ it seems to be a safe assumption.)


lua_arith

[-(2|1), +1, e] -

int lua_arith (lua_State *L, int op);
+
void lua_arith (lua_State *L, int op);

Performs an arithmetic operation over the two values @@ -3129,8 +3160,8 @@ might need to close states as soon as they are not needed.

Compares two Lua values. -Returns 1 if the value at acceptable index index1 satisfies op -when compared with the value at acceptable index index2, +Returns 1 if the value at index index1 satisfies op +when compared with the value at index index2, following the semantics of the corresponding Lua operator (that is, it may call metamethods). Otherwise returns 0. @@ -3173,7 +3204,7 @@ Concatenation is performed following the usual semantics of Lua

void lua_copy (lua_State *L, int fromidx, int toidx);

-Moves the element at the valid index fromidx +Moves the element at index fromidx into the valid index toidx without shifting any element (therefore replacing the value at that position). @@ -3183,7 +3214,7 @@ without shifting any element


lua_createtable

-[-0, +1, m] +[-0, +1, e]

void lua_createtable (lua_State *L, int narr, int nrec);

@@ -3202,7 +3233,7 @@ Otherwise you can use the function lua_newtable

lua_dump

-[-0, +0, m] +[-0, +0, e]

int lua_dump (lua_State *L, lua_Writer writer, void *data);

@@ -3343,7 +3374,7 @@ opaque pointer passed to lua_newstate.


lua_getctx

[-0, +0, –] -

int lua_getctx  (lua_State *L, int *ctx);
+
int lua_getctx (lua_State *L, int *ctx);

This function is called by a continuation function (see §4.7) @@ -3383,7 +3414,7 @@ as in the case of a yield.

Pushes onto the stack the value t[k], -where t is the value at the given valid index. +where t is the value at the given index. As in Lua, this function may trigger a metamethod for the "index" event (see §2.4). @@ -3407,8 +3438,7 @@ Pushes onto the stack the value of the global name.

int lua_getmetatable (lua_State *L, int index);

-Pushes onto the stack the metatable of the value at the given -acceptable index. +Pushes onto the stack the metatable of the value at the given index. If the value does not have a metatable, the function returns 0 and pushes nothing on the stack. @@ -3422,7 +3452,7 @@ the function returns 0 and pushes nothing on the stack.

Pushes onto the stack the value t[k], -where t is the value at the given valid index +where t is the value at the given index and k is the value at the top of the stack. @@ -3470,7 +3500,7 @@ This Lua value must be a table or nil.

Moves the top element into the given valid index, shifting up the elements above this index to open space. -Cannot be called with a pseudo-index, +This function cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position. @@ -3498,7 +3528,7 @@ which is usually the largest signed integral type the machine handles

int lua_isboolean (lua_State *L, int index);

-Returns 1 if the value at the given acceptable index is a boolean, +Returns 1 if the value at the given index is a boolean, and 0 otherwise. @@ -3510,7 +3540,7 @@ and 0 otherwise.

int lua_iscfunction (lua_State *L, int index);

-Returns 1 if the value at the given acceptable index is a C function, +Returns 1 if the value at the given index is a C function, and 0 otherwise. @@ -3522,7 +3552,7 @@ and 0 otherwise.

int lua_isfunction (lua_State *L, int index);

-Returns 1 if the value at the given acceptable index is a function +Returns 1 if the value at the given index is a function (either C or Lua), and 0 otherwise. @@ -3534,7 +3564,7 @@ Returns 1 if the value at the given acceptable index is a function

int lua_islightuserdata (lua_State *L, int index);

-Returns 1 if the value at the given acceptable index is a light userdata, +Returns 1 if the value at the given index is a light userdata, and 0 otherwise. @@ -3546,7 +3576,7 @@ and 0 otherwise.

int lua_isnil (lua_State *L, int index);

-Returns 1 if the value at the given acceptable index is nil, +Returns 1 if the value at the given index is nil, and 0 otherwise. @@ -3558,8 +3588,7 @@ and 0 otherwise.

int lua_isnone (lua_State *L, int index);

-Returns 1 if the given acceptable index is not valid -(that is, it refers to an element outside the current stack), +Returns 1 if the given index is not valid, and 0 otherwise. @@ -3571,8 +3600,7 @@ and 0 otherwise.

int lua_isnoneornil (lua_State *L, int index);

-Returns 1 if the given acceptable index is not valid -(that is, it refers to an element outside the current stack) +Returns 1 if the given index is not valid or if the value at this index is nil, and 0 otherwise. @@ -3585,7 +3613,7 @@ and 0 otherwise.

int lua_isnumber (lua_State *L, int index);

-Returns 1 if the value at the given acceptable index is a number +Returns 1 if the value at the given index is a number or a string convertible to a number, and 0 otherwise. @@ -3598,7 +3626,7 @@ and 0 otherwise.

int lua_isstring (lua_State *L, int index);

-Returns 1 if the value at the given acceptable index is a string +Returns 1 if the value at the given index is a string or a number (which is always convertible to a string), and 0 otherwise. @@ -3611,7 +3639,7 @@ and 0 otherwise.

int lua_istable (lua_State *L, int index);

-Returns 1 if the value at the given acceptable index is a table, +Returns 1 if the value at the given index is a table, and 0 otherwise. @@ -3623,7 +3651,7 @@ and 0 otherwise.

int lua_isthread (lua_State *L, int index);

-Returns 1 if the value at the given acceptable index is a thread, +Returns 1 if the value at the given index is a thread, and 0 otherwise. @@ -3635,7 +3663,7 @@ and 0 otherwise.

int lua_isuserdata (lua_State *L, int index);

-Returns 1 if the value at the given acceptable index is a userdata +Returns 1 if the value at the given index is a userdata (either full or light), and 0 otherwise. @@ -3647,7 +3675,7 @@ Returns 1 if the value at the given acceptable index is a userdata

void lua_len (lua_State *L, int index);

-Returns the "length" of the value at the given acceptable index; +Returns the "length" of the value at the given index; it is equivalent to the '#' operator in Lua (see §3.4.6). The result is pushed on the stack. @@ -3712,6 +3740,12 @@ a NULL value is equivalent to the string "bt".

+lua_load uses the stack internally, +so the reader function should always leave the stack +unmodified when returning. + + +

If the resulting function has one upvalue, this upvalue is set to the value of the global environment stored at index LUA_RIDX_GLOBALS in the registry (see §4.5). @@ -3740,7 +3774,7 @@ passes to the allocator in every call.


lua_newtable

-[-0, +1, m] +[-0, +1, e]

void lua_newtable (lua_State *L);

@@ -3752,7 +3786,7 @@ It is equivalent to lua_createtable(L, 0, 0).


lua_newthread

-[-0, +1, m] +[-0, +1, e]

lua_State *lua_newthread (lua_State *L);

@@ -3773,7 +3807,7 @@ like any Lua object.


lua_newuserdata

-[-0, +1, m] +[-0, +1, e]

void *lua_newuserdata (lua_State *L, size_t size);

@@ -3959,7 +3993,7 @@ Pushes a boolean value with value b onto the stack.


lua_pushcclosure

-[-n, +1, m] +[-n, +1, e]

void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);

@@ -4025,13 +4059,13 @@ Note that f is used twice.


lua_pushfstring

-[-0, +1, m] +[-0, +1, e]

const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

Pushes onto the stack a formatted string and returns a pointer to this string. -It is similar to the C function sprintf, +It is similar to the ANSI C function sprintf, but has some important differences:

    @@ -4059,6 +4093,17 @@ The conversion specifiers can only be +

    lua_pushglobaltable

    +[-0, +1, –] +

    void lua_pushglobaltable (lua_State *L);
    + +

    +Pushes the global environment onto the stack. + + + + +


    lua_pushinteger

    [-0, +1, –]

    void lua_pushinteger (lua_State *L, lua_Integer n);
    @@ -4092,7 +4137,7 @@ light userdata with the same C address.

    lua_pushliteral

    -[-0, +1, m] +[-0, +1, e]

    const char *lua_pushliteral (lua_State *L, const char *s);

    @@ -4105,7 +4150,7 @@ It automatically provides the string length.


    lua_pushlstring

    -[-0, +1, m] +[-0, +1, e]

    const char *lua_pushlstring (lua_State *L, const char *s, size_t len);

    @@ -4148,7 +4193,7 @@ Pushes a number with value n onto the stack.


    lua_pushstring

    -[-0, +1, m] +[-0, +1, e]

    const char *lua_pushstring (lua_State *L, const char *s);

    @@ -4182,12 +4227,23 @@ Returns 1 if this thread is the main thread of its state. +


    lua_pushunsigned

    +[-0, +1, –] +

    void lua_pushunsigned (lua_State *L, lua_Unsigned n);
    + +

    +Pushes a number with value n onto the stack. + + + + +


    lua_pushvalue

    [-0, +1, –]

    void lua_pushvalue (lua_State *L, int index);

    -Pushes a copy of the element at the given valid index +Pushes a copy of the element at the given index onto the stack. @@ -4195,7 +4251,7 @@ onto the stack.


    lua_pushvfstring

    -[-0, +1, m] +[-0, +1, e]

    const char *lua_pushvfstring (lua_State *L,
                                   const char *fmt,
                                   va_list argp);
    @@ -4213,7 +4269,7 @@ instead of a variable number of arguments.
    int lua_rawequal (lua_State *L, int index1, int index2);

    -Returns 1 if the two values in acceptable indices index1 and +Returns 1 if the two values in indices index1 and index2 are primitively equal (that is, without calling metamethods). Otherwise returns 0. @@ -4241,7 +4297,7 @@ Similar to lua_gettable, but does a raw

    Pushes onto the stack the value t[n], -where t is the table at the given valid index. +where t is the table at the given index. The access is raw; that is, it does not invoke metamethods. @@ -4255,7 +4311,7 @@ that is, it does not invoke metamethods.

    Pushes onto the stack the value t[k], -where t is the table at the given valid index and +where t is the table at the given index and k is the pointer p represented as a light userdata. The access is raw; that is, it does not invoke metamethods. @@ -4269,7 +4325,7 @@ that is, it does not invoke metamethods.

    size_t lua_rawlen (lua_State *L, int index);

    -Returns the raw "length" of the value at the given acceptable index: +Returns the raw "length" of the value at the given index: for strings, this is the string length; for tables, this is the result of the length operator ('#') with no metamethods; @@ -4282,7 +4338,7 @@ for other values, it is 0.


    lua_rawset

    -[-2, +0, m] +[-2, +0, e]

    void lua_rawset (lua_State *L, int index);

    @@ -4294,12 +4350,12 @@ Similar to lua_settable, but does a raw


    lua_rawseti

    -[-1, +0, m] +[-1, +0, e]

    void lua_rawseti (lua_State *L, int index, int n);

    Does the equivalent of t[n] = v, -where t is the table at the given valid index +where t is the table at the given index and v is the value at the top of the stack. @@ -4313,12 +4369,12 @@ that is, it does not invoke metamethods.


    lua_rawsetp

    -[-1, +0, m] +[-1, +0, e]

    void lua_rawsetp (lua_State *L, int index, const void *p);

    Does the equivalent of t[k] = v, -where t is the table at the given valid index, +where t is the table at the given index, k is the pointer p represented as a light userdata, and v is the value at the top of the stack. @@ -4377,7 +4433,7 @@ It is defined as a macro:

    Removes the element at the given valid index, shifting down the elements above this index to fill the gap. -Cannot be called with a pseudo-index, +This function cannot be called with a pseudo-index, because a pseudo-index is not an actual stack position. @@ -4389,9 +4445,9 @@ because a pseudo-index is not an actual stack position.

    void lua_replace (lua_State *L, int index);

    -Moves the top element into the given position +Moves the top element into the given valid index without shifting any element -(therefore replacing the value at the given position), +(therefore replacing the value at the given index), and then pops the top element. @@ -4400,7 +4456,7 @@ and then pops the top element.


    lua_resume

    [-?, +?, –] -

    int lua_resume (lua_State *L, lua_State *from, int narg);
    +
    int lua_resume (lua_State *L, lua_State *from, int nargs);

    Starts and resumes a coroutine in a given thread. @@ -4410,7 +4466,7 @@ Starts and resumes a coroutine in a given thread. To start a coroutine, you push onto the thread stack the main function plus any arguments; then you call lua_resume, -with narg being the number of arguments. +with nargs being the number of arguments. This call returns when the coroutine suspends or finishes its execution. When it returns, the stack contains all values passed to lua_yield, or all values returned by the body function. @@ -4429,7 +4485,9 @@ The error message is on the top of the stack.

    -To resume a coroutine, you put on its stack only the values to +To resume a coroutine, +you remove any results from the last lua_yield, +put on its stack only the values to be passed as results from yield, and then call lua_resume. @@ -4461,7 +4519,7 @@ with user data ud.

    Does the equivalent to t[k] = v, -where t is the value at the given valid index +where t is the value at the given index and v is the value at the top of the stack. @@ -4492,8 +4550,7 @@ sets it as the new value of global name.

    Pops a table from the stack and -sets it as the new metatable for the value at the given -acceptable index. +sets it as the new metatable for the value at the given index. @@ -4505,7 +4562,7 @@ acceptable index.

    Does the equivalent to t[k] = v, -where t is the value at the given valid index, +where t is the value at the given index, v is the value at the top of the stack, and k is the value just below the top. @@ -4524,7 +4581,7 @@ for the "newindex" event (see §2.4).

    void lua_settop (lua_State *L, int index);

    -Accepts any acceptable index, or 0, +Accepts any index, or 0, and sets the stack top to this index. If the new top is larger than the old one, then the new elements are filled with nil. @@ -4550,14 +4607,15 @@ the new value associated to the userdata at the given index.

    typedef struct lua_State lua_State;

    -An opaque structure that keeps the whole state of a Lua interpreter. +An opaque structure that points to a thread and indirectly +(through the thread) to the whole state of a Lua interpreter. The Lua library is fully reentrant: it has no global variables. -All information about a state is kept in this structure. +All information about a state is accessible through this structure.

    -A pointer to this state must be passed as the first argument to +A pointer to this structure must be passed as the first argument to every function in the library, except to lua_newstate, which creates a Lua state from scratch. @@ -4595,13 +4653,12 @@ You can resume threads with status LUA_OK

    int lua_toboolean (lua_State *L, int index);

    -Converts the Lua value at the given acceptable index to a C boolean +Converts the Lua value at the given index to a C boolean value (0 or 1). Like all tests in Lua, lua_toboolean returns true for any Lua value different from false and nil; otherwise it returns false. -It also returns false when called with a non-valid index. (If you want to accept only actual boolean values, use lua_isboolean to test the value's type.) @@ -4614,7 +4671,7 @@ use lua_isboolean to test the value's

    lua_CFunction lua_tocfunction (lua_State *L, int index);

    -Converts a value at the given acceptable index to a C function. +Converts a value at the given index to a C function. That value must be a C function; otherwise, returns NULL. @@ -4638,7 +4695,7 @@ Equivalent to lua_tointegerx with lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);

-Converts the Lua value at the given acceptable index +Converts the Lua value at the given index to the signed integral type lua_Integer. The Lua value must be a number or a string convertible to a number (see §3.4.2); @@ -4660,11 +4717,11 @@ indicates whether the operation succeeded.


lua_tolstring

-[-0, +0, m] +[-0, +0, e]

const char *lua_tolstring (lua_State *L, int index, size_t *len);

-Converts the Lua value at the given acceptable index to a C string. +Converts the Lua value at the given index to a C string. If len is not NULL, it also sets *len with the string length. The Lua value must be a string or a number; @@ -4706,7 +4763,7 @@ Equivalent to lua_tonumberx with lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);

-Converts the Lua value at the given acceptable index +Converts the Lua value at the given index to the C type lua_Number (see lua_Number). The Lua value must be a number or a string convertible to a number (see §3.4.2); @@ -4727,7 +4784,7 @@ indicates whether the operation succeeded.

const void *lua_topointer (lua_State *L, int index);

-Converts the value at the given acceptable index to a generic +Converts the value at the given index to a generic C pointer (void*). The value can be a userdata, a table, a thread, or a function; otherwise, lua_topointer returns NULL. @@ -4743,7 +4800,7 @@ Typically this function is used only for debug information.


lua_tostring

-[-0, +0, m] +[-0, +0, e]

const char *lua_tostring (lua_State *L, int index);

@@ -4758,7 +4815,7 @@ Equivalent to lua_tolstring with lua_State *lua_tothread (lua_State *L, int index);

-Converts the value at the given acceptable index to a Lua thread +Converts the value at the given index to a Lua thread (represented as lua_State*). This value must be a thread; otherwise, the function returns NULL. @@ -4783,7 +4840,7 @@ Equivalent to lua_tounsignedx with <

lua_Unsigned lua_tounsignedx (lua_State *L, int index, int *isnum);

-Converts the Lua value at the given acceptable index +Converts the Lua value at the given index to the unsigned integral type lua_Unsigned. The Lua value must be a number or a string convertible to a number (see §3.4.2); @@ -4812,7 +4869,7 @@ indicates whether the operation succeeded.

void *lua_touserdata (lua_State *L, int index);

-If the value at the given acceptable index is a full userdata, +If the value at the given index is a full userdata, returns its block address. If the value is a light userdata, returns its pointer. @@ -4827,8 +4884,8 @@ Otherwise, returns NULL.

int lua_type (lua_State *L, int index);

-Returns the type of the value in the given acceptable index, -or LUA_TNONE for a non-valid index. +Returns the type of the value in the given valid index, +or LUA_TNONE for a non-valid (but acceptable) index. The types returned by lua_type are coded by the following constants defined in lua.h: LUA_TNIL, @@ -4848,7 +4905,7 @@ and


lua_typename

[-0, +0, –] -

const char *lua_typename  (lua_State *L, int tp);
+
const char *lua_typename (lua_State *L, int tp);

Returns the name of the type encoded by the value tp, @@ -4874,6 +4931,18 @@ whichever can hold 32-bit values. +


lua_upvalueindex

+[-0, +0, –] +

int lua_upvalueindex (int i);
+ +

+Returns the pseudo-index that represents the i-th upvalue of +the running function (see §4.4). + + + + +


lua_version

[-0, +0, v]

const lua_Number *lua_version (lua_State *L);
@@ -4932,7 +5001,7 @@ and pushes them onto the stack to.

lua_yield

[-?, +?, –] -

int lua_yield  (lua_State *L, int nresults);
+
int lua_yield (lua_State *L, int nresults);

This function is equivalent to lua_yieldk, @@ -4947,7 +5016,7 @@ the function calling lua_yield.


lua_yieldk

[-?, +?, –] -

int lua_yieldk  (lua_State *L, int nresults, int ctx, lua_CFunction k);
+
int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k);

Yields a coroutine. @@ -5145,11 +5214,11 @@ Returns the current hook mask.


lua_getinfo

-[-(0|1), +(0|1|2), m] +[-(0|1), +(0|1|2), e]

int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

-Returns information about a specific function or function invocation. +Gets information about a specific function or function invocation.

@@ -5268,7 +5337,7 @@ the number of active local variables.

int lua_getstack (lua_State *L, int level, lua_Debug *ar);

-Get information about the interpreter runtime stack. +Gets information about the interpreter runtime stack.

@@ -5345,6 +5414,20 @@ Therefore, if a hook calls back Lua to execute a function or a chunk, this execution occurs without any calls to hooks. +

+Hook functions cannot have continuations, +that is, they cannot call lua_yieldk, +lua_pcallk, or lua_callk with a non-null k. + + +

+Hook functions can yield under the following conditions: +Only count and line events can yield +and they cannot yield any value; +to yield a hook function must finish its execution +calling lua_yield with nresults equal to zero. + + @@ -5450,7 +5533,7 @@ when the index is greater than the number of upvalues.

Returns an unique identifier for the upvalue numbered n -from the closure at index fidx. +from the closure at index funcindex. Parameters funcindex and n are as in the lua_getupvalue (see lua_getupvalue) (but n cannot be greater than the number of upvalues). @@ -5467,13 +5550,14 @@ will return identical ids for those upvalue indices. -


lua_upvaluejoin

-
void lua_upvaluejoin (lua_State *L, int fidx1, int n1,
-                                    int fidx2, int n2);
+

lua_upvaluejoin

+[-0, +0, –] +

void lua_upvaluejoin (lua_State *L, int funcindex1, int n1,
+                                    int funcindex2, int n2);

-Make the n1-th upvalue of the Lua closure at index fidx1 -refer to the n2-th upvalue of the Lua closure at index fidx2. +Make the n1-th upvalue of the Lua closure at index funcindex1 +refer to the n2-th upvalue of the Lua closure at index funcindex2. @@ -5538,7 +5622,7 @@ in alphabetical order.


luaL_addchar

-[-?, +?, m] +[-?, +?, e]

void luaL_addchar (luaL_Buffer *B, char c);

@@ -5550,7 +5634,7 @@ Adds the byte c to the buffer B


luaL_addlstring

-[-?, +?, m] +[-?, +?, e]

void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);

@@ -5564,7 +5648,7 @@ The string can contain embedded zeros.


luaL_addsize

-[-?, +?, m] +[-?, +?, e]

void luaL_addsize (luaL_Buffer *B, size_t n);

@@ -5577,7 +5661,7 @@ buffer area (see luaL_prepbuffer).


luaL_addstring

-[-?, +?, m] +[-?, +?, e]

void luaL_addstring (luaL_Buffer *B, const char *s);

@@ -5591,7 +5675,7 @@ The string cannot contain embedded zeros.


luaL_addvalue

-[-1, +?, m] +[-1, +?, e]

void luaL_addvalue (luaL_Buffer *B);

@@ -5614,7 +5698,7 @@ which is the value to be added to the buffer. [-0, +0, v]

void luaL_argcheck (lua_State *L,
                     int cond,
-                    int narg,
+                    int arg,
                     const char *extramsg);

@@ -5627,7 +5711,7 @@ If not, raises an error with a standard message.


luaL_argerror

[-0, +0, v] -

int luaL_argerror (lua_State *L, int narg, const char *extramsg);
+
int luaL_argerror (lua_State *L, int arg, const char *extramsg);

Raises an error with a standard message @@ -5686,7 +5770,7 @@ size sz with a call luaL_buffinitsize(L, &b, sz).<

  • Then copy the string into that space.
  • -Finish by calling luaL_pushresult(&b, sz), +Finish by calling luaL_pushresultsize(&b, sz), where sz is the total size of the resulting string copied into that space.
  • @@ -5728,7 +5812,7 @@ the buffer must be declared as a variable

    luaL_buffinitsize

    -[-?, +?, m] +[-?, +?, e]

    char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);

    @@ -5762,11 +5846,11 @@ this function returns false (without pushing any value on the stack).


    luaL_checkany

    [-0, +0, v] -

    void luaL_checkany (lua_State *L, int narg);
    +
    void luaL_checkany (lua_State *L, int arg);

    Checks whether the function has an argument -of any type (including nil) at position narg. +of any type (including nil) at position arg. @@ -5774,10 +5858,10 @@ of any type (including nil) at position narg.


    luaL_checkint

    [-0, +0, v] -

    int luaL_checkint (lua_State *L, int narg);
    +
    int luaL_checkint (lua_State *L, int arg);

    -Checks whether the function argument narg is a number +Checks whether the function argument arg is a number and returns this number cast to an int. @@ -5786,10 +5870,10 @@ and returns this number cast to an int.


    luaL_checkinteger

    [-0, +0, v] -

    lua_Integer luaL_checkinteger (lua_State *L, int narg);
    +
    lua_Integer luaL_checkinteger (lua_State *L, int arg);

    -Checks whether the function argument narg is a number +Checks whether the function argument arg is a number and returns this number cast to a lua_Integer. @@ -5798,10 +5882,10 @@ and returns this number cast to a lua_Integer

    luaL_checklong

    [-0, +0, v] -

    long luaL_checklong (lua_State *L, int narg);
    +
    long luaL_checklong (lua_State *L, int arg);

    -Checks whether the function argument narg is a number +Checks whether the function argument arg is a number and returns this number cast to a long. @@ -5810,10 +5894,10 @@ and returns this number cast to a long.


    luaL_checklstring

    [-0, +0, v] -

    const char *luaL_checklstring (lua_State *L, int narg, size_t *l);
    +
    const char *luaL_checklstring (lua_State *L, int arg, size_t *l);

    -Checks whether the function argument narg is a string +Checks whether the function argument arg is a string and returns this string; if l is not NULL fills *l with the string's length. @@ -5829,10 +5913,10 @@ so all conversions and caveats of that function apply here.


    luaL_checknumber

    [-0, +0, v] -

    lua_Number luaL_checknumber (lua_State *L, int narg);
    +
    lua_Number luaL_checknumber (lua_State *L, int arg);

    -Checks whether the function argument narg is a number +Checks whether the function argument arg is a number and returns this number. @@ -5842,12 +5926,12 @@ and returns this number.


    luaL_checkoption

    [-0, +0, v]

    int luaL_checkoption (lua_State *L,
    -                      int narg,
    +                      int arg,
                           const char *def,
                           const char *const lst[]);

    -Checks whether the function argument narg is a string and +Checks whether the function argument arg is a string and searches for this string in the array lst (which must be NULL-terminated). Returns the index in the array where the string was found. @@ -5858,7 +5942,7 @@ if the string cannot be found.

    If def is not NULL, the function uses def as a default value when -there is no argument narg or when this argument is nil. +there is no argument arg or when this argument is nil.

    @@ -5886,10 +5970,10 @@ raising an error if the stack cannot grow to that size.


    luaL_checkstring

    [-0, +0, v] -

    const char *luaL_checkstring (lua_State *L, int narg);
    +
    const char *luaL_checkstring (lua_State *L, int arg);

    -Checks whether the function argument narg is a string +Checks whether the function argument arg is a string and returns this string. @@ -5903,10 +5987,10 @@ so all conversions and caveats of that function apply here.


    luaL_checktype

    [-0, +0, v] -

    void luaL_checktype (lua_State *L, int narg, int t);
    +
    void luaL_checktype (lua_State *L, int arg, int t);

    -Checks whether the function argument narg has type t. +Checks whether the function argument arg has type t. See lua_type for the encoding of types for t. @@ -5915,10 +5999,10 @@ See lua_type for the encoding of types for


    luaL_checkudata

    [-0, +0, v] -

    void *luaL_checkudata (lua_State *L, int narg, const char *tname);
    +
    void *luaL_checkudata (lua_State *L, int arg, const char *tname);

    -Checks whether the function argument narg is a userdata +Checks whether the function argument arg is a userdata of the type tname (see luaL_newmetatable) and returns the userdata address (see lua_touserdata). @@ -5928,10 +6012,10 @@ returns the userdata address (see lua_touserdata


    luaL_checkunsigned

    [-0, +0, v] -

    lua_Unsigned luaL_checkunsigned (lua_State *L, int narg);
    +
    lua_Unsigned luaL_checkunsigned (lua_State *L, int arg);

    -Checks whether the function argument narg is a number +Checks whether the function argument arg is a number and returns this number cast to a lua_Unsigned. @@ -5955,7 +6039,7 @@ are using the same address space.


    luaL_dofile

    -[-0, +?, m] +[-0, +?, e]

    int luaL_dofile (lua_State *L, const char *filename);

    @@ -6014,7 +6098,7 @@ as return luaL_error(args).


    luaL_execresult

    -[-0, +3, m] +[-0, +3, e]

    int luaL_execresult (lua_State *L, int stat);

    @@ -6027,7 +6111,7 @@ process-related functions in the standard library


    luaL_fileresult

    -[-0, +(1|3), m] +[-0, +(1|3), e]

    int luaL_fileresult (lua_State *L, int stat, const char *fname);

    @@ -6040,7 +6124,7 @@ file-related functions in the standard library


    luaL_getmetafield

    -[-0, +(0|1), m] +[-0, +(0|1), e]

    int luaL_getmetafield (lua_State *L, int obj, const char *e);

    @@ -6067,12 +6151,12 @@ in the registry (see luaL_newmetatable


    luaL_getsubtable

    -[-0, +1, m] +[-0, +1, e]

    int luaL_getsubtable (lua_State *L, int idx, const char *fname);

    Ensures that the value t[fname], -where t is the value at the valid index idx, +where t is the value at index idx, is a table, and pushes that table onto the stack. Returns true if it finds a previous table there @@ -6083,7 +6167,7 @@ and false if it creates a new table.


    luaL_gsub

    -[-0, +1, m] +[-0, +1, e]

    const char *luaL_gsub (lua_State *L,
                            const char *s,
                            const char *p,
    @@ -6100,15 +6184,15 @@ Pushes the resulting string on the stack and returns it.
     
     
     

    luaL_len

    -[-0, +1, e] +[-0, +0, e]

    int luaL_len (lua_State *L, int index);

    -Returns the "length" of the value at the given acceptable index +Returns the "length" of the value at the given index as a number; it is equivalent to the '#' operator in Lua (see §3.4.6). Raises an error if the result of the operation is not a number. -(This only can happen through metamethods.) +(This case only can happen through metamethods.) @@ -6153,7 +6237,7 @@ The string mode works as in function lua_


    luaL_loadfile

    -[-0, +1, m] +[-0, +1, e]

    int luaL_loadfile (lua_State *L, const char *filename);

    @@ -6164,7 +6248,7 @@ Equivalent to luaL_loadfilex with

    luaL_loadfilex

    -[-0, +1, m] +[-0, +1, e]

    int luaL_loadfilex (lua_State *L, const char *filename,
                                                 const char *mode);
    @@ -6218,8 +6302,8 @@ it does not run it.

    luaL_newlib

    -[-0, +1, m] -

    int luaL_newlib (lua_State *L, const luaL_Reg *l);
    +[-0, +1, e] +
    void luaL_newlib (lua_State *L, const luaL_Reg *l);

    Creates a new table and registers there @@ -6234,8 +6318,8 @@ It is implemented as the following macro:


    luaL_newlibtable

    -[-0, +1, m] -

    int luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
    +[-0, +1, e] +
    void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);

    Creates a new table with a size optimized @@ -6255,7 +6339,7 @@ not a pointer to it.


    luaL_newmetatable

    -[-0, +1, m] +[-0, +1, e]

    int luaL_newmetatable (lua_State *L, const char *tname);

    @@ -6309,10 +6393,10 @@ Opens all standard Lua libraries into the given state.


    luaL_optint

    [-0, +0, v] -

    int luaL_optint (lua_State *L, int narg, int d);
    +
    int luaL_optint (lua_State *L, int arg, int d);

    -If the function argument narg is a number, +If the function argument arg is a number, returns this number cast to an int. If this argument is absent or is nil, returns d. @@ -6325,11 +6409,11 @@ Otherwise, raises an error.


    luaL_optinteger

    [-0, +0, v]

    lua_Integer luaL_optinteger (lua_State *L,
    -                             int narg,
    +                             int arg,
                                  lua_Integer d);

    -If the function argument narg is a number, +If the function argument arg is a number, returns this number cast to a lua_Integer. If this argument is absent or is nil, returns d. @@ -6341,10 +6425,10 @@ Otherwise, raises an error.


    luaL_optlong

    [-0, +0, v] -

    long luaL_optlong (lua_State *L, int narg, long d);
    +
    long luaL_optlong (lua_State *L, int arg, long d);

    -If the function argument narg is a number, +If the function argument arg is a number, returns this number cast to a long. If this argument is absent or is nil, returns d. @@ -6357,12 +6441,12 @@ Otherwise, raises an error.


    luaL_optlstring

    [-0, +0, v]

    const char *luaL_optlstring (lua_State *L,
    -                             int narg,
    +                             int arg,
                                  const char *d,
                                  size_t *l);

    -If the function argument narg is a string, +If the function argument arg is a string, returns this string. If this argument is absent or is nil, returns d. @@ -6379,10 +6463,10 @@ fills the position *l with the result's length.


    luaL_optnumber

    [-0, +0, v] -

    lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number d);
    +
    lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);

    -If the function argument narg is a number, +If the function argument arg is a number, returns this number. If this argument is absent or is nil, returns d. @@ -6395,11 +6479,11 @@ Otherwise, raises an error.


    luaL_optstring

    [-0, +0, v]

    const char *luaL_optstring (lua_State *L,
    -                            int narg,
    +                            int arg,
                                 const char *d);

    -If the function argument narg is a string, +If the function argument arg is a string, returns this string. If this argument is absent or is nil, returns d. @@ -6412,11 +6496,11 @@ Otherwise, raises an error.


    luaL_optunsigned

    [-0, +0, v]

    lua_Unsigned luaL_optunsigned (lua_State *L,
    -                               int narg,
    +                               int arg,
                                    lua_Unsigned u);

    -If the function argument narg is a number, +If the function argument arg is a number, returns this number cast to a lua_Unsigned. If this argument is absent or is nil, returns u. @@ -6427,7 +6511,7 @@ Otherwise, raises an error.


    luaL_prepbuffer

    -[-?, +?, m] +[-?, +?, e]

    char *luaL_prepbuffer (luaL_Buffer *B);

    @@ -6439,7 +6523,7 @@ with the predefined size LUAL_BUFFERSIZE

    luaL_prepbuffsize

    -[-?, +?, m] +[-?, +?, e]

    char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);

    @@ -6455,7 +6539,7 @@ it to the buffer.


    luaL_pushresult

    -[-?, +1, m] +[-?, +1, e]

    void luaL_pushresult (luaL_Buffer *B);

    @@ -6467,7 +6551,7 @@ the top of the stack.


    luaL_pushresultsize

    -[-?, +1, m] +[-?, +1, e]

    void luaL_pushresultsize (luaL_Buffer *B, size_t sz);

    @@ -6478,7 +6562,7 @@ Equivalent to the sequence luaL_addsize


    luaL_ref

    -[-1, +0, m] +[-1, +0, e]

    int luaL_ref (lua_State *L, int t);

    @@ -6582,8 +6666,8 @@ in the registry (see luaL_newmetatable


    luaL_testudata

    -[-0, +0, m] -

    void *luaL_testudata (lua_State *L, int narg, const char *tname);
    +[-0, +0, e] +
    void *luaL_testudata (lua_State *L, int arg, const char *tname);

    This function works like luaL_checkudata, @@ -6599,7 +6683,7 @@ it returns NULL instead of throwing an error.

    const char *luaL_tolstring (lua_State *L, int idx, size_t *len);

    -Converts any Lua value at the given acceptable index to a C string +Converts any Lua value at the given index to a C string in a reasonable format. The resulting string is pushed onto the stack and also returned by the function. @@ -6618,7 +6702,7 @@ and uses the result of the call as its result.


    luaL_traceback

    -[-0, +1, m] +[-0, +1, e]

    void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
                          int level);
    @@ -6665,7 +6749,7 @@ If ref is LUA_NOREF or

    luaL_where

    -[-0, +1, m] +[-0, +1, e]

    void luaL_where (lua_State *L, int lvl);

    @@ -6749,7 +6833,7 @@ the host program can open them individually by using luaopen_string (for the string library), luaopen_table (for the table library), luaopen_math (for the mathematical library), -luaopen_bitlib (for the bit library), +luaopen_bit32 (for the bit library), luaopen_io (for the I/O library), luaopen_os (for the Operating System library), and luaopen_debug (for the debug library). @@ -6963,11 +7047,14 @@ otherwise, returns nil plus the error message.

    If the resulting function has upvalues, -the first upvalue is set to the value of the -global environment or to env, -if that parameter is given. -When loading main chunks, -the first upvalue will be the _ENV variable (see §2.2). +the first upvalue is set to the value of env, +if that parameter is given, +or to the value of the global environment. +(When you load a main chunk, +the resulting function will always have exactly one upvalue, +the _ENV variable (see §2.2). +When you load a binary chunk created from a function (see string.dump), +the resulting function can have arbitrary upvalues.)

    @@ -7487,7 +7574,6 @@ or a default path defined in luaconf.h.

    -


    package.loaded

    @@ -7523,7 +7609,8 @@ available to other dynamically linked libraries. Otherwise, it looks for a function funcname inside the library and returns this function as a C function. -(So, funcname must follow the prototype lua_CFunction). +So, funcname must follow the lua_CFunction prototype +(see lua_CFunction).

    @@ -7819,7 +7906,7 @@ after the two indices.

    Returns a formatted version of its variable number of arguments following the description given in its first argument (which must be a string). -The format string follows the same rules as the C function sprintf. +The format string follows the same rules as the ANSI C function sprintf. The only differences are that the options/modifiers *, h, L, l, n, and p are not supported @@ -7914,24 +8001,26 @@ If repl is a string, then its value is used for replacement. The character % works as an escape character: any sequence in repl of the form %d, with d between 1 and 9, -stands for the value of the d-th captured substring (see below). +stands for the value of the d-th captured substring. The sequence %0 stands for the whole match. The sequence %% stands for a single %.

    If repl is a table, then the table is queried for every match, -using the first capture as the key; -if the pattern specifies no captures, -then the whole match is used as the key. +using the first capture as the key.

    If repl is a function, then this function is called every time a match occurs, with all captured substrings passed as arguments, -in order; +in order. + + +

    +In any case, if the pattern specifies no captures, -then the whole match is passed as a sole argument. +then it behaves as if the whole pattern was inside a capture.

    @@ -8281,7 +8370,7 @@ all table accesses (get/set) performed by these functions are raw.

    Given a list where all elements are strings or numbers, -returns list[i]..sep..list[i+1] ··· sep..list[j]. +returns the string list[i]..sep..list[i+1] ··· sep..list[j]. The default value for sep is the empty string, the default for i is 1, and the default for j is #list. @@ -8323,10 +8412,17 @@ Note that the resulting table may not be a sequence.

    Removes from list the element at position pos, -shifting down the elements +returning the value of the removed element. +When pos is an integer between 1 and #list, +it shifts down the elements list[pos+1], list[pos+2], ···, list[#list] -and erasing element list[#list]. -Returns the value of the removed element. +and erases element list[#list]; +The index pos can also be 0 when #list is 0, +or #list + 1; +in those cases, the function erases the element list[pos]. + + +

    The default value for pos is #list, so that a call table.remove(t) removes the last element of list t. @@ -8965,6 +9061,11 @@ all I/O functions return nil on failure (plus an error message as a second result and a system-dependent error code as a third result) and some value different from nil on success. +On non-Posix systems, +the computation of the error message and error code +in case of errors +may be not thread safe, +because they rely on the global C variable errno.

    @@ -9385,7 +9486,7 @@ if the information is not available.

    If format is not "*t", then date returns the date as a string, -formatted according to the same rules as the C function strftime. +formatted according to the same rules as the ANSI C function strftime.

    @@ -9396,8 +9497,9 @@ the host system and on the current locale

    -On some systems, -this function may be not thread safe. +On non-Posix systems, +this function may be not thread safe +because of its reliance on C function gmtime and C function localtime. @@ -9419,7 +9521,7 @@ this value is exactly t2-t1.

    -This function is equivalent to the C function system. +This function is equivalent to the ANSI C function system. It passes command to be executed by an operating system shell. Its first result is true if the command terminated successfully, @@ -9454,7 +9556,7 @@ When called without a command,

    -Calls the C function exit to terminate the host program. +Calls the ANSI C function exit to terminate the host program. If code is true, the returned status is EXIT_SUCCESS; if code is false, @@ -9535,6 +9637,11 @@ this function only returns the name of the current locale for the given category. +

    +This function may be not thread safe +because of its reliance on C function setlocale. + +

    @@ -9721,7 +9828,7 @@ and raises an error when called with a level out of range.

    -Variable names starting with '(' (open parentheses) +Variable names starting with '(' (open parenthesis) represent internal variables (loop control variables, temporaries, varargs, and C function locals). @@ -10091,6 +10198,9 @@ You can avoid some incompatibilities by compiling Lua with appropriate options (see file luaconf.h). However, all these compatibility options will be removed in the next version of Lua. +Similarly, +all features marked as deprecated in Lua 5.1 +have been removed in Lua 5.2. @@ -10387,10 +10497,10 @@ Here is the complete syntax of Lua in extended BNF.


    Last update: -Mon Dec 12 15:21:08 BRST 2011 +Thu Mar 21 12:58:59 BRT 2013 diff --git a/development/compilers/lua/doc/readme.html b/development/compilers/lua/doc/readme.html index f0c77a160..5b9e47ecb 100644 --- a/development/compilers/lua/doc/readme.html +++ b/development/compilers/lua/doc/readme.html @@ -43,7 +43,6 @@ Welcome to Lua 5.2 license · reference manual -

    About Lua

    @@ -101,14 +100,6 @@ Try also Lua for Windows, an easy-to-use distribution of Lua that includes many useful libraries. - -

    Building Lua

    @@ -118,7 +109,7 @@ Here are the details.

    1. Open a terminal window and move to -the top-level directory, which is named lua-5.2.0. +the top-level directory, which is named lua-5.2.2. The Makefile there controls both the build process and the installation process.

    2. @@ -149,6 +140,8 @@ and liblua.a (the library).

      If you're running Linux and get compilation errors, make sure you have installed the readline development package. +If you get link errors after that, +then try "make linux MYLIBS=-ltermcap".

      Installing Lua

      @@ -381,7 +374,7 @@ For details, see this.

      -Copyright © 1994–2011 Lua.org, PUC-Rio. +Copyright © 1994–2013 Lua.org, PUC-Rio.

      Permission is hereby granted, free of charge, to any person obtaining a copy @@ -409,10 +402,10 @@ THE SOFTWARE.


      Last update: -Wed Nov 23 16:17:22 BRST 2011 +Fri Feb 22 09:24:20 BRT 2013 diff --git a/development/compilers/lua/src/Makefile b/development/compilers/lua/src/Makefile index bba1693f9..fea895bc0 100644 --- a/development/compilers/lua/src/Makefile +++ b/development/compilers/lua/src/Makefile @@ -56,7 +56,7 @@ o: $(ALL_O) a: $(ALL_A) $(LUA_A): $(BASE_O) - $(AR) $@ $? + $(AR) $@ $(BASE_O) $(RANLIB) $@ $(LUA_T): $(LUA_O) $(LUA_A) @@ -103,7 +103,7 @@ freebsd: generic: $(ALL) linux: - $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline -lncurses" + $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lreadline" macosx: $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_MACOSX" SYSLIBS="-lreadline" diff --git a/development/compilers/lua/src/lapi.c b/development/compilers/lua/src/lapi.c index d97d721e7..05f6f6445 100644 --- a/development/compilers/lua/src/lapi.c +++ b/development/compilers/lua/src/lapi.c @@ -40,7 +40,16 @@ const char lua_ident[] = /* corresponding test */ #define isvalid(o) ((o) != luaO_nilobject) -#define api_checkvalidindex(L, i) api_check(L, isvalid(i), "invalid index") +/* test for pseudo index */ +#define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) + +/* test for valid but not pseudo index */ +#define isstackindex(i, o) (isvalid(o) && !ispseudo(i)) + +#define api_checkvalidindex(L, o) api_check(L, isvalid(o), "invalid index") + +#define api_checkstackindex(L, i, o) \ + api_check(L, isstackindex(i, o), "index not in the stack") static TValue *index2addr (lua_State *L, int idx) { @@ -51,7 +60,7 @@ static TValue *index2addr (lua_State *L, int idx) { if (o >= L->top) return NONVALIDVALUE; else return o; } - else if (idx > LUA_REGISTRYINDEX) { + else if (!ispseudo(idx)) { /* negative index */ api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); return L->top + idx; } @@ -142,7 +151,7 @@ LUA_API const lua_Number *lua_version (lua_State *L) { ** convert an acceptable stack index into an absolute index */ LUA_API int lua_absindex (lua_State *L, int idx) { - return (idx > 0 || idx <= LUA_REGISTRYINDEX) + return (idx > 0 || ispseudo(idx)) ? idx : cast_int(L->top - L->ci->func + idx); } @@ -174,7 +183,7 @@ LUA_API void lua_remove (lua_State *L, int idx) { StkId p; lua_lock(L); p = index2addr(L, idx); - api_checkvalidindex(L, p); + api_checkstackindex(L, idx, p); while (++p < L->top) setobjs2s(L, p-1, p); L->top--; lua_unlock(L); @@ -186,8 +195,9 @@ LUA_API void lua_insert (lua_State *L, int idx) { StkId q; lua_lock(L); p = index2addr(L, idx); - api_checkvalidindex(L, p); - for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); + api_checkstackindex(L, idx, p); + for (q = L->top; q > p; q--) /* use L->top as a temporary */ + setobjs2s(L, q, q - 1); setobjs2s(L, p, L->top); lua_unlock(L); } @@ -217,7 +227,6 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { TValue *fr; lua_lock(L); fr = index2addr(L, fromidx); - api_checkvalidindex(L, fr); moveto(L, fr, toidx); lua_unlock(L); } @@ -281,7 +290,7 @@ LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { } -LUA_API void lua_arith (lua_State *L, int op) { +LUA_API void lua_arith (lua_State *L, int op) { StkId o1; /* 1st operand */ StkId o2; /* 2nd operand */ lua_lock(L); @@ -295,7 +304,7 @@ LUA_API void lua_arith (lua_State *L, int op) { o1 = L->top - 2; o2 = L->top - 1; if (ttisnumber(o1) && ttisnumber(o2)) { - changenvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2))); + setnvalue(o1, luaO_arith(op, nvalue(o1), nvalue(o2))); } else luaV_arith(L, o1, o1, o2, cast(TMS, op - LUA_OPADD + TM_ADD)); @@ -611,7 +620,6 @@ LUA_API void lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); - api_checkvalidindex(L, t); luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); } @@ -621,7 +629,6 @@ LUA_API void lua_getfield (lua_State *L, int idx, const char *k) { StkId t; lua_lock(L); t = index2addr(L, idx); - api_checkvalidindex(L, t); setsvalue2s(L, L->top, luaS_new(L, k)); api_incr_top(L); luaV_gettable(L, t, L->top - 1, L->top - 1); @@ -709,7 +716,6 @@ LUA_API void lua_getuservalue (lua_State *L, int idx) { StkId o; lua_lock(L); o = index2addr(L, idx); - api_checkvalidindex(L, o); api_check(L, ttisuserdata(o), "userdata expected"); if (uvalue(o)->env) { sethvalue(L, L->top, uvalue(o)->env); @@ -743,7 +749,6 @@ LUA_API void lua_settable (lua_State *L, int idx) { lua_lock(L); api_checknelems(L, 2); t = index2addr(L, idx); - api_checkvalidindex(L, t); luaV_settable(L, t, L->top - 2, L->top - 1); L->top -= 2; /* pop index and value */ lua_unlock(L); @@ -755,7 +760,6 @@ LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { lua_lock(L); api_checknelems(L, 1); t = index2addr(L, idx); - api_checkvalidindex(L, t); setsvalue2s(L, L->top++, luaS_new(L, k)); luaV_settable(L, t, L->top - 1, L->top - 2); L->top -= 2; /* pop value and key */ @@ -811,7 +815,6 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { lua_lock(L); api_checknelems(L, 1); obj = index2addr(L, objindex); - api_checkvalidindex(L, obj); if (ttisnil(L->top - 1)) mt = NULL; else { @@ -821,9 +824,10 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { switch (ttypenv(obj)) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; - if (mt) + if (mt) { luaC_objbarrierback(L, gcvalue(obj), mt); luaC_checkfinalizer(L, gcvalue(obj), mt); + } break; } case LUA_TUSERDATA: { @@ -850,7 +854,6 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) { lua_lock(L); api_checknelems(L, 1); o = index2addr(L, idx); - api_checkvalidindex(L, o); api_check(L, ttisuserdata(o), "userdata expected"); if (ttisnil(L->top - 1)) uvalue(o)->env = NULL; @@ -937,7 +940,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, func = 0; else { StkId o = index2addr(L, errfunc); - api_checkvalidindex(L, o); + api_checkstackindex(L, errfunc, o); func = savestack(L, o); } c.func = L->top - (nargs+1); /* function to be called */ @@ -950,7 +953,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, ci->u.c.k = k; /* save continuation */ ci->u.c.ctx = ctx; /* save context */ /* save information for error recovery */ - ci->u.c.extra = savestack(L, c.func); + ci->extra = savestack(L, c.func); ci->u.c.old_allowhook = L->allowhook; ci->u.c.old_errfunc = L->errfunc; L->errfunc = func; @@ -1006,7 +1009,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data) { } -LUA_API int lua_status (lua_State *L) { +LUA_API int lua_status (lua_State *L) { return L->status; } @@ -1045,17 +1048,17 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { } case LUA_GCSTEP: { if (g->gckind == KGC_GEN) { /* generational mode? */ - res = (g->lastmajormem == 0); /* 1 if will do major collection */ + res = (g->GCestimate == 0); /* true if it will do major collection */ luaC_forcestep(L); /* do a single step */ } else { - while (data-- >= 0) { - luaC_forcestep(L); - if (g->gcstate == GCSpause) { /* end of cycle? */ - res = 1; /* signal it */ - break; - } - } + lu_mem debt = cast(lu_mem, data) * 1024 - GCSTEPSIZE; + if (g->gcrunning) + debt += g->GCdebt; /* include current debt */ + luaE_setdebt(g, debt); + luaC_forcestep(L); + if (g->gcstate == GCSpause) /* end of cycle? */ + res = 1; /* signal it */ } break; } @@ -1103,7 +1106,7 @@ LUA_API int lua_error (lua_State *L) { lua_lock(L); api_checknelems(L, 1); luaG_errormsg(L); - lua_unlock(L); + /* code unreachable; will unlock when control actually leaves the kernel */ return 0; /* to avoid warnings */ } diff --git a/development/compilers/lua/src/lauxlib.c b/development/compilers/lua/src/lauxlib.c index a2f72d6d7..6ea22b67a 100644 --- a/development/compilers/lua/src/lauxlib.c +++ b/development/compilers/lua/src/lauxlib.c @@ -84,7 +84,7 @@ static void pushfuncname (lua_State *L, lua_Debug *ar) { if (*ar->namewhat != '\0') /* is there a name? */ lua_pushfstring(L, "function " LUA_QS, ar->name); else if (*ar->what == 'm') /* main? */ - lua_pushfstring(L, "main chunk"); + lua_pushliteral(L, "main chunk"); else if (*ar->what == 'C') { if (pushglobalfuncname(L, ar)) { lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1)); @@ -158,7 +158,8 @@ LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { if (strcmp(ar.namewhat, "method") == 0) { narg--; /* do not count `self' */ if (narg == 0) /* error is in the self argument itself? */ - return luaL_error(L, "calling " LUA_QS " on bad self", ar.name); + return luaL_error(L, "calling " LUA_QS " on bad self (%s)", + ar.name, extramsg); } if (ar.name == NULL) ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; @@ -214,7 +215,7 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { if (fname) lua_pushfstring(L, "%s: %s", fname, strerror(en)); else - lua_pushfstring(L, "%s", strerror(en)); + lua_pushstring(L, strerror(en)); lua_pushinteger(L, en); return 3; } @@ -438,7 +439,7 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { if (B->size - B->n < sz) { /* not enough space? */ char *newbuff; size_t newsize = B->size * 2; /* double buffer size */ - if (newsize - B->n < sz) /* not bit enough? */ + if (newsize - B->n < sz) /* not big enough? */ newsize = B->n + sz; if (newsize < B->n || newsize - B->n < sz) luaL_error(L, "buffer too large"); @@ -520,11 +521,11 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; - t = lua_absindex(L, t); if (lua_isnil(L, -1)) { lua_pop(L, 1); /* remove from stack */ return LUA_REFNIL; /* `nil' has a unique fixed reference */ } + t = lua_absindex(L, t); lua_rawgeti(L, t, freelist); /* get first free element */ ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ lua_pop(L, 1); /* remove it from stack */ @@ -598,7 +599,7 @@ static int skipBOM (LoadF *lf) { lf->n = 0; do { c = getc(lf->f); - if (c == EOF || c != *(unsigned char *)p++) return c; + if (c == EOF || c != *(const unsigned char *)p++) return c; lf->buff[lf->n++] = c; /* to be read by the parser */ } while (*p != '\0'); lf->n = 0; /* prefix matched; discard it */ @@ -616,8 +617,10 @@ static int skipBOM (LoadF *lf) { static int skipcomment (LoadF *lf, int *cp) { int c = *cp = skipBOM(lf); if (c == '#') { /* first line is a comment (Unix exec. file)? */ - while ((c = getc(lf->f)) != EOF && c != '\n') ; /* skip first line */ - *cp = getc(lf->f); /* skip end-of-line */ + do { /* skip first line */ + c = getc(lf->f); + } while (c != EOF && c != '\n') ; + *cp = getc(lf->f); /* skip end-of-line, if present */ return 1; /* there was a comment */ } else return 0; /* no comment */ @@ -843,6 +846,7 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname, ** Returns with only the table at the stack. */ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { + luaL_checkversion(L); luaL_checkstack(L, nup, "too many upvalues"); for (; l->name != NULL; l++) { /* fill the table with given functions */ int i; @@ -863,8 +867,8 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { lua_getfield(L, idx, fname); if (lua_istable(L, -1)) return 1; /* table already there */ else { - idx = lua_absindex(L, idx); lua_pop(L, 1); /* remove previous result */ + idx = lua_absindex(L, idx); lua_newtable(L); lua_pushvalue(L, -1); /* copy to be left at top */ lua_setfield(L, idx, fname); /* assign new table to field */ @@ -889,10 +893,8 @@ LUALIB_API void luaL_requiref (lua_State *L, const char *modname, lua_setfield(L, -2, modname); /* _LOADED[modname] = module */ lua_pop(L, 1); /* remove _LOADED table */ if (glb) { - lua_pushglobaltable(L); - lua_pushvalue(L, -2); /* copy of 'mod' */ - lua_setfield(L, -2, modname); /* _G[modname] = module */ - lua_pop(L, 1); /* remove _G table */ + lua_pushvalue(L, -1); /* copy of 'mod' */ + lua_setglobal(L, modname); /* _G[modname] = module */ } } diff --git a/development/compilers/lua/src/lbaselib.c b/development/compilers/lua/src/lbaselib.c index 98db288c7..7ab0117b0 100644 --- a/development/compilers/lua/src/lbaselib.c +++ b/development/compilers/lua/src/lbaselib.c @@ -242,10 +242,16 @@ static int luaB_ipairs (lua_State *L) { } -static int load_aux (lua_State *L, int status) { - if (status == LUA_OK) +static int load_aux (lua_State *L, int status, int envidx) { + if (status == LUA_OK) { + if (envidx != 0) { /* 'env' parameter? */ + lua_pushvalue(L, envidx); /* environment for loaded function */ + if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ + lua_pop(L, 1); /* remove 'env' if not used by previous call */ + } return 1; - else { + } + else { /* error (message is on top of the stack) */ lua_pushnil(L); lua_insert(L, -2); /* put before error message */ return 2; /* return nil plus error message */ @@ -256,13 +262,9 @@ static int load_aux (lua_State *L, int status) { static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); const char *mode = luaL_optstring(L, 2, NULL); - int env = !lua_isnone(L, 3); /* 'env' parameter? */ + int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ int status = luaL_loadfilex(L, fname, mode); - if (status == LUA_OK && env) { /* 'env' parameter? */ - lua_pushvalue(L, 3); - lua_setupvalue(L, -2, 1); /* set it as 1st upvalue of loaded chunk */ - } - return load_aux(L, status); + return load_aux(L, status, env); } @@ -293,6 +295,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { lua_pushvalue(L, 1); /* get function */ lua_call(L, 0, 1); /* call it */ if (lua_isnil(L, -1)) { + lua_pop(L, 1); /* pop result */ *size = 0; return NULL; } @@ -306,9 +309,9 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { static int luaB_load (lua_State *L) { int status; size_t l; - int top = lua_gettop(L); const char *s = lua_tolstring(L, 1, &l); const char *mode = luaL_optstring(L, 3, "bt"); + int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ if (s != NULL) { /* loading a string? */ const char *chunkname = luaL_optstring(L, 2, s); status = luaL_loadbufferx(L, s, l, chunkname, mode); @@ -319,11 +322,7 @@ static int luaB_load (lua_State *L) { lua_settop(L, RESERVEDSLOT); /* create reserved slot */ status = lua_load(L, generic_reader, NULL, chunkname, mode); } - if (status == LUA_OK && top >= 4) { /* is there an 'env' argument */ - lua_pushvalue(L, 4); /* environment for loaded function */ - lua_setupvalue(L, -2, 1); /* set it as 1st upvalue */ - } - return load_aux(L, status); + return load_aux(L, status, env); } /* }====================================================== */ @@ -337,7 +336,8 @@ static int dofilecont (lua_State *L) { static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); lua_settop(L, 1); - if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L); + if (luaL_loadfile(L, fname) != LUA_OK) + return lua_error(L); lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); return dofilecont(L); } diff --git a/development/compilers/lua/src/lbitlib.c b/development/compilers/lua/src/lbitlib.c index 0d4fd90e0..0547c0f80 100644 --- a/development/compilers/lua/src/lbitlib.c +++ b/development/compilers/lua/src/lbitlib.c @@ -147,7 +147,9 @@ static int b_rrot (lua_State *L) { /* ** get field and width arguments for field-manipulation functions, -** checking whether they are valid +** checking whether they are valid. +** ('luaL_error' called without 'return' to avoid later warnings about +** 'width' being used uninitialized.) */ static int fieldargs (lua_State *L, int farg, int *width) { int f = luaL_checkint(L, farg); diff --git a/development/compilers/lua/src/lcode.c b/development/compilers/lua/src/lcode.c index 06ce80435..a80b28ea2 100644 --- a/development/compilers/lua/src/lcode.c +++ b/development/compilers/lua/src/lcode.c @@ -330,10 +330,9 @@ int luaK_numberK (FuncState *fs, lua_Number r) { setnvalue(&o, r); if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */ /* use raw representation as key to avoid numeric problems */ - setsvalue(L, L->top, luaS_newlstr(L, (char *)&r, sizeof(r))); - incr_top(L); - n = addk(fs, L->top - 1, &o); - L->top--; + setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r))); + n = addk(fs, L->top - 1, &o); + L->top--; } else n = addk(fs, &o, &o); /* regular case */ @@ -426,7 +425,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_nil(fs, reg, 1); break; } - case VFALSE: case VTRUE: { + case VFALSE: case VTRUE: { luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); break; } diff --git a/development/compilers/lua/src/lcorolib.c b/development/compilers/lua/src/lcorolib.c index 7daea08e9..13993eb47 100644 --- a/development/compilers/lua/src/lcorolib.c +++ b/development/compilers/lua/src/lcorolib.c @@ -73,15 +73,16 @@ static int luaB_auxwrap (lua_State *L) { lua_insert(L, -2); lua_concat(L, 2); } - lua_error(L); /* propagate error */ + return lua_error(L); /* propagate error */ } return r; } static int luaB_cocreate (lua_State *L) { - lua_State *NL = lua_newthread(L); + lua_State *NL; luaL_checktype(L, 1, LUA_TFUNCTION); + NL = lua_newthread(L); lua_pushvalue(L, 1); /* move function to top */ lua_xmove(L, NL, 1); /* move function from L to NL */ return 1; diff --git a/development/compilers/lua/src/ldblib.c b/development/compilers/lua/src/ldblib.c index 5c549f35e..893384b64 100644 --- a/development/compilers/lua/src/ldblib.c +++ b/development/compilers/lua/src/ldblib.c @@ -253,14 +253,15 @@ static int db_upvaluejoin (lua_State *L) { } -#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY); +#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY) static void hookf (lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = {"call", "return", "line", "count", "tail call"}; gethooktable(L); - lua_rawgetp(L, -1, L); + lua_pushthread(L); + lua_rawget(L, -2); if (lua_isfunction(L, -1)) { lua_pushstring(L, hooknames[(int)ar->event]); if (ar->currentline >= 0) @@ -306,10 +307,15 @@ static int db_sethook (lua_State *L) { count = luaL_optint(L, arg+3, 0); func = hookf; mask = makemask(smask, count); } - gethooktable(L); + if (gethooktable(L) == 0) { /* creating hook table? */ + lua_pushstring(L, "k"); + lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ + lua_pushvalue(L, -1); + lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ + } + lua_pushthread(L1); lua_xmove(L1, L, 1); lua_pushvalue(L, arg+1); - lua_rawsetp(L, -2, L1); /* set new hook */ - lua_pop(L, 1); /* remove hook table */ + lua_rawset(L, -3); /* set new hook */ lua_sethook(L1, func, mask, count); /* set hooks */ return 0; } @@ -325,7 +331,8 @@ static int db_gethook (lua_State *L) { lua_pushliteral(L, "external hook"); else { gethooktable(L); - lua_rawgetp(L, -1, L1); /* get hook */ + lua_pushthread(L1); lua_xmove(L1, L, 1); + lua_rawget(L, -2); /* get hook */ lua_remove(L, -2); /* remove hook table */ } lua_pushstring(L, unmakemask(mask, buff)); diff --git a/development/compilers/lua/src/ldebug.c b/development/compilers/lua/src/ldebug.c index eb27401a6..5f140c806 100644 --- a/development/compilers/lua/src/ldebug.c +++ b/development/compilers/lua/src/ldebug.c @@ -30,6 +30,9 @@ +#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) + + static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); @@ -173,7 +176,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { static void funcinfo (lua_Debug *ar, Closure *cl) { - if (cl == NULL || cl->c.isC) { + if (noLuaClosure(cl)) { ar->source = "=[C]"; ar->linedefined = -1; ar->lastlinedefined = -1; @@ -191,9 +194,9 @@ static void funcinfo (lua_Debug *ar, Closure *cl) { static void collectvalidlines (lua_State *L, Closure *f) { - if (f == NULL || f->c.isC) { + if (noLuaClosure(f)) { setnilvalue(L->top); - incr_top(L); + api_incr_top(L); } else { int i; @@ -201,7 +204,7 @@ static void collectvalidlines (lua_State *L, Closure *f) { int *lineinfo = f->l.p->lineinfo; Table *t = luaH_new(L); /* new table to store active lines */ sethvalue(L, L->top, t); /* push it on stack */ - incr_top(L); + api_incr_top(L); setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */ for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */ luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */ @@ -210,7 +213,7 @@ static void collectvalidlines (lua_State *L, Closure *f) { static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, - Closure *f, CallInfo *ci) { + Closure *f, CallInfo *ci) { int status = 1; for (; *what; what++) { switch (*what) { @@ -224,7 +227,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, } case 'u': { ar->nups = (f == NULL) ? 0 : f->c.nupvalues; - if (f == NULL || f->c.isC) { + if (noLuaClosure(f)) { ar->isvararg = 1; ar->nparams = 0; } @@ -282,7 +285,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { status = auxgetinfo(L, what, ar, cl, ci); if (strchr(what, 'f')) { setobjs2s(L, L->top, func); - incr_top(L); + api_incr_top(L); } if (strchr(what, 'L')) collectvalidlines(L, cl); @@ -560,7 +563,7 @@ l_noret luaG_errormsg (lua_State *L) { if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ - incr_top(L); + L->top++; luaD_call(L, L->top - 2, 1, 0); /* call it */ } luaD_throw(L, LUA_ERRRUN); diff --git a/development/compilers/lua/src/ldo.c b/development/compilers/lua/src/ldo.c index df82944b8..b0aa8182e 100644 --- a/development/compilers/lua/src/ldo.c +++ b/development/compilers/lua/src/ldo.c @@ -311,6 +311,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); ci->callstatus = 0; + luaC_checkGC(L); /* stack grow uses memory */ if (L->hookmask & LUA_MASKCALL) luaD_hook(L, LUA_HOOKCALL, -1); lua_unlock(L); @@ -338,6 +339,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { ci->u.l.savedpc = p->code; /* starting point */ ci->callstatus = CIST_LUA; L->top = ci->top; + luaC_checkGC(L); /* stack grow uses memory */ if (L->hookmask & LUA_MASKCALL) callhook(L, ci); return 0; @@ -393,7 +395,6 @@ void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) { luaV_execute(L); /* call it */ if (!allowyield) L->nny--; L->nCcalls--; - luaC_checkGC(L); } @@ -402,9 +403,11 @@ static void finishCcall (lua_State *L) { int n; lua_assert(ci->u.c.k != NULL); /* must have a continuation */ lua_assert(L->nny == 0); - /* finish 'luaD_call' */ - L->nCcalls--; - /* finish 'lua_callk' */ + if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ + ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */ + L->errfunc = ci->u.c.old_errfunc; + } + /* finish 'lua_callk'/'lua_pcall' */ adjustresults(L, ci->nresults); /* call continuation function */ if (!(ci->callstatus & CIST_STAT)) /* no call status? */ @@ -453,7 +456,7 @@ static int recover (lua_State *L, int status) { CallInfo *ci = findpcall(L); if (ci == NULL) return 0; /* no recovery point */ /* "finish" luaD_pcall */ - oldtop = restorestack(L, ci->u.c.extra); + oldtop = restorestack(L, ci->extra); luaF_close(L, oldtop); seterrorobj(L, status, oldtop); L->ci = ci; @@ -475,7 +478,7 @@ static int recover (lua_State *L, int status) { static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { L->top = firstArg; /* remove args from the stack */ setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ - incr_top(L); + api_incr_top(L); luaD_throw(L, -1); /* jump back to 'lua_resume' */ } @@ -484,9 +487,10 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { ** do the work for 'lua_resume' in protected mode */ static void resume (lua_State *L, void *ud) { + int nCcalls = L->nCcalls; StkId firstArg = cast(StkId, ud); CallInfo *ci = L->ci; - if (L->nCcalls >= LUAI_MAXCCALLS) + if (nCcalls >= LUAI_MAXCCALLS) resume_error(L, "C stack overflow", firstArg); if (L->status == LUA_OK) { /* may be starting a coroutine */ if (ci != &L->base_ci) /* not in base level? */ @@ -499,10 +503,10 @@ static void resume (lua_State *L, void *ud) { resume_error(L, "cannot resume dead coroutine", firstArg); else { /* resuming from previous yield */ L->status = LUA_OK; + ci->func = restorestack(L, ci->extra); if (isLua(ci)) /* yielded inside a hook? */ luaV_execute(L); /* just continue running Lua code */ else { /* 'common' yield */ - ci->func = restorestack(L, ci->u.c.extra); if (ci->u.c.k != NULL) { /* does it have a continuation? */ int n; ci->u.c.status = LUA_YIELD; /* 'default' status */ @@ -513,11 +517,11 @@ static void resume (lua_State *L, void *ud) { api_checknelems(L, n); firstArg = L->top - n; /* yield results come from continuation */ } - L->nCcalls--; /* finish 'luaD_call' */ luaD_poscall(L, firstArg); /* finish 'luaD_precall' */ } unroll(L, NULL); } + lua_assert(nCcalls == L->nCcalls); } @@ -559,18 +563,18 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) { api_checknelems(L, nresults); if (L->nny > 0) { if (L != G(L)->mainthread) - luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); + luaG_runerror(L, "attempt to yield across a C-call boundary"); else luaG_runerror(L, "attempt to yield from outside a coroutine"); } L->status = LUA_YIELD; + ci->extra = savestack(L, ci->func); /* save current 'func' */ if (isLua(ci)) { /* inside a hook? */ api_check(L, k == NULL, "hooks cannot continue after yielding"); } else { if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ ci->u.c.ctx = ctx; /* save context */ - ci->u.c.extra = savestack(L, ci->func); /* save current 'func' */ ci->func = L->top - nresults - 1; /* protect stack below results */ luaD_throw(L, LUA_YIELD); } @@ -627,24 +631,23 @@ static void checkmode (lua_State *L, const char *mode, const char *x) { static void f_parser (lua_State *L, void *ud) { int i; - Proto *tf; Closure *cl; struct SParser *p = cast(struct SParser *, ud); int c = zgetc(p->z); /* read first character */ if (c == LUA_SIGNATURE[0]) { checkmode(L, p->mode, "binary"); - tf = luaU_undump(L, p->z, &p->buff, p->name); + cl = luaU_undump(L, p->z, &p->buff, p->name); } else { checkmode(L, p->mode, "text"); - tf = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); + cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); + } + lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); + for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */ + UpVal *up = luaF_newupval(L); + cl->l.upvals[i] = up; + luaC_objbarrier(L, cl, up); } - setptvalue2s(L, L->top, tf); - incr_top(L); - cl = luaF_newLclosure(L, tf); - setclLvalue(L, L->top - 1, cl); - for (i = 0; i < tf->sizeupvalues; i++) /* initialize upvalues */ - cl->l.upvals[i] = luaF_newupval(L); } diff --git a/development/compilers/lua/src/ldump.c b/development/compilers/lua/src/ldump.c index 4cb746fbd..9419531dd 100644 --- a/development/compilers/lua/src/ldump.c +++ b/development/compilers/lua/src/ldump.c @@ -84,8 +84,8 @@ static void DumpConstants(const Proto* f, DumpState* D) for (i=0; ik[i]; - DumpChar(ttype(o),D); - switch (ttype(o)) + DumpChar(ttypenv(o),D); + switch (ttypenv(o)) { case LUA_TNIL: break; @@ -98,6 +98,7 @@ static void DumpConstants(const Proto* f, DumpState* D) case LUA_TSTRING: DumpString(rawtsvalue(o),D); break; + default: lua_assert(0); } } n=f->sizep; diff --git a/development/compilers/lua/src/lfunc.c b/development/compilers/lua/src/lfunc.c index b6da88c1e..27874832d 100644 --- a/development/compilers/lua/src/lfunc.c +++ b/development/compilers/lua/src/lfunc.c @@ -21,18 +21,15 @@ Closure *luaF_newCclosure (lua_State *L, int n) { - Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeCclosure(n), NULL, 0)->cl; - c->c.isC = 1; + Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl; c->c.nupvalues = cast_byte(n); return c; } -Closure *luaF_newLclosure (lua_State *L, Proto *p) { - int n = p->sizeupvalues; - Closure *c = &luaC_newobj(L, LUA_TFUNCTION, sizeLclosure(n), NULL, 0)->cl; - c->l.isC = 0; - c->l.p = p; +Closure *luaF_newLclosure (lua_State *L, int n) { + Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl; + c->l.p = NULL; c->l.nupvalues = cast_byte(n); while (n--) c->l.upvals[n] = NULL; return c; @@ -55,12 +52,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { while (*pp != NULL && (p = gco2uv(*pp))->v >= level) { GCObject *o = obj2gco(p); lua_assert(p->v != &p->u.value); + lua_assert(!isold(o) || isold(obj2gco(L))); if (p->v == level) { /* found a corresponding upvalue? */ if (isdead(g, o)) /* is it dead? */ changewhite(o); /* resurrect it */ return p; } - resetoldbit(o); /* may create a newer upval after this one */ pp = &p->next; } /* not found: create a new one */ @@ -146,13 +143,6 @@ void luaF_freeproto (lua_State *L, Proto *f) { } -void luaF_freeclosure (lua_State *L, Closure *c) { - int size = (c->c.isC) ? sizeCclosure(c->c.nupvalues) : - sizeLclosure(c->l.nupvalues); - luaM_freemem(L, c, size); -} - - /* ** Look for n-th local variable at line `line' in function `func'. ** Returns NULL if not found. diff --git a/development/compilers/lua/src/lfunc.h b/development/compilers/lua/src/lfunc.h index 70ba8fed4..4a194f287 100644 --- a/development/compilers/lua/src/lfunc.h +++ b/development/compilers/lua/src/lfunc.h @@ -20,12 +20,11 @@ LUAI_FUNC Proto *luaF_newproto (lua_State *L); LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems); -LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, Proto *p); +LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems); LUAI_FUNC UpVal *luaF_newupval (lua_State *L); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_close (lua_State *L, StkId level); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); -LUAI_FUNC void luaF_freeclosure (lua_State *L, Closure *c); LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv); LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, int pc); diff --git a/development/compilers/lua/src/lgc.c b/development/compilers/lua/src/lgc.c index 6e62427eb..d9204bfcb 100644 --- a/development/compilers/lua/src/lgc.c +++ b/development/compilers/lua/src/lgc.c @@ -24,34 +24,31 @@ -/* how much to allocate before next GC step */ -#define GCSTEPSIZE 1024 +/* +** cost of sweeping one element (the size of a small object divided +** by some adjust for the sweep speed) +*/ +#define GCSWEEPCOST ((sizeof(TString) + 4) / 4) /* maximum number of elements to sweep in each single step */ -#define GCSWEEPMAX 40 - -/* cost of sweeping one element */ -#define GCSWEEPCOST 1 +#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) /* maximum number of finalizers to call in each GC step */ #define GCFINALIZENUM 4 -/* cost of marking the root set */ -#define GCROOTCOST 10 -/* cost of atomic step */ -#define GCATOMICCOST 1000 - -/* basic cost to traverse one object (to be added to the links the - object may have) */ -#define TRAVCOST 5 +/* +** macro to adjust 'stepmul': 'stepmul' is actually used like +** 'stepmul / STEPMULADJ' (value chosen by tests) +*/ +#define STEPMULADJ 200 /* -** standard negative debt for GC; a reasonable "time" to wait before -** starting a new cycle +** macro to adjust 'pause': 'pause' is actually used like +** 'pause / PAUSEADJ' (value chosen by tests) */ -#define stddebt(g) (-cast(l_mem, gettotalbytes(g)/100) * g->gcpause) +#define PAUSEADJ 100 /* @@ -65,8 +62,6 @@ #define white2gray(x) resetbits(gch(x)->marked, WHITEBITS) #define black2gray(x) resetbit(gch(x)->marked, BLACKBIT) -#define stringmark(s) ((void)((s) && resetbits((s)->tsv.marked, WHITEBITS))) - #define isfinalized(x) testbit(gch(x)->marked, FINALIZEDBIT) @@ -123,10 +118,10 @@ static void removeentry (Node *n) { ** other objects: if really collected, cannot keep them; for objects ** being finalized, keep them in keys, but not in values */ -static int iscleared (const TValue *o) { +static int iscleared (global_State *g, const TValue *o) { if (!iscollectable(o)) return 0; else if (ttisstring(o)) { - stringmark(rawtsvalue(o)); /* strings are `values', so are never weak */ + markobject(g, rawtsvalue(o)); /* strings are `values', so are never weak */ return 0; } else return iswhite(gcvalue(o)); @@ -140,9 +135,9 @@ static int iscleared (const TValue *o) { void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(isgenerational(g) || g->gcstate != GCSpause); + lua_assert(g->gcstate != GCSpause); lua_assert(gch(o)->tt != LUA_TTABLE); - if (keepinvariant(g)) /* must keep invariant? */ + if (keepinvariantout(g)) /* must keep invariant? */ reallymarkobject(g, v); /* restore invariant */ else { /* sweep phase */ lua_assert(issweepphase(g)); @@ -217,7 +212,8 @@ void luaC_checkupvalcolor (global_State *g, UpVal *uv) { GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, int offset) { global_State *g = G(L); - GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset); + char *raw = cast(char *, luaM_newobject(L, novariant(tt), sz)); + GCObject *o = obj2gco(raw + offset); if (list == NULL) list = &g->allgc; /* standard list for collectable objects */ gch(o)->marked = luaC_white(g); @@ -239,54 +235,63 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list, /* -** mark an object. Userdata and closed upvalues are visited and turned -** black here. Strings remain gray (it is the same as making them -** black). Other objects are marked gray and added to appropriate list -** to be visited (and turned black) later. (Open upvalues are already -** linked in 'headuv' list.) +** mark an object. Userdata, strings, and closed upvalues are visited +** and turned black here. Other objects are marked gray and added +** to appropriate list to be visited (and turned black) later. (Open +** upvalues are already linked in 'headuv' list.) */ static void reallymarkobject (global_State *g, GCObject *o) { - lua_assert(iswhite(o) && !isdead(g, o)); + lu_mem size; white2gray(o); switch (gch(o)->tt) { - case LUA_TSTRING: { - return; /* for strings, gray is as good as black */ + case LUA_TSHRSTR: + case LUA_TLNGSTR: { + size = sizestring(gco2ts(o)); + break; /* nothing else to mark; make it black */ } case LUA_TUSERDATA: { Table *mt = gco2u(o)->metatable; markobject(g, mt); markobject(g, gco2u(o)->env); - gray2black(o); /* all pointers marked */ - return; + size = sizeudata(gco2u(o)); + break; } case LUA_TUPVAL: { UpVal *uv = gco2uv(o); markvalue(g, uv->v); - if (uv->v == &uv->u.value) /* closed? (open upvalues remain gray) */ - gray2black(o); /* make it black */ + if (uv->v != &uv->u.value) /* open? */ + return; /* open upvalues remain gray */ + size = sizeof(UpVal); + break; + } + case LUA_TLCL: { + gco2lcl(o)->gclist = g->gray; + g->gray = o; return; } - case LUA_TFUNCTION: { - gco2cl(o)->c.gclist = g->gray; + case LUA_TCCL: { + gco2ccl(o)->gclist = g->gray; g->gray = o; - break; + return; } case LUA_TTABLE: { linktable(gco2t(o), &g->gray); - break; + return; } case LUA_TTHREAD: { gco2th(o)->gclist = g->gray; g->gray = o; - break; + return; } case LUA_TPROTO: { gco2p(o)->gclist = g->gray; g->gray = o; - break; + return; } - default: lua_assert(0); + default: lua_assert(0); return; } + gray2black(o); + g->GCmemtrav += size; } @@ -329,7 +334,7 @@ static void remarkupvals (global_State *g) { ** mark root set and reset all gray lists, to start a new ** incremental (or full) collection */ -static void markroot (global_State *g) { +static void restartcollection (global_State *g) { g->gray = g->grayagain = NULL; g->weak = g->allweak = g->ephemeron = NULL; markobject(g, g->mainthread); @@ -359,7 +364,7 @@ static void traverseweakvalue (global_State *g, Table *h) { else { lua_assert(!ttisnil(gkey(n))); markvalue(g, gkey(n)); /* mark key */ - if (!hasclears && iscleared(gval(n))) /* is there a white value? */ + if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ hasclears = 1; /* table will have to be cleared */ } } @@ -388,7 +393,7 @@ static int traverseephemeron (global_State *g, Table *h) { checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ - else if (iscleared(gkey(n))) { /* key is not marked (yet)? */ + else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ hasclears = 1; /* table must be cleared */ if (valiswhite(gval(n))) /* value not marked yet? */ prop = 1; /* must propagate again */ @@ -426,30 +431,26 @@ static void traversestrongtable (global_State *g, Table *h) { } -static int traversetable (global_State *g, Table *h) { +static lu_mem traversetable (global_State *g, Table *h) { + const char *weakkey, *weakvalue; const TValue *mode = gfasttm(g, h->metatable, TM_MODE); markobject(g, h->metatable); - if (mode && ttisstring(mode)) { /* is there a weak mode? */ - int weakkey = (strchr(svalue(mode), 'k') != NULL); - int weakvalue = (strchr(svalue(mode), 'v') != NULL); - if (weakkey || weakvalue) { /* is really weak? */ - black2gray(obj2gco(h)); /* keep table gray */ - if (!weakkey) { /* strong keys? */ - traverseweakvalue(g, h); - return TRAVCOST + sizenode(h); - } - else if (!weakvalue) { /* strong values? */ - traverseephemeron(g, h); - return TRAVCOST + h->sizearray + sizenode(h); - } - else { - linktable(h, &g->allweak); /* nothing to traverse now */ - return TRAVCOST; - } - } /* else go through */ + if (mode && ttisstring(mode) && /* is there a weak mode? */ + ((weakkey = strchr(svalue(mode), 'k')), + (weakvalue = strchr(svalue(mode), 'v')), + (weakkey || weakvalue))) { /* is really weak? */ + black2gray(obj2gco(h)); /* keep table gray */ + if (!weakkey) /* strong keys? */ + traverseweakvalue(g, h); + else if (!weakvalue) /* strong values? */ + traverseephemeron(g, h); + else /* all weak */ + linktable(h, &g->allweak); /* nothing to traverse now */ } - traversestrongtable(g, h); - return TRAVCOST + h->sizearray + (2 * sizenode(h)); + else /* not weak */ + traversestrongtable(g, h); + return sizeof(Table) + sizeof(TValue) * h->sizearray + + sizeof(Node) * cast(size_t, sizenode(h)); } @@ -457,86 +458,101 @@ static int traverseproto (global_State *g, Proto *f) { int i; if (f->cache && iswhite(obj2gco(f->cache))) f->cache = NULL; /* allow cache to be collected */ - stringmark(f->source); + markobject(g, f->source); for (i = 0; i < f->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ - stringmark(f->upvalues[i].name); + markobject(g, f->upvalues[i].name); for (i = 0; i < f->sizep; i++) /* mark nested protos */ markobject(g, f->p[i]); for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ - stringmark(f->locvars[i].varname); - return TRAVCOST + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; + markobject(g, f->locvars[i].varname); + return sizeof(Proto) + sizeof(Instruction) * f->sizecode + + sizeof(Proto *) * f->sizep + + sizeof(TValue) * f->sizek + + sizeof(int) * f->sizelineinfo + + sizeof(LocVar) * f->sizelocvars + + sizeof(Upvaldesc) * f->sizeupvalues; } -static int traverseclosure (global_State *g, Closure *cl) { - if (cl->c.isC) { - int i; - for (i=0; ic.nupvalues; i++) /* mark its upvalues */ - markvalue(g, &cl->c.upvalue[i]); - } - else { - int i; - lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues); - markobject(g, cl->l.p); /* mark its prototype */ - for (i=0; il.nupvalues; i++) /* mark its upvalues */ - markobject(g, cl->l.upvals[i]); - } - return TRAVCOST + cl->c.nupvalues; +static lu_mem traverseCclosure (global_State *g, CClosure *cl) { + int i; + for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ + markvalue(g, &cl->upvalue[i]); + return sizeCclosure(cl->nupvalues); +} + +static lu_mem traverseLclosure (global_State *g, LClosure *cl) { + int i; + markobject(g, cl->p); /* mark its prototype */ + for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ + markobject(g, cl->upvals[i]); + return sizeLclosure(cl->nupvalues); } -static int traversestack (global_State *g, lua_State *L) { - StkId o = L->stack; +static lu_mem traversestack (global_State *g, lua_State *th) { + StkId o = th->stack; if (o == NULL) return 1; /* stack not completely built yet */ - for (; o < L->top; o++) + for (; o < th->top; o++) markvalue(g, o); if (g->gcstate == GCSatomic) { /* final traversal? */ - StkId lim = L->stack + L->stacksize; /* real end of stack */ + StkId lim = th->stack + th->stacksize; /* real end of stack */ for (; o < lim; o++) /* clear not-marked stack slice */ setnilvalue(o); } - return TRAVCOST + cast_int(o - L->stack); + return sizeof(lua_State) + sizeof(TValue) * th->stacksize; } /* ** traverse one gray object, turning it to black (except for threads, ** which are always gray). -** Returns number of values traversed. */ -static int propagatemark (global_State *g) { +static void propagatemark (global_State *g) { + lu_mem size; GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); switch (gch(o)->tt) { case LUA_TTABLE: { Table *h = gco2t(o); - g->gray = h->gclist; - return traversetable(g, h); + g->gray = h->gclist; /* remove from 'gray' list */ + size = traversetable(g, h); + break; } - case LUA_TFUNCTION: { - Closure *cl = gco2cl(o); - g->gray = cl->c.gclist; - return traverseclosure(g, cl); + case LUA_TLCL: { + LClosure *cl = gco2lcl(o); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseLclosure(g, cl); + break; + } + case LUA_TCCL: { + CClosure *cl = gco2ccl(o); + g->gray = cl->gclist; /* remove from 'gray' list */ + size = traverseCclosure(g, cl); + break; } case LUA_TTHREAD: { lua_State *th = gco2th(o); - g->gray = th->gclist; + g->gray = th->gclist; /* remove from 'gray' list */ th->gclist = g->grayagain; - g->grayagain = o; + g->grayagain = o; /* insert into 'grayagain' list */ black2gray(o); - return traversestack(g, th); + size = traversestack(g, th); + break; } case LUA_TPROTO: { Proto *p = gco2p(o); - g->gray = p->gclist; - return traverseproto(g, p); + g->gray = p->gclist; /* remove from 'gray' list */ + size = traverseproto(g, p); + break; } - default: lua_assert(0); return 0; + default: lua_assert(0); return; } + g->GCmemtrav += size; } @@ -599,12 +615,12 @@ static void convergeephemerons (global_State *g) { ** clear entries with unmarked keys from all weaktables in list 'l' up ** to element 'f' */ -static void clearkeys (GCObject *l, GCObject *f) { +static void clearkeys (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && (iscleared(gkey(n)))) { + if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* and remove entry from table */ } @@ -617,18 +633,18 @@ static void clearkeys (GCObject *l, GCObject *f) { ** clear entries with unmarked values from all weaktables in list 'l' up ** to element 'f' */ -static void clearvalues (GCObject *l, GCObject *f) { +static void clearvalues (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); int i; for (i = 0; i < h->sizearray; i++) { TValue *o = &h->array[i]; - if (iscleared(o)) /* value was collected? */ + if (iscleared(g, o)) /* value was collected? */ setnilvalue(o); /* remove value */ } for (n = gnode(h, 0); n < limit; n++) { - if (!ttisnil(gval(n)) && iscleared(gval(n))) { + if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* and remove entry from table */ } @@ -640,13 +656,22 @@ static void clearvalues (GCObject *l, GCObject *f) { static void freeobj (lua_State *L, GCObject *o) { switch (gch(o)->tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; - case LUA_TFUNCTION: luaF_freeclosure(L, gco2cl(o)); break; + case LUA_TLCL: { + luaM_freemem(L, o, sizeLclosure(gco2lcl(o)->nupvalues)); + break; + } + case LUA_TCCL: { + luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); + break; + } case LUA_TUPVAL: luaF_freeupval(L, gco2uv(o)); break; case LUA_TTABLE: luaH_free(L, gco2t(o)); break; case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; - case LUA_TSTRING: { + case LUA_TSHRSTR: G(L)->strt.nuse--; + /* go through */ + case LUA_TLNGSTR: { luaM_freemem(L, o, sizestring(gco2ts(o))); break; } @@ -689,7 +714,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { int ow = otherwhite(g); int toclear, toset; /* bits to clear and to set in all live objects */ int tostop; /* stop sweep when this is true */ - l_mem debt = g->GCdebt; /* current debt */ if (isgenerational(g)) { /* generational mode? */ toclear = ~0; /* clear nothing */ toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */ @@ -708,19 +732,30 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { freeobj(L, curr); /* erase 'curr' */ } else { + if (testbits(marked, tostop)) + return NULL; /* stop sweeping this list */ if (gch(curr)->tt == LUA_TTHREAD) sweepthread(L, gco2th(curr)); /* sweep thread's upvalues */ - if (testbits(marked, tostop)) { - static GCObject *nullp = NULL; - p = &nullp; /* stop sweeping this list */ - break; - } /* update marks */ gch(curr)->marked = cast_byte((marked & toclear) | toset); p = &gch(curr)->next; /* go to next element */ } } - luaE_setdebt(g, debt); /* sweeping should not change debt */ + return (*p == NULL) ? NULL : p; +} + + +/* +** sweep a list until a live object (or end of list) +*/ +static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { + GCObject ** old = p; + int i = 0; + do { + i++; + p = sweeplist(L, p, 1); + } while (p == old); + if (n) *n += i; return p; } @@ -752,7 +787,7 @@ static GCObject *udata2finalize (global_State *g) { g->allgc = o; resetbit(gch(o)->marked, SEPARATED); /* mark that it is not in 'tobefnz' */ lua_assert(!isold(o)); /* see MOVE OLD rule */ - if (!keepinvariant(g)) /* not keeping invariant? */ + if (!keepinvariantout(g)) /* not keeping invariant? */ makewhite(g, o); /* "sweep" object */ return o; } @@ -783,12 +818,14 @@ static void GCTM (lua_State *L, int propagateerrors) { L->allowhook = oldah; /* restore hooks */ g->gcrunning = running; /* restore state */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ - if (status == LUA_ERRRUN) { /* is there an error msg.? */ - luaO_pushfstring(L, "error in __gc metamethod (%s)", - lua_tostring(L, -1)); + if (status == LUA_ERRRUN) { /* is there an error object? */ + const char *msg = (ttisstring(L->top - 1)) + ? svalue(L->top - 1) + : "no message"; + luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); status = LUA_ERRGCMM; /* error in __gc metamethod */ } - luaD_throw(L, status); /* re-send error */ + luaD_throw(L, status); /* re-throw error */ } } } @@ -809,7 +846,7 @@ static void separatetobefnz (lua_State *L, int all) { while ((curr = *p) != NULL) { /* traverse all finalizable objects */ lua_assert(!isfinalized(curr)); lua_assert(testbit(gch(curr)->marked, SEPARATED)); - if (!(all || iswhite(curr))) /* not being collected? */ + if (!(iswhite(curr) || all)) /* not being collected? */ p = &gch(curr)->next; /* don't bother with it */ else { l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */ @@ -834,12 +871,21 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { return; /* nothing to be done */ else { /* move 'o' to 'finobj' list */ GCObject **p; - for (p = &g->allgc; *p != o; p = &gch(*p)->next) ; - *p = gch(o)->next; /* remove 'o' from root list */ - gch(o)->next = g->finobj; /* link it in list 'finobj' */ + GCheader *ho = gch(o); + if (g->sweepgc == &ho->next) { /* avoid removing current sweep object */ + lua_assert(issweepphase(g)); + g->sweepgc = sweeptolive(L, g->sweepgc, NULL); + } + /* search for pointer pointing to 'o' */ + for (p = &g->allgc; *p != o; p = &gch(*p)->next) { /* empty */ } + *p = ho->next; /* remove 'o' from root list */ + ho->next = g->finobj; /* link it in list 'finobj' */ g->finobj = o; - l_setbit(gch(o)->marked, SEPARATED); /* mark it as such */ - resetoldbit(o); /* see MOVE OLD rule */ + l_setbit(ho->marked, SEPARATED); /* mark it as such */ + if (!keepinvariantout(g)) /* not keeping invariant? */ + makewhite(g, o); /* "sweep" object */ + else + resetoldbit(o); /* see MOVE OLD rule */ } } @@ -853,9 +899,46 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { */ +/* +** set a reasonable "time" to wait before starting a new GC cycle; +** cycle will start when memory use hits threshold +*/ +static void setpause (global_State *g, l_mem estimate) { + l_mem debt, threshold; + estimate = estimate / PAUSEADJ; /* adjust 'estimate' */ + threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ + ? estimate * g->gcpause /* no overflow */ + : MAX_LMEM; /* overflow; truncate to maximum */ + debt = -cast(l_mem, threshold - gettotalbytes(g)); + luaE_setdebt(g, debt); +} + + #define sweepphases \ (bitmask(GCSsweepstring) | bitmask(GCSsweepudata) | bitmask(GCSsweep)) + +/* +** enter first sweep phase (strings) and prepare pointers for other +** sweep phases. The calls to 'sweeptolive' make pointers point to an +** object inside the list (instead of to the header), so that the real +** sweep do not need to skip objects created between "now" and the start +** of the real sweep. +** Returns how many objects it swept. +*/ +static int entersweep (lua_State *L) { + global_State *g = G(L); + int n = 0; + g->gcstate = GCSsweepstring; + lua_assert(g->sweepgc == NULL && g->sweepfin == NULL); + /* prepare to sweep strings, finalizable objects, and regular objects */ + g->sweepstrgc = 0; + g->sweepfin = sweeptolive(L, &g->finobj, &n); + g->sweepgc = sweeptolive(L, &g->allgc, &n); + return n; +} + + /* ** change GC mode */ @@ -865,15 +948,14 @@ void luaC_changemode (lua_State *L, int mode) { if (mode == KGC_GEN) { /* change to generational mode */ /* make sure gray lists are consistent */ luaC_runtilstate(L, bitmask(GCSpropagate)); - g->lastmajormem = gettotalbytes(g); + g->GCestimate = gettotalbytes(g); g->gckind = KGC_GEN; } else { /* change to incremental mode */ /* sweep all objects to turn them back to white (as white has not changed, nothing extra will be collected) */ - g->sweepstrgc = 0; - g->gcstate = GCSsweepstring; g->gckind = KGC_NORMAL; + entersweep(L); luaC_runtilstate(L, ~sweepphases); } } @@ -907,8 +989,9 @@ void luaC_freeallobjects (lua_State *L) { } -static void atomic (lua_State *L) { +static l_mem atomic (lua_State *L) { global_State *g = G(L); + l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */ GCObject *origweak, *origall; lua_assert(!iswhite(obj2gco(g->mainthread))); markobject(g, L); /* mark running thread */ @@ -917,77 +1000,85 @@ static void atomic (lua_State *L) { markmt(g); /* mark basic metatables */ /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); + propagateall(g); /* propagate changes */ + work += g->GCmemtrav; /* stop counting (do not (re)count grays) */ /* traverse objects caught by write barrier and by 'remarkupvals' */ retraversegrays(g); + work -= g->GCmemtrav; /* restart counting */ convergeephemerons(g); /* at this point, all strongly accessible objects are marked. */ /* clear values from weak tables, before checking finalizers */ - clearvalues(g->weak, NULL); - clearvalues(g->allweak, NULL); + clearvalues(g, g->weak, NULL); + clearvalues(g, g->allweak, NULL); origweak = g->weak; origall = g->allweak; + work += g->GCmemtrav; /* stop counting (objects being finalized) */ separatetobefnz(L, 0); /* separate objects to be finalized */ - markbeingfnz(g); /* mark userdata that will be finalized */ + markbeingfnz(g); /* mark objects that will be finalized */ propagateall(g); /* remark, to propagate `preserveness' */ + work -= g->GCmemtrav; /* restart counting */ convergeephemerons(g); /* at this point, all resurrected objects are marked. */ /* remove dead objects from weak tables */ - clearkeys(g->ephemeron, NULL); /* clear keys from all ephemeron tables */ - clearkeys(g->allweak, NULL); /* clear keys from all allweak tables */ + clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ + clearkeys(g, g->allweak, NULL); /* clear keys from all allweak tables */ /* clear values from resurrected weak tables */ - clearvalues(g->weak, origweak); - clearvalues(g->allweak, origall); - g->sweepstrgc = 0; /* prepare to sweep strings */ - g->gcstate = GCSsweepstring; + clearvalues(g, g->weak, origweak); + clearvalues(g, g->allweak, origall); g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ - /*lua_checkmemory(L);*/ + work += g->GCmemtrav; /* complete counting */ + return work; /* estimate of memory marked by 'atomic' */ } -static l_mem singlestep (lua_State *L) { +static lu_mem singlestep (lua_State *L) { global_State *g = G(L); switch (g->gcstate) { case GCSpause: { - if (!isgenerational(g)) - markroot(g); /* start a new collection */ - /* in any case, root must be marked */ - lua_assert(!iswhite(obj2gco(g->mainthread)) - && !iswhite(gcvalue(&g->l_registry))); + /* start to count memory traversed */ + g->GCmemtrav = g->strt.size * sizeof(GCObject*); + lua_assert(!isgenerational(g)); + restartcollection(g); g->gcstate = GCSpropagate; - return GCROOTCOST; + return g->GCmemtrav; } case GCSpropagate: { - if (g->gray) - return propagatemark(g); + if (g->gray) { + lu_mem oldtrav = g->GCmemtrav; + propagatemark(g); + return g->GCmemtrav - oldtrav; /* memory traversed in this step */ + } else { /* no more `gray' objects */ + lu_mem work; + int sw; g->gcstate = GCSatomic; /* finish mark phase */ - atomic(L); - return GCATOMICCOST; + g->GCestimate = g->GCmemtrav; /* save what was counted */; + work = atomic(L); /* add what was traversed by 'atomic' */ + g->GCestimate += work; /* estimate of total memory traversed */ + sw = entersweep(L); + return work + sw * GCSWEEPCOST; } } case GCSsweepstring: { - if (g->sweepstrgc < g->strt.size) { - sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); - return GCSWEEPCOST; - } - else { /* no more strings to sweep */ - g->sweepgc = &g->finobj; /* prepare to sweep finalizable objects */ + int i; + for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++) + sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]); + g->sweepstrgc += i; + if (g->sweepstrgc >= g->strt.size) /* no more strings to sweep? */ g->gcstate = GCSsweepudata; - return 0; - } + return i * GCSWEEPCOST; } case GCSsweepudata: { - if (*g->sweepgc) { - g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); + if (g->sweepfin) { + g->sweepfin = sweeplist(L, g->sweepfin, GCSWEEPMAX); return GCSWEEPMAX*GCSWEEPCOST; } else { - g->sweepgc = &g->allgc; /* go to next phase */ g->gcstate = GCSsweep; - return GCSWEEPCOST; + return 0; } } case GCSsweep: { - if (*g->sweepgc) { + if (g->sweepgc) { g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); return GCSWEEPMAX*GCSWEEPCOST; } @@ -1018,43 +1109,58 @@ void luaC_runtilstate (lua_State *L, int statesmask) { static void generationalcollection (lua_State *L) { global_State *g = G(L); - if (g->lastmajormem == 0) { /* signal for another major collection? */ + lua_assert(g->gcstate == GCSpropagate); + if (g->GCestimate == 0) { /* signal for another major collection? */ luaC_fullgc(L, 0); /* perform a full regular collection */ - g->lastmajormem = gettotalbytes(g); /* update control */ + g->GCestimate = gettotalbytes(g); /* update control */ } else { - luaC_runtilstate(L, ~bitmask(GCSpause)); /* run complete cycle */ - luaC_runtilstate(L, bitmask(GCSpause)); - if (gettotalbytes(g) > g->lastmajormem/100 * g->gcmajorinc) - g->lastmajormem = 0; /* signal for a major collection */ + lu_mem estimate = g->GCestimate; + luaC_runtilstate(L, bitmask(GCSpause)); /* run complete (minor) cycle */ + g->gcstate = GCSpropagate; /* skip restart */ + if (gettotalbytes(g) > (estimate / 100) * g->gcmajorinc) + g->GCestimate = 0; /* signal for a major collection */ + else + g->GCestimate = estimate; /* keep estimate from last major coll. */ + } - luaE_setdebt(g, stddebt(g)); + setpause(g, gettotalbytes(g)); + lua_assert(g->gcstate == GCSpropagate); } -static void step (lua_State *L) { +static void incstep (lua_State *L) { global_State *g = G(L); - l_mem lim = g->gcstepmul; /* how much to work */ + l_mem debt = g->GCdebt; + int stepmul = g->gcstepmul; + if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values (and 0) */ + /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */ + debt = (debt / STEPMULADJ) + 1; + debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; do { /* always perform at least one single step */ - lim -= singlestep(L); - } while (lim > 0 && g->gcstate != GCSpause); - if (g->gcstate != GCSpause) - luaE_setdebt(g, g->GCdebt - GCSTEPSIZE); - else - luaE_setdebt(g, stddebt(g)); + lu_mem work = singlestep(L); /* do some work */ + debt -= work; + } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); + if (g->gcstate == GCSpause) + setpause(g, g->GCestimate); /* pause until next cycle */ + else { + debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */ + luaE_setdebt(g, debt); + } } /* -** performs a basic GC step even if the collector is stopped +** performs a basic GC step */ void luaC_forcestep (lua_State *L) { global_State *g = G(L); int i; if (isgenerational(g)) generationalcollection(L); - else step(L); - for (i = 0; i < GCFINALIZENUM && g->tobefnz; i++) - GCTM(L, 1); /* Call a few pending finalizers */ + else incstep(L); + /* run a few finalizers (or all of them at the end of a collect cycle) */ + for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) + GCTM(L, 1); /* call one finalizer */ } @@ -1062,10 +1168,13 @@ void luaC_forcestep (lua_State *L) { ** performs a basic GC step only if collector is running */ void luaC_step (lua_State *L) { - if (G(L)->gcrunning) luaC_forcestep(L); + global_State *g = G(L); + if (g->gcrunning) luaC_forcestep(L); + else luaE_setdebt(g, -GCSTEPSIZE); /* avoid being called too often */ } + /* ** performs a full GC cycle; if "isemergency", does not call ** finalizers (which could change stack positions) @@ -1074,26 +1183,27 @@ void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); int origkind = g->gckind; lua_assert(origkind != KGC_EMERGENCY); - if (!isemergency) /* do not run finalizers during emergency GC */ + if (isemergency) /* do not run finalizers during emergency GC */ + g->gckind = KGC_EMERGENCY; + else { + g->gckind = KGC_NORMAL; callallpendingfinalizers(L, 1); - if (keepinvariant(g)) { /* marking phase? */ + } + if (keepinvariant(g)) { /* may there be some black objects? */ /* must sweep all objects to turn them back to white (as white has not changed, nothing will be collected) */ - g->sweepstrgc = 0; - g->gcstate = GCSsweepstring; + entersweep(L); } - g->gckind = isemergency ? KGC_EMERGENCY : KGC_NORMAL; /* finish any pending sweep phase to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpause)); - /* run entire collector */ - luaC_runtilstate(L, ~bitmask(GCSpause)); - luaC_runtilstate(L, bitmask(GCSpause)); + luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ + luaC_runtilstate(L, bitmask(GCSpause)); /* run entire collection */ if (origkind == KGC_GEN) { /* generational mode? */ - /* generational mode must always start in propagate phase */ + /* generational mode must be kept in propagate phase */ luaC_runtilstate(L, bitmask(GCSpropagate)); } g->gckind = origkind; - luaE_setdebt(g, stddebt(g)); + setpause(g, gettotalbytes(g)); if (!isemergency) /* do not run finalizers during emergency GC */ callallpendingfinalizers(L, 1); } diff --git a/development/compilers/lua/src/lgc.h b/development/compilers/lua/src/lgc.h index 8a2cc70a8..888f35680 100644 --- a/development/compilers/lua/src/lgc.h +++ b/development/compilers/lua/src/lgc.h @@ -25,6 +25,14 @@ */ + +/* how much to allocate before next GC step */ +#if !defined(GCSTEPSIZE) +/* ~100 small strings */ +#define GCSTEPSIZE (cast_int(100 * sizeof(TString))) +#endif + + /* ** Possible states of the Garbage Collector */ @@ -42,14 +50,24 @@ #define isgenerational(g) ((g)->gckind == KGC_GEN) /* -** macro to tell when main invariant (white objects cannot point to black +** macros to tell when main invariant (white objects cannot point to black ** ones) must be kept. During a non-generational collection, the sweep ** phase may break the invariant, as objects turned white may point to ** still-black objects. The invariant is restored when sweep ends and ** all objects are white again. During a generational collection, the ** invariant must be kept all times. */ -#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic) + +#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic) + + +/* +** Outside the collector, the state in generational mode is kept in +** 'propagate', so 'keepinvariant' is always true. +*/ +#define keepinvariantout(g) \ + check_exp(g->gcstate == GCSpropagate || !isgenerational(g), \ + g->gcstate <= GCSatomic) /* diff --git a/development/compilers/lua/src/liolib.c b/development/compilers/lua/src/liolib.c index ae5bb1287..c563fa3f9 100644 --- a/development/compilers/lua/src/liolib.c +++ b/development/compilers/lua/src/liolib.c @@ -29,6 +29,20 @@ #include "lualib.h" +#if !defined(lua_checkmode) + +/* +** Check whether 'mode' matches '[rwa]%+?b?'. +** Change this macro to accept other modes for 'fopen' besides +** the standard ones. +*/ +#define lua_checkmode(mode) \ + (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \ + (*mode != '+' || ++mode) && /* skip if char is '+' */ \ + (*mode != 'b' || ++mode) && /* skip if char is 'b' */ \ + (*mode == '\0')) + +#endif /* ** {====================================================== @@ -212,14 +226,8 @@ static int io_open (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newfile(L); - int i = 0; - /* check whether 'mode' matches '[rwa]%+?b?' */ - if (!(mode[i] != '\0' && strchr("rwa", mode[i++]) != NULL && - (mode[i] != '+' || ++i) && /* skip if char is '+' */ - (mode[i] != 'b' || ++i) && /* skip if char is 'b' */ - (mode[i] == '\0'))) - return luaL_error(L, "invalid mode " LUA_QS - " (should match " LUA_QL("[rwa]%%+?b?") ")", mode); + const char *md = mode; /* to traverse/check mode */ + luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode"); p->f = fopen(filename, mode); return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } diff --git a/development/compilers/lua/src/llex.c b/development/compilers/lua/src/llex.c index 4a9fcdfa0..79fdfc799 100644 --- a/development/compilers/lua/src/llex.c +++ b/development/compilers/lua/src/llex.c @@ -67,22 +67,22 @@ void luaX_init (lua_State *L) { for (i=0; itsv.reserved = cast_byte(i+1); /* reserved word */ + ts->tsv.extra = cast_byte(i+1); /* reserved word */ } } const char *luaX_token2str (LexState *ls, int token) { - if (token < FIRST_RESERVED) { + if (token < FIRST_RESERVED) { /* single-byte symbols? */ lua_assert(token == cast(unsigned char, token)); return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) : luaO_pushfstring(ls->L, "char(%d)", token); } else { const char *s = luaX_tokens[token - FIRST_RESERVED]; - if (token < TK_EOS) + if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ return luaO_pushfstring(ls->L, LUA_QS, s); - else + else /* names, strings, and numerals */ return s; } } @@ -222,13 +222,24 @@ static void trydecpoint (LexState *ls, SemInfo *seminfo) { /* LUA_NUMBER */ +/* +** this function is quite liberal in what it accepts, as 'luaO_str2d' +** will reject ill-formed numerals. +*/ static void read_numeral (LexState *ls, SemInfo *seminfo) { + const char *expo = "Ee"; + int first = ls->current; lua_assert(lisdigit(ls->current)); - do { - save_and_next(ls); - if (check_next(ls, "EePp")) /* exponent part? */ + save_and_next(ls); + if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */ + expo = "Pp"; + for (;;) { + if (check_next(ls, expo)) /* exponent part? */ check_next(ls, "+-"); /* optional exponent sign */ - } while (lislalnum(ls->current) || ls->current == '.'); + if (lisxdigit(ls->current) || ls->current == '.') + save_and_next(ls); + else break; + } save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ if (!buff2d(ls->buff, &seminfo->r)) /* format error? */ @@ -302,7 +313,7 @@ static int readhexaesc (LexState *ls) { int c[3], i; /* keep input for error message */ int r = 0; /* result accumulator */ c[0] = 'x'; /* for error message */ - for (i = 1; i < 3; i++) { /* read two hexa digits */ + for (i = 1; i < 3; i++) { /* read two hexadecimal digits */ c[i] = next(ls); if (!lisxdigit(c[i])) escerror(ls, c, i + 1, "hexadecimal digit expected"); @@ -480,8 +491,8 @@ static int llex (LexState *ls, SemInfo *seminfo) { ts = luaX_newstring(ls, luaZ_buffer(ls->buff), luaZ_bufflen(ls->buff)); seminfo->ts = ts; - if (ts->tsv.reserved > 0) /* reserved word? */ - return ts->tsv.reserved - 1 + FIRST_RESERVED; + if (isreserved(ts)) /* reserved word? */ + return ts->tsv.extra - 1 + FIRST_RESERVED; else { return TK_NAME; } diff --git a/development/compilers/lua/src/llimits.h b/development/compilers/lua/src/llimits.h index 560836de0..3195672e8 100644 --- a/development/compilers/lua/src/llimits.h +++ b/development/compilers/lua/src/llimits.h @@ -31,6 +31,8 @@ typedef unsigned char lu_byte; #define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2) +#define MAX_LMEM ((l_mem) ((MAX_LUMEM >> 1) - 2)) + #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ @@ -198,7 +200,7 @@ typedef lu_int32 Instruction; ** both small and large values (outside the range of integers). */ -#if defined(MS_ASMTRICK) /* { */ +#if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK) /* { */ /* trick with Microsoft assembler for X86 */ #define lua_number2int(i,n) __asm {__asm fld n __asm fistp i} @@ -209,31 +211,36 @@ typedef lu_int32 Instruction; #elif defined(LUA_IEEE754TRICK) /* }{ */ /* the next trick should work on any machine using IEEE754 with - a 32-bit integer type */ + a 32-bit int type */ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; #if !defined(LUA_IEEEENDIAN) /* { */ #define LUAI_EXTRAIEEE \ static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)}; -#define LUA_IEEEENDIAN (ieeeendian.l_p[1] == 33) +#define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33) #else +#define LUA_IEEEENDIANLOC LUA_IEEEENDIAN #define LUAI_EXTRAIEEE /* empty */ #endif /* } */ #define lua_number2int32(i,n,t) \ { LUAI_EXTRAIEEE \ volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \ - (i) = (t)u.l_p[LUA_IEEEENDIAN]; } + (i) = (t)u.l_p[LUA_IEEEENDIANLOC]; } #define luai_hashnum(i,n) \ { volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \ (i) = u.l_p[0]; (i) += u.l_p[1]; } /* add double bits for his hash */ #define lua_number2int(i,n) lua_number2int32(i, n, int) -#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer) #define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned) +/* the trick can be expanded to lua_Integer when it is a 32-bit value */ +#if defined(LUA_IEEELL) +#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer) +#endif + #endif /* } */ @@ -249,7 +256,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; #if !defined(lua_number2unsigned) /* { */ /* the following definition assures proper modulo behavior */ -#if defined(LUA_NUMBER_DOUBLE) +#if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT) #include #define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1) #define lua_number2unsigned(i,n) \ @@ -275,7 +282,7 @@ union luai_Cast { double l_d; LUA_INT32 l_p[2]; }; #include #define luai_hashnum(i,n) { int e; \ - n = frexp(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ + n = l_mathop(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \ lua_number2int(i, n); i += e; } #endif diff --git a/development/compilers/lua/src/lmathlib.c b/development/compilers/lua/src/lmathlib.c index d4f884736..581d72169 100644 --- a/development/compilers/lua/src/lmathlib.c +++ b/development/compilers/lua/src/lmathlib.c @@ -18,105 +18,100 @@ #undef PI -#define PI (3.14159265358979323846) -#define RADIANS_PER_DEGREE (PI/180.0) - - -/* macro 'l_tg' allows the addition of an 'l' or 'f' to all math operations */ -#if !defined(l_tg) -#define l_tg(x) (x) -#endif +#define PI ((lua_Number)(3.1415926535897932384626433832795)) +#define RADIANS_PER_DEGREE ((lua_Number)(PI/180.0)) static int math_abs (lua_State *L) { - lua_pushnumber(L, l_tg(fabs)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); return 1; } static int math_sin (lua_State *L) { - lua_pushnumber(L, l_tg(sin)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); return 1; } static int math_sinh (lua_State *L) { - lua_pushnumber(L, l_tg(sinh)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); return 1; } static int math_cos (lua_State *L) { - lua_pushnumber(L, l_tg(cos)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); return 1; } static int math_cosh (lua_State *L) { - lua_pushnumber(L, l_tg(cosh)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); return 1; } static int math_tan (lua_State *L) { - lua_pushnumber(L, l_tg(tan)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); return 1; } static int math_tanh (lua_State *L) { - lua_pushnumber(L, l_tg(tanh)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); return 1; } static int math_asin (lua_State *L) { - lua_pushnumber(L, l_tg(asin)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); return 1; } static int math_acos (lua_State *L) { - lua_pushnumber(L, l_tg(acos)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); return 1; } static int math_atan (lua_State *L) { - lua_pushnumber(L, l_tg(atan)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(atan)(luaL_checknumber(L, 1))); return 1; } static int math_atan2 (lua_State *L) { - lua_pushnumber(L, l_tg(atan2)(luaL_checknumber(L, 1), + lua_pushnumber(L, l_mathop(atan2)(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_ceil (lua_State *L) { - lua_pushnumber(L, l_tg(ceil)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(ceil)(luaL_checknumber(L, 1))); return 1; } static int math_floor (lua_State *L) { - lua_pushnumber(L, l_tg(floor)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(floor)(luaL_checknumber(L, 1))); return 1; } static int math_fmod (lua_State *L) { - lua_pushnumber(L, l_tg(fmod)(luaL_checknumber(L, 1), + lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } static int math_modf (lua_State *L) { lua_Number ip; - lua_Number fp = l_tg(modf)(luaL_checknumber(L, 1), &ip); + lua_Number fp = l_mathop(modf)(luaL_checknumber(L, 1), &ip); lua_pushnumber(L, ip); lua_pushnumber(L, fp); return 2; } static int math_sqrt (lua_State *L) { - lua_pushnumber(L, l_tg(sqrt)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); return 1; } static int math_pow (lua_State *L) { - lua_pushnumber(L, l_tg(pow)(luaL_checknumber(L, 1), - luaL_checknumber(L, 2))); + lua_Number x = luaL_checknumber(L, 1); + lua_Number y = luaL_checknumber(L, 2); + lua_pushnumber(L, l_mathop(pow)(x, y)); return 1; } @@ -124,11 +119,11 @@ static int math_log (lua_State *L) { lua_Number x = luaL_checknumber(L, 1); lua_Number res; if (lua_isnoneornil(L, 2)) - res = l_tg(log)(x); + res = l_mathop(log)(x); else { lua_Number base = luaL_checknumber(L, 2); - if (base == 10.0) res = l_tg(log10)(x); - else res = l_tg(log)(x)/l_tg(log)(base); + if (base == (lua_Number)10.0) res = l_mathop(log10)(x); + else res = l_mathop(log)(x)/l_mathop(log)(base); } lua_pushnumber(L, res); return 1; @@ -136,13 +131,13 @@ static int math_log (lua_State *L) { #if defined(LUA_COMPAT_LOG10) static int math_log10 (lua_State *L) { - lua_pushnumber(L, l_tg(log10)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); return 1; } #endif static int math_exp (lua_State *L) { - lua_pushnumber(L, l_tg(exp)(luaL_checknumber(L, 1))); + lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); return 1; } @@ -158,14 +153,15 @@ static int math_rad (lua_State *L) { static int math_frexp (lua_State *L) { int e; - lua_pushnumber(L, l_tg(frexp)(luaL_checknumber(L, 1), &e)); + lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); lua_pushinteger(L, e); return 2; } static int math_ldexp (lua_State *L) { - lua_pushnumber(L, l_tg(ldexp)(luaL_checknumber(L, 1), - luaL_checkint(L, 2))); + lua_Number x = luaL_checknumber(L, 1); + int ep = luaL_checkint(L, 2); + lua_pushnumber(L, l_mathop(ldexp)(x, ep)); return 1; } @@ -210,15 +206,15 @@ static int math_random (lua_State *L) { } case 1: { /* only upper limit */ lua_Number u = luaL_checknumber(L, 1); - luaL_argcheck(L, 1.0 <= u, 1, "interval is empty"); - lua_pushnumber(L, l_tg(floor)(r*u) + 1.0); /* int in [1, u] */ + luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty"); + lua_pushnumber(L, l_mathop(floor)(r*u) + (lua_Number)(1.0)); /* [1, u] */ break; } case 2: { /* lower and upper limits */ lua_Number l = luaL_checknumber(L, 1); lua_Number u = luaL_checknumber(L, 2); luaL_argcheck(L, l <= u, 2, "interval is empty"); - lua_pushnumber(L, l_tg(floor)(r*(u-l+1)) + l); /* int in [l, u] */ + lua_pushnumber(L, l_mathop(floor)(r*(u-l+1)) + l); /* [l, u] */ break; } default: return luaL_error(L, "wrong number of arguments"); diff --git a/development/compilers/lua/src/lmem.c b/development/compilers/lua/src/lmem.c index 0bf57cff3..f1ee21b87 100644 --- a/development/compilers/lua/src/lmem.c +++ b/development/compilers/lua/src/lmem.c @@ -94,22 +94,6 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { } lua_assert((nsize == 0) == (newblock == NULL)); g->GCdebt = (g->GCdebt + nsize) - realosize; -#if defined(TRACEMEM) - { /* auxiliary patch to monitor garbage collection. - ** To plot, gnuplot with following command: - ** plot TRACEMEM using 1:2 with lines, TRACEMEM using 1:3 with lines - */ - static unsigned long total = 0; /* our "time" */ - static FILE *f = NULL; /* output file */ - total++; /* "time" always grows */ - if ((total % 200) == 0) { - if (f == NULL) f = fopen(TRACEMEM, "w"); - fprintf(f, "%lu %u %d %d\n", total, - gettotalbytes(g), g->GCdebt, g->gcstate * 10000); - } - } -#endif - return newblock; } diff --git a/development/compilers/lua/src/lmem.h b/development/compilers/lua/src/lmem.h index 2aa7baa7b..c27725a78 100644 --- a/development/compilers/lua/src/lmem.h +++ b/development/compilers/lua/src/lmem.h @@ -14,10 +14,17 @@ #include "lua.h" +/* +** This macro avoids the runtime division MAX_SIZET/(e), as 'e' is +** always constant. +** The macro is somewhat complex to avoid warnings: +** +1 avoids warnings of "comparison has constant result"; +** cast to 'void' avoids warnings of "value unused". +*/ #define luaM_reallocv(L,b,on,n,e) \ - ((cast(size_t, (n)+1) > MAX_SIZET/(e)) ? /* +1 to avoid warnings */ \ - (luaM_toobig(L), (void *)0) : \ - luaM_realloc_(L, (b), (on)*(e), (n)*(e))) + (cast(void, \ + (cast(size_t, (n)+1) > MAX_SIZET/(e)) ? (luaM_toobig(L), 0) : 0), \ + luaM_realloc_(L, (b), (on)*(e), (n)*(e))) #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) diff --git a/development/compilers/lua/src/loadlib.c b/development/compilers/lua/src/loadlib.c index c1fb0c6b1..fb9e4aeaf 100644 --- a/development/compilers/lua/src/loadlib.c +++ b/development/compilers/lua/src/loadlib.c @@ -92,9 +92,9 @@ #define LUA_OFSEP "_" -#define LIBPREFIX "LOADLIB: " +/* table (in the registry) that keeps handles for all loaded C libraries */ +#define CLIBS "_CLIBS" -#define POF LUA_POF #define LIB_FAIL "open" @@ -248,48 +248,54 @@ static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { #endif - -static void **ll_register (lua_State *L, const char *path) { - void **plib; - lua_pushfstring(L, "%s%s", LIBPREFIX, path); - lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ - if (!lua_isnil(L, -1)) /* is there an entry? */ - plib = (void **)lua_touserdata(L, -1); - else { /* no entry yet; create one */ - lua_pop(L, 1); /* remove result from gettable */ - plib = (void **)lua_newuserdata(L, sizeof(const void *)); - *plib = NULL; - luaL_setmetatable(L, "_LOADLIB"); - lua_pushfstring(L, "%s%s", LIBPREFIX, path); - lua_pushvalue(L, -2); - lua_settable(L, LUA_REGISTRYINDEX); - } +static void *ll_checkclib (lua_State *L, const char *path) { + void *plib; + lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_getfield(L, -1, path); + plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ + lua_pop(L, 2); /* pop CLIBS table and 'plib' */ return plib; } +static void ll_addtoclib (lua_State *L, const char *path, void *plib) { + lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); + lua_pushlightuserdata(L, plib); + lua_pushvalue(L, -1); + lua_setfield(L, -3, path); /* CLIBS[path] = plib */ + lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ + lua_pop(L, 1); /* pop CLIBS table */ +} + + /* -** __gc tag method: calls library's `ll_unloadlib' function with the lib -** handle +** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib +** handles in list CLIBS */ static int gctm (lua_State *L) { - void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); - if (*lib) ll_unloadlib(*lib); - *lib = NULL; /* mark library as closed */ + int n = luaL_len(L, 1); + for (; n >= 1; n--) { /* for each handle, in reverse order */ + lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ + ll_unloadlib(lua_touserdata(L, -1)); + lua_pop(L, 1); /* pop handle */ + } return 0; } static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { - void **reg = ll_register(L, path); - if (*reg == NULL) *reg = ll_load(L, path, *sym == '*'); - if (*reg == NULL) return ERRLIB; /* unable to load library */ + void *reg = ll_checkclib(L, path); /* check loaded C libraries */ + if (reg == NULL) { /* must load library? */ + reg = ll_load(L, path, *sym == '*'); + if (reg == NULL) return ERRLIB; /* unable to load library */ + ll_addtoclib(L, path, reg); + } if (*sym == '*') { /* loading only library (no function)? */ lua_pushboolean(L, 1); /* return 'true' */ return 0; /* no errors */ } else { - lua_CFunction f = ll_sym(L, *reg, sym); + lua_CFunction f = ll_sym(L, reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ lua_pushcfunction(L, f); /* else create new function */ @@ -418,12 +424,12 @@ static int loadfunc (lua_State *L, const char *filename, const char *modname) { if (mark) { int stat; funcname = lua_pushlstring(L, modname, mark - modname); - funcname = lua_pushfstring(L, POF"%s", funcname); + funcname = lua_pushfstring(L, LUA_POF"%s", funcname); stat = ll_loadfunc(L, filename, funcname); if (stat != ERRFUNC) return stat; modname = mark + 1; /* else go ahead and try old-style name */ } - funcname = lua_pushfstring(L, POF"%s", modname); + funcname = lua_pushfstring(L, LUA_POF"%s", modname); return ll_loadfunc(L, filename, funcname); } @@ -476,9 +482,9 @@ static void findloader (lua_State *L, const char *name) { lua_getfield(L, lua_upvalueindex(1), "searchers"); /* will be at index 3 */ if (!lua_istable(L, 3)) luaL_error(L, LUA_QL("package.searchers") " must be a table"); - /* iterate over available seachers to find a loader */ + /* iterate over available searchers to find a loader */ for (i = 1; ; i++) { - lua_rawgeti(L, 3, i); /* get a seacher */ + lua_rawgeti(L, 3, i); /* get a searcher */ if (lua_isnil(L, -1)) { /* no more searchers? */ lua_pop(L, 1); /* remove nil */ luaL_pushresult(&msg); /* create error message */ @@ -666,18 +672,10 @@ static const luaL_Reg ll_funcs[] = { }; -static const lua_CFunction searchers[] = - {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; - - -LUAMOD_API int luaopen_package (lua_State *L) { +static void createsearcherstable (lua_State *L) { + static const lua_CFunction searchers[] = + {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; int i; - /* create new type _LOADLIB */ - luaL_newmetatable(L, "_LOADLIB"); - lua_pushcfunction(L, gctm); - lua_setfield(L, -2, "__gc"); - /* create `package' table */ - luaL_newlib(L, pk_funcs); /* create 'searchers' table */ lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); /* fill it with pre-defined searchers */ @@ -686,6 +684,19 @@ LUAMOD_API int luaopen_package (lua_State *L) { lua_pushcclosure(L, searchers[i], 1); lua_rawseti(L, -2, i+1); } +} + + +LUAMOD_API int luaopen_package (lua_State *L) { + /* create table CLIBS to keep track of loaded C libraries */ + luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); + lua_createtable(L, 0, 1); /* metatable for CLIBS */ + lua_pushcfunction(L, gctm); + lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ + lua_setmetatable(L, -2); + /* create `package' table */ + luaL_newlib(L, pk_funcs); + createsearcherstable(L); #if defined(LUA_COMPAT_LOADERS) lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ lua_setfield(L, -3, "loaders"); /* put it in field `loaders' */ diff --git a/development/compilers/lua/src/lobject.c b/development/compilers/lua/src/lobject.c index 4bbb01196..b4e90c9ed 100644 --- a/development/compilers/lua/src/lobject.c +++ b/development/compilers/lua/src/lobject.c @@ -104,7 +104,7 @@ static int isneg (const char **s) { static lua_Number readhexa (const char **s, lua_Number r, int *count) { for (; lisxdigit(cast_uchar(**s)); (*s)++) { /* read integer part */ - r = (r * 16.0) + cast_num(luaO_hexavalue(cast_uchar(**s))); + r = (r * cast_num(16.0)) + cast_num(luaO_hexavalue(cast_uchar(**s))); (*count)++; } return r; @@ -149,7 +149,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { *endptr = cast(char *, s); /* valid up to here */ ret: if (neg) r = -r; - return ldexp(r, e); + return l_mathop(ldexp)(r, e); } #endif @@ -171,8 +171,7 @@ int luaO_str2d (const char *s, size_t len, lua_Number *result) { static void pushstr (lua_State *L, const char *str, size_t l) { - setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); - incr_top(L); + setsvalue2s(L, L->top++, luaS_newlstr(L, str, l)); } @@ -182,8 +181,8 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; - setsvalue2s(L, L->top, luaS_newlstr(L, fmt, e-fmt)); - incr_top(L); + luaD_checkstack(L, 2); /* fmt + item */ + pushstr(L, fmt, e - fmt); switch (*(e+1)) { case 's': { const char *s = va_arg(argp, char *); @@ -198,13 +197,11 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { break; } case 'd': { - setnvalue(L->top, cast_num(va_arg(argp, int))); - incr_top(L); + setnvalue(L->top++, cast_num(va_arg(argp, int))); break; } case 'f': { - setnvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); - incr_top(L); + setnvalue(L->top++, cast_num(va_arg(argp, l_uacNumber))); break; } case 'p': { @@ -226,6 +223,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { n += 2; fmt = e+2; } + luaD_checkstack(L, 1); pushstr(L, fmt, strlen(fmt)); if (n > 0) luaV_concat(L, n + 1); return svalue(L->top - 1); diff --git a/development/compilers/lua/src/lobject.h b/development/compilers/lua/src/lobject.h index eaee9770f..459e11377 100644 --- a/development/compilers/lua/src/lobject.h +++ b/development/compilers/lua/src/lobject.h @@ -36,6 +36,9 @@ ** bit 6: whether value is collectable */ +#define VARBITS (3 << 4) + + /* ** LUA_TFUNCTION variants: ** 0 - Lua function @@ -49,6 +52,11 @@ #define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */ +/* Variant tags for strings */ +#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ +#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ + + /* Bit mark for collectable types */ #define BIT_ISCOLLECTABLE (1 << 6) @@ -109,23 +117,28 @@ typedef struct lua_TValue TValue; /* raw type tag of a TValue */ #define rttype(o) ((o)->tt_) +/* tag with no variants (bits 0-3) */ +#define novariant(x) ((x) & 0x0F) + /* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ #define ttype(o) (rttype(o) & 0x3F) - /* type tag of a TValue with no variants (bits 0-3) */ -#define ttypenv(o) (rttype(o) & 0x0F) +#define ttypenv(o) (novariant(rttype(o))) /* Macros to test type */ #define checktag(o,t) (rttype(o) == (t)) +#define checktype(o,t) (ttypenv(o) == (t)) #define ttisnumber(o) checktag((o), LUA_TNUMBER) #define ttisnil(o) checktag((o), LUA_TNIL) #define ttisboolean(o) checktag((o), LUA_TBOOLEAN) #define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA) -#define ttisstring(o) checktag((o), ctb(LUA_TSTRING)) +#define ttisstring(o) checktype((o), LUA_TSTRING) +#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR)) +#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR)) #define ttistable(o) checktag((o), ctb(LUA_TTABLE)) -#define ttisfunction(o) (ttypenv(o) == LUA_TFUNCTION) +#define ttisfunction(o) checktype(o, LUA_TFUNCTION) #define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION) #define ttisCclosure(o) checktag((o), ctb(LUA_TCCL)) #define ttisLclosure(o) checktag((o), ctb(LUA_TLCL)) @@ -161,7 +174,7 @@ typedef struct lua_TValue TValue; /* Macros for internal tests */ -#define righttt(obj) (ttypenv(obj) == gcvalue(obj)->gch.tt) +#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt) #define checkliveness(g,obj) \ lua_longassert(!iscollectable(obj) || \ @@ -174,8 +187,6 @@ typedef struct lua_TValue TValue; #define setnvalue(obj,x) \ { TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); } -#define changenvalue(o,x) check_exp(ttisnumber(o), num_(o)=(x)) - #define setnilvalue(obj) settt_(obj, LUA_TNIL) #define setfvalue(obj,x) \ @@ -193,7 +204,8 @@ typedef struct lua_TValue TValue; #define setsvalue(L,obj,x) \ { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TSTRING)); \ + TString *x_ = (x); \ + val_(io).gc=cast(GCObject *, x_); settt_(io, ctb(x_->tsv.tt)); \ checkliveness(G(L),io); } #define setuvalue(L,obj,x) \ @@ -221,11 +233,6 @@ typedef struct lua_TValue TValue; val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \ checkliveness(G(L),io); } -#define setptvalue(L,obj,x) \ - { TValue *io=(obj); \ - val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TPROTO)); \ - checkliveness(G(L),io); } - #define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) @@ -256,6 +263,8 @@ typedef struct lua_TValue TValue; #define setsvalue2n setsvalue +/* check whether a number is valid (useful only for NaN trick) */ +#define luai_checknum(L,o,c) { /* empty */ } /* @@ -263,10 +272,7 @@ typedef struct lua_TValue TValue; ** NaN Trick ** ======================================================= */ - -#if defined(LUA_NANTRICK) \ - || defined(LUA_NANTRICK_LE) \ - || defined(LUA_NANTRICK_BE) +#if defined(LUA_NANTRICK) /* ** numbers are represented in the 'd_' field. All other values have the @@ -274,15 +280,23 @@ typedef struct lua_TValue TValue; ** a "signaled NaN", which is never generated by regular operations by ** the CPU (nor by 'strtod') */ -#if !defined(NNMARK) + +/* allows for external implementation for part of the trick */ +#if !defined(NNMARK) /* { */ + + +#if !defined(LUA_IEEEENDIAN) +#error option 'LUA_NANTRICK' needs 'LUA_IEEEENDIAN' +#endif + + #define NNMARK 0x7FF7A500 #define NNMASK 0x7FFFFF00 -#endif #undef TValuefields #undef NILCONSTANT -#if defined(LUA_NANTRICK_LE) +#if (LUA_IEEEENDIAN == 0) /* { */ /* little endian */ #define TValuefields \ @@ -293,7 +307,7 @@ typedef struct lua_TValue TValue; #define d_(o) ((o)->u.d__) #define tt_(o) ((o)->u.i.tt__) -#elif defined(LUA_NANTRICK_BE) +#else /* }{ */ /* big endian */ #define TValuefields \ @@ -304,10 +318,9 @@ typedef struct lua_TValue TValue; #define d_(o) ((o)->u.d__) #define tt_(o) ((o)->u.i.tt__) -#elif !defined(TValuefields) -#error option 'LUA_NANTRICK' needs declaration for 'TValuefields' +#endif /* } */ -#endif +#endif /* } */ /* correspondence with standard representation */ @@ -348,21 +361,18 @@ typedef struct lua_TValue TValue; */ #undef checktag +#undef checktype #define checktag(o,t) (tt_(o) == tag2tt(t)) +#define checktype(o,t) (ctb(tt_(o) | VARBITS) == ctb(tag2tt(t) | VARBITS)) #undef ttisequal #define ttisequal(o1,o2) \ (ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2))) - +#undef luai_checknum #define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; } - -#else - -#define luai_checknum(L,o,c) { /* empty */ } - #endif /* }====================================================== */ @@ -401,7 +411,7 @@ typedef union TString { L_Umaxalign dummy; /* ensures maximum alignment for strings */ struct { CommonHeader; - lu_byte reserved; + lu_byte extra; /* reserved words for short strings; "has hash" for longs */ unsigned int hash; size_t len; /* number of characters in string */ } tsv; @@ -501,7 +511,7 @@ typedef struct UpVal { */ #define ClosureHeader \ - CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist + CommonHeader; lu_byte nupvalues; GCObject *gclist typedef struct CClosure { ClosureHeader; diff --git a/development/compilers/lua/src/lopcodes.c b/development/compilers/lua/src/lopcodes.c index 18c2c9e74..ef7d9a3a6 100644 --- a/development/compilers/lua/src/lopcodes.c +++ b/development/compilers/lua/src/lopcodes.c @@ -1,5 +1,6 @@ /* ** $Id$ +** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ diff --git a/development/compilers/lua/src/loslib.c b/development/compilers/lua/src/loslib.c index 4952cc393..1188ecfe5 100644 --- a/development/compilers/lua/src/loslib.c +++ b/development/compilers/lua/src/loslib.c @@ -26,11 +26,12 @@ #if !defined(LUA_STRFTIMEOPTIONS) #if !defined(LUA_USE_POSIX) -#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } +#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } #else -#define LUA_STRFTIMEOPTIONS { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \ - "E", "cCxXyY", \ - "O", "deHImMSuUVwWy" } +#define LUA_STRFTIMEOPTIONS \ + { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \ + "", "E", "cCxXyY", \ + "O", "deHImMSuUVwWy" } #endif #endif @@ -43,7 +44,7 @@ */ #if defined(LUA_USE_MKSTEMP) #include -#define LUA_TMPNAMBUFSIZE 32 +#define LUA_TMPNAMBUFSIZE 32 #define lua_tmpnam(b,e) { \ strcpy(b, "/tmp/lua_XXXXXX"); \ e = mkstemp(b); \ @@ -52,8 +53,8 @@ #elif !defined(lua_tmpnam) -#define LUA_TMPNAMBUFSIZE L_tmpnam -#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } +#define LUA_TMPNAMBUFSIZE L_tmpnam +#define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } #endif @@ -97,7 +98,7 @@ static int os_remove (lua_State *L) { static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); - return luaL_fileresult(L, rename(fromname, toname) == 0, fromname); + return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); } diff --git a/development/compilers/lua/src/lparser.c b/development/compilers/lua/src/lparser.c index b3b47f7fb..fe7951294 100644 --- a/development/compilers/lua/src/lparser.c +++ b/development/compilers/lua/src/lparser.c @@ -222,7 +222,7 @@ static int searchupvalue (FuncState *fs, TString *name) { int i; Upvaldesc *up = fs->f->upvalues; for (i = 0; i < fs->nups; i++) { - if (eqstr(up[i].name, name)) return i; + if (luaS_eqstr(up[i].name, name)) return i; } return -1; /* not found */ } @@ -245,8 +245,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { static int searchvar (FuncState *fs, TString *n) { int i; - for (i=fs->nactvar-1; i >= 0; i--) { - if (eqstr(n, getlocvar(fs, i)->varname)) + for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { + if (luaS_eqstr(n, getlocvar(fs, i)->varname)) return i; } return -1; /* not found */ @@ -342,7 +342,7 @@ static void closegoto (LexState *ls, int g, Labeldesc *label) { FuncState *fs = ls->fs; Labellist *gl = &ls->dyd->gt; Labeldesc *gt = &gl->arr[g]; - lua_assert(eqstr(gt->name, label->name)); + lua_assert(luaS_eqstr(gt->name, label->name)); if (gt->nactvar < label->nactvar) { TString *vname = getlocvar(fs, gt->nactvar)->varname; const char *msg = luaO_pushfstring(ls->L, @@ -369,7 +369,7 @@ static int findlabel (LexState *ls, int g) { /* check labels in current block for a match */ for (i = bl->firstlabel; i < dyd->label.n; i++) { Labeldesc *lb = &dyd->label.arr[i]; - if (eqstr(lb->name, gt->name)) { /* correct label? */ + if (luaS_eqstr(lb->name, gt->name)) { /* correct label? */ if (gt->nactvar > lb->nactvar && (bl->upval || dyd->label.n > bl->firstlabel)) luaK_patchclose(ls->fs, gt->pc, lb->nactvar); @@ -403,7 +403,7 @@ static void findgotos (LexState *ls, Labeldesc *lb) { Labellist *gl = &ls->dyd->gt; int i = ls->fs->bl->firstgoto; while (i < gl->n) { - if (eqstr(gl->arr[i].name, lb->name)) + if (luaS_eqstr(gl->arr[i].name, lb->name)) closegoto(ls, i, lb); else i++; @@ -461,7 +461,7 @@ static void breaklabel (LexState *ls) { ** message when label name is a reserved word (which can only be 'break') */ static l_noret undefgoto (LexState *ls, Labeldesc *gt) { - const char *msg = (gt->name->tsv.reserved > 0) + const char *msg = isreserved(gt->name) ? "<%s> at line %d not inside a loop" : "no visible label " LUA_QS " for at line %d"; msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); @@ -493,22 +493,34 @@ static void leaveblock (FuncState *fs) { /* -** adds prototype being created into its parent list of prototypes -** and codes instruction to create new closure +** adds a new prototype into list of prototypes */ -static void codeclosure (LexState *ls, Proto *clp, expdesc *v) { - FuncState *fs = ls->fs->prev; - Proto *f = fs->f; /* prototype of function creating new closure */ +static Proto *addprototype (LexState *ls) { + Proto *clp; + lua_State *L = ls->L; + FuncState *fs = ls->fs; + Proto *f = fs->f; /* prototype of current function */ if (fs->np >= f->sizep) { int oldsize = f->sizep; - luaM_growvector(ls->L, f->p, fs->np, f->sizep, Proto *, - MAXARG_Bx, "functions"); + luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); while (oldsize < f->sizep) f->p[oldsize++] = NULL; } - f->p[fs->np++] = clp; - luaC_objbarrier(ls->L, f, clp); - init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np-1)); - luaK_exp2nextreg(fs, v); /* fix it at stack top (for GC) */ + f->p[fs->np++] = clp = luaF_newproto(L); + luaC_objbarrier(L, f, clp); + return clp; +} + + +/* +** codes instruction to create new closure in parent function. +** The OP_CLOSURE instruction must use the last available register, +** so that, if it invokes the GC, the GC knows which registers +** are in use at that time. +*/ +static void codeclosure (LexState *ls, expdesc *v) { + FuncState *fs = ls->fs->prev; + init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); + luaK_exp2nextreg(fs, v); /* fix it at the last register */ } @@ -529,13 +541,9 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { fs->nactvar = 0; fs->firstlocal = ls->dyd->actvar.n; fs->bl = NULL; - f = luaF_newproto(L); - fs->f = f; + f = fs->f; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ - /* anchor prototype (to avoid being collected) */ - setptvalue2s(L, L->top, f); - incr_top(L); fs->h = luaH_new(L); /* anchor table of constants (to avoid being collected) */ sethvalue2s(L, L->top, fs->h); @@ -568,20 +576,6 @@ static void close_func (LexState *ls) { anchor_token(ls); L->top--; /* pop table of constants */ luaC_checkGC(L); - L->top--; /* pop prototype (after possible collection) */ -} - - -/* -** opens the main function, which is a regular vararg function with an -** upvalue named LUA_ENV -*/ -static void open_mainfunc (LexState *ls, FuncState *fs, BlockCnt *bl) { - expdesc v; - open_func(ls, fs, bl); - fs->f->is_vararg = 1; /* main function is always vararg */ - init_exp(&v, VLOCAL, 0); - newupvalue(fs, ls->envn, &v); /* create environment upvalue */ } @@ -795,8 +789,9 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) { /* body -> `(' parlist `)' block END */ FuncState new_fs; BlockCnt bl; - open_func(ls, &new_fs, &bl); + new_fs.f = addprototype(ls); new_fs.f->linedefined = line; + open_func(ls, &new_fs, &bl); checknext(ls, '('); if (ismethod) { new_localvarliteral(ls, "self"); /* create 'self' parameter */ @@ -807,7 +802,7 @@ static void body (LexState *ls, expdesc *e, int ismethod, int line) { statlist(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); - codeclosure(ls, new_fs.f, e); + codeclosure(ls, e); close_func(ls); } @@ -879,8 +874,8 @@ static void funcargs (LexState *ls, expdesc *f, int line) { */ -static void prefixexp (LexState *ls, expdesc *v) { - /* prefixexp -> NAME | '(' expr ')' */ +static void primaryexp (LexState *ls, expdesc *v) { + /* primaryexp -> NAME | '(' expr ')' */ switch (ls->t.token) { case '(': { int line = ls->linenumber; @@ -901,12 +896,12 @@ static void prefixexp (LexState *ls, expdesc *v) { } -static void primaryexp (LexState *ls, expdesc *v) { - /* primaryexp -> - prefixexp { `.' NAME | `[' exp `]' | `:' NAME funcargs | funcargs } */ +static void suffixedexp (LexState *ls, expdesc *v) { + /* suffixedexp -> + primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; int line = ls->linenumber; - prefixexp(ls, v); + primaryexp(ls, v); for (;;) { switch (ls->t.token) { case '.': { /* fieldsel */ @@ -941,7 +936,7 @@ static void primaryexp (LexState *ls, expdesc *v) { static void simpleexp (LexState *ls, expdesc *v) { /* simpleexp -> NUMBER | STRING | NIL | TRUE | FALSE | ... | - constructor | FUNCTION body | primaryexp */ + constructor | FUNCTION body | suffixedexp */ switch (ls->t.token) { case TK_NUMBER: { init_exp(v, VKNUM, 0); @@ -981,7 +976,7 @@ static void simpleexp (LexState *ls, expdesc *v) { return; } default: { - primaryexp(ls, v); + suffixedexp(ls, v); return; } } @@ -1141,10 +1136,10 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { expdesc e; check_condition(ls, vkisvar(lh->v.k), "syntax error"); - if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ + if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ struct LHS_assign nv; nv.prev = lh; - primaryexp(ls, &nv.v); + suffixedexp(ls, &nv.v); if (nv.v.k != VINDEXED) check_conflict(ls, lh, &nv.v); checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, @@ -1200,7 +1195,7 @@ static void gotostat (LexState *ls, int pc) { static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { int i; for (i = fs->bl->firstlabel; i < ll->n; i++) { - if (eqstr(label, ll->arr[i].name)) { + if (luaS_eqstr(label, ll->arr[i].name)) { const char *msg = luaO_pushfstring(fs->ls->L, "label " LUA_QS " already defined on line %d", getstr(label), ll->arr[i].line); @@ -1210,6 +1205,13 @@ static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { } +/* skip no-op statements */ +static void skipnoopstat (LexState *ls) { + while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) + statement(ls); +} + + static void labelstat (LexState *ls, TString *label, int line) { /* label -> '::' NAME '::' */ FuncState *fs = ls->fs; @@ -1219,9 +1221,7 @@ static void labelstat (LexState *ls, TString *label, int line) { checknext(ls, TK_DBCOLON); /* skip double colon */ /* create new entry for this label */ l = newlabelentry(ls, ll, label, line, fs->pc); - /* skip other no-op statements */ - while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) - statement(ls); + skipnoopstat(ls); /* skip other no-op statements */ if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ /* assume that locals are already out of scope */ ll->arr[l].nactvar = fs->bl->nactvar; @@ -1384,6 +1384,7 @@ static void test_then_block (LexState *ls, int *escapelist) { luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ enterblock(fs, &bl, 0); /* must enter block before 'goto' */ gotostat(ls, v.t); /* handle goto/break */ + skipnoopstat(ls); /* skip other no-op statements */ if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ leaveblock(fs); return; /* and that is it */ @@ -1480,13 +1481,15 @@ static void exprstat (LexState *ls) { /* stat -> func | assignment */ FuncState *fs = ls->fs; struct LHS_assign v; - primaryexp(ls, &v.v); - if (v.v.k == VCALL) /* stat -> func */ - SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ - else { /* stat -> assignment */ + suffixedexp(ls, &v.v); + if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ v.prev = NULL; assignment(ls, &v, 1); } + else { /* stat -> func */ + check_condition(ls, v.v.k == VCALL, "syntax error"); + SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ + } } @@ -1594,27 +1597,42 @@ static void statement (LexState *ls) { /* }====================================================================== */ -Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar) { +/* +** compiles the main function, which is a regular vararg function with an +** upvalue named LUA_ENV +*/ +static void mainfunc (LexState *ls, FuncState *fs) { + BlockCnt bl; + expdesc v; + open_func(ls, fs, &bl); + fs->f->is_vararg = 1; /* main function is always vararg */ + init_exp(&v, VLOCAL, 0); /* create and... */ + newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ + luaX_next(ls); /* read first token */ + statlist(ls); /* parse main body */ + check(ls, TK_EOS); + close_func(ls); +} + + +Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar) { LexState lexstate; FuncState funcstate; - BlockCnt bl; - TString *tname = luaS_new(L, name); - setsvalue2s(L, L->top, tname); /* push name to protect it */ + Closure *cl = luaF_newLclosure(L, 1); /* create main closure */ + /* anchor closure (to avoid being collected) */ + setclLvalue(L, L->top, cl); incr_top(L); + funcstate.f = cl->l.p = luaF_newproto(L); + funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ lexstate.buff = buff; lexstate.dyd = dyd; dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; - luaX_setinput(L, &lexstate, z, tname, firstchar); - open_mainfunc(&lexstate, &funcstate, &bl); - luaX_next(&lexstate); /* read first token */ - statlist(&lexstate); /* main body */ - check(&lexstate, TK_EOS); - close_func(&lexstate); - L->top--; /* pop name */ + luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); + mainfunc(&lexstate, &funcstate); lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); /* all scopes should be correctly finished */ lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); - return funcstate.f; + return cl; /* it's on the stack too */ } diff --git a/development/compilers/lua/src/lparser.h b/development/compilers/lua/src/lparser.h index af5341771..dfc250759 100644 --- a/development/compilers/lua/src/lparser.h +++ b/development/compilers/lua/src/lparser.h @@ -112,8 +112,8 @@ typedef struct FuncState { } FuncState; -LUAI_FUNC Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, - Dyndata *dyd, const char *name, int firstchar); +LUAI_FUNC Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, + Dyndata *dyd, const char *name, int firstchar); #endif diff --git a/development/compilers/lua/src/lstate.c b/development/compilers/lua/src/lstate.c index aba91fde8..e02877ad5 100644 --- a/development/compilers/lua/src/lstate.c +++ b/development/compilers/lua/src/lstate.c @@ -6,6 +6,7 @@ #include +#include #define lstate_c #define LUA_CORE @@ -38,7 +39,18 @@ #endif -#define MEMERRMSG "not enough memory" +#define MEMERRMSG "not enough memory" + + +/* +** a macro to help the creation of a unique random seed when a state is +** created; the seed is used to randomize hashes. +*/ +#if !defined(luai_makeseed) +#include +#define luai_makeseed() cast(unsigned int, time(NULL)) +#endif + /* @@ -66,6 +78,28 @@ typedef struct LG { /* +** Compute an initial seed as random as possible. In ANSI, rely on +** Address Space Layout Randomization (if present) to increase +** randomness.. +*/ +#define addbuff(b,p,e) \ + { size_t t = cast(size_t, e); \ + memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); } + +static unsigned int makeseed (lua_State *L) { + char buff[4 * sizeof(size_t)]; + unsigned int h = luai_makeseed(); + int p = 0; + addbuff(buff, p, L); /* heap variable */ + addbuff(buff, p, &h); /* local variable */ + addbuff(buff, p, luaO_nilobject); /* global variable */ + addbuff(buff, p, &lua_newstate); /* public function */ + lua_assert(p == sizeof(buff)); + return luaS_hash(buff, p, h); +} + + +/* ** set GCdebt to a new value keeping the value (totalbytes + GCdebt) ** invariant */ @@ -242,10 +276,11 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->frealloc = f; g->ud = ud; g->mainthread = L; + g->seed = makeseed(L); g->uvhead.u.l.prev = &g->uvhead; g->uvhead.u.l.next = &g->uvhead; g->gcrunning = 0; /* no GC while building state */ - g->lastmajormem = 0; + g->GCestimate = 0; g->strt.size = 0; g->strt.nuse = 0; g->strt.hash = NULL; @@ -257,6 +292,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->allgc = NULL; g->finobj = NULL; g->tobefnz = NULL; + g->sweepgc = g->sweepfin = NULL; g->gray = g->grayagain = NULL; g->weak = g->ephemeron = g->allweak = NULL; g->totalbytes = sizeof(LG); diff --git a/development/compilers/lua/src/lstate.h b/development/compilers/lua/src/lstate.h index 956b822fc..e0ccc7f32 100644 --- a/development/compilers/lua/src/lstate.h +++ b/development/compilers/lua/src/lstate.h @@ -72,6 +72,7 @@ typedef struct CallInfo { struct CallInfo *previous, *next; /* dynamic call link */ short nresults; /* expected number of results from this function */ lu_byte callstatus; + ptrdiff_t extra; union { struct { /* only for Lua functions */ StkId base; /* base for this function */ @@ -81,7 +82,6 @@ typedef struct CallInfo { int ctx; /* context info. in case of yields */ lua_CFunction k; /* continuation in case of yields */ ptrdiff_t old_errfunc; - ptrdiff_t extra; lu_byte old_allowhook; lu_byte status; } c; @@ -100,6 +100,7 @@ typedef struct CallInfo { #define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ #define CIST_STAT (1<<5) /* call has an error status (pcall) */ #define CIST_TAIL (1<<6) /* call was tail called */ +#define CIST_HOOKYIELD (1<<7) /* last hook called yielded */ #define isLua(ci) ((ci)->callstatus & CIST_LUA) @@ -113,9 +114,11 @@ typedef struct global_State { void *ud; /* auxiliary data to `frealloc' */ lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */ l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ - lu_mem lastmajormem; /* memory in use after last major collection */ + lu_mem GCmemtrav; /* memory traversed by the GC */ + lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ stringtable strt; /* hash table for strings */ TValue l_registry; + unsigned int seed; /* randomized seed for hashes */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ lu_byte gckind; /* kind of GC running */ @@ -123,7 +126,8 @@ typedef struct global_State { int sweepstrgc; /* position of sweep in `strt' */ GCObject *allgc; /* list of all collectable objects */ GCObject *finobj; /* list of collectable objects with finalizers */ - GCObject **sweepgc; /* current position of sweep */ + GCObject **sweepgc; /* current position of sweep in list 'allgc' */ + GCObject **sweepfin; /* current position of sweep in list 'finobj' */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of tables with weak values */ @@ -133,7 +137,7 @@ typedef struct global_State { UpVal uvhead; /* head of double-linked list of all open upvalues */ Mbuffer buff; /* temporary buffer for string concatenation */ int gcpause; /* size of pause between successive GCs */ - int gcmajorinc; /* how much to wait for a major GC (only in gen. mode) */ + int gcmajorinc; /* pause between major collections (only in gen. mode) */ int gcstepmul; /* GC `granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ struct lua_State *mainthread; @@ -193,11 +197,15 @@ union GCObject { #define gch(o) (&(o)->gch) /* macros to convert a GCObject into a specific value */ -#define rawgco2ts(o) check_exp((o)->gch.tt == LUA_TSTRING, &((o)->ts)) +#define rawgco2ts(o) \ + check_exp(novariant((o)->gch.tt) == LUA_TSTRING, &((o)->ts)) #define gco2ts(o) (&rawgco2ts(o)->tsv) #define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u)) #define gco2u(o) (&rawgco2u(o)->uv) -#define gco2cl(o) check_exp((o)->gch.tt == LUA_TFUNCTION, &((o)->cl)) +#define gco2lcl(o) check_exp((o)->gch.tt == LUA_TLCL, &((o)->cl.l)) +#define gco2ccl(o) check_exp((o)->gch.tt == LUA_TCCL, &((o)->cl.c)) +#define gco2cl(o) \ + check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl)) #define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h)) #define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p)) #define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv)) diff --git a/development/compilers/lua/src/lstring.c b/development/compilers/lua/src/lstring.c index b18d963a6..5347fb5a0 100644 --- a/development/compilers/lua/src/lstring.c +++ b/development/compilers/lua/src/lstring.c @@ -18,7 +18,49 @@ #include "lstring.h" +/* +** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to +** compute its hash +*/ +#if !defined(LUAI_HASHLIMIT) +#define LUAI_HASHLIMIT 5 +#endif + + +/* +** equality for long strings +*/ +int luaS_eqlngstr (TString *a, TString *b) { + size_t len = a->tsv.len; + lua_assert(a->tsv.tt == LUA_TLNGSTR && b->tsv.tt == LUA_TLNGSTR); + return (a == b) || /* same instance or... */ + ((len == b->tsv.len) && /* equal length and ... */ + (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ +} + + +/* +** equality for strings +*/ +int luaS_eqstr (TString *a, TString *b) { + return (a->tsv.tt == b->tsv.tt) && + (a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b)); +} + + +unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { + unsigned int h = seed ^ cast(unsigned int, l); + size_t l1; + size_t step = (l >> LUAI_HASHLIMIT) + 1; + for (l1 = l; l1 >= step; l1 -= step) + h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1])); + return h; +} + +/* +** resizes the string table +*/ void luaS_resize (lua_State *L, int newsize) { int i; stringtable *tb = &G(L)->strt; @@ -50,52 +92,81 @@ void luaS_resize (lua_State *L, int newsize) { } -static TString *newlstr (lua_State *L, const char *str, size_t l, - unsigned int h) { - size_t totalsize; /* total size of TString object */ - GCObject **list; /* (pointer to) list where it will be inserted */ +/* +** creates a new string object +*/ +static TString *createstrobj (lua_State *L, const char *str, size_t l, + int tag, unsigned int h, GCObject **list) { TString *ts; - stringtable *tb = &G(L)->strt; - if (l+1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) - luaM_toobig(L); - if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) - luaS_resize(L, tb->size*2); /* too crowded */ + size_t totalsize; /* total size of TString object */ totalsize = sizeof(TString) + ((l + 1) * sizeof(char)); - list = &tb->hash[lmod(h, tb->size)]; - ts = &luaC_newobj(L, LUA_TSTRING, totalsize, list, 0)->ts; + ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts; ts->tsv.len = l; ts->tsv.hash = h; - ts->tsv.reserved = 0; + ts->tsv.extra = 0; memcpy(ts+1, str, l*sizeof(char)); ((char *)(ts+1))[l] = '\0'; /* ending 0 */ - tb->nuse++; return ts; } -TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { +/* +** creates a new short string, inserting it into string table +*/ +static TString *newshrstr (lua_State *L, const char *str, size_t l, + unsigned int h) { + GCObject **list; /* (pointer to) list where it will be inserted */ + stringtable *tb = &G(L)->strt; + TString *s; + if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2) + luaS_resize(L, tb->size*2); /* too crowded */ + list = &tb->hash[lmod(h, tb->size)]; + s = createstrobj(L, str, l, LUA_TSHRSTR, h, list); + tb->nuse++; + return s; +} + + +/* +** checks whether short string exists and reuses it or creates a new one +*/ +static TString *internshrstr (lua_State *L, const char *str, size_t l) { GCObject *o; - unsigned int h = cast(unsigned int, l); /* seed */ - size_t step = (l>>5)+1; /* if string is too long, don't hash all its chars */ - size_t l1; - for (l1=l; l1>=step; l1-=step) /* compute hash */ - h = h ^ ((h<<5)+(h>>2)+cast(unsigned char, str[l1-1])); - for (o = G(L)->strt.hash[lmod(h, G(L)->strt.size)]; + global_State *g = G(L); + unsigned int h = luaS_hash(str, l, g->seed); + for (o = g->strt.hash[lmod(h, g->strt.size)]; o != NULL; o = gch(o)->next) { TString *ts = rawgco2ts(o); if (h == ts->tsv.hash && - ts->tsv.len == l && + l == ts->tsv.len && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */ changewhite(o); /* resurrect it */ return ts; } } - return newlstr(L, str, l, h); /* not found; create a new string */ + return newshrstr(L, str, l, h); /* not found; create a new string */ +} + + +/* +** new string (with explicit length) +*/ +TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { + if (l <= LUAI_MAXSHORTLEN) /* short string? */ + return internshrstr(L, str, l); + else { + if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char)) + luaM_toobig(L); + return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL); + } } +/* +** new zero-terminated string +*/ TString *luaS_new (lua_State *L, const char *str) { return luaS_newlstr(L, str, strlen(str)); } diff --git a/development/compilers/lua/src/lstring.h b/development/compilers/lua/src/lstring.h index 40fad26e4..f1a94ab19 100644 --- a/development/compilers/lua/src/lstring.h +++ b/development/compilers/lua/src/lstring.h @@ -23,11 +23,20 @@ /* -** as all string are internalized, string equality becomes -** pointer equality +** test whether a string is a reserved word */ -#define eqstr(a,b) ((a) == (b)) +#define isreserved(s) ((s)->tsv.tt == LUA_TSHRSTR && (s)->tsv.extra > 0) + +/* +** equality for short strings, which are always internalized +*/ +#define eqshrstr(a,b) check_exp((a)->tsv.tt == LUA_TSHRSTR, (a) == (b)) + + +LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); +LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); +LUAI_FUNC int luaS_eqstr (TString *a, TString *b); LUAI_FUNC void luaS_resize (lua_State *L, int newsize); LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); diff --git a/development/compilers/lua/src/lstrlib.c b/development/compilers/lua/src/lstrlib.c index 098a1fb36..c34044346 100644 --- a/development/compilers/lua/src/lstrlib.c +++ b/development/compilers/lua/src/lstrlib.c @@ -30,7 +30,7 @@ /* macro to `unsign' a character */ -#define uchar(c) ((unsigned char)(c)) +#define uchar(c) ((unsigned char)(c)) @@ -119,7 +119,9 @@ static int str_rep (lua_State *L) { char *p = luaL_buffinitsize(L, &b, totallen); while (n-- > 1) { /* first n-1 copies (followed by separator) */ memcpy(p, s, l * sizeof(char)); p += l; - memcpy(p, sep, lsep * sizeof(char)); p += lsep; + if (lsep > 0) { /* avoid empty 'memcpy' (may be expensive) */ + memcpy(p, sep, lsep * sizeof(char)); p += lsep; + } } memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ luaL_pushresultsize(&b, totallen); @@ -192,7 +194,9 @@ static int str_dump (lua_State *L) { #define CAP_UNFINISHED (-1) #define CAP_POSITION (-2) + typedef struct MatchState { + int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ const char *src_init; /* init of source string */ const char *src_end; /* end ('\0') of source string */ const char *p_end; /* end ('\0') of pattern */ @@ -205,6 +209,16 @@ typedef struct MatchState { } MatchState; +/* recursive function */ +static const char *match (MatchState *ms, const char *s, const char *p); + + +/* maximum recursion depth for 'match' */ +#if !defined(MAXCCALLS) +#define MAXCCALLS 200 +#endif + + #define L_ESC '%' #define SPECIALS "^$*+?.([%-" @@ -292,19 +306,22 @@ static int matchbracketclass (int c, const char *p, const char *ec) { } -static int singlematch (int c, const char *p, const char *ep) { - switch (*p) { - case '.': return 1; /* matches any char */ - case L_ESC: return match_class(c, uchar(*(p+1))); - case '[': return matchbracketclass(c, p, ep-1); - default: return (uchar(*p) == c); +static int singlematch (MatchState *ms, const char *s, const char *p, + const char *ep) { + if (s >= ms->src_end) + return 0; + else { + int c = uchar(*s); + switch (*p) { + case '.': return 1; /* matches any char */ + case L_ESC: return match_class(c, uchar(*(p+1))); + case '[': return matchbracketclass(c, p, ep-1); + default: return (uchar(*p) == c); + } } } -static const char *match (MatchState *ms, const char *s, const char *p); - - static const char *matchbalance (MatchState *ms, const char *s, const char *p) { if (p >= ms->p_end - 1) @@ -329,7 +346,7 @@ static const char *matchbalance (MatchState *ms, const char *s, static const char *max_expand (MatchState *ms, const char *s, const char *p, const char *ep) { ptrdiff_t i = 0; /* counts maximum expand for item */ - while ((s+i)src_end && singlematch(uchar(*(s+i)), p, ep)) + while (singlematch(ms, s + i, p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { @@ -347,7 +364,7 @@ static const char *min_expand (MatchState *ms, const char *s, const char *res = match(ms, s, ep+1); if (res != NULL) return res; - else if (ssrc_end && singlematch(uchar(*s), p, ep)) + else if (singlematch(ms, s, p, ep)) s++; /* try with one more repetition */ else return NULL; } @@ -391,79 +408,105 @@ static const char *match_capture (MatchState *ms, const char *s, int l) { static const char *match (MatchState *ms, const char *s, const char *p) { + if (ms->matchdepth-- == 0) + luaL_error(ms->L, "pattern too complex"); init: /* using goto's to optimize tail recursion */ - if (p == ms->p_end) /* end of pattern? */ - return s; /* match succeeded */ - switch (*p) { - case '(': { /* start capture */ - if (*(p+1) == ')') /* position capture? */ - return start_capture(ms, s, p+2, CAP_POSITION); - else - return start_capture(ms, s, p+1, CAP_UNFINISHED); - } - case ')': { /* end capture */ - return end_capture(ms, s, p+1); - } - case '$': { - if ((p+1) == ms->p_end) /* is the `$' the last char in pattern? */ - return (s == ms->src_end) ? s : NULL; /* check end of string */ - else goto dflt; - } - case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ - switch (*(p+1)) { - case 'b': { /* balanced string? */ - s = matchbalance(ms, s, p+2); - if (s == NULL) return NULL; - p+=4; goto init; /* else return match(ms, s, p+4); */ - } - case 'f': { /* frontier? */ - const char *ep; char previous; - p += 2; - if (*p != '[') - luaL_error(ms->L, "missing " LUA_QL("[") " after " - LUA_QL("%%f") " in pattern"); - ep = classend(ms, p); /* points to what is next */ - previous = (s == ms->src_init) ? '\0' : *(s-1); - if (matchbracketclass(uchar(previous), p, ep-1) || - !matchbracketclass(uchar(*s), p, ep-1)) return NULL; - p=ep; goto init; /* else return match(ms, s, ep); */ - } - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - case '8': case '9': { /* capture results (%0-%9)? */ - s = match_capture(ms, s, uchar(*(p+1))); - if (s == NULL) return NULL; - p+=2; goto init; /* else return match(ms, s, p+2) */ - } - default: goto dflt; + if (p != ms->p_end) { /* end of pattern? */ + switch (*p) { + case '(': { /* start capture */ + if (*(p + 1) == ')') /* position capture? */ + s = start_capture(ms, s, p + 2, CAP_POSITION); + else + s = start_capture(ms, s, p + 1, CAP_UNFINISHED); + break; } - } - default: dflt: { /* pattern class plus optional suffix */ - const char *ep = classend(ms, p); /* points to what is next */ - int m = s < ms->src_end && singlematch(uchar(*s), p, ep); - switch (*ep) { - case '?': { /* optional */ - const char *res; - if (m && ((res=match(ms, s+1, ep+1)) != NULL)) - return res; - p=ep+1; goto init; /* else return match(ms, s, ep+1); */ - } - case '*': { /* 0 or more repetitions */ - return max_expand(ms, s, p, ep); - } - case '+': { /* 1 or more repetitions */ - return (m ? max_expand(ms, s+1, p, ep) : NULL); + case ')': { /* end capture */ + s = end_capture(ms, s, p + 1); + break; + } + case '$': { + if ((p + 1) != ms->p_end) /* is the `$' the last char in pattern? */ + goto dflt; /* no; go to default */ + s = (s == ms->src_end) ? s : NULL; /* check end of string */ + break; + } + case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ + switch (*(p + 1)) { + case 'b': { /* balanced string? */ + s = matchbalance(ms, s, p + 2); + if (s != NULL) { + p += 4; goto init; /* return match(ms, s, p + 4); */ + } /* else fail (s == NULL) */ + break; + } + case 'f': { /* frontier? */ + const char *ep; char previous; + p += 2; + if (*p != '[') + luaL_error(ms->L, "missing " LUA_QL("[") " after " + LUA_QL("%%f") " in pattern"); + ep = classend(ms, p); /* points to what is next */ + previous = (s == ms->src_init) ? '\0' : *(s - 1); + if (!matchbracketclass(uchar(previous), p, ep - 1) && + matchbracketclass(uchar(*s), p, ep - 1)) { + p = ep; goto init; /* return match(ms, s, ep); */ + } + s = NULL; /* match failed */ + break; + } + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': { /* capture results (%0-%9)? */ + s = match_capture(ms, s, uchar(*(p + 1))); + if (s != NULL) { + p += 2; goto init; /* return match(ms, s, p + 2) */ + } + break; + } + default: goto dflt; } - case '-': { /* 0 or more repetitions (minimum) */ - return min_expand(ms, s, p, ep); + break; + } + default: dflt: { /* pattern class plus optional suffix */ + const char *ep = classend(ms, p); /* points to optional suffix */ + /* does not match at least once? */ + if (!singlematch(ms, s, p, ep)) { + if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ + p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ + } + else /* '+' or no suffix */ + s = NULL; /* fail */ } - default: { - if (!m) return NULL; - s++; p=ep; goto init; /* else return match(ms, s+1, ep); */ + else { /* matched once */ + switch (*ep) { /* handle optional suffix */ + case '?': { /* optional */ + const char *res; + if ((res = match(ms, s + 1, ep + 1)) != NULL) + s = res; + else { + p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ + } + break; + } + case '+': /* 1 or more repetitions */ + s++; /* 1 match already done */ + /* go through */ + case '*': /* 0 or more repetitions */ + s = max_expand(ms, s, p, ep); + break; + case '-': /* 0 or more repetitions (minimum) */ + s = min_expand(ms, s, p, ep); + break; + default: /* no suffix */ + s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ + } } + break; } } } + ms->matchdepth++; + return s; } @@ -559,12 +602,14 @@ static int str_find_aux (lua_State *L, int find) { p++; lp--; /* skip anchor character */ } ms.L = L; + ms.matchdepth = MAXCCALLS; ms.src_init = s; ms.src_end = s + ls; ms.p_end = p + lp; do { const char *res; ms.level = 0; + lua_assert(ms.matchdepth == MAXCCALLS); if ((res=match(&ms, s1, p)) != NULL) { if (find) { lua_pushinteger(L, s1 - s + 1); /* start */ @@ -598,6 +643,7 @@ static int gmatch_aux (lua_State *L) { const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp); const char *src; ms.L = L; + ms.matchdepth = MAXCCALLS; ms.src_init = s; ms.src_end = s+ls; ms.p_end = p + lp; @@ -606,6 +652,7 @@ static int gmatch_aux (lua_State *L) { src++) { const char *e; ms.level = 0; + lua_assert(ms.matchdepth == MAXCCALLS); if ((e = match(&ms, src, p)) != NULL) { lua_Integer newstart = e-s; if (e == src) newstart++; /* empty match? go at least one position */ @@ -703,12 +750,14 @@ static int str_gsub (lua_State *L) { p++; lp--; /* skip anchor character */ } ms.L = L; + ms.matchdepth = MAXCCALLS; ms.src_init = src; ms.src_end = src+srcl; ms.p_end = p + lp; while (n < max_s) { const char *e; ms.level = 0; + lua_assert(ms.matchdepth == MAXCCALLS); e = match(&ms, src, p); if (e) { n++; @@ -745,20 +794,17 @@ static int str_gsub (lua_State *L) { #if !defined(LUA_INTFRMLEN) /* { */ #if defined(LUA_USE_LONGLONG) -#define LUA_INTFRMLEN "ll" -#define LUA_INTFRM_T long long +#define LUA_INTFRMLEN "ll" +#define LUA_INTFRM_T long long #else -#define LUA_INTFRMLEN "l" -#define LUA_INTFRM_T long +#define LUA_INTFRMLEN "l" +#define LUA_INTFRM_T long #endif #endif /* } */ -#define MAX_UINTFRM ((lua_Number)(~(unsigned LUA_INTFRM_T)0)) -#define MAX_INTFRM ((lua_Number)((~(unsigned LUA_INTFRM_T)0)/2)) -#define MIN_INTFRM (-(lua_Number)((~(unsigned LUA_INTFRM_T)0)/2) - 1) /* ** LUA_FLTFRMLEN is the length modifier for float conversions in @@ -767,8 +813,8 @@ static int str_gsub (lua_State *L) { */ #if !defined(LUA_FLTFRMLEN) -#define LUA_FLTFRMLEN "" -#define LUA_FLTFRM_T double +#define LUA_FLTFRMLEN "" +#define LUA_FLTFRM_T double #endif @@ -868,23 +914,27 @@ static int str_format (lua_State *L) { nb = sprintf(buff, form, luaL_checkint(L, arg)); break; } - case 'd': case 'i': { + case 'd': case 'i': { lua_Number n = luaL_checknumber(L, arg); - luaL_argcheck(L, (MIN_INTFRM - 1) < n && n < (MAX_INTFRM + 1), arg, + LUA_INTFRM_T ni = (LUA_INTFRM_T)n; + lua_Number diff = n - (lua_Number)ni; + luaL_argcheck(L, -1 < diff && diff < 1, arg, "not a number in proper range"); addlenmod(form, LUA_INTFRMLEN); - nb = sprintf(buff, form, (LUA_INTFRM_T)n); + nb = sprintf(buff, form, ni); break; } - case 'o': case 'u': case 'x': case 'X': { + case 'o': case 'u': case 'x': case 'X': { lua_Number n = luaL_checknumber(L, arg); - luaL_argcheck(L, 0 <= n && n < (MAX_UINTFRM + 1), arg, + unsigned LUA_INTFRM_T ni = (unsigned LUA_INTFRM_T)n; + lua_Number diff = n - (lua_Number)ni; + luaL_argcheck(L, -1 < diff && diff < 1, arg, "not a non-negative number in proper range"); addlenmod(form, LUA_INTFRMLEN); - nb = sprintf(buff, form, (unsigned LUA_INTFRM_T)n); + nb = sprintf(buff, form, ni); break; } - case 'e': case 'E': case 'f': + case 'e': case 'E': case 'f': #if defined(LUA_USE_AFORMAT) case 'a': case 'A': #endif diff --git a/development/compilers/lua/src/ltable.c b/development/compilers/lua/src/ltable.c index 71e501523..ddf7492cc 100644 --- a/development/compilers/lua/src/ltable.c +++ b/development/compilers/lua/src/ltable.c @@ -48,10 +48,10 @@ #define MAXASIZE (1 << MAXBITS) -#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) +#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) -#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) -#define hashboolean(t,p) hashpow2(t, p) +#define hashstr(t,str) hashpow2(t, (str)->tsv.hash) +#define hashboolean(t,p) hashpow2(t, p) /* @@ -98,7 +98,15 @@ static Node *mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNUMBER: return hashnum(t, nvalue(key)); - case LUA_TSTRING: + case LUA_TLNGSTR: { + TString *s = rawtsvalue(key); + if (s->tsv.extra == 0) { /* no hash? */ + s->tsv.hash = luaS_hash(getstr(s), s->tsv.len, s->tsv.hash); + s->tsv.extra = 1; /* now it has its hash */ + } + return hashstr(t, rawtsvalue(key)); + } + case LUA_TSHRSTR: return hashstr(t, rawtsvalue(key)); case LUA_TBOOLEAN: return hashboolean(t, bvalue(key)); @@ -453,12 +461,13 @@ const TValue *luaH_getint (Table *t, int key) { /* -** search function for strings +** search function for short strings */ const TValue *luaH_getstr (Table *t, TString *key) { Node *n = hashstr(t, key); + lua_assert(key->tsv.tt == LUA_TSHRSTR); do { /* check whether `key' is somewhere in the chain */ - if (ttisstring(gkey(n)) && eqstr(rawtsvalue(gkey(n)), key)) + if (ttisshrstring(gkey(n)) && eqshrstr(rawtsvalue(gkey(n)), key)) return gval(n); /* that's it */ else n = gnext(n); } while (n); @@ -470,14 +479,14 @@ const TValue *luaH_getstr (Table *t, TString *key) { ** main search function */ const TValue *luaH_get (Table *t, const TValue *key) { - switch (ttypenv(key)) { + switch (ttype(key)) { + case LUA_TSHRSTR: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNIL: return luaO_nilobject; - case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key)); case LUA_TNUMBER: { int k; lua_Number n = nvalue(key); lua_number2int(k, n); - if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */ + if (luai_numeq(cast_num(k), n)) /* index is int? */ return luaH_getint(t, k); /* use specialized version */ /* else go through */ } diff --git a/development/compilers/lua/src/ltablib.c b/development/compilers/lua/src/ltablib.c index 3e3d008a5..72071d975 100644 --- a/development/compilers/lua/src/ltablib.c +++ b/development/compilers/lua/src/ltablib.c @@ -16,8 +16,8 @@ #include "lualib.h" -#define aux_getn(L,n) \ - (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n)) +#define aux_getn(L,n) (luaL_checktype(L, n, LUA_TTABLE), luaL_len(L, n)) + #if defined(LUA_COMPAT_MAXN) @@ -49,7 +49,7 @@ static int tinsert (lua_State *L) { case 3: { int i; pos = luaL_checkint(L, 2); /* 2nd argument is the position */ - if (pos > e) e = pos; /* `grow' array if necessary */ + luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); for (i = e; i > pos; i--) { /* move up elements */ lua_rawgeti(L, 1, i-1); lua_rawseti(L, 1, i); /* t[i] = t[i-1] */ @@ -66,17 +66,17 @@ static int tinsert (lua_State *L) { static int tremove (lua_State *L) { - int e = aux_getn(L, 1); - int pos = luaL_optint(L, 2, e); - if (!(1 <= pos && pos <= e)) /* position is outside bounds? */ - return 0; /* nothing to remove */ + int size = aux_getn(L, 1); + int pos = luaL_optint(L, 2, size); + if (pos != size) /* validate 'pos' if given */ + luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); lua_rawgeti(L, 1, pos); /* result = t[pos] */ - for ( ;pos -#define lua_stdin_is_tty() isatty(0) +#define lua_stdin_is_tty() isatty(0) #elif defined(LUA_WIN) #include #include -#define lua_stdin_is_tty() _isatty(_fileno(stdin)) +#define lua_stdin_is_tty() _isatty(_fileno(stdin)) #else -#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ +#define lua_stdin_is_tty() 1 /* assume stdin is a tty */ #endif @@ -66,19 +66,19 @@ #include #include #include -#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) +#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) #define lua_saveline(L,idx) \ if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \ add_history(lua_tostring(L, idx)); /* add it to history */ -#define lua_freeline(L,b) ((void)L, free(b)) +#define lua_freeline(L,b) ((void)L, free(b)) #elif !defined(lua_readline) -#define lua_readline(L,b,p) \ +#define lua_readline(L,b,p) \ ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ -#define lua_saveline(L,idx) { (void)L; (void)idx; } -#define lua_freeline(L,b) { (void)L; (void)b; } +#define lua_saveline(L,idx) { (void)L; (void)idx; } +#define lua_freeline(L,b) { (void)L; (void)b; } #endif @@ -223,16 +223,11 @@ static int dostring (lua_State *L, const char *s, const char *name) { static int dolibrary (lua_State *L, const char *name) { int status; - lua_pushglobaltable(L); - lua_getfield(L, -1, "require"); + lua_getglobal(L, "require"); lua_pushstring(L, name); - status = docall(L, 1, 1); - if (status == LUA_OK) { - lua_setfield(L, -2, name); /* global[name] = require return */ - lua_pop(L, 1); /* remove global table */ - } - else - lua_remove(L, -2); /* remove global table (below error msg.) */ + status = docall(L, 1, 1); /* call 'require(name)' */ + if (status == LUA_OK) + lua_setglobal(L, name); /* global[name] = require return */ return report(L, status); } @@ -242,7 +237,6 @@ static const char *get_prompt (lua_State *L, int firstline) { lua_getglobal(L, firstline ? "_PROMPT" : "_PROMPT2"); p = lua_tostring(L, -1); if (p == NULL) p = (firstline ? LUA_PROMPT : LUA_PROMPT2); - lua_pop(L, 1); /* remove global */ return p; } @@ -268,7 +262,9 @@ static int pushline (lua_State *L, int firstline) { char *b = buffer; size_t l; const char *prmt = get_prompt(L, firstline); - if (lua_readline(L, b, prmt) == 0) + int readstatus = lua_readline(L, b, prmt); + lua_pop(L, 1); /* remove result from 'get_prompt' */ + if (readstatus == 0) return 0; /* no input */ l = strlen(b); if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ diff --git a/development/compilers/lua/src/lua.h b/development/compilers/lua/src/lua.h index b3b0cdafb..885845bd2 100644 --- a/development/compilers/lua/src/lua.h +++ b/development/compilers/lua/src/lua.h @@ -19,11 +19,11 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "2" #define LUA_VERSION_NUM 502 -#define LUA_VERSION_RELEASE "0" +#define LUA_VERSION_RELEASE "2" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2011 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2013 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -119,6 +119,11 @@ typedef LUA_UNSIGNED lua_Unsigned; #endif +/* +** RCS ident string +*/ +extern const char lua_ident[]; + /* ** state manipulation @@ -413,7 +418,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2011 Lua.org, PUC-Rio. All rights reserved. +* Copyright (C) 1994-2013 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/development/compilers/lua/src/luaconf.h b/development/compilers/lua/src/luaconf.h index 460e889a3..cc7bb65c9 100644 --- a/development/compilers/lua/src/luaconf.h +++ b/development/compilers/lua/src/luaconf.h @@ -44,7 +44,7 @@ #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ #define LUA_USE_READLINE /* needs some extra libraries */ -#define LUA_USE_STRTODHEX /* assume 'strtod' handles hexa formats */ +#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */ #define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ #define LUA_USE_LONGLONG /* assume support for long long */ #endif @@ -53,7 +53,7 @@ #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* does not need -ldl */ #define LUA_USE_READLINE /* needs an extra library: -lreadline */ -#define LUA_USE_STRTODHEX /* assume 'strtod' handles hexa formats */ +#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */ #define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */ #define LUA_USE_LONGLONG /* assume support for long long */ #endif @@ -223,6 +223,13 @@ (fprintf(stderr, (s), (p)), fflush(stderr)) +/* +@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is, +** strings that are internalized. (Cannot be smaller than reserved words +** or tags for metamethods, as these strings must be internalized; +** #("function") = 8, #("__newindex") = 10.) +*/ +#define LUAI_MAXSHORTLEN 40 @@ -399,9 +406,15 @@ /* +@@ l_mathop allows the addition of an 'l' or 'f' to all math operations +*/ +#define l_mathop(x) (x) + + +/* @@ lua_str2number converts a decimal numeric string to a number. @@ lua_strx2number converts an hexadecimal numeric string to a number. -** In C99, 'strtod' do both conversions. C89, however, has no function +** In C99, 'strtod' does both conversions. C89, however, has no function ** to convert floating hexadecimal strings to numbers. For these ** systems, you can leave 'lua_strx2number' undefined and Lua will ** provide its own implementation. @@ -420,8 +433,8 @@ /* the following operations need the math library */ #if defined(lobject_c) || defined(lvm_c) #include -#define luai_nummod(L,a,b) ((a) - floor((a)/(b))*(b)) -#define luai_numpow(L,a,b) (pow(a,b)) +#define luai_nummod(L,a,b) ((a) - l_mathop(floor)((a)/(b))*(b)) +#define luai_numpow(L,a,b) (l_mathop(pow)(a,b)) #endif /* these are quite standard operations */ @@ -453,66 +466,75 @@ #define LUA_UNSIGNED unsigned LUA_INT32 -#if defined(LUA_CORE) /* { */ + +/* +** Some tricks with doubles +*/ #if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ +/* +** The next definitions activate some tricks to speed up the +** conversion from doubles to integer types, mainly to LUA_UNSIGNED. +** +@@ LUA_MSASMTRICK uses Microsoft assembler to avoid clashes with a +** DirectX idiosyncrasy. +** +@@ LUA_IEEE754TRICK uses a trick that should work on any machine +** using IEEE754 with a 32-bit integer type. +** +@@ LUA_IEEELL extends the trick to LUA_INTEGER; should only be +** defined when LUA_INTEGER is a 32-bit integer. +** +@@ LUA_IEEEENDIAN is the endianness of doubles in your machine +** (0 for little endian, 1 for big endian); if not defined, Lua will +** check it dynamically for LUA_IEEE754TRICK (but not for LUA_NANTRICK). +** +@@ LUA_NANTRICK controls the use of a trick to pack all types into +** a single double value, using NaN values to represent non-number +** values. The trick only works on 32-bit machines (ints and pointers +** are 32-bit values) with numbers represented as IEEE 754-2008 doubles +** with conventional endianess (12345678 or 87654321), in CPUs that do +** not produce signaling NaN values (all NaNs are quiet). +*/ -/* On a Microsoft compiler on a Pentium, use assembler to avoid clashes - with a DirectX idiosyncrasy */ +/* Microsoft compiler on a Pentium (32 bit) ? */ #if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */ -#define MS_ASMTRICK - -#else /* }{ */ -/* the next definition uses a trick that should work on any machine - using IEEE754 with a 32-bit integer type */ - -#define LUA_IEEE754TRICK +#define LUA_MSASMTRICK +#define LUA_IEEEENDIAN 0 +#define LUA_NANTRICK -/* -@@ LUA_IEEEENDIAN is the endianness of doubles in your machine -** (0 for little endian, 1 for big endian); if not defined, Lua will -** check it dynamically. -*/ -/* check for known architectures */ -#if defined(__i386__) || defined(__i386) || defined(__X86__) || \ - defined (__x86_64) -#define LUA_IEEEENDIAN 0 -#elif defined(__POWERPC__) || defined(__ppc__) -#define LUA_IEEEENDIAN 1 -#endif -#endif /* } */ +/* pentium 32 bits? */ +#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */ -#endif /* } */ +#define LUA_IEEE754TRICK +#define LUA_IEEELL +#define LUA_IEEEENDIAN 0 +#define LUA_NANTRICK -#endif /* } */ +/* pentium 64 bits? */ +#elif defined(__x86_64) /* }{ */ -/* }================================================================== */ +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN 0 +#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */ -/* -@@ LUA_NANTRICK_LE/LUA_NANTRICK_BE controls the use of a trick to -** pack all types into a single double value, using NaN values to -** represent non-number values. The trick only works on 32-bit machines -** (ints and pointers are 32-bit values) with numbers represented as -** IEEE 754-2008 doubles with conventional endianess (12345678 or -** 87654321), in CPUs that do not produce signaling NaN values (all NaNs -** are quiet). -*/ -#if defined(LUA_CORE) && \ - defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */ +#define LUA_IEEE754TRICK +#define LUA_IEEEENDIAN 1 -/* little-endian architectures that satisfy those conditions */ -#if defined(__i386__) || defined(__i386) || defined(__X86__) || \ - defined(_M_IX86) +#else /* }{ */ -#define LUA_NANTRICK_LE +/* assume IEEE754 and a 32-bit integer type */ +#define LUA_IEEE754TRICK -#endif +#endif /* } */ #endif /* } */ +/* }================================================================== */ + diff --git a/development/compilers/lua/src/lundump.c b/development/compilers/lua/src/lundump.c index 7b5bfb58e..bb07bede6 100644 --- a/development/compilers/lua/src/lundump.c +++ b/development/compilers/lua/src/lundump.c @@ -27,7 +27,7 @@ typedef struct { const char* name; } LoadState; -static void error(LoadState* S, const char* why) +static l_noret error(LoadState* S, const char* why) { luaO_pushfstring(S->L,"%s: %s precompiled chunk",S->name,why); luaD_throw(S->L,LUA_ERRSYNTAX); @@ -39,7 +39,7 @@ static void error(LoadState* S, const char* why) #define LoadVector(S,b,n,size) LoadMem(S,b,n,size) #if !defined(luai_verifycode) -#define luai_verifycode(L,b,f) (f) +#define luai_verifycode(L,b,f) /* empty */ #endif static void LoadBlock(LoadState* S, void* b, size_t size) @@ -91,7 +91,7 @@ static void LoadCode(LoadState* S, Proto* f) LoadVector(S,f->code,n,sizeof(Instruction)); } -static Proto* LoadFunction(LoadState* S); +static void LoadFunction(LoadState* S, Proto* f); static void LoadConstants(LoadState* S, Proto* f) { @@ -118,13 +118,18 @@ static void LoadConstants(LoadState* S, Proto* f) case LUA_TSTRING: setsvalue2n(S->L,o,LoadString(S)); break; + default: lua_assert(0); } } n=LoadInt(S); f->p=luaM_newvector(S->L,n,Proto*); f->sizep=n; for (i=0; ip[i]=NULL; - for (i=0; ip[i]=LoadFunction(S); + for (i=0; ip[i]=luaF_newproto(S->L); + LoadFunction(S,f->p[i]); + } } static void LoadUpvalues(LoadState* S, Proto* f) @@ -163,10 +168,8 @@ static void LoadDebug(LoadState* S, Proto* f) for (i=0; iupvalues[i].name=LoadString(S); } -static Proto* LoadFunction(LoadState* S) +static void LoadFunction(LoadState* S, Proto* f) { - Proto* f=luaF_newproto(S->L); - setptvalue2s(S->L,S->L->top,f); incr_top(S->L); f->linedefined=LoadInt(S); f->lastlinedefined=LoadInt(S); f->numparams=LoadByte(S); @@ -176,8 +179,6 @@ static Proto* LoadFunction(LoadState* S) LoadConstants(S,f); LoadUpvalues(S,f); LoadDebug(S,f); - S->L->top--; - return f; } /* the code below must be consistent with the code in luaU_header */ @@ -202,9 +203,10 @@ static void LoadHeader(LoadState* S) /* ** load precompiled chunk */ -Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) +Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) { LoadState S; + Closure* cl; if (*name=='@' || *name=='=') S.name=name+1; else if (*name==LUA_SIGNATURE[0]) @@ -215,7 +217,19 @@ Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name) S.Z=Z; S.b=buff; LoadHeader(&S); - return luai_verifycode(L,buff,LoadFunction(&S)); + cl=luaF_newLclosure(L,1); + setclLvalue(L,L->top,cl); incr_top(L); + cl->l.p=luaF_newproto(L); + LoadFunction(&S,cl->l.p); + if (cl->l.p->sizeupvalues != 1) + { + Proto* p=cl->l.p; + cl=luaF_newLclosure(L,cl->l.p->sizeupvalues); + cl->l.p=p; + setclLvalue(L,L->top-1,cl); + } + luai_verifycode(L,buff,cl->l.p); + return cl; } #define MYINT(s) (s[0]-'0') diff --git a/development/compilers/lua/src/lundump.h b/development/compilers/lua/src/lundump.h index 26436a79d..613449581 100644 --- a/development/compilers/lua/src/lundump.h +++ b/development/compilers/lua/src/lundump.h @@ -11,7 +11,7 @@ #include "lzio.h" /* load one chunk; from lundump.c */ -LUAI_FUNC Proto* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); +LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name); /* make header; from lundump.c */ LUAI_FUNC void luaU_header (lu_byte* h); diff --git a/development/compilers/lua/src/lvm.c b/development/compilers/lua/src/lvm.c index da13dbe70..7b206b807 100644 --- a/development/compilers/lua/src/lvm.c +++ b/development/compilers/lua/src/lvm.c @@ -60,10 +60,15 @@ int luaV_tostring (lua_State *L, StkId obj) { static void traceexec (lua_State *L) { CallInfo *ci = L->ci; lu_byte mask = L->hookmask; - if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { - resethookcount(L); - luaD_hook(L, LUA_HOOKCOUNT, -1); + int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0); + if (counthook) + resethookcount(L); /* reset count */ + if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ + return; /* do not call hook again (VM yielded, so it did not move) */ } + if (counthook) + luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ if (mask & LUA_MASKLINE) { Proto *p = ci_func(ci)->p; int npc = pcRel(ci->u.l.savedpc, p); @@ -71,11 +76,15 @@ static void traceexec (lua_State *L) { if (npc == 0 || /* call linehook when enter a new function, */ ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ - luaD_hook(L, LUA_HOOKLINE, newline); + luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ } L->oldpc = ci->u.l.savedpc; if (L->status == LUA_YIELD) { /* did hook yield? */ + if (counthook) + L->hookcount = 1; /* undo decrement to zero */ ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ + ci->func = L->top - 1; /* protect stack below results */ luaD_throw(L, LUA_YIELD); } } @@ -89,7 +98,6 @@ static void callTM (lua_State *L, const TValue *f, const TValue *p1, setobj2s(L, L->top++, p2); /* 2nd argument */ if (!hasres) /* no result? 'p3' is third argument */ setobj2s(L, L->top++, p3); /* 3rd argument */ - luaD_checkstack(L, 0); /* metamethod may yield only when called from Lua code */ luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci)); if (hasres) { /* if has result, move it to its place */ @@ -258,7 +266,8 @@ int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2) { case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TLCF: return fvalue(t1) == fvalue(t2); - case LUA_TSTRING: return eqstr(rawtsvalue(t1), rawtsvalue(t2)); + case LUA_TSHRSTR: return eqshrstr(rawtsvalue(t1), rawtsvalue(t2)); + case LUA_TLNGSTR: return luaS_eqlngstr(rawtsvalue(t1), rawtsvalue(t2)); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; else if (L == NULL) return 0; @@ -293,7 +302,7 @@ void luaV_concat (lua_State *L, int total) { else if (tsvalue(top-1)->len == 0) /* second operand is empty? */ (void)tostring(L, top - 2); /* result is first operand */ else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) { - setsvalue2s(L, top-2, rawtsvalue(top-1)); /* result is second op. */ + setobjs2s(L, top - 2, top - 1); /* result is second op. */ } else { /* at least two non-empty string values; get as many as possible */ @@ -394,7 +403,8 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, int nup = p->sizeupvalues; Upvaldesc *uv = p->upvalues; int i; - Closure *ncl = luaF_newLclosure(L, p); + Closure *ncl = luaF_newLclosure(L, nup); + ncl->l.p = p; setclLvalue(L, ra, ncl); /* anchor new closure in stack */ for (i = 0; i < nup; i++) { /* fill in its upvalues */ if (uv[i].instack) /* upvalue refers to local variable? */ @@ -459,7 +469,7 @@ void luaV_finishOp (lua_State *L) { L->top = ci->top; /* adjust results */ break; } - case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: + case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: break; default: lua_assert(0); } @@ -500,7 +510,11 @@ void luaV_finishOp (lua_State *L) { #define Protect(x) { {x;}; base = ci->u.l.base; } -#define checkGC(L,c) Protect(luaC_condGC(L, c); luai_threadyield(L);) +#define checkGC(L,c) \ + Protect( luaC_condGC(L,{L->top = (c); /* limit of live values */ \ + luaC_step(L); \ + L->top = ci->top;}) /* restore top */ \ + luai_threadyield(L); ) #define arith_op(op,tm) { \ @@ -593,11 +607,7 @@ void luaV_execute (lua_State *L) { sethvalue(L, ra, t); if (b != 0 || c != 0) luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); - checkGC(L, - L->top = ra + 1; /* limit of live values */ - luaC_step(L); - L->top = ci->top; /* restore top */ - ) + checkGC(L, ra + 1); ) vmcase(OP_SELF, StkId rb = RB(i); @@ -649,10 +659,7 @@ void luaV_execute (lua_State *L) { ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */ rb = b + base; setobjs2s(L, ra, rb); - checkGC(L, - L->top = (ra >= rb ? ra + 1 : rb); /* limit of live values */ - luaC_step(L); - ) + checkGC(L, (ra >= rb ? ra + 1 : rb)); L->top = ci->top; /* restore top */ ) vmcase(OP_JMP, @@ -830,11 +837,7 @@ void luaV_execute (lua_State *L) { pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ else setclLvalue(L, ra, ncl); /* push cashed closure */ - checkGC(L, - L->top = ra + 1; /* limit of live values */ - luaC_step(L); - L->top = ci->top; /* restore top */ - ) + checkGC(L, ra + 1); ) vmcase(OP_VARARG, int b = GETARG_B(i) - 1; diff --git a/development/compilers/lua/src/lvm.h b/development/compilers/lua/src/lvm.h index 7f8899b96..8b096b386 100644 --- a/development/compilers/lua/src/lvm.h +++ b/development/compilers/lua/src/lvm.h @@ -19,8 +19,7 @@ #define equalobj(L,o1,o2) (ttisequal(o1, o2) && luaV_equalobj_(L, o1, o2)) -#define luaV_rawequalobj(t1,t2) \ - (ttisequal(t1,t2) && luaV_equalobj_(NULL,t1,t2)) +#define luaV_rawequalobj(o1,o2) equalobj(NULL,o1,o2) /* not to called directly */ diff --git a/development/compilers/lua/src/lzio.c b/development/compilers/lua/src/lzio.c index 28b622230..ab8c47fdb 100644 --- a/development/compilers/lua/src/lzio.c +++ b/development/compilers/lua/src/lzio.c @@ -1,6 +1,6 @@ /* ** $Id$ -** a generic input stream interface +** Buffered streams ** See Copyright Notice in lua.h */ -- 2.11.4.GIT