mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-22 11:03:12 +00:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98311b9b91 | ||
|
|
499610965a | ||
|
|
94a76269aa | ||
|
|
ae35b3c4e8 | ||
|
|
1a1d8abd2e | ||
|
|
feeda06e9d | ||
|
|
bc4800f326 | ||
|
|
ccfdc9440a | ||
|
|
182a1a8d56 | ||
|
|
44e2583dc2 | ||
|
|
7b76bcd039 | ||
|
|
2d5e4ae528 | ||
|
|
b61daaccf1 | ||
|
|
01314de8e1 | ||
|
|
c8197328a4 | ||
|
|
800a3376d6 | ||
|
|
6dda5f7f98 | ||
|
|
2a8c095e38 | ||
|
|
01b5d67b11 | ||
|
|
c1eeba215d | ||
|
|
6bd6f53ab8 | ||
|
|
dfc706615e | ||
|
|
8efad53631 | ||
|
|
0c1491ba99 | ||
|
|
1b54306509 | ||
|
|
3911e0738b | ||
|
|
fad27d7775 | ||
|
|
e98378e874 | ||
|
|
389146167f | ||
|
|
73c0e306cf | ||
|
|
6d86016247 | ||
|
|
acefd8de27 | ||
|
|
448fe14b9e | ||
|
|
341b7924a0 | ||
|
|
013cb42122 | ||
|
|
bcd012f9cf | ||
|
|
c4da547259 | ||
|
|
6ad379b7a7 | ||
|
|
ee103e97cd | ||
|
|
e37eb3cba0 | ||
|
|
0ddd938400 | ||
|
|
2d42adb739 | ||
|
|
9fd7a51b34 | ||
|
|
2660b10442 | ||
|
|
969d3291b6 | ||
|
|
c84f7354ff | ||
|
|
b555aa19e7 | ||
|
|
f72573a2aa | ||
|
|
bee8a0e731 | ||
|
|
5d48c02725 | ||
|
|
fad62566dc | ||
|
|
d1ce950dc1 | ||
|
|
eaba8f969c | ||
|
|
40ee98b40e | ||
|
|
b13281b77d | ||
|
|
3c4f673740 | ||
|
|
6d6be8dec6 | ||
|
|
923651ada3 | ||
|
|
8304747d8e | ||
|
|
5b5d5906cb | ||
|
|
9d3edae797 | ||
|
|
208be03a6f | ||
|
|
3b54b3bd80 | ||
|
|
839975415d | ||
|
|
27866518ef | ||
|
|
53292d1c93 | ||
|
|
1e2ed7e6ff | ||
|
|
350248a7cc | ||
|
|
d115e626e6 |
23
.github/ISSUE_TEMPLATE/readme-first.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/readme-first.md
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: Readme First
|
||||
about: Issues is bug report only
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
The **Issues** is for bug report only.
|
||||
|
||||
Goto **Discussions** for feature request , questions, etc.
|
||||
|
||||
**Update to master branch HEAD first**, and
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@
|
||||
/skynet.pid
|
||||
3rd/lua/lua
|
||||
3rd/lua/luac
|
||||
3rd/lua/all
|
||||
/cservice
|
||||
/luaclib
|
||||
*.so
|
||||
|
||||
Submodule 3rd/jemalloc updated: ea6b3e973b...54eaed1d8b
@@ -1,6 +1,10 @@
|
||||
HISTORY for LPeg 1.0
|
||||
HISTORY for LPeg 1.0.2
|
||||
|
||||
* Changes from version 0.12 to 1.0
|
||||
* Changes from version 1.0.1 to 1.0.2
|
||||
---------------------------------
|
||||
+ some bugs fixed
|
||||
|
||||
* Changes from version 0.12 to 1.0.1
|
||||
---------------------------------
|
||||
+ group "names" can be any Lua value
|
||||
+ some bugs fixed
|
||||
@@ -13,14 +17,14 @@ HISTORY for LPeg 1.0
|
||||
+ some bugs fixed
|
||||
|
||||
* Changes from version 0.10 to 0.11
|
||||
-------------------------------
|
||||
-------------------------------
|
||||
+ complete reimplementation of the code generator
|
||||
+ new syntax for table captures
|
||||
+ new functions in module 're'
|
||||
+ other small improvements
|
||||
|
||||
* Changes from version 0.9 to 0.10
|
||||
-------------------------------
|
||||
-------------------------------
|
||||
+ backtrack stack has configurable size
|
||||
+ better error messages
|
||||
+ Notation for non-terminals in 're' back to A instead o <A>
|
||||
@@ -32,34 +36,34 @@ HISTORY for LPeg 1.0
|
||||
- "and" predicates do not keep captures
|
||||
|
||||
* Changes from version 0.8 to 0.9
|
||||
-------------------------------
|
||||
-------------------------------
|
||||
+ The accumulator capture was replaced by a fold capture;
|
||||
programs that used the old 'lpeg.Ca' will need small changes.
|
||||
+ Some support for character classes from old C locales.
|
||||
+ A new named-group capture.
|
||||
|
||||
* Changes from version 0.7 to 0.8
|
||||
-------------------------------
|
||||
-------------------------------
|
||||
+ New "match-time" capture.
|
||||
+ New "argument capture" that allows passing arguments into the pattern.
|
||||
+ Better documentation for 're'.
|
||||
+ Several small improvements for 're'.
|
||||
+ The 're' module has an incompatibility with previous versions:
|
||||
now, any use of a non-terminal must be enclosed in angle brackets
|
||||
+ The 're' module has an incompatibility with previous versions:
|
||||
now, any use of a non-terminal must be enclosed in angle brackets
|
||||
(like <B>).
|
||||
|
||||
* Changes from version 0.6 to 0.7
|
||||
-------------------------------
|
||||
-------------------------------
|
||||
+ Several improvements in module 're':
|
||||
- better documentation;
|
||||
- support for most captures (all but accumulator);
|
||||
- limited repetitions p{n,m}.
|
||||
+ Small improvements in efficiency.
|
||||
+ Several small bugs corrected (special thanks to Hans Hagen
|
||||
+ Several small bugs corrected (special thanks to Hans Hagen
|
||||
and Taco Hoekwater).
|
||||
|
||||
* Changes from version 0.5 to 0.6
|
||||
-------------------------------
|
||||
-------------------------------
|
||||
+ Support for non-numeric indices in grammars.
|
||||
+ Some bug fixes (thanks to the luatex team).
|
||||
+ Some new optimizations; (thanks to Mike Pall).
|
||||
@@ -67,7 +71,7 @@ HISTORY for LPeg 1.0
|
||||
+ Minimal documentation for module 're'.
|
||||
|
||||
* Changes from version 0.4 to 0.5
|
||||
-------------------------------
|
||||
-------------------------------
|
||||
+ Several optimizations.
|
||||
+ lpeg.P now accepts booleans.
|
||||
+ Some new examples.
|
||||
@@ -75,18 +79,18 @@ HISTORY for LPeg 1.0
|
||||
+ Several small improvements.
|
||||
|
||||
* Changes from version 0.3 to 0.4
|
||||
-------------------------------
|
||||
-------------------------------
|
||||
+ Static check for loops in repetitions and grammars.
|
||||
+ Removed label option in captures.
|
||||
+ The implementation of captures uses less memory.
|
||||
|
||||
* Changes from version 0.2 to 0.3
|
||||
-------------------------------
|
||||
-------------------------------
|
||||
+ User-defined patterns in Lua.
|
||||
+ Several new captures.
|
||||
|
||||
* Changes from version 0.1 to 0.2
|
||||
-------------------------------
|
||||
-------------------------------
|
||||
+ Several small corrections.
|
||||
+ Handles embedded zeros like any other character.
|
||||
+ Capture "name" can be any Lua value.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lpcap.c,v 1.6 2015/06/15 16:09:57 roberto Exp $
|
||||
** $Id: lpcap.c $
|
||||
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
||||
*/
|
||||
|
||||
@@ -271,15 +271,15 @@ int finddyncap (Capture *cap, Capture *last) {
|
||||
|
||||
|
||||
/*
|
||||
** Calls a runtime capture. Returns number of captures removed by
|
||||
** the call, including the initial Cgroup. (Captures to be added are
|
||||
** on the Lua stack.)
|
||||
** Calls a runtime capture. Returns number of captures "removed" by the
|
||||
** call, that is, those inside the group capture. Captures to be added
|
||||
** are on the Lua stack.
|
||||
*/
|
||||
int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) {
|
||||
int n, id;
|
||||
lua_State *L = cs->L;
|
||||
int otop = lua_gettop(L);
|
||||
Capture *open = findopen(close);
|
||||
Capture *open = findopen(close); /* get open group capture */
|
||||
assert(captype(open) == Cgroup);
|
||||
id = finddyncap(open, close); /* get first dynamic capture argument */
|
||||
close->kind = Cclose; /* closes the group */
|
||||
@@ -299,7 +299,7 @@ int runtimecap (CapState *cs, Capture *close, const char *s, int *rem) {
|
||||
}
|
||||
else
|
||||
*rem = 0; /* no dynamic captures removed */
|
||||
return close - open; /* number of captures of all kinds removed */
|
||||
return close - open - 1; /* number of captures to be removed */
|
||||
}
|
||||
|
||||
|
||||
@@ -441,70 +441,88 @@ static int addonestring (luaL_Buffer *b, CapState *cs, const char *what) {
|
||||
}
|
||||
|
||||
|
||||
#if !defined(MAXRECLEVEL)
|
||||
#define MAXRECLEVEL 200
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Push all values of the current capture into the stack; returns
|
||||
** number of values pushed
|
||||
*/
|
||||
static int pushcapture (CapState *cs) {
|
||||
lua_State *L = cs->L;
|
||||
int res;
|
||||
luaL_checkstack(L, 4, "too many captures");
|
||||
if (cs->reclevel++ > MAXRECLEVEL)
|
||||
return luaL_error(L, "subcapture nesting too deep");
|
||||
switch (captype(cs->cap)) {
|
||||
case Cposition: {
|
||||
lua_pushinteger(L, cs->cap->s - cs->s + 1);
|
||||
cs->cap++;
|
||||
return 1;
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
case Cconst: {
|
||||
pushluaval(cs);
|
||||
cs->cap++;
|
||||
return 1;
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
case Carg: {
|
||||
int arg = (cs->cap++)->idx;
|
||||
if (arg + FIXEDARGS > cs->ptop)
|
||||
return luaL_error(L, "reference to absent extra argument #%d", arg);
|
||||
lua_pushvalue(L, arg + FIXEDARGS);
|
||||
return 1;
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
case Csimple: {
|
||||
int k = pushnestedvalues(cs, 1);
|
||||
lua_insert(L, -k); /* make whole match be first result */
|
||||
return k;
|
||||
res = k;
|
||||
break;
|
||||
}
|
||||
case Cruntime: {
|
||||
lua_pushvalue(L, (cs->cap++)->idx); /* value is in the stack */
|
||||
return 1;
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
case Cstring: {
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
stringcap(&b, cs);
|
||||
luaL_pushresult(&b);
|
||||
return 1;
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
case Csubst: {
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
substcap(&b, cs);
|
||||
luaL_pushresult(&b);
|
||||
return 1;
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
case Cgroup: {
|
||||
if (cs->cap->idx == 0) /* anonymous group? */
|
||||
return pushnestedvalues(cs, 0); /* add all nested values */
|
||||
res = pushnestedvalues(cs, 0); /* add all nested values */
|
||||
else { /* named group: add no values */
|
||||
nextcap(cs); /* skip capture */
|
||||
return 0;
|
||||
res = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Cbackref: return backrefcap(cs);
|
||||
case Ctable: return tablecap(cs);
|
||||
case Cfunction: return functioncap(cs);
|
||||
case Cnum: return numcap(cs);
|
||||
case Cquery: return querycap(cs);
|
||||
case Cfold: return foldcap(cs);
|
||||
default: assert(0); return 0;
|
||||
case Cbackref: res = backrefcap(cs); break;
|
||||
case Ctable: res = tablecap(cs); break;
|
||||
case Cfunction: res = functioncap(cs); break;
|
||||
case Cnum: res = numcap(cs); break;
|
||||
case Cquery: res = querycap(cs); break;
|
||||
case Cfold: res = foldcap(cs); break;
|
||||
default: assert(0); res = 0;
|
||||
}
|
||||
cs->reclevel--;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -521,7 +539,7 @@ int getcaptures (lua_State *L, const char *s, const char *r, int ptop) {
|
||||
int n = 0;
|
||||
if (!isclosecap(capture)) { /* is there any capture? */
|
||||
CapState cs;
|
||||
cs.ocap = cs.cap = capture; cs.L = L;
|
||||
cs.ocap = cs.cap = capture; cs.L = L; cs.reclevel = 0;
|
||||
cs.s = s; cs.valuecached = 0; cs.ptop = ptop;
|
||||
do { /* collect their values */
|
||||
n += pushcapture(&cs);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lpcap.h,v 1.3 2016/09/13 17:45:58 roberto Exp $
|
||||
** $Id: lpcap.h $
|
||||
*/
|
||||
|
||||
#if !defined(lpcap_h)
|
||||
@@ -44,6 +44,7 @@ typedef struct CapState {
|
||||
int ptop; /* index of last argument to 'match' */
|
||||
const char *s; /* original string */
|
||||
int valuecached; /* value stored in cache slot */
|
||||
int reclevel; /* recursion level */
|
||||
} CapState;
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lpcode.c,v 1.24 2016/09/15 17:46:13 roberto Exp $
|
||||
** $Id: lpcode.c $
|
||||
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lpcode.h,v 1.8 2016/09/15 17:46:13 roberto Exp $
|
||||
** $Id: lpcode.h $
|
||||
*/
|
||||
|
||||
#if !defined(lpcode_h)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- $Id: lpeg.html,v 1.77 2017/01/13 13:40:05 roberto Exp $ -->
|
||||
<!-- $Id: lpeg.html $ -->
|
||||
|
||||
<div id="container">
|
||||
|
||||
@@ -1391,13 +1391,13 @@ and the new term for each repetition.
|
||||
<h2><a name="download"></a>Download</h2>
|
||||
|
||||
<p>LPeg
|
||||
<a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.1.tar.gz">source code</a>.</p>
|
||||
<a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz">source code</a>.</p>
|
||||
|
||||
|
||||
<h2><a name="license">License</a></h2>
|
||||
|
||||
<p>
|
||||
Copyright © 2007-2017 Lua.org, PUC-Rio.
|
||||
Copyright © 2007-2019 Lua.org, PUC-Rio.
|
||||
</p>
|
||||
<p>
|
||||
Permission is hereby granted, free of charge,
|
||||
@@ -1433,12 +1433,6 @@ THE SOFTWARE.
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><small>
|
||||
$Id: lpeg.html,v 1.77 2017/01/13 13:40:05 roberto Exp $
|
||||
</small></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
|
||||
</body>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lpprint.c,v 1.10 2016/09/13 16:06:03 roberto Exp $
|
||||
** $Id: lpprint.c $
|
||||
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lpprint.h,v 1.2 2015/06/12 18:18:08 roberto Exp $
|
||||
** $Id: lpprint.h $
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lptree.c,v 1.22 2016/09/13 18:10:22 roberto Exp $
|
||||
** $Id: lptree.c $
|
||||
** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
||||
*/
|
||||
|
||||
@@ -716,6 +716,7 @@ static int capture_aux (lua_State *L, int cap, int labelidx) {
|
||||
|
||||
/*
|
||||
** Fill a tree with an empty capture, using an empty (TTrue) sibling.
|
||||
** (The 'key' field must be filled by the caller to finish the tree.)
|
||||
*/
|
||||
static TTree *auxemptycap (TTree *tree, int cap) {
|
||||
tree->tag = TCapture;
|
||||
@@ -726,15 +727,17 @@ static TTree *auxemptycap (TTree *tree, int cap) {
|
||||
|
||||
|
||||
/*
|
||||
** Create a tree for an empty capture
|
||||
** Create a tree for an empty capture.
|
||||
*/
|
||||
static TTree *newemptycap (lua_State *L, int cap) {
|
||||
return auxemptycap(newtree(L, 2), cap);
|
||||
static TTree *newemptycap (lua_State *L, int cap, int key) {
|
||||
TTree *tree = auxemptycap(newtree(L, 2), cap);
|
||||
tree->key = key;
|
||||
return tree;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Create a tree for an empty capture with an associated Lua value
|
||||
** Create a tree for an empty capture with an associated Lua value.
|
||||
*/
|
||||
static TTree *newemptycapkey (lua_State *L, int cap, int idx) {
|
||||
TTree *tree = auxemptycap(newtree(L, 2), cap);
|
||||
@@ -795,16 +798,15 @@ static int lp_simplecapture (lua_State *L) {
|
||||
|
||||
|
||||
static int lp_poscapture (lua_State *L) {
|
||||
newemptycap(L, Cposition);
|
||||
newemptycap(L, Cposition, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int lp_argcapture (lua_State *L) {
|
||||
int n = (int)luaL_checkinteger(L, 1);
|
||||
TTree *tree = newemptycap(L, Carg);
|
||||
tree->key = n;
|
||||
luaL_argcheck(L, 0 < n && n <= SHRT_MAX, 1, "invalid argument index");
|
||||
newemptycap(L, Carg, n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lptree.h,v 1.3 2016/09/13 18:07:51 roberto Exp $
|
||||
** $Id: lptree.h $
|
||||
*/
|
||||
|
||||
#if !defined(lptree_h)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
** $Id: lptypes.h,v 1.16 2017/01/13 13:33:17 roberto Exp $
|
||||
** $Id: lptypes.h $
|
||||
** LPeg - PEG pattern matching for Lua
|
||||
** Copyright 2007-2017, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
||||
** Copyright 2007-2019, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
||||
** written by Roberto Ierusalimschy
|
||||
*/
|
||||
|
||||
@@ -9,17 +9,13 @@
|
||||
#define lptypes_h
|
||||
|
||||
|
||||
#if !defined(LPEG_DEBUG)
|
||||
#define NDEBUG
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
#define VERSION "1.0.1"
|
||||
#define VERSION "1.0.2"
|
||||
|
||||
|
||||
#define PATTERN_T "lpeg-pattern"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lpvm.c,v 1.9 2016/06/03 20:11:18 roberto Exp $
|
||||
** $Id: lpvm.c $
|
||||
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
|
||||
*/
|
||||
|
||||
@@ -45,18 +45,29 @@ typedef struct Stack {
|
||||
|
||||
|
||||
/*
|
||||
** Make the size of the array of captures 'cap' twice as large as needed
|
||||
** (which is 'captop'). ('n' is the number of new elements.)
|
||||
** Ensures the size of array 'capture' (with size '*capsize' and
|
||||
** 'captop' elements being used) is enough to accomodate 'n' extra
|
||||
** elements plus one. (Because several opcodes add stuff to the capture
|
||||
** array, it is simpler to ensure the array always has at least one free
|
||||
** slot upfront and check its size later.)
|
||||
*/
|
||||
static Capture *doublecap (lua_State *L, Capture *cap, int captop,
|
||||
int n, int ptop) {
|
||||
Capture *newc;
|
||||
if (captop >= INT_MAX/((int)sizeof(Capture) * 2))
|
||||
luaL_error(L, "too many captures");
|
||||
newc = (Capture *)lua_newuserdata(L, captop * 2 * sizeof(Capture));
|
||||
memcpy(newc, cap, (captop - n) * sizeof(Capture));
|
||||
lua_replace(L, caplistidx(ptop));
|
||||
return newc;
|
||||
static Capture *growcap (lua_State *L, Capture *capture, int *capsize,
|
||||
int captop, int n, int ptop) {
|
||||
if (*capsize - captop > n)
|
||||
return capture; /* no need to grow array */
|
||||
else { /* must grow */
|
||||
Capture *newc;
|
||||
int newsize = captop + n + 1; /* minimum size needed */
|
||||
if (newsize < INT_MAX/((int)sizeof(Capture) * 2))
|
||||
newsize *= 2; /* twice that size, if not too big */
|
||||
else if (newsize >= INT_MAX/((int)sizeof(Capture)))
|
||||
luaL_error(L, "too many captures");
|
||||
newc = (Capture *)lua_newuserdata(L, newsize * sizeof(Capture));
|
||||
memcpy(newc, capture, captop * sizeof(Capture));
|
||||
*capsize = newsize;
|
||||
lua_replace(L, caplistidx(ptop));
|
||||
return newc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -109,24 +120,24 @@ static int resdyncaptures (lua_State *L, int fr, int curr, int limit) {
|
||||
|
||||
|
||||
/*
|
||||
** Add capture values returned by a dynamic capture to the capture list
|
||||
** 'base', nested inside a group capture. 'fd' indexes the first capture
|
||||
** value, 'n' is the number of values (at least 1).
|
||||
** Add capture values returned by a dynamic capture to the list
|
||||
** 'capture', nested inside a group. 'fd' indexes the first capture
|
||||
** value, 'n' is the number of values (at least 1). The open group
|
||||
** capture is already in 'capture', before the place for the new entries.
|
||||
*/
|
||||
static void adddyncaptures (const char *s, Capture *base, int n, int fd) {
|
||||
static void adddyncaptures (const char *s, Capture *capture, int n, int fd) {
|
||||
int i;
|
||||
base[0].kind = Cgroup; /* create group capture */
|
||||
base[0].siz = 0;
|
||||
base[0].idx = 0; /* make it an anonymous group */
|
||||
for (i = 1; i <= n; i++) { /* add runtime captures */
|
||||
base[i].kind = Cruntime;
|
||||
base[i].siz = 1; /* mark it as closed */
|
||||
base[i].idx = fd + i - 1; /* stack index of capture value */
|
||||
base[i].s = s;
|
||||
assert(capture[-1].kind == Cgroup && capture[-1].siz == 0);
|
||||
capture[-1].idx = 0; /* make group capture an anonymous group */
|
||||
for (i = 0; i < n; i++) { /* add runtime captures */
|
||||
capture[i].kind = Cruntime;
|
||||
capture[i].siz = 1; /* mark it as closed */
|
||||
capture[i].idx = fd + i; /* stack index of capture value */
|
||||
capture[i].s = s;
|
||||
}
|
||||
base[i].kind = Cclose; /* close group */
|
||||
base[i].siz = 1;
|
||||
base[i].s = s;
|
||||
capture[n].kind = Cclose; /* close group */
|
||||
capture[n].siz = 1;
|
||||
capture[n].s = s;
|
||||
}
|
||||
|
||||
|
||||
@@ -296,7 +307,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
|
||||
CapState cs;
|
||||
int rem, res, n;
|
||||
int fr = lua_gettop(L) + 1; /* stack index of first result */
|
||||
cs.s = o; cs.L = L; cs.ocap = capture; cs.ptop = ptop;
|
||||
cs.reclevel = 0; cs.L = L;
|
||||
cs.s = o; cs.ocap = capture; cs.ptop = ptop;
|
||||
n = runtimecap(&cs, capture + captop, s, &rem); /* call function */
|
||||
captop -= n; /* remove nested captures */
|
||||
ndyncap -= rem; /* update number of dynamic captures */
|
||||
@@ -307,15 +319,15 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
|
||||
s = o + res; /* else update current position */
|
||||
n = lua_gettop(L) - fr + 1; /* number of new captures */
|
||||
ndyncap += n; /* update number of dynamic captures */
|
||||
if (n > 0) { /* any new capture? */
|
||||
if (n == 0) /* no new captures? */
|
||||
captop--; /* remove open group */
|
||||
else { /* new captures; keep original open group */
|
||||
if (fr + n >= SHRT_MAX)
|
||||
luaL_error(L, "too many results in match-time capture");
|
||||
if ((captop += n + 2) >= capsize) {
|
||||
capture = doublecap(L, capture, captop, n + 2, ptop);
|
||||
capsize = 2 * captop;
|
||||
}
|
||||
/* add new captures to 'capture' list */
|
||||
adddyncaptures(s, capture + captop - n - 2, n, fr);
|
||||
/* add new captures + close group to 'capture' list */
|
||||
capture = growcap(L, capture, &capsize, captop, n + 1, ptop);
|
||||
adddyncaptures(s, capture + captop, n, fr);
|
||||
captop += n + 1; /* new captures + close group */
|
||||
}
|
||||
p++;
|
||||
continue;
|
||||
@@ -347,10 +359,8 @@ const char *match (lua_State *L, const char *o, const char *s, const char *e,
|
||||
pushcapture: {
|
||||
capture[captop].idx = p->i.key;
|
||||
capture[captop].kind = getkind(p);
|
||||
if (++captop >= capsize) {
|
||||
capture = doublecap(L, capture, captop, 0, ptop);
|
||||
capsize = 2 * captop;
|
||||
}
|
||||
captop++;
|
||||
capture = growcap(L, capture, &capsize, captop, 0, ptop);
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lpvm.h,v 1.3 2014/02/21 13:06:41 roberto Exp $
|
||||
** $Id: lpvm.h $
|
||||
*/
|
||||
|
||||
#if !defined(lpvm_h)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
LIBNAME = lpeg
|
||||
LUADIR = ../lua/
|
||||
|
||||
COPT = -O2
|
||||
# COPT = -DLPEG_DEBUG -g
|
||||
COPT = -O2 -DNDEBUG
|
||||
# COPT = -g
|
||||
|
||||
CWARNS = -Wall -Wextra -pedantic \
|
||||
-Waggregate-return \
|
||||
@@ -29,11 +29,11 @@ FILES = lpvm.o lpcap.o lptree.o lpcode.o lpprint.o
|
||||
|
||||
# For Linux
|
||||
linux:
|
||||
make lpeg.so "DLLFLAGS = -shared -fPIC"
|
||||
$(MAKE) lpeg.so "DLLFLAGS = -shared -fPIC"
|
||||
|
||||
# For Mac OS
|
||||
macosx:
|
||||
make lpeg.so "DLLFLAGS = -bundle -undefined dynamic_lookup"
|
||||
$(MAKE) lpeg.so "DLLFLAGS = -bundle -undefined dynamic_lookup"
|
||||
|
||||
lpeg.so: $(FILES)
|
||||
env $(CC) $(DLLFLAGS) $(FILES) -o lpeg.so
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- $Id: re.html,v 1.24 2016/09/20 17:41:27 roberto Exp $ -->
|
||||
<!-- $Id: re.html $ -->
|
||||
|
||||
<div id="container">
|
||||
|
||||
@@ -93,6 +93,8 @@ Constructions are listed in order of decreasing precedence.
|
||||
equivalent to <code>p / defs[name]</code></td></tr>
|
||||
<tr><td><code>p => name</code></td> <td>match-time capture
|
||||
equivalent to <code>lpeg.Cmt(p, defs[name])</code></td></tr>
|
||||
<tr><td><code>p ~> name</code></td> <td>fold capture
|
||||
equivalent to <code>lpeg.Cf(p, defs[name])</code></td></tr>
|
||||
<tr><td><code>& p</code></td> <td>and predicate</td></tr>
|
||||
<tr><td><code>! p</code></td> <td>not predicate</td></tr>
|
||||
<tr><td><code>p1 p2</code></td> <td>concatenation</td></tr>
|
||||
@@ -486,12 +488,6 @@ THE SOFTWARE.
|
||||
|
||||
</div> <!-- id="main" -->
|
||||
|
||||
<div id="about">
|
||||
<p><small>
|
||||
$Id: re.html,v 1.24 2016/09/20 17:41:27 roberto Exp $
|
||||
</small></p>
|
||||
</div> <!-- id="about" -->
|
||||
|
||||
</div> <!-- id="container" -->
|
||||
|
||||
</body>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-- $Id: re.lua,v 1.44 2013/03/26 20:11:40 roberto Exp $
|
||||
-- $Id: re.lua $
|
||||
|
||||
-- imported functions and modules
|
||||
local tonumber, type, print, error = tonumber, type, print, error
|
||||
@@ -71,13 +71,6 @@ updatelocale()
|
||||
local I = m.P(function (s,i) print(i, s:sub(1, i-1)); return i end)
|
||||
|
||||
|
||||
local function getdef (id, defs)
|
||||
local c = defs and defs[id]
|
||||
if not c then error("undefined name: " .. id) end
|
||||
return c
|
||||
end
|
||||
|
||||
|
||||
local function patt_error (s, i)
|
||||
local msg = (#s < i + 20) and s:sub(i)
|
||||
or s:sub(i,i+20) .. "..."
|
||||
@@ -116,6 +109,20 @@ name = m.C(name)
|
||||
-- a defined name only have meaning in a given environment
|
||||
local Def = name * m.Carg(1)
|
||||
|
||||
|
||||
local function getdef (id, defs)
|
||||
local c = defs and defs[id]
|
||||
if not c then error("undefined name: " .. id) end
|
||||
return c
|
||||
end
|
||||
|
||||
-- match a name and return a group of its corresponding definition
|
||||
-- and 'f' (to be folded in 'Suffix')
|
||||
local function defwithfunc (f)
|
||||
return m.Cg(Def / getdef * m.Cc(f))
|
||||
end
|
||||
|
||||
|
||||
local num = m.C(m.R"09"^1) * S / tonumber
|
||||
|
||||
local String = "'" * m.C((any - "'")^0) * "'" +
|
||||
@@ -130,7 +137,7 @@ end
|
||||
|
||||
local Range = m.Cs(any * (m.P"-"/"") * (any - "]")) / mm.R
|
||||
|
||||
local item = defined + Range + m.C(any)
|
||||
local item = (defined + Range + m.C(any)) / m.P
|
||||
|
||||
local Class =
|
||||
"["
|
||||
@@ -176,9 +183,10 @@ local exp = m.P{ "Exp",
|
||||
)
|
||||
+ "->" * S * ( m.Cg((String + num) * m.Cc(mt.__div))
|
||||
+ m.P"{}" * m.Cc(nil, m.Ct)
|
||||
+ m.Cg(Def / getdef * m.Cc(mt.__div))
|
||||
+ defwithfunc(mt.__div)
|
||||
)
|
||||
+ "=>" * S * m.Cg(Def / getdef * m.Cc(m.Cmt))
|
||||
+ "=>" * S * defwithfunc(m.Cmt)
|
||||
+ "~>" * S * defwithfunc(m.Cf)
|
||||
) * S
|
||||
)^0, function (a,b,f) return f(a,b) end );
|
||||
Primary = "(" * m.V"Exp" * ")"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env lua
|
||||
|
||||
-- $Id: test.lua,v 1.112 2017/01/14 18:55:22 roberto Exp $
|
||||
-- $Id: test.lua $
|
||||
|
||||
-- require"strict" -- just to be pedantic
|
||||
|
||||
@@ -424,6 +424,16 @@ do
|
||||
end
|
||||
|
||||
|
||||
do
|
||||
-- nesting of captures too deep
|
||||
local p = m.C(1)
|
||||
for i = 1, 300 do
|
||||
p = m.Ct(p)
|
||||
end
|
||||
checkerr("too deep", p.match, p, "x")
|
||||
end
|
||||
|
||||
|
||||
-- tests for non-pattern as arguments to pattern functions
|
||||
|
||||
p = { ('a' * m.V(1))^-1 } * m.P'b' * { 'a' * m.V(2); m.V(1)^-1 }
|
||||
@@ -1186,6 +1196,9 @@ assert(not match("abbcde", " [b-z] + "))
|
||||
assert(match("abb\"de", '"abb"["]"de"') == 7)
|
||||
assert(match("abceeef", "'ac' ? 'ab' * 'c' { 'e' * } / 'abceeef' ") == "eee")
|
||||
assert(match("abceeef", "'ac'? 'ab'* 'c' { 'f'+ } / 'abceeef' ") == 8)
|
||||
|
||||
assert(re.match("aaand", "[a]^2") == 3)
|
||||
|
||||
local t = {match("abceefe", "( ( & 'e' {} ) ? . ) * ")}
|
||||
checkeq(t, {4, 5, 7})
|
||||
local t = {match("abceefe", "((&&'e' {})? .)*")}
|
||||
@@ -1360,6 +1373,13 @@ checkeq(x, {tag='x', 'hi', {tag = 'b', 'hello'}, 'but',
|
||||
{'totheend'}})
|
||||
|
||||
|
||||
-- test for folding captures
|
||||
c = re.compile([[
|
||||
S <- (number (%s+ number)*) ~> add
|
||||
number <- %d+ -> tonumber
|
||||
]], {tonumber = tonumber, add = function (a,b) return a + b end})
|
||||
assert(c:match("3 401 50") == 3 + 401 + 50)
|
||||
|
||||
-- tests for look-ahead captures
|
||||
x = {re.match("alo", "&(&{.}) !{'b'} {&(...)} &{..} {...} {!.}")}
|
||||
checkeq(x, {"", "alo", ""})
|
||||
|
||||
7
3rd/lua/README.md
Normal file
7
3rd/lua/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Lua
|
||||
|
||||
This is the repository of Lua development code, as seen by the Lua team. It contains the full history of all commits but is mirrored irregularly. For complete information about Lua, visit [Lua.org](https://www.lua.org/).
|
||||
|
||||
Please **do not** send pull requests. To report issues, post a message to the [Lua mailing list](https://www.lua.org/lua-l.html).
|
||||
|
||||
Download official Lua releases from [Lua.org](https://www.lua.org/download.html).
|
||||
298
3rd/lua/lapi.c
298
3rd/lua/lapi.c
@@ -53,45 +53,57 @@ const char lua_ident[] =
|
||||
#define isupvalue(i) ((i) < LUA_REGISTRYINDEX)
|
||||
|
||||
|
||||
/*
|
||||
** Convert an acceptable index to a pointer to its respective value.
|
||||
** Non-valid indices return the special nil value 'G(L)->nilvalue'.
|
||||
*/
|
||||
static TValue *index2value (lua_State *L, int idx) {
|
||||
CallInfo *ci = L->ci;
|
||||
if (idx > 0) {
|
||||
StkId o = ci->func + idx;
|
||||
api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index");
|
||||
if (o >= L->top) return &G(L)->nilvalue;
|
||||
StkId o = ci->func.p + idx;
|
||||
api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
|
||||
if (o >= L->top.p) return &G(L)->nilvalue;
|
||||
else return s2v(o);
|
||||
}
|
||||
else if (!ispseudo(idx)) { /* negative index */
|
||||
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
|
||||
return s2v(L->top + idx);
|
||||
api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
|
||||
"invalid index");
|
||||
return s2v(L->top.p + idx);
|
||||
}
|
||||
else if (idx == LUA_REGISTRYINDEX)
|
||||
return &G(L)->l_registry;
|
||||
else { /* upvalues */
|
||||
idx = LUA_REGISTRYINDEX - idx;
|
||||
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
|
||||
if (ttislcf(s2v(ci->func))) /* light C function? */
|
||||
return &G(L)->nilvalue; /* it has no upvalues */
|
||||
else {
|
||||
CClosure *func = clCvalue(s2v(ci->func));
|
||||
if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */
|
||||
CClosure *func = clCvalue(s2v(ci->func.p));
|
||||
return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
|
||||
: &G(L)->nilvalue;
|
||||
}
|
||||
else { /* light C function or Lua function (through a hook)?) */
|
||||
api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function");
|
||||
return &G(L)->nilvalue; /* no upvalues */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static StkId index2stack (lua_State *L, int idx) {
|
||||
|
||||
/*
|
||||
** Convert a valid actual index (not a pseudo-index) to its address.
|
||||
*/
|
||||
l_sinline StkId index2stack (lua_State *L, int idx) {
|
||||
CallInfo *ci = L->ci;
|
||||
if (idx > 0) {
|
||||
StkId o = ci->func + idx;
|
||||
api_check(L, o < L->top, "unacceptable index");
|
||||
StkId o = ci->func.p + idx;
|
||||
api_check(L, o < L->top.p, "invalid index");
|
||||
return o;
|
||||
}
|
||||
else { /* non-positive index */
|
||||
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
|
||||
api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
|
||||
"invalid index");
|
||||
api_check(L, !ispseudo(idx), "invalid index");
|
||||
return L->top + idx;
|
||||
return L->top.p + idx;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,17 +114,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
|
||||
lua_lock(L);
|
||||
ci = L->ci;
|
||||
api_check(L, n >= 0, "negative 'n'");
|
||||
if (L->stack_last - L->top > n) /* stack large enough? */
|
||||
if (L->stack_last.p - L->top.p > n) /* stack large enough? */
|
||||
res = 1; /* yes; check is OK */
|
||||
else { /* no; need to grow stack */
|
||||
int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
|
||||
if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
|
||||
res = 0; /* no */
|
||||
else /* try to grow stack */
|
||||
res = luaD_growstack(L, n, 0);
|
||||
}
|
||||
if (res && ci->top < L->top + n)
|
||||
ci->top = L->top + n; /* adjust frame top */
|
||||
else /* need to grow stack */
|
||||
res = luaD_growstack(L, n, 0);
|
||||
if (res && ci->top.p < L->top.p + n)
|
||||
ci->top.p = L->top.p + n; /* adjust frame top */
|
||||
lua_unlock(L);
|
||||
return res;
|
||||
}
|
||||
@@ -124,11 +131,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
|
||||
lua_lock(to);
|
||||
api_checknelems(from, n);
|
||||
api_check(from, G(from) == G(to), "moving among independent states");
|
||||
api_check(from, to->ci->top - to->top >= n, "stack overflow");
|
||||
from->top -= n;
|
||||
api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
|
||||
from->top.p -= n;
|
||||
for (i = 0; i < n; i++) {
|
||||
setobjs2s(to, to->top, from->top + i);
|
||||
to->top++; /* stack already checked by previous 'api_check' */
|
||||
setobjs2s(to, to->top.p, from->top.p + i);
|
||||
to->top.p++; /* stack already checked by previous 'api_check' */
|
||||
}
|
||||
lua_unlock(to);
|
||||
}
|
||||
@@ -162,12 +169,12 @@ LUA_API lua_Number lua_version (lua_State *L) {
|
||||
LUA_API int lua_absindex (lua_State *L, int idx) {
|
||||
return (idx > 0 || ispseudo(idx))
|
||||
? idx
|
||||
: cast_int(L->top - L->ci->func) + idx;
|
||||
: cast_int(L->top.p - L->ci->func.p) + idx;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_gettop (lua_State *L) {
|
||||
return cast_int(L->top - (L->ci->func + 1));
|
||||
return cast_int(L->top.p - (L->ci->func.p + 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -177,24 +184,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
|
||||
ptrdiff_t diff; /* difference for new top */
|
||||
lua_lock(L);
|
||||
ci = L->ci;
|
||||
func = ci->func;
|
||||
func = ci->func.p;
|
||||
if (idx >= 0) {
|
||||
api_check(L, idx <= ci->top - (func + 1), "new top too large");
|
||||
diff = ((func + 1) + idx) - L->top;
|
||||
api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
|
||||
diff = ((func + 1) + idx) - L->top.p;
|
||||
for (; diff > 0; diff--)
|
||||
setnilvalue(s2v(L->top++)); /* clear new slots */
|
||||
setnilvalue(s2v(L->top.p++)); /* clear new slots */
|
||||
}
|
||||
else {
|
||||
api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
|
||||
api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
|
||||
diff = idx + 1; /* will "subtract" index (as it is negative) */
|
||||
}
|
||||
api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
|
||||
newtop = L->top + diff;
|
||||
if (diff < 0 && L->tbclist >= newtop) {
|
||||
api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
|
||||
newtop = L->top.p + diff;
|
||||
if (diff < 0 && L->tbclist.p >= newtop) {
|
||||
lua_assert(hastocloseCfunc(ci->nresults));
|
||||
luaF_close(L, newtop, CLOSEKTOP, 0);
|
||||
newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
|
||||
}
|
||||
L->top = newtop; /* correct top only after closing any upvalue */
|
||||
L->top.p = newtop; /* correct top only after closing any upvalue */
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
@@ -203,10 +210,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
|
||||
StkId level;
|
||||
lua_lock(L);
|
||||
level = index2stack(L, idx);
|
||||
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
|
||||
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
|
||||
"no variable to close at given level");
|
||||
luaF_close(L, level, CLOSEKTOP, 0);
|
||||
level = index2stack(L, idx); /* stack may be moved */
|
||||
level = luaF_close(L, level, CLOSEKTOP, 0);
|
||||
setnilvalue(s2v(level));
|
||||
lua_unlock(L);
|
||||
}
|
||||
@@ -218,7 +224,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
|
||||
** Note that we move(copy) only the value inside the stack.
|
||||
** (We do not move additional fields that may exist.)
|
||||
*/
|
||||
static void reverse (lua_State *L, StkId from, StkId to) {
|
||||
l_sinline void reverse (lua_State *L, StkId from, StkId to) {
|
||||
for (; from < to; from++, to--) {
|
||||
TValue temp;
|
||||
setobj(L, &temp, s2v(from));
|
||||
@@ -235,7 +241,7 @@ static void reverse (lua_State *L, StkId from, StkId to) {
|
||||
LUA_API void lua_rotate (lua_State *L, int idx, int n) {
|
||||
StkId p, t, m;
|
||||
lua_lock(L);
|
||||
t = L->top - 1; /* end of stack segment being rotated */
|
||||
t = L->top.p - 1; /* end of stack segment being rotated */
|
||||
p = index2stack(L, idx); /* start of segment */
|
||||
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
|
||||
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
|
||||
@@ -254,7 +260,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
|
||||
api_check(L, isvalid(L, to), "invalid index");
|
||||
setobj(L, to, fr);
|
||||
if (isupvalue(toidx)) /* function upvalue? */
|
||||
luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr);
|
||||
luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr);
|
||||
/* LUA_REGISTRYINDEX does not need gc barrier
|
||||
(collector revisits it before finishing collection) */
|
||||
lua_unlock(L);
|
||||
@@ -263,7 +269,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
|
||||
|
||||
LUA_API void lua_pushvalue (lua_State *L, int idx) {
|
||||
lua_lock(L);
|
||||
setobj2s(L, L->top, index2value(L, idx));
|
||||
setobj2s(L, L->top.p, index2value(L, idx));
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
@@ -332,12 +338,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
|
||||
api_checknelems(L, 2); /* all other operations expect two operands */
|
||||
else { /* for unary operations, add fake 2nd operand */
|
||||
api_checknelems(L, 1);
|
||||
setobjs2s(L, L->top, L->top - 1);
|
||||
setobjs2s(L, L->top.p, L->top.p - 1);
|
||||
api_incr_top(L);
|
||||
}
|
||||
/* first operand at top - 2, second at top - 1; result go to top - 2 */
|
||||
luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2);
|
||||
L->top--; /* remove second operand */
|
||||
luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
|
||||
L->top.p--; /* remove second operand */
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
@@ -363,7 +369,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
|
||||
|
||||
|
||||
LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
|
||||
size_t sz = luaO_str2num(s, s2v(L->top));
|
||||
size_t sz = luaO_str2num(s, s2v(L->top.p));
|
||||
if (sz != 0)
|
||||
api_incr_top(L);
|
||||
return sz;
|
||||
@@ -438,7 +444,7 @@ LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) {
|
||||
}
|
||||
|
||||
|
||||
static void *touserdata (const TValue *o) {
|
||||
l_sinline void *touserdata (const TValue *o) {
|
||||
switch (ttype(o)) {
|
||||
case LUA_TUSERDATA: return getudatamem(uvalue(o));
|
||||
case LUA_TLIGHTUSERDATA: return pvalue(o);
|
||||
@@ -490,7 +496,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
|
||||
|
||||
LUA_API void lua_pushnil (lua_State *L) {
|
||||
lua_lock(L);
|
||||
setnilvalue(s2v(L->top));
|
||||
setnilvalue(s2v(L->top.p));
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
@@ -498,7 +504,7 @@ LUA_API void lua_pushnil (lua_State *L) {
|
||||
|
||||
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
|
||||
lua_lock(L);
|
||||
setfltvalue(s2v(L->top), n);
|
||||
setfltvalue(s2v(L->top.p), n);
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
@@ -506,7 +512,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
|
||||
|
||||
LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
|
||||
lua_lock(L);
|
||||
setivalue(s2v(L->top), n);
|
||||
setivalue(s2v(L->top.p), n);
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
@@ -521,7 +527,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
|
||||
TString *ts;
|
||||
lua_lock(L);
|
||||
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
|
||||
setsvalue2s(L, L->top, ts);
|
||||
setsvalue2s(L, L->top.p, ts);
|
||||
api_incr_top(L);
|
||||
luaC_checkGC(L);
|
||||
lua_unlock(L);
|
||||
@@ -532,11 +538,11 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
|
||||
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
|
||||
lua_lock(L);
|
||||
if (s == NULL)
|
||||
setnilvalue(s2v(L->top));
|
||||
setnilvalue(s2v(L->top.p));
|
||||
else {
|
||||
TString *ts;
|
||||
ts = luaS_new(L, s);
|
||||
setsvalue2s(L, L->top, ts);
|
||||
setsvalue2s(L, L->top.p, ts);
|
||||
s = getstr(ts); /* internal copy's address */
|
||||
}
|
||||
api_incr_top(L);
|
||||
@@ -573,7 +579,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
|
||||
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
|
||||
lua_lock(L);
|
||||
if (n == 0) {
|
||||
setfvalue(s2v(L->top), fn);
|
||||
setfvalue(s2v(L->top.p), fn);
|
||||
api_incr_top(L);
|
||||
}
|
||||
else {
|
||||
@@ -582,13 +588,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
|
||||
api_check(L, n <= MAXUPVAL, "upvalue index too large");
|
||||
cl = luaF_newCclosure(L, n);
|
||||
cl->f = fn;
|
||||
L->top -= n;
|
||||
L->top.p -= n;
|
||||
while (n--) {
|
||||
setobj2n(L, &cl->upvalue[n], s2v(L->top + n));
|
||||
setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
|
||||
/* does not need barrier because closure is white */
|
||||
lua_assert(iswhite(cl));
|
||||
}
|
||||
setclCvalue(L, s2v(L->top), cl);
|
||||
setclCvalue(L, s2v(L->top.p), cl);
|
||||
api_incr_top(L);
|
||||
luaC_checkGC(L);
|
||||
}
|
||||
@@ -599,9 +605,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
|
||||
LUA_API void lua_pushboolean (lua_State *L, int b) {
|
||||
lua_lock(L);
|
||||
if (b)
|
||||
setbtvalue(s2v(L->top));
|
||||
setbtvalue(s2v(L->top.p));
|
||||
else
|
||||
setbfvalue(s2v(L->top));
|
||||
setbfvalue(s2v(L->top.p));
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
@@ -609,7 +615,7 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
|
||||
|
||||
LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
|
||||
lua_lock(L);
|
||||
setpvalue(s2v(L->top), p);
|
||||
setpvalue(s2v(L->top.p), p);
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
@@ -617,7 +623,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
|
||||
|
||||
LUA_API int lua_pushthread (lua_State *L) {
|
||||
lua_lock(L);
|
||||
setthvalue(L, s2v(L->top), L);
|
||||
setthvalue(L, s2v(L->top.p), L);
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
return (G(L)->mainthread == L);
|
||||
@@ -630,20 +636,20 @@ LUA_API int lua_pushthread (lua_State *L) {
|
||||
*/
|
||||
|
||||
|
||||
static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
|
||||
l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
|
||||
const TValue *slot;
|
||||
TString *str = luaS_new(L, k);
|
||||
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
|
||||
setobj2s(L, L->top, slot);
|
||||
setobj2s(L, L->top.p, slot);
|
||||
api_incr_top(L);
|
||||
}
|
||||
else {
|
||||
setsvalue2s(L, L->top, str);
|
||||
setsvalue2s(L, L->top.p, str);
|
||||
api_incr_top(L);
|
||||
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
|
||||
luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
|
||||
}
|
||||
lua_unlock(L);
|
||||
return ttype(s2v(L->top - 1));
|
||||
return ttype(s2v(L->top.p - 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -670,13 +676,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
|
||||
TValue *t;
|
||||
lua_lock(L);
|
||||
t = index2value(L, idx);
|
||||
if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) {
|
||||
setobj2s(L, L->top - 1, slot);
|
||||
if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
|
||||
setobj2s(L, L->top.p - 1, slot);
|
||||
}
|
||||
else
|
||||
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot);
|
||||
luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
|
||||
lua_unlock(L);
|
||||
return ttype(s2v(L->top - 1));
|
||||
return ttype(s2v(L->top.p - 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -692,27 +698,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
|
||||
lua_lock(L);
|
||||
t = index2value(L, idx);
|
||||
if (luaV_fastgeti(L, t, n, slot)) {
|
||||
setobj2s(L, L->top, slot);
|
||||
setobj2s(L, L->top.p, slot);
|
||||
}
|
||||
else {
|
||||
TValue aux;
|
||||
setivalue(&aux, n);
|
||||
luaV_finishget(L, t, &aux, L->top, slot);
|
||||
luaV_finishget(L, t, &aux, L->top.p, slot);
|
||||
}
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
return ttype(s2v(L->top - 1));
|
||||
return ttype(s2v(L->top.p - 1));
|
||||
}
|
||||
|
||||
|
||||
static int finishrawget (lua_State *L, const TValue *val) {
|
||||
l_sinline int finishrawget (lua_State *L, const TValue *val) {
|
||||
if (isempty(val)) /* avoid copying empty items to the stack */
|
||||
setnilvalue(s2v(L->top));
|
||||
setnilvalue(s2v(L->top.p));
|
||||
else
|
||||
setobj2s(L, L->top, val);
|
||||
setobj2s(L, L->top.p, val);
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
return ttype(s2v(L->top - 1));
|
||||
return ttype(s2v(L->top.p - 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -729,8 +735,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
|
||||
lua_lock(L);
|
||||
api_checknelems(L, 1);
|
||||
t = gettable(L, idx);
|
||||
val = luaH_get(t, s2v(L->top - 1));
|
||||
L->top--; /* remove key */
|
||||
val = luaH_get(t, s2v(L->top.p - 1));
|
||||
L->top.p--; /* remove key */
|
||||
return finishrawget(L, val);
|
||||
}
|
||||
|
||||
@@ -757,7 +763,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
|
||||
Table *t;
|
||||
lua_lock(L);
|
||||
t = luaH_new(L);
|
||||
sethvalue2s(L, L->top, t);
|
||||
sethvalue2s(L, L->top.p, t);
|
||||
api_incr_top(L);
|
||||
if (narray > 0 || nrec > 0)
|
||||
luaH_resize(L, t, narray, nrec);
|
||||
@@ -784,7 +790,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
|
||||
break;
|
||||
}
|
||||
if (mt != NULL) {
|
||||
sethvalue2s(L, L->top, mt);
|
||||
sethvalue2s(L, L->top.p, mt);
|
||||
api_incr_top(L);
|
||||
res = 1;
|
||||
}
|
||||
@@ -800,12 +806,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
|
||||
o = index2value(L, idx);
|
||||
api_check(L, ttisfulluserdata(o), "full userdata expected");
|
||||
if (n <= 0 || n > uvalue(o)->nuvalue) {
|
||||
setnilvalue(s2v(L->top));
|
||||
setnilvalue(s2v(L->top.p));
|
||||
t = LUA_TNONE;
|
||||
}
|
||||
else {
|
||||
setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv);
|
||||
t = ttype(s2v(L->top));
|
||||
setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
|
||||
t = ttype(s2v(L->top.p));
|
||||
}
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
@@ -825,14 +831,14 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
|
||||
TString *str = luaS_new(L, k);
|
||||
api_checknelems(L, 1);
|
||||
if (luaV_fastset(L, t, str, slot, luaH_getstr)) {
|
||||
luaV_finishfastset(L, t, slot, s2v(L->top - 1));
|
||||
L->top--; /* pop value */
|
||||
luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
|
||||
L->top.p--; /* pop value */
|
||||
}
|
||||
else {
|
||||
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
|
||||
setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */
|
||||
api_incr_top(L);
|
||||
luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot);
|
||||
L->top -= 2; /* pop value and key */
|
||||
luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
|
||||
L->top.p -= 2; /* pop value and key */
|
||||
}
|
||||
lua_unlock(L); /* lock done by caller */
|
||||
}
|
||||
@@ -852,12 +858,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
|
||||
lua_lock(L);
|
||||
api_checknelems(L, 2);
|
||||
t = index2value(L, idx);
|
||||
if (luaV_fastset(L, t, s2v(L->top - 2), slot, luaH_get)) {
|
||||
luaV_finishfastset(L, t, slot, s2v(L->top - 1));
|
||||
if (luaV_fastset(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
|
||||
luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
|
||||
}
|
||||
else
|
||||
luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot);
|
||||
L->top -= 2; /* pop index and value */
|
||||
luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
|
||||
L->top.p -= 2; /* pop index and value */
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
@@ -875,14 +881,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
|
||||
api_checknelems(L, 1);
|
||||
t = index2value(L, idx);
|
||||
if (luaV_fastseti(L, t, n, slot)) {
|
||||
luaV_finishfastset(L, t, slot, s2v(L->top - 1));
|
||||
luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
|
||||
}
|
||||
else {
|
||||
TValue aux;
|
||||
setivalue(&aux, n);
|
||||
luaV_finishset(L, t, &aux, s2v(L->top - 1), slot);
|
||||
luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
|
||||
}
|
||||
L->top--; /* pop value */
|
||||
L->top.p--; /* pop value */
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
@@ -892,16 +898,16 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
|
||||
lua_lock(L);
|
||||
api_checknelems(L, n);
|
||||
t = gettable(L, idx);
|
||||
luaH_set(L, t, key, s2v(L->top - 1));
|
||||
luaH_set(L, t, key, s2v(L->top.p - 1));
|
||||
invalidateTMcache(t);
|
||||
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
|
||||
L->top -= n;
|
||||
luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
|
||||
L->top.p -= n;
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
|
||||
LUA_API void lua_rawset (lua_State *L, int idx) {
|
||||
aux_rawset(L, idx, s2v(L->top - 2), 2);
|
||||
aux_rawset(L, idx, s2v(L->top.p - 2), 2);
|
||||
}
|
||||
|
||||
|
||||
@@ -917,9 +923,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
|
||||
lua_lock(L);
|
||||
api_checknelems(L, 1);
|
||||
t = gettable(L, idx);
|
||||
luaH_setint(L, t, n, s2v(L->top - 1));
|
||||
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
|
||||
L->top--;
|
||||
luaH_setint(L, t, n, s2v(L->top.p - 1));
|
||||
luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
|
||||
L->top.p--;
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
@@ -930,11 +936,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
|
||||
lua_lock(L);
|
||||
api_checknelems(L, 1);
|
||||
obj = index2value(L, objindex);
|
||||
if (ttisnil(s2v(L->top - 1)))
|
||||
if (ttisnil(s2v(L->top.p - 1)))
|
||||
mt = NULL;
|
||||
else {
|
||||
api_check(L, ttistable(s2v(L->top - 1)), "table expected");
|
||||
mt = hvalue(s2v(L->top - 1));
|
||||
api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
|
||||
mt = hvalue(s2v(L->top.p - 1));
|
||||
}
|
||||
switch (ttype(obj)) {
|
||||
case LUA_TTABLE: {
|
||||
@@ -960,7 +966,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
L->top--;
|
||||
L->top.p--;
|
||||
lua_unlock(L);
|
||||
return 1;
|
||||
}
|
||||
@@ -976,11 +982,11 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
|
||||
if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
|
||||
res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
|
||||
else {
|
||||
setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1));
|
||||
luaC_barrierback(L, gcvalue(o), s2v(L->top - 1));
|
||||
setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
|
||||
luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
|
||||
res = 1;
|
||||
}
|
||||
L->top--;
|
||||
L->top.p--;
|
||||
lua_unlock(L);
|
||||
return res;
|
||||
}
|
||||
@@ -992,7 +998,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
|
||||
|
||||
|
||||
#define checkresults(L,na,nr) \
|
||||
api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
|
||||
api_check(L, (nr) == LUA_MULTRET \
|
||||
|| (L->ci->top.p - L->top.p >= (nr) - (na)), \
|
||||
"results from function overflow current stack size")
|
||||
|
||||
|
||||
@@ -1005,7 +1012,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
|
||||
api_checknelems(L, nargs+1);
|
||||
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
|
||||
checkresults(L, nargs, nresults);
|
||||
func = L->top - (nargs+1);
|
||||
func = L->top.p - (nargs+1);
|
||||
if (k != NULL && yieldable(L)) { /* need to prepare continuation? */
|
||||
L->ci->u.c.k = k; /* save continuation */
|
||||
L->ci->u.c.ctx = ctx; /* save context */
|
||||
@@ -1053,7 +1060,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
|
||||
api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
|
||||
func = savestack(L, o);
|
||||
}
|
||||
c.func = L->top - (nargs+1); /* function to be called */
|
||||
c.func = L->top.p - (nargs+1); /* function to be called */
|
||||
if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */
|
||||
c.nresults = nresults; /* do a 'conventional' protected call */
|
||||
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
|
||||
@@ -1083,7 +1090,7 @@ static void set_env (lua_State *L, LClosure *f) {
|
||||
/* get global table from registry */
|
||||
const TValue *gt = getGtable(L);
|
||||
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
|
||||
setobj(L, f->upvals[0]->v, gt);
|
||||
setobj(L, f->upvals[0]->v.p, gt);
|
||||
luaC_barrier(L, f->upvals[0], gt);
|
||||
}
|
||||
}
|
||||
@@ -1097,7 +1104,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
|
||||
luaZ_init(L, &z, reader, data);
|
||||
status = luaD_protectedparser(L, &z, chunkname, mode);
|
||||
if (status == LUA_OK) { /* no errors? */
|
||||
LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */
|
||||
LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */
|
||||
set_env(L,f);
|
||||
}
|
||||
lua_unlock(L);
|
||||
@@ -1110,7 +1117,7 @@ LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
|
||||
api_check(L, isshared(f->p), "Not a shared proto");
|
||||
lua_lock(L);
|
||||
cl = luaF_newLclosure(L,f->nupvalues);
|
||||
setclLvalue2s(L,L->top,cl);
|
||||
setclLvalue2s(L,L->top.p,cl);
|
||||
api_incr_top(L);
|
||||
cl->p = f->p;
|
||||
luaF_initupvals(L, cl);
|
||||
@@ -1119,16 +1126,18 @@ LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
|
||||
}
|
||||
|
||||
LUA_API void lua_sharefunction (lua_State *L, int index) {
|
||||
LClosure *f;
|
||||
if (!lua_isfunction(L,index) || lua_iscfunction(L,index))
|
||||
luaG_runerror(L, "Only Lua function can share");
|
||||
LClosure *f = cast(LClosure *, lua_topointer(L, index));
|
||||
f = cast(LClosure *, lua_topointer(L, index));
|
||||
luaF_shareproto(f->p);
|
||||
}
|
||||
|
||||
LUA_API void lua_sharestring (lua_State *L, int index) {
|
||||
TString *ts;
|
||||
if (lua_type(L,index) != LUA_TSTRING)
|
||||
luaG_runerror(L, "need a string to share");
|
||||
TString *ts = tsvalue(index2value(L,index));
|
||||
ts = tsvalue(index2value(L,index));
|
||||
luaS_share(ts);
|
||||
}
|
||||
|
||||
@@ -1139,7 +1148,7 @@ LUA_API void lua_clonetable(lua_State *L, const void * tp) {
|
||||
luaG_runerror(L, "Not a shared table");
|
||||
|
||||
lua_lock(L);
|
||||
sethvalue2s(L, L->top, t);
|
||||
sethvalue2s(L, L->top.p, t);
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
@@ -1149,7 +1158,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
|
||||
TValue *o;
|
||||
lua_lock(L);
|
||||
api_checknelems(L, 1);
|
||||
o = s2v(L->top - 1);
|
||||
o = s2v(L->top.p - 1);
|
||||
if (isLfunction(o))
|
||||
status = luaU_dump(L, getproto(o), writer, data, strip);
|
||||
else
|
||||
@@ -1170,18 +1179,19 @@ LUA_API int lua_status (lua_State *L) {
|
||||
LUA_API int lua_gc (lua_State *L, int what, ...) {
|
||||
va_list argp;
|
||||
int res = 0;
|
||||
global_State *g;
|
||||
global_State *g = G(L);
|
||||
if (g->gcstp & GCSTPGC) /* internal stop? */
|
||||
return -1; /* all options are invalid when stopped */
|
||||
lua_lock(L);
|
||||
g = G(L);
|
||||
va_start(argp, what);
|
||||
switch (what) {
|
||||
case LUA_GCSTOP: {
|
||||
g->gcrunning = 0;
|
||||
g->gcstp = GCSTPUSR; /* stopped by the user */
|
||||
break;
|
||||
}
|
||||
case LUA_GCRESTART: {
|
||||
luaE_setdebt(g, 0);
|
||||
g->gcrunning = 1;
|
||||
g->gcstp = 0; /* (GCSTPGC must be already zero here) */
|
||||
break;
|
||||
}
|
||||
case LUA_GCCOLLECT: {
|
||||
@@ -1200,8 +1210,8 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
|
||||
case LUA_GCSTEP: {
|
||||
int data = va_arg(argp, int);
|
||||
l_mem debt = 1; /* =1 to signal that it did an actual step */
|
||||
lu_byte oldrunning = g->gcrunning;
|
||||
g->gcrunning = 1; /* allow GC to run */
|
||||
lu_byte oldstp = g->gcstp;
|
||||
g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */
|
||||
if (data == 0) {
|
||||
luaE_setdebt(g, 0); /* do a basic step */
|
||||
luaC_step(L);
|
||||
@@ -1211,7 +1221,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
|
||||
luaE_setdebt(g, debt);
|
||||
luaC_checkGC(L);
|
||||
}
|
||||
g->gcrunning = oldrunning; /* restore previous state */
|
||||
g->gcstp = oldstp; /* restore previous state */
|
||||
if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */
|
||||
res = 1; /* signal it */
|
||||
break;
|
||||
@@ -1229,7 +1239,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
|
||||
break;
|
||||
}
|
||||
case LUA_GCISRUNNING: {
|
||||
res = g->gcrunning;
|
||||
res = gcrunning(g);
|
||||
break;
|
||||
}
|
||||
case LUA_GCGEN: {
|
||||
@@ -1274,7 +1284,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
|
||||
LUA_API int lua_error (lua_State *L) {
|
||||
TValue *errobj;
|
||||
lua_lock(L);
|
||||
errobj = s2v(L->top - 1);
|
||||
errobj = s2v(L->top.p - 1);
|
||||
api_checknelems(L, 1);
|
||||
/* error object is the memory error message? */
|
||||
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
|
||||
@@ -1292,12 +1302,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
|
||||
lua_lock(L);
|
||||
api_checknelems(L, 1);
|
||||
t = gettable(L, idx);
|
||||
more = luaH_next(L, t, L->top - 1);
|
||||
more = luaH_next(L, t, L->top.p - 1);
|
||||
if (more) {
|
||||
api_incr_top(L);
|
||||
}
|
||||
else /* no more elements */
|
||||
L->top -= 1; /* remove key */
|
||||
L->top.p -= 1; /* remove key */
|
||||
lua_unlock(L);
|
||||
return more;
|
||||
}
|
||||
@@ -1309,7 +1319,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
|
||||
lua_lock(L);
|
||||
o = index2stack(L, idx);
|
||||
nresults = L->ci->nresults;
|
||||
api_check(L, L->tbclist < o, "given index below or equal a marked one");
|
||||
api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
|
||||
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
|
||||
if (!hastocloseCfunc(nresults)) /* function not marked yet? */
|
||||
L->ci->nresults = codeNresults(nresults); /* mark it */
|
||||
@@ -1324,7 +1334,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
|
||||
if (n > 0)
|
||||
luaV_concat(L, n);
|
||||
else { /* nothing to concatenate */
|
||||
setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */
|
||||
setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */
|
||||
api_incr_top(L);
|
||||
}
|
||||
luaC_checkGC(L);
|
||||
@@ -1336,7 +1346,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
|
||||
TValue *t;
|
||||
lua_lock(L);
|
||||
t = index2value(L, idx);
|
||||
luaV_objlen(L, L->top, t);
|
||||
luaV_objlen(L, L->top.p, t);
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
}
|
||||
@@ -1381,7 +1391,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
|
||||
lua_lock(L);
|
||||
api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
|
||||
u = luaS_newudata(L, size, nuvalue);
|
||||
setuvalue(L, s2v(L->top), u);
|
||||
setuvalue(L, s2v(L->top.p), u);
|
||||
api_incr_top(L);
|
||||
luaC_checkGC(L);
|
||||
lua_unlock(L);
|
||||
@@ -1407,7 +1417,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
|
||||
Proto *p = f->p;
|
||||
if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
|
||||
return NULL; /* 'n' not in [1, p->sizeupvalues] */
|
||||
*val = f->upvals[n-1]->v;
|
||||
*val = f->upvals[n-1]->v.p;
|
||||
if (owner) *owner = obj2gco(f->upvals[n - 1]);
|
||||
name = p->upvalues[n-1].name;
|
||||
return (name == NULL) ? "(no name)" : getstr(name);
|
||||
@@ -1423,7 +1433,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
|
||||
lua_lock(L);
|
||||
name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
|
||||
if (name) {
|
||||
setobj2s(L, L->top, val);
|
||||
setobj2s(L, L->top.p, val);
|
||||
api_incr_top(L);
|
||||
}
|
||||
lua_unlock(L);
|
||||
@@ -1441,8 +1451,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
|
||||
api_checknelems(L, 1);
|
||||
name = aux_upvalue(fi, n, &val, &owner);
|
||||
if (name) {
|
||||
L->top--;
|
||||
setobj(L, val, s2v(L->top));
|
||||
L->top.p--;
|
||||
setobj(L, val, s2v(L->top.p));
|
||||
luaC_barrier(L, owner, val);
|
||||
}
|
||||
lua_unlock(L);
|
||||
|
||||
@@ -12,23 +12,26 @@
|
||||
#include "lstate.h"
|
||||
|
||||
|
||||
/* Increments 'L->top', checking for stack overflows */
|
||||
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
|
||||
"stack overflow");}
|
||||
/* Increments 'L->top.p', checking for stack overflows */
|
||||
#define api_incr_top(L) {L->top.p++; \
|
||||
api_check(L, L->top.p <= L->ci->top.p, \
|
||||
"stack overflow");}
|
||||
|
||||
|
||||
/*
|
||||
** If a call returns too many multiple returns, the callee may not have
|
||||
** stack space to accommodate all results. In this case, this macro
|
||||
** increases its stack space ('L->ci->top').
|
||||
** increases its stack space ('L->ci->top.p').
|
||||
*/
|
||||
#define adjustresults(L,nres) \
|
||||
{ if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
|
||||
{ if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
|
||||
L->ci->top.p = L->top.p; }
|
||||
|
||||
|
||||
/* Ensure the stack has at least 'n' elements */
|
||||
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
|
||||
"not enough elements in the stack")
|
||||
#define api_checknelems(L,n) \
|
||||
api_check(L, (n) < (L->top.p - L->ci->func.p), \
|
||||
"not enough elements in the stack")
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -526,13 +526,14 @@ static void newbox (lua_State *L) {
|
||||
|
||||
/*
|
||||
** Compute new size for buffer 'B', enough to accommodate extra 'sz'
|
||||
** bytes.
|
||||
** bytes. (The test for "not big enough" also gets the case when the
|
||||
** computation of 'newsize' overflows.)
|
||||
*/
|
||||
static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
|
||||
size_t newsize = B->size * 2; /* double buffer size */
|
||||
size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */
|
||||
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
|
||||
return luaL_error(B->L, "buffer too large");
|
||||
if (newsize < B->n + sz) /* double is not big enough? */
|
||||
if (newsize < B->n + sz) /* not big enough? */
|
||||
newsize = B->n + sz;
|
||||
return newsize;
|
||||
}
|
||||
@@ -611,7 +612,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
|
||||
** box (if existent) is not on the top of the stack. So, instead of
|
||||
** calling 'luaL_addlstring', it replicates the code using -2 as the
|
||||
** last argument to 'prepbuffsize', signaling that the box is (or will
|
||||
** be) bellow the string being added to the buffer. (Box creation can
|
||||
** be) below the string being added to the buffer. (Box creation can
|
||||
** trigger an emergency GC, so we should not remove the string from the
|
||||
** stack before we have the space guaranteed.)
|
||||
*/
|
||||
@@ -739,17 +740,18 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
|
||||
}
|
||||
|
||||
|
||||
static int skipBOM (LoadF *lf) {
|
||||
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
|
||||
int c;
|
||||
lf->n = 0;
|
||||
do {
|
||||
c = getc(lf->f);
|
||||
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 */
|
||||
return getc(lf->f); /* return next character */
|
||||
/*
|
||||
** Skip an optional BOM at the start of a stream. If there is an
|
||||
** incomplete BOM (the first character is correct but the rest is
|
||||
** not), returns the first character anyway to force an error
|
||||
** (as no chunk can start with 0xEF).
|
||||
*/
|
||||
static int skipBOM (FILE *f) {
|
||||
int c = getc(f); /* read first character */
|
||||
if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
|
||||
return getc(f); /* ignore BOM and return next char */
|
||||
else /* no (valid) BOM */
|
||||
return c; /* return first character */
|
||||
}
|
||||
|
||||
|
||||
@@ -760,13 +762,13 @@ static int skipBOM (LoadF *lf) {
|
||||
** first "valid" character of the file (after the optional BOM and
|
||||
** a first-line comment).
|
||||
*/
|
||||
static int skipcomment (LoadF *lf, int *cp) {
|
||||
int c = *cp = skipBOM(lf);
|
||||
static int skipcomment (FILE *f, int *cp) {
|
||||
int c = *cp = skipBOM(f);
|
||||
if (c == '#') { /* first line is a comment (Unix exec. file)? */
|
||||
do { /* skip first line */
|
||||
c = getc(lf->f);
|
||||
c = getc(f);
|
||||
} while (c != EOF && c != '\n');
|
||||
*cp = getc(lf->f); /* skip end-of-line, if present */
|
||||
*cp = getc(f); /* next character after comment, if present */
|
||||
return 1; /* there was a comment */
|
||||
}
|
||||
else return 0; /* no comment */
|
||||
@@ -788,12 +790,16 @@ LUALIB_API int luaL_loadfilex_ (lua_State *L, const char *filename,
|
||||
lf.f = fopen(filename, "r");
|
||||
if (lf.f == NULL) return errfile(L, "open", fnameindex);
|
||||
}
|
||||
if (skipcomment(&lf, &c)) /* read initial portion */
|
||||
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
|
||||
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
|
||||
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
|
||||
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
|
||||
skipcomment(&lf, &c); /* re-read initial portion */
|
||||
lf.n = 0;
|
||||
if (skipcomment(lf.f, &c)) /* read initial portion */
|
||||
lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
|
||||
if (c == LUA_SIGNATURE[0]) { /* binary file? */
|
||||
lf.n = 0; /* remove possible newline */
|
||||
if (filename) { /* "real" file? */
|
||||
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
|
||||
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
|
||||
skipcomment(lf.f, &c); /* re-read initial portion */
|
||||
}
|
||||
}
|
||||
if (c != EOF)
|
||||
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
|
||||
@@ -881,6 +887,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
|
||||
|
||||
|
||||
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
||||
idx = lua_absindex(L,idx);
|
||||
if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */
|
||||
if (!lua_isstring(L, -1))
|
||||
luaL_error(L, "'__tostring' must return a string");
|
||||
@@ -1115,7 +1122,7 @@ struct codecache {
|
||||
static struct codecache CC;
|
||||
|
||||
static void
|
||||
clearcache() {
|
||||
clearcache(void) {
|
||||
if (CC.L == NULL)
|
||||
return;
|
||||
SPIN_LOCK(&CC)
|
||||
@@ -1125,10 +1132,13 @@ clearcache() {
|
||||
}
|
||||
|
||||
static void
|
||||
init() {
|
||||
init(void) {
|
||||
CC.L = luaL_newstate();
|
||||
}
|
||||
|
||||
|
||||
void luaL_initcodecache(void);
|
||||
|
||||
LUALIB_API void
|
||||
luaL_initcodecache(void) {
|
||||
SPIN_INIT(&CC);
|
||||
@@ -1136,13 +1146,15 @@ luaL_initcodecache(void) {
|
||||
|
||||
static const void *
|
||||
load_proto(const char *key) {
|
||||
lua_State *L;
|
||||
const void * result;
|
||||
if (CC.L == NULL)
|
||||
return NULL;
|
||||
SPIN_LOCK(&CC)
|
||||
lua_State *L = CC.L;
|
||||
L = CC.L;
|
||||
lua_pushstring(L, key);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
const void * result = lua_touserdata(L, -1);
|
||||
result = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
SPIN_UNLOCK(&CC)
|
||||
|
||||
@@ -1198,9 +1210,10 @@ static int cache_mode(lua_State *L) {
|
||||
"ON",
|
||||
NULL,
|
||||
};
|
||||
int t,r;
|
||||
if (lua_isnoneornil(L,1)) {
|
||||
int t = lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key);
|
||||
int r = lua_tointeger(L, -1);
|
||||
t = lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key);
|
||||
r = lua_tointeger(L, -1);
|
||||
if (t == LUA_TNUMBER) {
|
||||
if (r < 0 || r >= CACHE_ON) {
|
||||
r = CACHE_ON;
|
||||
@@ -1211,7 +1224,7 @@ static int cache_mode(lua_State *L) {
|
||||
lua_pushstring(L, lst[r]);
|
||||
return 1;
|
||||
}
|
||||
int t = luaL_checkoption(L, 1, "OFF" , lst);
|
||||
t = luaL_checkoption(L, 1, "OFF" , lst);
|
||||
lua_pushinteger(L, t);
|
||||
lua_rawsetp(L, LUA_REGISTRYINDEX, &cache_key);
|
||||
return 0;
|
||||
@@ -1220,10 +1233,14 @@ static int cache_mode(lua_State *L) {
|
||||
LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
|
||||
const char *mode) {
|
||||
int level = cache_level(L);
|
||||
const void * proto;
|
||||
lua_State * eL;
|
||||
int err;
|
||||
const void * oldv;
|
||||
if (level == CACHE_OFF) {
|
||||
return luaL_loadfilex_(L, filename, mode);
|
||||
}
|
||||
const void * proto = load_proto(filename);
|
||||
proto = load_proto(filename);
|
||||
if (proto) {
|
||||
lua_clonefunction(L, proto);
|
||||
return LUA_OK;
|
||||
@@ -1231,12 +1248,12 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
|
||||
if (level == CACHE_EXIST) {
|
||||
return luaL_loadfilex_(L, filename, mode);
|
||||
}
|
||||
lua_State * eL = luaL_newstate();
|
||||
eL = luaL_newstate();
|
||||
if (eL == NULL) {
|
||||
lua_pushliteral(L, "New state failed");
|
||||
return LUA_ERRMEM;
|
||||
}
|
||||
int err = luaL_loadfilex_(eL, filename, mode);
|
||||
err = luaL_loadfilex_(eL, filename, mode);
|
||||
if (err != LUA_OK) {
|
||||
size_t sz = 0;
|
||||
const char * msg = lua_tolstring(eL, -1, &sz);
|
||||
@@ -1246,7 +1263,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
|
||||
}
|
||||
lua_sharefunction(eL, -1);
|
||||
proto = lua_topointer(eL, -1);
|
||||
const void * oldv = save_proto(filename, proto);
|
||||
oldv = save_proto(filename, proto);
|
||||
if (oldv) {
|
||||
lua_close(eL);
|
||||
lua_clonefunction(L, oldv);
|
||||
@@ -1265,6 +1282,8 @@ cache_clear(lua_State *L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int luaopen_cache(lua_State *L);
|
||||
|
||||
LUAMOD_API int luaopen_cache(lua_State *L) {
|
||||
luaL_Reg l[] = {
|
||||
{ "clear", cache_clear },
|
||||
|
||||
@@ -104,7 +104,7 @@ LUALIB_API lua_State *(luaL_newstate) (void);
|
||||
|
||||
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
|
||||
|
||||
LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s,
|
||||
LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s,
|
||||
const char *p, const char *r);
|
||||
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s,
|
||||
const char *p, const char *r);
|
||||
@@ -156,6 +156,14 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
|
||||
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
|
||||
|
||||
|
||||
/*
|
||||
** Perform arithmetic operations on lua_Integer values with wrap-around
|
||||
** semantics, as the Lua core does.
|
||||
*/
|
||||
#define luaL_intop(op,v1,v2) \
|
||||
((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2)))
|
||||
|
||||
|
||||
/* push the value used to represent failure/error */
|
||||
#define luaL_pushfail(L) lua_pushnil(L)
|
||||
|
||||
|
||||
@@ -182,12 +182,20 @@ static int luaB_rawset (lua_State *L) {
|
||||
|
||||
|
||||
static int pushmode (lua_State *L, int oldmode) {
|
||||
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
|
||||
: "generational");
|
||||
if (oldmode == -1)
|
||||
luaL_pushfail(L); /* invalid call to 'lua_gc' */
|
||||
else
|
||||
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
|
||||
: "generational");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** check whether call to 'lua_gc' was valid (not inside a finalizer)
|
||||
*/
|
||||
#define checkvalres(res) { if (res == -1) break; }
|
||||
|
||||
static int luaB_collectgarbage (lua_State *L) {
|
||||
static const char *const opts[] = {"stop", "restart", "collect",
|
||||
"count", "step", "setpause", "setstepmul",
|
||||
@@ -200,12 +208,14 @@ static int luaB_collectgarbage (lua_State *L) {
|
||||
case LUA_GCCOUNT: {
|
||||
int k = lua_gc(L, o);
|
||||
int b = lua_gc(L, LUA_GCCOUNTB);
|
||||
checkvalres(k);
|
||||
lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024));
|
||||
return 1;
|
||||
}
|
||||
case LUA_GCSTEP: {
|
||||
int step = (int)luaL_optinteger(L, 2, 0);
|
||||
int res = lua_gc(L, o, step);
|
||||
checkvalres(res);
|
||||
lua_pushboolean(L, res);
|
||||
return 1;
|
||||
}
|
||||
@@ -213,11 +223,13 @@ static int luaB_collectgarbage (lua_State *L) {
|
||||
case LUA_GCSETSTEPMUL: {
|
||||
int p = (int)luaL_optinteger(L, 2, 0);
|
||||
int previous = lua_gc(L, o, p);
|
||||
checkvalres(previous);
|
||||
lua_pushinteger(L, previous);
|
||||
return 1;
|
||||
}
|
||||
case LUA_GCISRUNNING: {
|
||||
int res = lua_gc(L, o);
|
||||
checkvalres(res);
|
||||
lua_pushboolean(L, res);
|
||||
return 1;
|
||||
}
|
||||
@@ -234,10 +246,13 @@ static int luaB_collectgarbage (lua_State *L) {
|
||||
}
|
||||
default: {
|
||||
int res = lua_gc(L, o);
|
||||
checkvalres(res);
|
||||
lua_pushinteger(L, res);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
luaL_pushfail(L); /* invalid call (inside a finalizer) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -261,6 +276,11 @@ static int luaB_next (lua_State *L) {
|
||||
}
|
||||
|
||||
|
||||
static int pairscont (lua_State *L, int status, lua_KContext k) {
|
||||
(void)L; (void)status; (void)k; /* unused */
|
||||
return 3;
|
||||
}
|
||||
|
||||
static int luaB_pairs (lua_State *L) {
|
||||
luaL_checkany(L, 1);
|
||||
if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */
|
||||
@@ -270,7 +290,7 @@ static int luaB_pairs (lua_State *L) {
|
||||
}
|
||||
else {
|
||||
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
|
||||
lua_call(L, 1, 3); /* get 3 values from metamethod */
|
||||
lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
@@ -280,7 +300,8 @@ static int luaB_pairs (lua_State *L) {
|
||||
** Traversal function for 'ipairs'
|
||||
*/
|
||||
static int ipairsaux (lua_State *L) {
|
||||
lua_Integer i = luaL_checkinteger(L, 2) + 1;
|
||||
lua_Integer i = luaL_checkinteger(L, 2);
|
||||
i = luaL_intop(+, i, 1);
|
||||
lua_pushinteger(L, i);
|
||||
return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2;
|
||||
}
|
||||
|
||||
104
3rd/lua/lcode.c
104
3rd/lua/lcode.c
@@ -10,6 +10,7 @@
|
||||
#include "lprefix.h"
|
||||
|
||||
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
@@ -580,24 +581,41 @@ static int stringK (FuncState *fs, TString *s) {
|
||||
|
||||
/*
|
||||
** Add an integer to list of constants and return its index.
|
||||
** Integers use userdata as keys to avoid collision with floats with
|
||||
** same value; conversion to 'void*' is used only for hashing, so there
|
||||
** are no "precision" problems.
|
||||
*/
|
||||
static int luaK_intK (FuncState *fs, lua_Integer n) {
|
||||
TValue k, o;
|
||||
setpvalue(&k, cast_voidp(cast_sizet(n)));
|
||||
TValue o;
|
||||
setivalue(&o, n);
|
||||
return addk(fs, &k, &o);
|
||||
return addk(fs, &o, &o); /* use integer itself as key */
|
||||
}
|
||||
|
||||
/*
|
||||
** Add a float to list of constants and return its index.
|
||||
** Add a float to list of constants and return its index. Floats
|
||||
** with integral values need a different key, to avoid collision
|
||||
** with actual integers. To that, we add to the number its smaller
|
||||
** power-of-two fraction that is still significant in its scale.
|
||||
** For doubles, that would be 1/2^52.
|
||||
** (This method is not bulletproof: there may be another float
|
||||
** with that value, and for floats larger than 2^53 the result is
|
||||
** still an integer. At worst, this only wastes an entry with
|
||||
** a duplicate.)
|
||||
*/
|
||||
static int luaK_numberK (FuncState *fs, lua_Number r) {
|
||||
TValue o;
|
||||
lua_Integer ik;
|
||||
setfltvalue(&o, r);
|
||||
return addk(fs, &o, &o); /* use number itself as key */
|
||||
if (!luaV_flttointeger(r, &ik, F2Ieq)) /* not an integral value? */
|
||||
return addk(fs, &o, &o); /* use number itself as key */
|
||||
else { /* must build an alternative key */
|
||||
const int nbm = l_floatatt(MANT_DIG);
|
||||
const lua_Number q = l_mathop(ldexp)(l_mathop(1.0), -nbm + 1);
|
||||
const lua_Number k = (ik == 0) ? q : r + r*q; /* new key */
|
||||
TValue kv;
|
||||
setfltvalue(&kv, k);
|
||||
/* result is not an integral value, unless value is too large */
|
||||
lua_assert(!luaV_flttointeger(k, &ik, F2Ieq) ||
|
||||
l_mathop(fabs)(r) >= l_mathop(1e6));
|
||||
return addk(fs, &kv, &o);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1373,7 +1391,10 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
|
||||
*/
|
||||
static void codebinexpval (FuncState *fs, OpCode op,
|
||||
expdesc *e1, expdesc *e2, int line) {
|
||||
int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */
|
||||
int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */
|
||||
/* 'e1' must be already in a register or it is a constant */
|
||||
lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
|
||||
e1->k == VNONRELOC || e1->k == VRELOC);
|
||||
lua_assert(OP_ADD <= op && op <= OP_SHR);
|
||||
finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN,
|
||||
cast(TMS, (op - OP_ADD) + TM_ADD));
|
||||
@@ -1392,6 +1413,18 @@ static void codebini (FuncState *fs, OpCode op,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Code binary operators with K operand.
|
||||
*/
|
||||
static void codebinK (FuncState *fs, BinOpr opr,
|
||||
expdesc *e1, expdesc *e2, int flip, int line) {
|
||||
TMS event = cast(TMS, opr + TM_ADD);
|
||||
int v2 = e2->u.info; /* K index */
|
||||
OpCode op = cast(OpCode, opr + OP_ADDK);
|
||||
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
|
||||
}
|
||||
|
||||
|
||||
/* Try to code a binary operator negating its second operand.
|
||||
** For the metamethod, 2nd operand must keep its original value.
|
||||
*/
|
||||
@@ -1419,24 +1452,28 @@ static void swapexps (expdesc *e1, expdesc *e2) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Code binary operators with no constant operand.
|
||||
*/
|
||||
static void codebinNoK (FuncState *fs, BinOpr opr,
|
||||
expdesc *e1, expdesc *e2, int flip, int line) {
|
||||
OpCode op = cast(OpCode, opr + OP_ADD);
|
||||
if (flip)
|
||||
swapexps(e1, e2); /* back to original order */
|
||||
codebinexpval(fs, op, e1, e2, line); /* use standard operators */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Code arithmetic operators ('+', '-', ...). If second operand is a
|
||||
** constant in the proper range, use variant opcodes with K operands.
|
||||
*/
|
||||
static void codearith (FuncState *fs, BinOpr opr,
|
||||
expdesc *e1, expdesc *e2, int flip, int line) {
|
||||
TMS event = cast(TMS, opr + TM_ADD);
|
||||
if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */
|
||||
int v2 = e2->u.info; /* K index */
|
||||
OpCode op = cast(OpCode, opr + OP_ADDK);
|
||||
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
|
||||
}
|
||||
else { /* 'e2' is neither an immediate nor a K operand */
|
||||
OpCode op = cast(OpCode, opr + OP_ADD);
|
||||
if (flip)
|
||||
swapexps(e1, e2); /* back to original order */
|
||||
codebinexpval(fs, op, e1, e2, line); /* use standard operators */
|
||||
}
|
||||
if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */
|
||||
codebinK(fs, opr, e1, e2, flip, line);
|
||||
else /* 'e2' is neither an immediate nor a K operand */
|
||||
codebinNoK(fs, opr, e1, e2, flip, line);
|
||||
}
|
||||
|
||||
|
||||
@@ -1460,28 +1497,20 @@ static void codecommutative (FuncState *fs, BinOpr op,
|
||||
|
||||
|
||||
/*
|
||||
** Code bitwise operations; they are all associative, so the function
|
||||
** Code bitwise operations; they are all commutative, so the function
|
||||
** tries to put an integer constant as the 2nd operand (a K operand).
|
||||
*/
|
||||
static void codebitwise (FuncState *fs, BinOpr opr,
|
||||
expdesc *e1, expdesc *e2, int line) {
|
||||
int flip = 0;
|
||||
int v2;
|
||||
OpCode op;
|
||||
if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
|
||||
if (e1->k == VKINT) {
|
||||
swapexps(e1, e2); /* 'e2' will be the constant operand */
|
||||
flip = 1;
|
||||
}
|
||||
else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */
|
||||
op = cast(OpCode, opr + OP_ADD);
|
||||
codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */
|
||||
return;
|
||||
}
|
||||
v2 = e2->u.info; /* index in K array */
|
||||
op = cast(OpCode, opr + OP_ADDK);
|
||||
lua_assert(ttisinteger(&fs->f->k[v2]));
|
||||
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
|
||||
cast(TMS, opr + TM_ADD));
|
||||
if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */
|
||||
codebinK(fs, opr, e1, e2, flip, line);
|
||||
else /* no constants */
|
||||
codebinNoK(fs, opr, e1, e2, flip, line);
|
||||
}
|
||||
|
||||
|
||||
@@ -1533,7 +1562,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
|
||||
op = OP_EQI;
|
||||
r2 = im; /* immediate operand */
|
||||
}
|
||||
else if (luaK_exp2RK(fs, e2)) { /* 1st expression is constant? */
|
||||
else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */
|
||||
op = OP_EQK;
|
||||
r2 = e2->u.info; /* constant index */
|
||||
}
|
||||
@@ -1593,7 +1622,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
|
||||
case OPR_SHL: case OPR_SHR: {
|
||||
if (!tonumeral(v, NULL))
|
||||
luaK_exp2anyreg(fs, v);
|
||||
/* else keep numeral, which may be folded with 2nd operand */
|
||||
/* else keep numeral, which may be folded or used as an immediate
|
||||
operand */
|
||||
break;
|
||||
}
|
||||
case OPR_EQ: case OPR_NE: {
|
||||
|
||||
@@ -76,9 +76,9 @@ static int luaB_auxwrap (lua_State *L) {
|
||||
if (l_unlikely(r < 0)) { /* error? */
|
||||
int stat = lua_status(co);
|
||||
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
|
||||
stat = lua_resetthread(co); /* close its tbc variables */
|
||||
stat = lua_resetthread(co, L); /* close its tbc variables */
|
||||
lua_assert(stat != LUA_OK);
|
||||
lua_xmove(co, L, 1); /* copy error message */
|
||||
lua_xmove(co, L, 1); /* move error message to the caller */
|
||||
}
|
||||
if (stat != LUA_ERRMEM && /* not a memory error and ... */
|
||||
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
|
||||
@@ -172,14 +172,14 @@ static int luaB_close (lua_State *L) {
|
||||
int status = auxstatus(L, co);
|
||||
switch (status) {
|
||||
case COS_DEAD: case COS_YIELD: {
|
||||
status = lua_resetthread(co);
|
||||
status = lua_resetthread(co, L);
|
||||
if (status == LUA_OK) {
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
lua_pushboolean(L, 0);
|
||||
lua_xmove(co, L, 1); /* copy error message */
|
||||
lua_xmove(co, L, 1); /* move error message */
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
158
3rd/lua/ldebug.c
158
3rd/lua/ldebug.c
@@ -34,8 +34,8 @@
|
||||
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL)
|
||||
|
||||
|
||||
static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
|
||||
const char **name);
|
||||
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
|
||||
const char **name);
|
||||
|
||||
|
||||
static int currentpc (CallInfo *ci) {
|
||||
@@ -64,7 +64,7 @@ static int getbaseline (const Proto *f, int pc, int *basepc) {
|
||||
}
|
||||
else {
|
||||
int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */
|
||||
/* estimate must be a lower bond of the correct base */
|
||||
/* estimate must be a lower bound of the correct base */
|
||||
lua_assert(i < 0 ||
|
||||
(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
|
||||
while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
|
||||
@@ -182,10 +182,10 @@ static const char *upvalname (const Proto *p, int uv) {
|
||||
|
||||
|
||||
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
||||
if (clLvalue(s2v(ci->func))->p->is_vararg) {
|
||||
if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
|
||||
int nextra = ci->u.l.nextraargs;
|
||||
if (n >= -nextra) { /* 'n' is negative */
|
||||
*pos = ci->func - nextra - (n + 1);
|
||||
*pos = ci->func.p - nextra - (n + 1);
|
||||
return "(vararg)"; /* generic name for any vararg */
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
|
||||
|
||||
|
||||
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
|
||||
StkId base = ci->func + 1;
|
||||
StkId base = ci->func.p + 1;
|
||||
const char *name = NULL;
|
||||
if (isLua(ci)) {
|
||||
if (n < 0) /* access to vararg values? */
|
||||
@@ -203,7 +203,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
|
||||
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
|
||||
}
|
||||
if (name == NULL) { /* no 'standard' name? */
|
||||
StkId limit = (ci == L->ci) ? L->top : ci->next->func;
|
||||
StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
|
||||
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
|
||||
/* generic name for any valid slot */
|
||||
name = isLua(ci) ? "(temporary)" : "(C temporary)";
|
||||
@@ -221,16 +221,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||
const char *name;
|
||||
lua_lock(L);
|
||||
if (ar == NULL) { /* information about non-active function? */
|
||||
if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */
|
||||
if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
|
||||
name = NULL;
|
||||
else /* consider live variables at function start (parameters) */
|
||||
name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0);
|
||||
name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
|
||||
}
|
||||
else { /* active function; get information through 'ar' */
|
||||
StkId pos = NULL; /* to avoid warnings */
|
||||
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
||||
if (name) {
|
||||
setobjs2s(L, L->top, pos);
|
||||
setobjs2s(L, L->top.p, pos);
|
||||
api_incr_top(L);
|
||||
}
|
||||
}
|
||||
@@ -245,8 +245,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
|
||||
lua_lock(L);
|
||||
name = luaG_findlocal(L, ar->i_ci, n, &pos);
|
||||
if (name) {
|
||||
setobjs2s(L, pos, L->top - 1);
|
||||
L->top--; /* pop value */
|
||||
setobjs2s(L, pos, L->top.p - 1);
|
||||
L->top.p--; /* pop value */
|
||||
}
|
||||
lua_unlock(L);
|
||||
return name;
|
||||
@@ -289,7 +289,7 @@ static int nextline (const Proto *p, int currentline, int pc) {
|
||||
|
||||
static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
if (noLuaClosure(f)) {
|
||||
setnilvalue(s2v(L->top));
|
||||
setnilvalue(s2v(L->top.p));
|
||||
api_incr_top(L);
|
||||
}
|
||||
else {
|
||||
@@ -298,10 +298,17 @@ static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
const Proto *p = f->l.p;
|
||||
int currentline = p->linedefined;
|
||||
Table *t = luaH_new(L); /* new table to store active lines */
|
||||
sethvalue2s(L, L->top, t); /* push it on stack */
|
||||
sethvalue2s(L, L->top.p, t); /* push it on stack */
|
||||
api_incr_top(L);
|
||||
setbtvalue(&v); /* boolean 'true' to be the value of all indices */
|
||||
for (i = 0; i < p->sizelineinfo; i++) { /* for all instructions */
|
||||
if (!p->is_vararg) /* regular function? */
|
||||
i = 0; /* consider all instructions */
|
||||
else { /* vararg function */
|
||||
lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP);
|
||||
currentline = nextline(p, currentline, 0);
|
||||
i = 1; /* skip first instruction (OP_VARARGPREP) */
|
||||
}
|
||||
for (; i < p->sizelineinfo; i++) { /* for each instruction */
|
||||
currentline = nextline(p, currentline, i); /* get its line */
|
||||
luaH_setint(L, t, currentline, &v); /* table[line] = true */
|
||||
}
|
||||
@@ -310,15 +317,9 @@ static void collectvalidlines (lua_State *L, Closure *f) {
|
||||
|
||||
|
||||
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
|
||||
if (ci == NULL) /* no 'ci'? */
|
||||
return NULL; /* no info */
|
||||
else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */
|
||||
*name = "__gc";
|
||||
return "metamethod"; /* report it as such */
|
||||
}
|
||||
/* calling function is a known Lua function? */
|
||||
else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
|
||||
return funcnamefromcode(L, ci->previous, name);
|
||||
/* calling function is a known function? */
|
||||
if (ci != NULL && !(ci->callstatus & CIST_TAIL))
|
||||
return funcnamefromcall(L, ci->previous, name);
|
||||
else return NULL; /* no way to find a name */
|
||||
}
|
||||
|
||||
@@ -387,20 +388,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
|
||||
lua_lock(L);
|
||||
if (*what == '>') {
|
||||
ci = NULL;
|
||||
func = s2v(L->top - 1);
|
||||
func = s2v(L->top.p - 1);
|
||||
api_check(L, ttisfunction(func), "function expected");
|
||||
what++; /* skip the '>' */
|
||||
L->top--; /* pop function */
|
||||
L->top.p--; /* pop function */
|
||||
}
|
||||
else {
|
||||
ci = ar->i_ci;
|
||||
func = s2v(ci->func);
|
||||
func = s2v(ci->func.p);
|
||||
lua_assert(ttisfunction(func));
|
||||
}
|
||||
cl = ttisclosure(func) ? clvalue(func) : NULL;
|
||||
status = auxgetinfo(L, what, ar, cl, ci);
|
||||
if (strchr(what, 'f')) {
|
||||
setobj2s(L, L->top, func);
|
||||
setobj2s(L, L->top.p, func);
|
||||
api_incr_top(L);
|
||||
}
|
||||
if (strchr(what, 'L'))
|
||||
@@ -590,16 +591,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg,
|
||||
** Returns what the name is (e.g., "for iterator", "method",
|
||||
** "metamethod") and sets '*name' to point to the name.
|
||||
*/
|
||||
static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
|
||||
const char **name) {
|
||||
static const char *funcnamefromcode (lua_State *L, const Proto *p,
|
||||
int pc, const char **name) {
|
||||
TMS tm = (TMS)0; /* (initial value avoids warnings) */
|
||||
const Proto *p = ci_func(ci)->p; /* calling function */
|
||||
int pc = currentpc(ci); /* calling instruction index */
|
||||
Instruction i = p->code[pc]; /* calling instruction */
|
||||
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
|
||||
*name = "?";
|
||||
return "hook";
|
||||
}
|
||||
switch (GET_OPCODE(i)) {
|
||||
case OP_CALL:
|
||||
case OP_TAILCALL:
|
||||
@@ -636,6 +631,26 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
|
||||
return "metamethod";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to find a name for a function based on how it was called.
|
||||
*/
|
||||
static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
|
||||
const char **name) {
|
||||
if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */
|
||||
*name = "?";
|
||||
return "hook";
|
||||
}
|
||||
else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */
|
||||
*name = "__gc";
|
||||
return "metamethod"; /* report it as such */
|
||||
}
|
||||
else if (isLua(ci))
|
||||
return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
@@ -648,7 +663,7 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
|
||||
*/
|
||||
static int isinstack (CallInfo *ci, const TValue *o) {
|
||||
StkId pos;
|
||||
for (pos = ci->func + 1; pos < ci->top; pos++) {
|
||||
for (pos = ci->func.p + 1; pos < ci->top.p; pos++) {
|
||||
if (o == s2v(pos))
|
||||
return 1;
|
||||
}
|
||||
@@ -666,7 +681,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
|
||||
LClosure *c = ci_func(ci);
|
||||
int i;
|
||||
for (i = 0; i < c->nupvalues; i++) {
|
||||
if (c->upvals[i]->v == o) {
|
||||
if (c->upvals[i]->v.p == o) {
|
||||
*name = upvalname(c->p, i);
|
||||
return "upvalue";
|
||||
}
|
||||
@@ -675,36 +690,62 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
|
||||
}
|
||||
|
||||
|
||||
static const char *formatvarinfo (lua_State *L, const char *kind,
|
||||
const char *name) {
|
||||
if (kind == NULL)
|
||||
return ""; /* no information */
|
||||
else
|
||||
return luaO_pushfstring(L, " (%s '%s')", kind, name);
|
||||
}
|
||||
|
||||
/*
|
||||
** Build a string with a "description" for the value 'o', such as
|
||||
** "variable 'x'" or "upvalue 'y'".
|
||||
*/
|
||||
static const char *varinfo (lua_State *L, const TValue *o) {
|
||||
const char *name = NULL; /* to avoid warnings */
|
||||
CallInfo *ci = L->ci;
|
||||
const char *name = NULL; /* to avoid warnings */
|
||||
const char *kind = NULL;
|
||||
if (isLua(ci)) {
|
||||
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
|
||||
if (!kind && isinstack(ci, o)) /* no? try a register */
|
||||
kind = getobjname(ci_func(ci)->p, currentpc(ci),
|
||||
cast_int(cast(StkId, o) - (ci->func + 1)), &name);
|
||||
cast_int(cast(StkId, o) - (ci->func.p + 1)), &name);
|
||||
}
|
||||
return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : "";
|
||||
return formatvarinfo(L, kind, name);
|
||||
}
|
||||
|
||||
|
||||
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
|
||||
/*
|
||||
** Raise a type error
|
||||
*/
|
||||
static l_noret typeerror (lua_State *L, const TValue *o, const char *op,
|
||||
const char *extra) {
|
||||
const char *t = luaT_objtypename(L, o);
|
||||
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
|
||||
luaG_runerror(L, "attempt to %s a %s value%s", op, t, extra);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Raise a type error with "standard" information about the faulty
|
||||
** object 'o' (using 'varinfo').
|
||||
*/
|
||||
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
|
||||
typeerror(L, o, op, varinfo(L, o));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Raise an error for calling a non-callable object. Try to find a name
|
||||
** for the object based on how it was called ('funcnamefromcall'); if it
|
||||
** cannot get a name there, try 'varinfo'.
|
||||
*/
|
||||
l_noret luaG_callerror (lua_State *L, const TValue *o) {
|
||||
CallInfo *ci = L->ci;
|
||||
const char *name = NULL; /* to avoid warnings */
|
||||
const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL;
|
||||
if (what != NULL) {
|
||||
const char *t = luaT_objtypename(L, o);
|
||||
luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t);
|
||||
}
|
||||
else
|
||||
luaG_typeerror(L, o, "call");
|
||||
const char *kind = funcnamefromcall(L, ci, &name);
|
||||
const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o);
|
||||
typeerror(L, o, "call", extra);
|
||||
}
|
||||
|
||||
|
||||
@@ -766,10 +807,10 @@ l_noret luaG_errormsg (lua_State *L) {
|
||||
if (L->errfunc != 0) { /* is there an error handling function? */
|
||||
StkId errfunc = restorestack(L, L->errfunc);
|
||||
lua_assert(ttisfunction(s2v(errfunc)));
|
||||
setobjs2s(L, L->top, L->top - 1); /* move argument */
|
||||
setobjs2s(L, L->top - 1, errfunc); /* push function */
|
||||
L->top++; /* assume EXTRA_STACK */
|
||||
luaD_callnoyield(L, L->top - 2, 1); /* call it */
|
||||
setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
|
||||
setobjs2s(L, L->top.p - 1, errfunc); /* push function */
|
||||
L->top.p++; /* assume EXTRA_STACK */
|
||||
luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
|
||||
}
|
||||
luaD_throw(L, LUA_ERRRUN);
|
||||
}
|
||||
@@ -783,8 +824,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
|
||||
va_start(argp, fmt);
|
||||
msg = luaO_pushvfstring(L, fmt, argp); /* format message */
|
||||
va_end(argp);
|
||||
if (isLua(ci)) /* if Lua function, add source:line information */
|
||||
if (isLua(ci)) { /* if Lua function, add source:line information */
|
||||
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
|
||||
setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
|
||||
L->top.p--;
|
||||
}
|
||||
luaG_errormsg(L);
|
||||
}
|
||||
|
||||
@@ -828,7 +872,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
|
||||
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
|
||||
** at most causes an extra call to a line hook.)
|
||||
** This function is not "Protected" when called, so it should correct
|
||||
** 'L->top' before calling anything that can run the GC.
|
||||
** 'L->top.p' before calling anything that can run the GC.
|
||||
*/
|
||||
int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
||||
CallInfo *ci = L->ci;
|
||||
@@ -851,7 +895,7 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
|
||||
return 1; /* do not call hook again (VM yielded, so it did not move) */
|
||||
}
|
||||
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
|
||||
L->top = ci->top; /* correct top */
|
||||
L->top.p = ci->top.p; /* correct top */
|
||||
if (counthook)
|
||||
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
|
||||
if (mask & LUA_MASKLINE) {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
|
||||
/* Active Lua function (given call info) */
|
||||
#define ci_func(ci) (clLvalue(s2v((ci)->func)))
|
||||
#define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
|
||||
|
||||
|
||||
#define resethookcount(L) (L->hookcount = L->basehookcount)
|
||||
|
||||
337
3rd/lua/ldo.c
337
3rd/lua/ldo.c
@@ -104,11 +104,11 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
|
||||
}
|
||||
default: {
|
||||
lua_assert(errorstatus(errcode)); /* real error */
|
||||
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
|
||||
setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */
|
||||
break;
|
||||
}
|
||||
}
|
||||
L->top = oldtop + 1;
|
||||
L->top.p = oldtop + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
|
||||
global_State *g = G(L);
|
||||
errcode = luaE_resetthread(L, errcode); /* close all upvalues */
|
||||
if (g->mainthread->errorJmp) { /* main thread has a handler? */
|
||||
setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
|
||||
setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */
|
||||
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
|
||||
}
|
||||
else { /* no handler at all; abort */
|
||||
@@ -157,16 +157,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
||||
** Stack reallocation
|
||||
** ===================================================================
|
||||
*/
|
||||
static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
|
||||
|
||||
|
||||
/*
|
||||
** Change all pointers to the stack into offsets.
|
||||
*/
|
||||
static void relstack (lua_State *L) {
|
||||
CallInfo *ci;
|
||||
UpVal *up;
|
||||
L->top = (L->top - oldstack) + newstack;
|
||||
L->tbclist = (L->tbclist - oldstack) + newstack;
|
||||
L->top.offset = savestack(L, L->top.p);
|
||||
L->tbclist.offset = savestack(L, L->tbclist.p);
|
||||
for (up = L->openupval; up != NULL; up = up->u.open.next)
|
||||
up->v = s2v((uplevel(up) - oldstack) + newstack);
|
||||
up->v.offset = savestack(L, uplevel(up));
|
||||
for (ci = L->ci; ci != NULL; ci = ci->previous) {
|
||||
ci->top = (ci->top - oldstack) + newstack;
|
||||
ci->func = (ci->func - oldstack) + newstack;
|
||||
ci->top.offset = savestack(L, ci->top.p);
|
||||
ci->func.offset = savestack(L, ci->func.p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Change back all offsets into pointers.
|
||||
*/
|
||||
static void correctstack (lua_State *L) {
|
||||
CallInfo *ci;
|
||||
UpVal *up;
|
||||
L->top.p = restorestack(L, L->top.offset);
|
||||
L->tbclist.p = restorestack(L, L->tbclist.offset);
|
||||
for (up = L->openupval; up != NULL; up = up->u.open.next)
|
||||
up->v.p = s2v(restorestack(L, up->v.offset));
|
||||
for (ci = L->ci; ci != NULL; ci = ci->previous) {
|
||||
ci->top.p = restorestack(L, ci->top.offset);
|
||||
ci->func.p = restorestack(L, ci->func.offset);
|
||||
if (isLua(ci))
|
||||
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
|
||||
}
|
||||
@@ -176,44 +198,45 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
|
||||
/* some space for error handling */
|
||||
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
|
||||
|
||||
|
||||
/*
|
||||
** Reallocate the stack to a new size, correcting all pointers into
|
||||
** it. (There are pointers to a stack from its upvalues, from its list
|
||||
** of call infos, plus a few individual pointers.) The reallocation is
|
||||
** done in two steps (allocation + free) because the correction must be
|
||||
** done while both addresses (the old stack and the new one) are valid.
|
||||
** (In ISO C, any pointer use after the pointer has been deallocated is
|
||||
** undefined behavior.)
|
||||
** Reallocate the stack to a new size, correcting all pointers into it.
|
||||
** In ISO C, any pointer use after the pointer has been deallocated is
|
||||
** undefined behavior. So, before the reallocation, all pointers are
|
||||
** changed to offsets, and after the reallocation they are changed back
|
||||
** to pointers. As during the reallocation the pointers are invalid, the
|
||||
** reallocation cannot run emergency collections.
|
||||
**
|
||||
** In case of allocation error, raise an error or return false according
|
||||
** to 'raiseerror'.
|
||||
*/
|
||||
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
|
||||
int oldsize = stacksize(L);
|
||||
int i;
|
||||
StkId newstack = luaM_reallocvector(L, NULL, 0,
|
||||
newsize + EXTRA_STACK, StackValue);
|
||||
StkId newstack;
|
||||
int oldgcstop = G(L)->gcstopem;
|
||||
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
|
||||
relstack(L); /* change pointers to offsets */
|
||||
G(L)->gcstopem = 1; /* stop emergency collection */
|
||||
newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
|
||||
newsize + EXTRA_STACK, StackValue);
|
||||
G(L)->gcstopem = oldgcstop; /* restore emergency collection */
|
||||
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
|
||||
correctstack(L); /* change offsets back to pointers */
|
||||
if (raiseerror)
|
||||
luaM_error(L);
|
||||
else return 0; /* do not raise an error */
|
||||
}
|
||||
/* number of elements to be copied to the new stack */
|
||||
i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
|
||||
memcpy(newstack, L->stack, i * sizeof(StackValue));
|
||||
for (; i < newsize + EXTRA_STACK; i++)
|
||||
L->stack.p = newstack;
|
||||
correctstack(L); /* change offsets back to pointers */
|
||||
L->stack_last.p = L->stack.p + newsize;
|
||||
for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
|
||||
setnilvalue(s2v(newstack + i)); /* erase new segment */
|
||||
correctstack(L, L->stack, newstack);
|
||||
luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
|
||||
L->stack = newstack;
|
||||
L->stack_last = L->stack + newsize;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Try to grow the stack by at least 'n' elements. when 'raiseerror'
|
||||
** Try to grow the stack by at least 'n' elements. When 'raiseerror'
|
||||
** is true, raises any error; otherwise, return 0 in case of errors.
|
||||
*/
|
||||
int luaD_growstack (lua_State *L, int n, int raiseerror) {
|
||||
@@ -227,35 +250,38 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
|
||||
luaD_throw(L, LUA_ERRERR); /* error inside message handler */
|
||||
return 0; /* if not 'raiseerror', just signal it */
|
||||
}
|
||||
else {
|
||||
else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */
|
||||
int newsize = 2 * size; /* tentative new size */
|
||||
int needed = cast_int(L->top - L->stack) + n;
|
||||
int needed = cast_int(L->top.p - L->stack.p) + n;
|
||||
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
|
||||
newsize = LUAI_MAXSTACK;
|
||||
if (newsize < needed) /* but must respect what was asked for */
|
||||
newsize = needed;
|
||||
if (l_likely(newsize <= LUAI_MAXSTACK))
|
||||
return luaD_reallocstack(L, newsize, raiseerror);
|
||||
else { /* stack overflow */
|
||||
/* add extra size to be able to handle the error message */
|
||||
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
|
||||
if (raiseerror)
|
||||
luaG_runerror(L, "stack overflow");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* else stack overflow */
|
||||
/* add extra size to be able to handle the error message */
|
||||
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
|
||||
if (raiseerror)
|
||||
luaG_runerror(L, "stack overflow");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Compute how much of the stack is being used, by computing the
|
||||
** maximum top of all call frames in the stack and the current top.
|
||||
*/
|
||||
static int stackinuse (lua_State *L) {
|
||||
CallInfo *ci;
|
||||
int res;
|
||||
StkId lim = L->top;
|
||||
StkId lim = L->top.p;
|
||||
for (ci = L->ci; ci != NULL; ci = ci->previous) {
|
||||
if (lim < ci->top) lim = ci->top;
|
||||
if (lim < ci->top.p) lim = ci->top.p;
|
||||
}
|
||||
lua_assert(lim <= L->stack_last);
|
||||
res = cast_int(lim - L->stack) + 1; /* part of stack in use */
|
||||
lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
|
||||
res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */
|
||||
if (res < LUA_MINSTACK)
|
||||
res = LUA_MINSTACK; /* ensure a minimum size */
|
||||
return res;
|
||||
@@ -292,7 +318,7 @@ void luaD_shrinkstack (lua_State *L) {
|
||||
|
||||
void luaD_inctop (lua_State *L) {
|
||||
luaD_checkstack(L, 1);
|
||||
L->top++;
|
||||
L->top.p++;
|
||||
}
|
||||
|
||||
/* }================================================================== */
|
||||
@@ -309,8 +335,8 @@ void luaD_hook (lua_State *L, int event, int line,
|
||||
if (hook && L->allowhook) { /* make sure there is a hook */
|
||||
int mask = CIST_HOOKED;
|
||||
CallInfo *ci = L->ci;
|
||||
ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */
|
||||
ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */
|
||||
ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */
|
||||
ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */
|
||||
lua_Debug ar;
|
||||
ar.event = event;
|
||||
ar.currentline = line;
|
||||
@@ -320,11 +346,11 @@ void luaD_hook (lua_State *L, int event, int line,
|
||||
ci->u2.transferinfo.ftransfer = ftransfer;
|
||||
ci->u2.transferinfo.ntransfer = ntransfer;
|
||||
}
|
||||
if (isLua(ci) && L->top < ci->top)
|
||||
L->top = ci->top; /* protect entire activation register */
|
||||
if (isLua(ci) && L->top.p < ci->top.p)
|
||||
L->top.p = ci->top.p; /* protect entire activation register */
|
||||
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
|
||||
if (ci->top < L->top + LUA_MINSTACK)
|
||||
ci->top = L->top + LUA_MINSTACK;
|
||||
if (ci->top.p < L->top.p + LUA_MINSTACK)
|
||||
ci->top.p = L->top.p + LUA_MINSTACK;
|
||||
L->allowhook = 0; /* cannot call hooks inside a hook */
|
||||
ci->callstatus |= mask;
|
||||
lua_unlock(L);
|
||||
@@ -332,8 +358,8 @@ void luaD_hook (lua_State *L, int event, int line,
|
||||
lua_lock(L);
|
||||
lua_assert(!L->allowhook);
|
||||
L->allowhook = 1;
|
||||
ci->top = restorestack(L, ci_top);
|
||||
L->top = restorestack(L, top);
|
||||
ci->top.p = restorestack(L, ci_top);
|
||||
L->top.p = restorestack(L, top);
|
||||
ci->callstatus &= ~mask;
|
||||
}
|
||||
}
|
||||
@@ -364,7 +390,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
|
||||
*/
|
||||
static void rethook (lua_State *L, CallInfo *ci, int nres) {
|
||||
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
|
||||
StkId firstres = L->top - nres; /* index of first result */
|
||||
StkId firstres = L->top.p - nres; /* index of first result */
|
||||
int delta = 0; /* correction for vararg functions */
|
||||
int ftransfer;
|
||||
if (isLua(ci)) {
|
||||
@@ -372,10 +398,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
|
||||
if (p->is_vararg)
|
||||
delta = ci->u.l.nextraargs + p->numparams + 1;
|
||||
}
|
||||
ci->func += delta; /* if vararg, back to virtual 'func' */
|
||||
ftransfer = cast(unsigned short, firstres - ci->func);
|
||||
ci->func.p += delta; /* if vararg, back to virtual 'func' */
|
||||
ftransfer = cast(unsigned short, firstres - ci->func.p);
|
||||
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
|
||||
ci->func -= delta;
|
||||
ci->func.p -= delta;
|
||||
}
|
||||
if (isLua(ci = ci->previous))
|
||||
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
|
||||
@@ -387,15 +413,18 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
|
||||
** stack, below original 'func', so that 'luaD_precall' can call it. Raise
|
||||
** an error if there is no '__call' metafield.
|
||||
*/
|
||||
void luaD_tryfuncTM (lua_State *L, StkId func) {
|
||||
const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL);
|
||||
StkId luaD_tryfuncTM (lua_State *L, StkId func) {
|
||||
const TValue *tm;
|
||||
StkId p;
|
||||
checkstackGCp(L, 1, func); /* space for metamethod */
|
||||
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
|
||||
if (l_unlikely(ttisnil(tm)))
|
||||
luaG_callerror(L, s2v(func)); /* nothing to call */
|
||||
for (p = L->top; p > func; p--) /* open space for metamethod */
|
||||
for (p = L->top.p; p > func; p--) /* open space for metamethod */
|
||||
setobjs2s(L, p, p-1);
|
||||
L->top++; /* stack space pre-allocated by the caller */
|
||||
L->top.p++; /* stack space pre-allocated by the caller */
|
||||
setobj2s(L, func, tm); /* metamethod is the new function to be called */
|
||||
return func;
|
||||
}
|
||||
|
||||
|
||||
@@ -405,33 +434,34 @@ void luaD_tryfuncTM (lua_State *L, StkId func) {
|
||||
** expressions, multiple results for tail calls/single parameters)
|
||||
** separated.
|
||||
*/
|
||||
static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
|
||||
l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
|
||||
StkId firstresult;
|
||||
int i;
|
||||
switch (wanted) { /* handle typical cases separately */
|
||||
case 0: /* no values needed */
|
||||
L->top = res;
|
||||
L->top.p = res;
|
||||
return;
|
||||
case 1: /* one value needed */
|
||||
if (nres == 0) /* no results? */
|
||||
setnilvalue(s2v(res)); /* adjust with nil */
|
||||
else /* at least one result */
|
||||
setobjs2s(L, res, L->top - nres); /* move it to proper place */
|
||||
L->top = res + 1;
|
||||
setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
|
||||
L->top.p = res + 1;
|
||||
return;
|
||||
case LUA_MULTRET:
|
||||
wanted = nres; /* we want all results */
|
||||
break;
|
||||
default: /* two/more results and/or to-be-closed variables */
|
||||
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
|
||||
ptrdiff_t savedres = savestack(L, res);
|
||||
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
|
||||
L->ci->u2.nres = nres;
|
||||
luaF_close(L, res, CLOSEKTOP, 1);
|
||||
res = luaF_close(L, res, CLOSEKTOP, 1);
|
||||
L->ci->callstatus &= ~CIST_CLSRET;
|
||||
if (L->hookmask) /* if needed, call hook after '__close's */
|
||||
if (L->hookmask) { /* if needed, call hook after '__close's */
|
||||
ptrdiff_t savedres = savestack(L, res);
|
||||
rethook(L, L->ci, nres);
|
||||
res = restorestack(L, savedres); /* close and hook can move stack */
|
||||
res = restorestack(L, savedres); /* hook can move stack */
|
||||
}
|
||||
wanted = decodeNresults(wanted);
|
||||
if (wanted == LUA_MULTRET)
|
||||
wanted = nres; /* we want all results */
|
||||
@@ -439,14 +469,14 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
|
||||
break;
|
||||
}
|
||||
/* generic case */
|
||||
firstresult = L->top - nres; /* index of first result */
|
||||
firstresult = L->top.p - nres; /* index of first result */
|
||||
if (nres > wanted) /* extra results? */
|
||||
nres = wanted; /* don't need them */
|
||||
for (i = 0; i < nres; i++) /* move all results to correct place */
|
||||
setobjs2s(L, res + i, firstresult + i);
|
||||
for (; i < wanted; i++) /* complete wanted number of results */
|
||||
setnilvalue(s2v(res + i));
|
||||
L->top = res + wanted; /* top points after the last result */
|
||||
L->top.p = res + wanted; /* top points after the last result */
|
||||
}
|
||||
|
||||
|
||||
@@ -461,7 +491,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
|
||||
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
|
||||
rethook(L, ci, nres);
|
||||
/* move results to proper place */
|
||||
moveresults(L, ci->func, nres, wanted);
|
||||
moveresults(L, ci->func.p, nres, wanted);
|
||||
/* function cannot be in any of these cases when returning */
|
||||
lua_assert(!(ci->callstatus &
|
||||
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
|
||||
@@ -473,27 +503,81 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
|
||||
#define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L))
|
||||
|
||||
|
||||
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
|
||||
int mask, StkId top) {
|
||||
CallInfo *ci = L->ci = next_ci(L); /* new frame */
|
||||
ci->func.p = func;
|
||||
ci->nresults = nret;
|
||||
ci->callstatus = mask;
|
||||
ci->top.p = top;
|
||||
return ci;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** precall for C functions
|
||||
*/
|
||||
l_sinline int precallC (lua_State *L, StkId func, int nresults,
|
||||
lua_CFunction f) {
|
||||
int n; /* number of returns */
|
||||
CallInfo *ci;
|
||||
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
|
||||
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
|
||||
L->top.p + LUA_MINSTACK);
|
||||
lua_assert(ci->top.p <= L->stack_last.p);
|
||||
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
|
||||
int narg = cast_int(L->top.p - func) - 1;
|
||||
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
|
||||
}
|
||||
lua_unlock(L);
|
||||
n = (*f)(L); /* do the actual call */
|
||||
lua_lock(L);
|
||||
api_checknelems(L, n);
|
||||
luaD_poscall(L, ci, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Prepare a function for a tail call, building its call info on top
|
||||
** of the current call info. 'narg1' is the number of arguments plus 1
|
||||
** (so that it includes the function itself).
|
||||
** (so that it includes the function itself). Return the number of
|
||||
** results, if it was a C function, or -1 for a Lua function.
|
||||
*/
|
||||
void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
|
||||
Proto *p = clLvalue(s2v(func))->p;
|
||||
int fsize = p->maxstacksize; /* frame size */
|
||||
int nfixparams = p->numparams;
|
||||
int i;
|
||||
for (i = 0; i < narg1; i++) /* move down function and arguments */
|
||||
setobjs2s(L, ci->func + i, func + i);
|
||||
checkstackGC(L, fsize);
|
||||
func = ci->func; /* moved-down function */
|
||||
for (; narg1 <= nfixparams; narg1++)
|
||||
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
|
||||
ci->top = func + 1 + fsize; /* top for new function */
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
ci->u.l.savedpc = p->code; /* starting point */
|
||||
ci->callstatus |= CIST_TAIL;
|
||||
L->top = func + narg1; /* set top */
|
||||
int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
|
||||
int narg1, int delta) {
|
||||
retry:
|
||||
switch (ttypetag(s2v(func))) {
|
||||
case LUA_VCCL: /* C closure */
|
||||
return precallC(L, func, LUA_MULTRET, clCvalue(s2v(func))->f);
|
||||
case LUA_VLCF: /* light C function */
|
||||
return precallC(L, func, LUA_MULTRET, fvalue(s2v(func)));
|
||||
case LUA_VLCL: { /* Lua function */
|
||||
Proto *p = clLvalue(s2v(func))->p;
|
||||
int fsize = p->maxstacksize; /* frame size */
|
||||
int nfixparams = p->numparams;
|
||||
int i;
|
||||
checkstackGCp(L, fsize - delta, func);
|
||||
ci->func.p -= delta; /* restore 'func' (if vararg) */
|
||||
for (i = 0; i < narg1; i++) /* move down function and arguments */
|
||||
setobjs2s(L, ci->func.p + i, func + i);
|
||||
func = ci->func.p; /* moved-down function */
|
||||
for (; narg1 <= nfixparams; narg1++)
|
||||
setnilvalue(s2v(func + narg1)); /* complete missing arguments */
|
||||
ci->top.p = func + 1 + fsize; /* top for new function */
|
||||
lua_assert(ci->top.p <= L->stack_last.p);
|
||||
ci->u.l.savedpc = p->code; /* starting point */
|
||||
ci->callstatus |= CIST_TAIL;
|
||||
L->top.p = func + narg1; /* set top */
|
||||
return -1;
|
||||
}
|
||||
default: { /* not a function */
|
||||
func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
|
||||
/* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */
|
||||
narg1++;
|
||||
goto retry; /* try again */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -506,56 +590,31 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
|
||||
** original function position.
|
||||
*/
|
||||
CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
|
||||
lua_CFunction f;
|
||||
retry:
|
||||
switch (ttypetag(s2v(func))) {
|
||||
case LUA_VCCL: /* C closure */
|
||||
f = clCvalue(s2v(func))->f;
|
||||
goto Cfunc;
|
||||
case LUA_VLCF: /* light C function */
|
||||
f = fvalue(s2v(func));
|
||||
Cfunc: {
|
||||
int n; /* number of returns */
|
||||
CallInfo *ci;
|
||||
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
|
||||
L->ci = ci = next_ci(L);
|
||||
ci->nresults = nresults;
|
||||
ci->callstatus = CIST_C;
|
||||
ci->top = L->top + LUA_MINSTACK;
|
||||
ci->func = func;
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
|
||||
int narg = cast_int(L->top - func) - 1;
|
||||
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
|
||||
}
|
||||
lua_unlock(L);
|
||||
n = (*f)(L); /* do the actual call */
|
||||
lua_lock(L);
|
||||
api_checknelems(L, n);
|
||||
luaD_poscall(L, ci, n);
|
||||
precallC(L, func, nresults, clCvalue(s2v(func))->f);
|
||||
return NULL;
|
||||
case LUA_VLCF: /* light C function */
|
||||
precallC(L, func, nresults, fvalue(s2v(func)));
|
||||
return NULL;
|
||||
}
|
||||
case LUA_VLCL: { /* Lua function */
|
||||
CallInfo *ci;
|
||||
Proto *p = clLvalue(s2v(func))->p;
|
||||
int narg = cast_int(L->top - func) - 1; /* number of real arguments */
|
||||
int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */
|
||||
int nfixparams = p->numparams;
|
||||
int fsize = p->maxstacksize; /* frame size */
|
||||
checkstackGCp(L, fsize, func);
|
||||
L->ci = ci = next_ci(L);
|
||||
ci->nresults = nresults;
|
||||
L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
|
||||
ci->u.l.savedpc = p->code; /* starting point */
|
||||
ci->top = func + 1 + fsize;
|
||||
ci->func = func;
|
||||
L->ci = ci;
|
||||
for (; narg < nfixparams; narg++)
|
||||
setnilvalue(s2v(L->top++)); /* complete missing arguments */
|
||||
lua_assert(ci->top <= L->stack_last);
|
||||
setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
|
||||
lua_assert(ci->top.p <= L->stack_last.p);
|
||||
return ci;
|
||||
}
|
||||
default: { /* not a function */
|
||||
checkstackGCp(L, 1, func); /* space for metamethod */
|
||||
luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
|
||||
func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */
|
||||
/* return luaD_precall(L, func, nresults); */
|
||||
goto retry; /* try again with metamethod */
|
||||
}
|
||||
}
|
||||
@@ -566,12 +625,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
|
||||
** Call a function (C or Lua) through C. 'inc' can be 1 (increment
|
||||
** number of recursive invocations in the C stack) or nyci (the same
|
||||
** plus increment number of non-yieldable calls).
|
||||
** This function can be called with some use of EXTRA_STACK, so it should
|
||||
** check the stack before doing anything else. 'luaD_precall' already
|
||||
** does that.
|
||||
*/
|
||||
static void ccall (lua_State *L, StkId func, int nResults, int inc) {
|
||||
l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) {
|
||||
CallInfo *ci;
|
||||
L->nCcalls += inc;
|
||||
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
|
||||
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
|
||||
checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
|
||||
luaE_checkcstack(L);
|
||||
}
|
||||
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
|
||||
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
|
||||
luaV_execute(L, ci); /* call it */
|
||||
@@ -619,8 +683,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
|
||||
else { /* error */
|
||||
StkId func = restorestack(L, ci->u2.funcidx);
|
||||
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
|
||||
luaF_close(L, func, status, 1); /* can yield or raise an error */
|
||||
func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
|
||||
func = luaF_close(L, func, status, 1); /* can yield or raise an error */
|
||||
luaD_seterrorobj(L, status, func);
|
||||
luaD_shrinkstack(L); /* restore stack size in case of overflow */
|
||||
setcistrecst(ci, LUA_OK); /* clear original status */
|
||||
@@ -708,8 +771,8 @@ static CallInfo *findpcall (lua_State *L) {
|
||||
** coroutine error handler and should not kill the coroutine.)
|
||||
*/
|
||||
static int resume_error (lua_State *L, const char *msg, int narg) {
|
||||
L->top -= narg; /* remove args from the stack */
|
||||
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
|
||||
L->top.p -= narg; /* remove args from the stack */
|
||||
setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */
|
||||
api_incr_top(L);
|
||||
lua_unlock(L);
|
||||
return LUA_ERRRUN;
|
||||
@@ -725,16 +788,15 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
|
||||
*/
|
||||
static void resume (lua_State *L, void *ud) {
|
||||
int n = *(cast(int*, ud)); /* number of arguments */
|
||||
StkId firstArg = L->top - n; /* first argument */
|
||||
StkId firstArg = L->top.p - n; /* first argument */
|
||||
CallInfo *ci = L->ci;
|
||||
if (L->status == LUA_OK) /* starting a coroutine? */
|
||||
ccall(L, firstArg - 1, LUA_MULTRET, 1); /* just call its body */
|
||||
ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
|
||||
else { /* resuming from previous yield */
|
||||
lua_assert(L->status == LUA_YIELD);
|
||||
L->status = LUA_OK; /* mark that it is running (again) */
|
||||
luaE_incCstack(L); /* control the C stack */
|
||||
if (isLua(ci)) { /* yielded inside a hook? */
|
||||
L->top = firstArg; /* discard arguments */
|
||||
L->top.p = firstArg; /* discard arguments */
|
||||
luaV_execute(L, ci); /* just continue running Lua code */
|
||||
}
|
||||
else { /* 'common' yield */
|
||||
@@ -777,12 +839,15 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
|
||||
if (L->status == LUA_OK) { /* may be starting a coroutine */
|
||||
if (L->ci != &L->base_ci) /* not in base level? */
|
||||
return resume_error(L, "cannot resume non-suspended coroutine", nargs);
|
||||
else if (L->top - (L->ci->func + 1) == nargs) /* no function? */
|
||||
else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */
|
||||
return resume_error(L, "cannot resume dead coroutine", nargs);
|
||||
}
|
||||
else if (L->status != LUA_YIELD) /* ended with errors? */
|
||||
return resume_error(L, "cannot resume dead coroutine", nargs);
|
||||
L->nCcalls = (from) ? getCcalls(from) : 0;
|
||||
if (getCcalls(L) >= LUAI_MAXCCALLS)
|
||||
return resume_error(L, "C stack overflow", nargs);
|
||||
L->nCcalls++;
|
||||
luai_userstateresume(L, nargs);
|
||||
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
|
||||
status = luaD_rawrunprotected(L, resume, &nargs);
|
||||
@@ -792,11 +857,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
|
||||
lua_assert(status == L->status); /* normal end or yield */
|
||||
else { /* unrecoverable error */
|
||||
L->status = cast_byte(status); /* mark thread as 'dead' */
|
||||
luaD_seterrorobj(L, status, L->top); /* push error message */
|
||||
L->ci->top = L->top;
|
||||
luaD_seterrorobj(L, status, L->top.p); /* push error message */
|
||||
L->ci->top.p = L->top.p;
|
||||
}
|
||||
*nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
|
||||
: cast_int(L->top - (L->ci->func + 1));
|
||||
: cast_int(L->top.p - (L->ci->func.p + 1));
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
}
|
||||
@@ -951,7 +1016,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
|
||||
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
|
||||
p.dyd.label.arr = NULL; p.dyd.label.size = 0;
|
||||
luaZ_initbuffer(L, &p.buff);
|
||||
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
|
||||
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
|
||||
luaZ_freebuffer(L, &p.buff);
|
||||
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
|
||||
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define ldo_h
|
||||
|
||||
|
||||
#include "llimits.h"
|
||||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
#include "lzio.h"
|
||||
@@ -23,7 +24,7 @@
|
||||
** at every check.
|
||||
*/
|
||||
#define luaD_checkstackaux(L,n,pre,pos) \
|
||||
if (l_unlikely(L->stack_last - L->top <= (n))) \
|
||||
if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
|
||||
{ pre; luaD_growstack(L, n, 1); pos; } \
|
||||
else { condmovestack(L,pre,pos); }
|
||||
|
||||
@@ -32,11 +33,18 @@
|
||||
|
||||
|
||||
|
||||
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
|
||||
#define restorestack(L,n) ((StkId)((char *)L->stack + (n)))
|
||||
#define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
|
||||
#define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
|
||||
|
||||
|
||||
/* macro to check stack size, preserving 'p' */
|
||||
#define checkstackp(L,n,p) \
|
||||
luaD_checkstackaux(L, n, \
|
||||
ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
|
||||
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
|
||||
|
||||
|
||||
/* macro to check stack size and GC, preserving 'p' */
|
||||
#define checkstackGCp(L,n,p) \
|
||||
luaD_checkstackaux(L, n, \
|
||||
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
|
||||
@@ -58,11 +66,12 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
|
||||
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
|
||||
int fTransfer, int nTransfer);
|
||||
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
|
||||
LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n);
|
||||
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
|
||||
int narg1, int delta);
|
||||
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
|
||||
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
|
||||
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
|
||||
LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func);
|
||||
LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func);
|
||||
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
|
||||
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
|
||||
ptrdiff_t oldtop, ptrdiff_t ef);
|
||||
|
||||
@@ -51,8 +51,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
|
||||
for (i = 0; i < cl->nupvalues; i++) {
|
||||
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
|
||||
UpVal *uv = gco2upv(o);
|
||||
uv->v = &uv->u.value; /* make it closed */
|
||||
setnilvalue(uv->v);
|
||||
uv->v.p = &uv->u.value; /* make it closed */
|
||||
setnilvalue(uv->v.p);
|
||||
cl->upvals[i] = uv;
|
||||
luaC_objbarrier(L, cl, uv);
|
||||
}
|
||||
@@ -63,12 +63,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
|
||||
** Create a new upvalue at the given level, and link it to the list of
|
||||
** open upvalues of 'L' after entry 'prev'.
|
||||
**/
|
||||
static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) {
|
||||
static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
|
||||
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
|
||||
UpVal *uv = gco2upv(o);
|
||||
UpVal *next = *prev;
|
||||
uv->v = s2v(level); /* current value lives in the stack */
|
||||
uv->tbc = tbc;
|
||||
uv->v.p = s2v(level); /* current value lives in the stack */
|
||||
uv->u.open.next = next; /* link it to list of open upvalues */
|
||||
uv->u.open.previous = prev;
|
||||
if (next)
|
||||
@@ -97,7 +96,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
|
||||
pp = &p->u.open.next;
|
||||
}
|
||||
/* not found: create a new upvalue after 'pp' */
|
||||
return newupval(L, 0, level, pp);
|
||||
return newupval(L, level, pp);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,12 +106,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
|
||||
** (This function assumes EXTRA_STACK.)
|
||||
*/
|
||||
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
|
||||
StkId top = L->top;
|
||||
StkId top = L->top.p;
|
||||
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
|
||||
setobj2s(L, top, tm); /* will call metamethod... */
|
||||
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
|
||||
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
|
||||
L->top = top + 3; /* add function and arguments */
|
||||
L->top.p = top + 3; /* add function and arguments */
|
||||
if (yy)
|
||||
luaD_call(L, top, 0);
|
||||
else
|
||||
@@ -127,7 +126,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
|
||||
static void checkclosemth (lua_State *L, StkId level) {
|
||||
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
|
||||
if (ttisnil(tm)) { /* no metamethod? */
|
||||
int idx = cast_int(level - L->ci->func); /* variable index */
|
||||
int idx = cast_int(level - L->ci->func.p); /* variable index */
|
||||
const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
|
||||
if (vname == NULL) vname = "?";
|
||||
luaG_runerror(L, "variable '%s' got a non-closable value", vname);
|
||||
@@ -161,23 +160,23 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
|
||||
** is used.)
|
||||
*/
|
||||
#define MAXDELTA \
|
||||
((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
|
||||
((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
|
||||
|
||||
|
||||
/*
|
||||
** Insert a variable in the list of to-be-closed variables.
|
||||
*/
|
||||
void luaF_newtbcupval (lua_State *L, StkId level) {
|
||||
lua_assert(level > L->tbclist);
|
||||
lua_assert(level > L->tbclist.p);
|
||||
if (l_isfalse(s2v(level)))
|
||||
return; /* false doesn't need to be closed */
|
||||
checkclosemth(L, level); /* value must have a close method */
|
||||
while (cast_uint(level - L->tbclist) > MAXDELTA) {
|
||||
L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
|
||||
L->tbclist->tbclist.delta = 0;
|
||||
while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
|
||||
L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
|
||||
L->tbclist.p->tbclist.delta = 0;
|
||||
}
|
||||
level->tbclist.delta = cast(unsigned short, level - L->tbclist);
|
||||
L->tbclist = level;
|
||||
level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
|
||||
L->tbclist.p = level;
|
||||
}
|
||||
|
||||
|
||||
@@ -197,10 +196,10 @@ void luaF_closeupval (lua_State *L, StkId level) {
|
||||
StkId upl; /* stack index pointed by 'uv' */
|
||||
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
|
||||
TValue *slot = &uv->u.value; /* new position for value */
|
||||
lua_assert(uplevel(uv) < L->top);
|
||||
lua_assert(uplevel(uv) < L->top.p);
|
||||
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
|
||||
setobj(L, slot, uv->v); /* move value to upvalue slot */
|
||||
uv->v = slot; /* now current value lives here */
|
||||
setobj(L, slot, uv->v.p); /* move value to upvalue slot */
|
||||
uv->v.p = slot; /* now current value lives here */
|
||||
if (!iswhite(uv)) { /* neither white nor dead? */
|
||||
nw2black(uv); /* closed upvalues cannot be gray */
|
||||
luaC_barrier(L, uv, slot);
|
||||
@@ -210,31 +209,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
|
||||
|
||||
|
||||
/*
|
||||
** Remove firt element from the tbclist plus its dummy nodes.
|
||||
** Remove first element from the tbclist plus its dummy nodes.
|
||||
*/
|
||||
static void poptbclist (lua_State *L) {
|
||||
StkId tbc = L->tbclist;
|
||||
StkId tbc = L->tbclist.p;
|
||||
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
|
||||
tbc -= tbc->tbclist.delta;
|
||||
while (tbc > L->stack && tbc->tbclist.delta == 0)
|
||||
while (tbc > L->stack.p && tbc->tbclist.delta == 0)
|
||||
tbc -= MAXDELTA; /* remove dummy nodes */
|
||||
L->tbclist = tbc;
|
||||
L->tbclist.p = tbc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Close all upvalues and to-be-closed variables up to the given stack
|
||||
** level.
|
||||
** level. Return restored 'level'.
|
||||
*/
|
||||
void luaF_close (lua_State *L, StkId level, int status, int yy) {
|
||||
StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
|
||||
ptrdiff_t levelrel = savestack(L, level);
|
||||
luaF_closeupval(L, level); /* first, close the upvalues */
|
||||
while (L->tbclist >= level) { /* traverse tbc's down to that level */
|
||||
StkId tbc = L->tbclist; /* get variable index */
|
||||
while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
|
||||
StkId tbc = L->tbclist.p; /* get variable index */
|
||||
poptbclist(L); /* remove it from list */
|
||||
prepcallclosemth(L, tbc, status, yy); /* close variable */
|
||||
level = restorestack(L, levelrel);
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -29,10 +29,10 @@
|
||||
#define MAXUPVAL 255
|
||||
|
||||
|
||||
#define upisopen(up) ((up)->v != &(up)->u.value)
|
||||
#define upisopen(up) ((up)->v.p != &(up)->u.value)
|
||||
|
||||
|
||||
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v))
|
||||
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
|
||||
|
||||
|
||||
/*
|
||||
@@ -54,7 +54,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
|
||||
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
|
||||
LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
|
||||
LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
|
||||
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
|
||||
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
|
||||
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
|
||||
|
||||
114
3rd/lua/lgc.c
114
3rd/lua/lgc.c
@@ -252,12 +252,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
|
||||
|
||||
|
||||
/*
|
||||
** create a new collectable object (with given type and size) and link
|
||||
** it to 'allgc' list.
|
||||
** create a new collectable object (with given type, size, and offset)
|
||||
** and link it to 'allgc' list.
|
||||
*/
|
||||
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
|
||||
GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
|
||||
global_State *g = G(L);
|
||||
GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
|
||||
char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
|
||||
GCObject *o = cast(GCObject *, p + offset);
|
||||
o->marked = luaC_white(g);
|
||||
o->tt = tt;
|
||||
o->next = g->allgc;
|
||||
@@ -265,6 +266,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
|
||||
return luaC_newobjdt(L, tt, sz, 0);
|
||||
}
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
@@ -301,7 +307,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
|
||||
set2gray(uv); /* open upvalues are kept gray */
|
||||
else
|
||||
set2black(uv); /* closed upvalues are visited here */
|
||||
markvalue(g, uv->v); /* mark its content */
|
||||
markvalue(g, uv->v.p); /* mark its content */
|
||||
break;
|
||||
}
|
||||
case LUA_VUSERDATA: {
|
||||
@@ -376,7 +382,7 @@ static int remarkupvals (global_State *g) {
|
||||
work++;
|
||||
if (!iswhite(uv)) { /* upvalue already visited? */
|
||||
lua_assert(upisopen(uv) && isgray(uv));
|
||||
markvalue(g, uv->v); /* mark its value */
|
||||
markvalue(g, uv->v.p); /* mark its value */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -620,19 +626,19 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
|
||||
*/
|
||||
static int traversethread (global_State *g, lua_State *th) {
|
||||
UpVal *uv;
|
||||
StkId o = th->stack;
|
||||
StkId o = th->stack.p;
|
||||
if (isold(th) || g->gcstate == GCSpropagate)
|
||||
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
|
||||
if (o == NULL)
|
||||
return 1; /* stack not completely built yet */
|
||||
lua_assert(g->gcstate == GCSatomic ||
|
||||
th->openupval == NULL || isintwups(th));
|
||||
for (; o < th->top; o++) /* mark live elements in the stack */
|
||||
for (; o < th->top.p; o++) /* mark live elements in the stack */
|
||||
markvalue(g, s2v(o));
|
||||
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
|
||||
markobject(g, uv); /* open upvalues cannot be collected */
|
||||
if (g->gcstate == GCSatomic) { /* final traversal? */
|
||||
for (; o < th->stack_last + EXTRA_STACK; o++)
|
||||
for (; o < th->stack_last.p + EXTRA_STACK; o++)
|
||||
setnilvalue(s2v(o)); /* clear dead stack slice */
|
||||
/* 'remarkupvals' may have removed thread from 'twups' list */
|
||||
if (!isintwups(th) && th->openupval != NULL) {
|
||||
@@ -894,7 +900,7 @@ static GCObject *udata2finalize (global_State *g) {
|
||||
|
||||
static void dothecall (lua_State *L, void *ud) {
|
||||
UNUSED(ud);
|
||||
luaD_callnoyield(L, L->top - 2, 0);
|
||||
luaD_callnoyield(L, L->top.p - 2, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -908,19 +914,19 @@ static void GCTM (lua_State *L) {
|
||||
if (!notm(tm)) { /* is there a finalizer? */
|
||||
int status;
|
||||
lu_byte oldah = L->allowhook;
|
||||
int running = g->gcrunning;
|
||||
int oldgcstp = g->gcstp;
|
||||
g->gcstp |= GCSTPGC; /* avoid GC steps */
|
||||
L->allowhook = 0; /* stop debug hooks during GC metamethod */
|
||||
g->gcrunning = 0; /* avoid GC steps */
|
||||
setobj2s(L, L->top++, tm); /* push finalizer... */
|
||||
setobj2s(L, L->top++, &v); /* ... and its argument */
|
||||
setobj2s(L, L->top.p++, tm); /* push finalizer... */
|
||||
setobj2s(L, L->top.p++, &v); /* ... and its argument */
|
||||
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
|
||||
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
|
||||
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
|
||||
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
|
||||
L->allowhook = oldah; /* restore hooks */
|
||||
g->gcrunning = running; /* restore state */
|
||||
g->gcstp = oldgcstp; /* restore state */
|
||||
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
|
||||
luaE_warnerror(L, "__gc metamethod");
|
||||
L->top--; /* pops error object */
|
||||
luaE_warnerror(L, "__gc");
|
||||
L->top.p--; /* pops error object */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1013,7 +1019,8 @@ static void correctpointers (global_State *g, GCObject *o) {
|
||||
void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
|
||||
global_State *g = G(L);
|
||||
if (tofinalize(o) || /* obj. is already marked... */
|
||||
gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */
|
||||
gfasttm(g, mt, TM_GC) == NULL || /* or has no finalizer... */
|
||||
(g->gcstp & GCSTPCLS)) /* or closing state? */
|
||||
return; /* nothing to be done */
|
||||
else { /* move 'o' to 'finobj' list */
|
||||
GCObject **p;
|
||||
@@ -1042,7 +1049,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
static void setpause (global_State *g);
|
||||
|
||||
/*
|
||||
** Set the "time" to wait before starting a new GC cycle; cycle will
|
||||
** start when memory use hits the threshold of ('estimate' * pause /
|
||||
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
|
||||
** because Lua cannot even start with less than PAUSEADJ bytes).
|
||||
*/
|
||||
static void setpause (global_State *g) {
|
||||
l_mem threshold, debt;
|
||||
int pause = getgcparam(g->gcpause);
|
||||
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
|
||||
lua_assert(estimate > 0);
|
||||
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
|
||||
? estimate * pause /* no overflow */
|
||||
: MAX_LMEM; /* overflow; truncate to maximum */
|
||||
debt = gettotalbytes(g) - threshold;
|
||||
if (debt > 0) debt = 0;
|
||||
luaE_setdebt(g, debt);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -1290,6 +1315,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Set debt for the next minor collection, which will happen when
|
||||
** memory grows 'genminormul'%.
|
||||
*/
|
||||
static void setminordebt (global_State *g) {
|
||||
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Enter generational mode. Must go until the end of an atomic cycle
|
||||
** to ensure that all objects are correctly marked and weak tables
|
||||
@@ -1302,6 +1336,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
|
||||
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
|
||||
numobjs = atomic(L); /* propagates all and then do the atomic stuff */
|
||||
atomic2gen(L, g);
|
||||
setminordebt(g); /* set debt assuming next cycle will be minor */
|
||||
return numobjs;
|
||||
}
|
||||
|
||||
@@ -1347,15 +1382,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Set debt for the next minor collection, which will happen when
|
||||
** memory grows 'genminormul'%.
|
||||
*/
|
||||
static void setminordebt (global_State *g) {
|
||||
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Does a major collection after last collection was a "bad collection".
|
||||
**
|
||||
@@ -1427,8 +1453,8 @@ static void genstep (lua_State *L, global_State *g) {
|
||||
lu_mem numobjs = fullgen(L, g); /* do a major collection */
|
||||
if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
|
||||
/* collected at least half of memory growth since last major
|
||||
collection; keep doing minor collections */
|
||||
setminordebt(g);
|
||||
collection; keep doing minor collections. */
|
||||
lua_assert(g->lastatomic == 0);
|
||||
}
|
||||
else { /* bad collection */
|
||||
g->lastatomic = numobjs; /* signal that last collection was bad */
|
||||
@@ -1454,26 +1480,6 @@ static void genstep (lua_State *L, global_State *g) {
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** Set the "time" to wait before starting a new GC cycle; cycle will
|
||||
** start when memory use hits the threshold of ('estimate' * pause /
|
||||
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
|
||||
** because Lua cannot even start with less than PAUSEADJ bytes).
|
||||
*/
|
||||
static void setpause (global_State *g) {
|
||||
l_mem threshold, debt;
|
||||
int pause = getgcparam(g->gcpause);
|
||||
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
|
||||
lua_assert(estimate > 0);
|
||||
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
|
||||
? estimate * pause /* no overflow */
|
||||
: MAX_LMEM; /* overflow; truncate to maximum */
|
||||
debt = gettotalbytes(g) - threshold;
|
||||
if (debt > 0) debt = 0;
|
||||
luaE_setdebt(g, debt);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Enter first sweep phase.
|
||||
** The call to 'sweeptolive' makes the pointer point to an object
|
||||
@@ -1508,12 +1514,13 @@ static void deletelist (lua_State *L, GCObject *p, GCObject *limit) {
|
||||
*/
|
||||
void luaC_freeallobjects (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
g->gcstp = GCSTPCLS; /* no extra finalizers after here */
|
||||
luaC_changemode(L, KGC_INC);
|
||||
separatetobefnz(g, 1); /* separate all objects with finalizers */
|
||||
lua_assert(g->finobj == NULL);
|
||||
callallpendingfinalizers(L);
|
||||
deletelist(L, g->allgc, obj2gco(g->mainthread));
|
||||
deletelist(L, g->finobj, NULL);
|
||||
lua_assert(g->finobj == NULL); /* no new finalizers */
|
||||
deletelist(L, g->fixedgc, NULL); /* collect fixed objects */
|
||||
lua_assert(g->strt.nuse == 0);
|
||||
}
|
||||
@@ -1653,6 +1660,7 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Performs a basic incremental step. The debt and step size are
|
||||
** converted from bytes to "units of work"; then the function loops
|
||||
@@ -1684,7 +1692,7 @@ static void incstep (lua_State *L, global_State *g) {
|
||||
void luaC_step (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
lua_assert(!g->gcemergency);
|
||||
if (g->gcrunning) { /* running? */
|
||||
if (gcrunning(g)) { /* running? */
|
||||
if(isdecGCmodegen(g))
|
||||
genstep(L, g);
|
||||
else
|
||||
|
||||
@@ -153,6 +153,16 @@
|
||||
*/
|
||||
#define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0)
|
||||
|
||||
|
||||
/*
|
||||
** Control when GC is running:
|
||||
*/
|
||||
#define GCSTPUSR 1 /* bit true when GC stopped by user */
|
||||
#define GCSTPGC 2 /* bit true when GC stopped by itself */
|
||||
#define GCSTPCLS 4 /* bit true when closing Lua state */
|
||||
#define gcrunning(g) ((g)->gcstp == 0)
|
||||
|
||||
|
||||
/*
|
||||
** Does one step of collection when debt becomes positive. 'pre'/'pos'
|
||||
** allows some adjustments to be done only when needed. macro
|
||||
@@ -185,6 +195,8 @@ LUAI_FUNC void luaC_step (lua_State *L);
|
||||
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
|
||||
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
|
||||
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
|
||||
LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
|
||||
size_t offset);
|
||||
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
|
||||
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
|
||||
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
|
||||
|
||||
@@ -138,12 +138,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
|
||||
if (!ttisnil(o)) /* string already present? */
|
||||
ts = keystrval(nodefromval(o)); /* get saved copy */
|
||||
else { /* not in use yet */
|
||||
TValue *stv = s2v(L->top++); /* reserve stack space for string */
|
||||
TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
|
||||
setsvalue(L, stv, ts); /* temporarily anchor the string */
|
||||
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
|
||||
/* table is not a metatable, so it does not need to invalidate cache */
|
||||
luaC_checkGC(L);
|
||||
L->top--; /* remove string from stack */
|
||||
L->top.p--; /* remove string from stack */
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
@@ -165,6 +165,20 @@ typedef LUAI_UACINT l_uacInt;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Inline functions
|
||||
*/
|
||||
#if !defined(LUA_USE_C89)
|
||||
#define l_inline inline
|
||||
#elif defined(__GNUC__)
|
||||
#define l_inline __inline__
|
||||
#else
|
||||
#define l_inline /* empty */
|
||||
#endif
|
||||
|
||||
#define l_sinline static l_inline
|
||||
|
||||
|
||||
/*
|
||||
** type for virtual-machine instructions;
|
||||
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
|
||||
@@ -347,7 +361,7 @@ typedef l_uint32 Instruction;
|
||||
#define condchangemem(L,pre,pos) ((void)0)
|
||||
#else
|
||||
#define condchangemem(L,pre,pos) \
|
||||
{ if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } }
|
||||
{ if (gcrunning(G(L))) { pre; luaC_fullgc(L, 0); pos; } }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -475,7 +475,7 @@ static lua_Number I2d (Rand64 x) {
|
||||
|
||||
/* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */
|
||||
#define scaleFIG \
|
||||
((lua_Number)1.0 / (UONE << 30) / 8.0 / (UONE << (FIGS - 33)))
|
||||
(l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33)))
|
||||
|
||||
/*
|
||||
** use FIGS - 32 bits from lower half, throwing out the other
|
||||
@@ -486,7 +486,7 @@ static lua_Number I2d (Rand64 x) {
|
||||
/*
|
||||
** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32)
|
||||
*/
|
||||
#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * 2.0)
|
||||
#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * l_mathop(2.0))
|
||||
|
||||
|
||||
static lua_Number I2d (Rand64 x) {
|
||||
|
||||
@@ -708,8 +708,13 @@ static const luaL_Reg ll_funcs[] = {
|
||||
|
||||
|
||||
static void createsearcherstable (lua_State *L) {
|
||||
static const lua_CFunction searchers[] =
|
||||
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};
|
||||
static const lua_CFunction searchers[] = {
|
||||
searcher_preload,
|
||||
searcher_Lua,
|
||||
searcher_C,
|
||||
searcher_Croot,
|
||||
NULL
|
||||
};
|
||||
int i;
|
||||
/* create 'searchers' table */
|
||||
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
|
||||
|
||||
@@ -62,7 +62,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
|
||||
case LUA_OPBOR: return intop(|, v1, v2);
|
||||
case LUA_OPBXOR: return intop(^, v1, v2);
|
||||
case LUA_OPSHL: return luaV_shiftl(v1, v2);
|
||||
case LUA_OPSHR: return luaV_shiftl(v1, -v2);
|
||||
case LUA_OPSHR: return luaV_shiftr(v1, v2);
|
||||
case LUA_OPUNM: return intop(-, 0, v1);
|
||||
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
|
||||
default: lua_assert(0); return 0;
|
||||
@@ -164,7 +164,7 @@ static int isneg (const char **s) {
|
||||
*/
|
||||
static lua_Number lua_strx2number (const char *s, char **endptr) {
|
||||
int dot = lua_getlocaledecpoint();
|
||||
lua_Number r = 0.0; /* result (accumulator) */
|
||||
lua_Number r = l_mathop(0.0); /* result (accumulator) */
|
||||
int sigdig = 0; /* number of significant digits */
|
||||
int nosigdig = 0; /* number of non-significant digits */
|
||||
int e = 0; /* exponent correction */
|
||||
@@ -174,7 +174,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
|
||||
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
|
||||
neg = isneg(&s); /* check sign */
|
||||
if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
|
||||
return 0.0; /* invalid format (no '0x') */
|
||||
return l_mathop(0.0); /* invalid format (no '0x') */
|
||||
for (s += 2; ; s++) { /* skip '0x' and read numeral */
|
||||
if (*s == dot) {
|
||||
if (hasdot) break; /* second dot? stop loop */
|
||||
@@ -184,14 +184,14 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
|
||||
if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
|
||||
nosigdig++;
|
||||
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
|
||||
r = (r * cast_num(16.0)) + luaO_hexavalue(*s);
|
||||
r = (r * l_mathop(16.0)) + luaO_hexavalue(*s);
|
||||
else e++; /* too many digits; ignore, but still count for exponent */
|
||||
if (hasdot) e--; /* decimal digit? correct exponent */
|
||||
}
|
||||
else break; /* neither a dot nor a digit */
|
||||
}
|
||||
if (nosigdig + sigdig == 0) /* no digits? */
|
||||
return 0.0; /* invalid format */
|
||||
return l_mathop(0.0); /* invalid format */
|
||||
*endptr = cast_charp(s); /* valid up to here */
|
||||
e *= 4; /* each digit multiplies/divides value by 2^4 */
|
||||
if (*s == 'p' || *s == 'P') { /* exponent part? */
|
||||
@@ -200,7 +200,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
|
||||
s++; /* skip 'p' */
|
||||
neg1 = isneg(&s); /* sign */
|
||||
if (!lisdigit(cast_uchar(*s)))
|
||||
return 0.0; /* invalid; must have at least one digit */
|
||||
return l_mathop(0.0); /* invalid; must have at least one digit */
|
||||
while (lisdigit(cast_uchar(*s))) /* read exponent */
|
||||
exp1 = exp1 * 10 + *(s++) - '0';
|
||||
if (neg1) exp1 = -exp1;
|
||||
@@ -386,29 +386,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/* size for buffer space used by 'luaO_pushvfstring' */
|
||||
#define BUFVFS 200
|
||||
/*
|
||||
** Size for buffer space used by 'luaO_pushvfstring'. It should be
|
||||
** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
|
||||
** so that 'luaG_addinfo' can work directly on the buffer.
|
||||
*/
|
||||
#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
|
||||
|
||||
/* buffer used by 'luaO_pushvfstring' */
|
||||
typedef struct BuffFS {
|
||||
lua_State *L;
|
||||
int pushed; /* number of string pieces already on the stack */
|
||||
int pushed; /* true if there is a part of the result on the stack */
|
||||
int blen; /* length of partial string in 'space' */
|
||||
char space[BUFVFS]; /* holds last part of the result */
|
||||
} BuffFS;
|
||||
|
||||
|
||||
/*
|
||||
** Push given string to the stack, as part of the buffer, and
|
||||
** join the partial strings in the stack into one.
|
||||
** Push given string to the stack, as part of the result, and
|
||||
** join it to previous partial result if there is one.
|
||||
** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
|
||||
** This call cannot invoke metamethods, as both operands must be
|
||||
** strings. It can, however, raise an error if the result is too
|
||||
** long. In that case, 'luaV_concat' frees the extra slot before
|
||||
** raising the error.
|
||||
*/
|
||||
static void pushstr (BuffFS *buff, const char *str, size_t l) {
|
||||
static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
|
||||
lua_State *L = buff->L;
|
||||
setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
|
||||
L->top++; /* may use one extra slot */
|
||||
buff->pushed++;
|
||||
luaV_concat(L, buff->pushed); /* join partial results into one */
|
||||
buff->pushed = 1;
|
||||
setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
|
||||
L->top.p++; /* may use one slot from EXTRA_STACK */
|
||||
if (!buff->pushed) /* no previous string on the stack? */
|
||||
buff->pushed = 1; /* now there is one */
|
||||
else /* join previous string with new one */
|
||||
luaV_concat(L, 2);
|
||||
}
|
||||
|
||||
|
||||
@@ -454,7 +464,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
|
||||
|
||||
|
||||
/*
|
||||
** Add a number to the buffer.
|
||||
** Add a numeral to the buffer.
|
||||
*/
|
||||
static void addnum2buff (BuffFS *buff, TValue *num) {
|
||||
char *numbuff = getbuff(buff, MAXNUMBER2STR);
|
||||
@@ -532,7 +542,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
|
||||
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
|
||||
clearbuff(&buff); /* empty buffer into the stack */
|
||||
lua_assert(buff.pushed == 1);
|
||||
return svalue(s2v(L->top - 1));
|
||||
return svalue(s2v(L->top.p - 1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ typedef union Value {
|
||||
lua_CFunction f; /* light C functions */
|
||||
lua_Integer i; /* integer numbers */
|
||||
lua_Number n; /* float numbers */
|
||||
/* not used, but may avoid warnings for uninitialized value */
|
||||
lu_byte ub;
|
||||
} Value;
|
||||
|
||||
|
||||
@@ -68,7 +70,7 @@ typedef struct TValue {
|
||||
|
||||
|
||||
#define val_(o) ((o)->value_)
|
||||
#define valraw(o) (&val_(o))
|
||||
#define valraw(o) (val_(o))
|
||||
|
||||
|
||||
/* raw type tag of a TValue */
|
||||
@@ -112,7 +114,7 @@ typedef struct TValue {
|
||||
#define settt_(o,t) ((o)->tt_=(t))
|
||||
|
||||
|
||||
/* main macro to copy values (from 'obj1' to 'obj2') */
|
||||
/* main macro to copy values (from 'obj2' to 'obj1') */
|
||||
#define setobj(L,obj1,obj2) \
|
||||
{ TValue *io1=(obj1); const TValue *io2=(obj2); \
|
||||
io1->value_ = io2->value_; settt_(io1, io2->tt_); \
|
||||
@@ -155,6 +157,17 @@ typedef union StackValue {
|
||||
/* index to stack elements */
|
||||
typedef StackValue *StkId;
|
||||
|
||||
|
||||
/*
|
||||
** When reallocating the stack, change all pointers to the stack into
|
||||
** proper offsets.
|
||||
*/
|
||||
typedef union {
|
||||
StkId p; /* actual pointer */
|
||||
ptrdiff_t offset; /* used while the stack is being reallocated */
|
||||
} StkIdRel;
|
||||
|
||||
|
||||
/* convert a 'StackValue' to a 'TValue' */
|
||||
#define s2v(o) (&(o)->val)
|
||||
|
||||
@@ -616,8 +629,10 @@ typedef struct Proto {
|
||||
*/
|
||||
typedef struct UpVal {
|
||||
CommonHeader;
|
||||
lu_byte tbc; /* true if it represents a to-be-closed variable */
|
||||
TValue *v; /* points to stack or to its own value */
|
||||
union {
|
||||
TValue *p; /* points to stack or to its own value */
|
||||
ptrdiff_t offset; /* used while the stack is being reallocated */
|
||||
} v;
|
||||
union {
|
||||
struct { /* (when open) */
|
||||
struct UpVal *next; /* linked list */
|
||||
|
||||
@@ -190,7 +190,8 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */
|
||||
|
||||
|
||||
/*
|
||||
** grep "ORDER OP" if you change these enums
|
||||
** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*)
|
||||
** has extra descriptions in the notes after the enumeration.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
@@ -203,7 +204,7 @@ OP_LOADF,/* A sBx R[A] := (lua_Number)sBx */
|
||||
OP_LOADK,/* A Bx R[A] := K[Bx] */
|
||||
OP_LOADKX,/* A R[A] := K[extra arg] */
|
||||
OP_LOADFALSE,/* A R[A] := false */
|
||||
OP_LFALSESKIP,/*A R[A] := false; pc++ */
|
||||
OP_LFALSESKIP,/*A R[A] := false; pc++ (*) */
|
||||
OP_LOADTRUE,/* A R[A] := true */
|
||||
OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */
|
||||
OP_GETUPVAL,/* A B R[A] := UpValue[B] */
|
||||
@@ -254,7 +255,7 @@ OP_BXOR,/* A B C R[A] := R[B] ~ R[C] */
|
||||
OP_SHL,/* A B C R[A] := R[B] << R[C] */
|
||||
OP_SHR,/* A B C R[A] := R[B] >> R[C] */
|
||||
|
||||
OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] */
|
||||
OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] (*) */
|
||||
OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */
|
||||
OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */
|
||||
|
||||
@@ -280,7 +281,7 @@ OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */
|
||||
OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */
|
||||
|
||||
OP_TEST,/* A k if (not R[A] == k) then pc++ */
|
||||
OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] */
|
||||
OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */
|
||||
|
||||
OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */
|
||||
OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */
|
||||
@@ -315,6 +316,18 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
|
||||
|
||||
/*===========================================================================
|
||||
Notes:
|
||||
|
||||
(*) Opcode OP_LFALSESKIP is used to convert a condition to a boolean
|
||||
value, in a code equivalent to (not cond ? false : true). (It
|
||||
produces false and skips the next instruction producing true.)
|
||||
|
||||
(*) Opcodes OP_MMBIN and variants follow each arithmetic and
|
||||
bitwise opcode. If the operation succeeds, it skips this next
|
||||
opcode. Otherwise, this opcode calls the corresponding metamethod.
|
||||
|
||||
(*) Opcode OP_TESTSET is used in short-circuit expressions that need
|
||||
both to jump and to produce a value, such as (a = b or c).
|
||||
|
||||
(*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then
|
||||
'top' is set to last_result+1, so next open instruction (OP_CALL,
|
||||
OP_RETURN*, OP_SETLIST) may use 'top'.
|
||||
|
||||
@@ -260,9 +260,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
|
||||
res = d;
|
||||
}
|
||||
else {
|
||||
/* unsigned avoids overflow when lua_Integer has 32 bits */
|
||||
if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
|
||||
: (lua_Integer)INT_MIN + delta <= res))
|
||||
if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
|
||||
return luaL_error(L, "field '%s' is out-of-bound", key);
|
||||
res -= delta;
|
||||
}
|
||||
|
||||
@@ -416,6 +416,17 @@ static void markupval (FuncState *fs, int level) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Mark that current block has a to-be-closed variable.
|
||||
*/
|
||||
static void marktobeclosed (FuncState *fs) {
|
||||
BlockCnt *bl = fs->bl;
|
||||
bl->upval = 1;
|
||||
bl->insidetbc = 1;
|
||||
fs->needclose = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Find a variable with the given name 'n'. If it is an upvalue, add
|
||||
** this upvalue into all intermediate functions. If it is a global, set
|
||||
@@ -457,6 +468,7 @@ static void singlevar (LexState *ls, expdesc *var) {
|
||||
expdesc key;
|
||||
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
|
||||
lua_assert(var->k != VVOID); /* this one must exist */
|
||||
luaK_exp2anyregup(fs, var); /* but could be a constant */
|
||||
codestring(&key, varname); /* key is variable name */
|
||||
luaK_indexed(fs, var, &key); /* env[varname] */
|
||||
}
|
||||
@@ -662,19 +674,19 @@ static void leaveblock (FuncState *fs) {
|
||||
LexState *ls = fs->ls;
|
||||
int hasclose = 0;
|
||||
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
|
||||
if (bl->isloop) /* fix pending breaks? */
|
||||
removevars(fs, bl->nactvar); /* remove block locals */
|
||||
lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
|
||||
if (bl->isloop) /* has to fix pending breaks? */
|
||||
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
|
||||
if (!hasclose && bl->previous && bl->upval)
|
||||
if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */
|
||||
luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
|
||||
fs->bl = bl->previous;
|
||||
removevars(fs, bl->nactvar);
|
||||
lua_assert(bl->nactvar == fs->nactvar);
|
||||
fs->freereg = stklevel; /* free registers */
|
||||
ls->dyd->label.n = bl->firstlabel; /* remove local labels */
|
||||
if (bl->previous) /* inner block? */
|
||||
movegotosout(fs, bl); /* update pending gotos to outer block */
|
||||
fs->bl = bl->previous; /* current block now is previous one */
|
||||
if (bl->previous) /* was it a nested block? */
|
||||
movegotosout(fs, bl); /* update pending gotos to enclosing block */
|
||||
else {
|
||||
if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */
|
||||
if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
|
||||
undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
|
||||
}
|
||||
}
|
||||
@@ -1599,7 +1611,7 @@ static void forlist (LexState *ls, TString *indexname) {
|
||||
line = ls->linenumber;
|
||||
adjust_assign(ls, 4, explist(ls, &e), &e);
|
||||
adjustlocalvars(ls, 4); /* control variables */
|
||||
markupval(fs, fs->nactvar); /* last control var. must be closed */
|
||||
marktobeclosed(fs); /* last control var. must be closed */
|
||||
luaK_checkstack(fs, 3); /* extra space to call generator */
|
||||
forbody(ls, base, line, nvars - 4, 1);
|
||||
}
|
||||
@@ -1703,11 +1715,9 @@ static int getlocalattribute (LexState *ls) {
|
||||
}
|
||||
|
||||
|
||||
static void checktoclose (LexState *ls, int level) {
|
||||
static void checktoclose (FuncState *fs, int level) {
|
||||
if (level != -1) { /* is there a to-be-closed variable? */
|
||||
FuncState *fs = ls->fs;
|
||||
markupval(fs, level + 1);
|
||||
fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
|
||||
marktobeclosed(fs);
|
||||
luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -1751,7 +1761,7 @@ static void localstat (LexState *ls) {
|
||||
adjust_assign(ls, nvars, nexps, &e);
|
||||
adjustlocalvars(ls, nvars);
|
||||
}
|
||||
checktoclose(ls, toclose);
|
||||
checktoclose(fs, toclose);
|
||||
}
|
||||
|
||||
|
||||
@@ -1776,6 +1786,7 @@ static void funcstat (LexState *ls, int line) {
|
||||
luaX_next(ls); /* skip FUNCTION */
|
||||
ismethod = funcname(ls, &v);
|
||||
body(ls, &b, ismethod, line);
|
||||
check_readonly(ls, &v);
|
||||
luaK_storevar(ls->fs, &v, &b);
|
||||
luaK_fixline(ls->fs, line); /* definition "happens" in the first line */
|
||||
}
|
||||
@@ -1933,10 +1944,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||
LexState lexstate;
|
||||
FuncState funcstate;
|
||||
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
|
||||
setclLvalue2s(L, L->top, cl); /* anchor it (to avoid being collected) */
|
||||
setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
|
||||
luaD_inctop(L);
|
||||
lexstate.h = luaH_new(L); /* create table for scanner */
|
||||
sethvalue2s(L, L->top, lexstate.h); /* anchor it */
|
||||
sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
|
||||
luaD_inctop(L);
|
||||
funcstate.f = cl->p = luaF_newproto(L);
|
||||
luaC_objbarrier(L, cl, cl->p);
|
||||
@@ -1950,7 +1961,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
|
||||
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);
|
||||
L->top--; /* remove scanner's table */
|
||||
L->top.p--; /* remove scanner's table */
|
||||
return cl; /* closure is on the stack, too */
|
||||
}
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ void luaE_checkcstack (lua_State *L) {
|
||||
if (getCcalls(L) == LUAI_MAXCCALLS)
|
||||
luaG_runerror(L, "C stack overflow");
|
||||
else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11))
|
||||
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
|
||||
luaD_throw(L, LUA_ERRERR); /* error while handling stack error */
|
||||
}
|
||||
|
||||
|
||||
@@ -180,33 +180,33 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
|
||||
static void stack_init (lua_State *L1, lua_State *L) {
|
||||
int i; CallInfo *ci;
|
||||
/* initialize stack array */
|
||||
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
|
||||
L1->tbclist = L1->stack;
|
||||
L1->stack.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
|
||||
L1->tbclist.p = L1->stack.p;
|
||||
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
|
||||
setnilvalue(s2v(L1->stack + i)); /* erase new stack */
|
||||
L1->top = L1->stack;
|
||||
L1->stack_last = L1->stack + BASIC_STACK_SIZE;
|
||||
setnilvalue(s2v(L1->stack.p + i)); /* erase new stack */
|
||||
L1->top.p = L1->stack.p;
|
||||
L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
|
||||
/* initialize first ci */
|
||||
ci = &L1->base_ci;
|
||||
ci->next = ci->previous = NULL;
|
||||
ci->callstatus = CIST_C;
|
||||
ci->func = L1->top;
|
||||
ci->func.p = L1->top.p;
|
||||
ci->u.c.k = NULL;
|
||||
ci->nresults = 0;
|
||||
setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */
|
||||
L1->top++;
|
||||
ci->top = L1->top + LUA_MINSTACK;
|
||||
setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
|
||||
L1->top.p++;
|
||||
ci->top.p = L1->top.p + LUA_MINSTACK;
|
||||
L1->ci = ci;
|
||||
}
|
||||
|
||||
|
||||
static void freestack (lua_State *L) {
|
||||
if (L->stack == NULL)
|
||||
if (L->stack.p == NULL)
|
||||
return; /* stack not completely built yet */
|
||||
L->ci = &L->base_ci; /* free the entire 'ci' list */
|
||||
luaE_freeCI(L);
|
||||
lua_assert(L->nci == 0);
|
||||
luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */
|
||||
luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
|
||||
}
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ static void f_luaopen (lua_State *L, void *ud) {
|
||||
luaS_init(L);
|
||||
luaT_init(L);
|
||||
luaX_init(L);
|
||||
g->gcrunning = 1; /* allow gc */
|
||||
g->gcstp = 0; /* allow gc */
|
||||
setnilvalue(&g->nilvalue); /* now state is complete */
|
||||
luai_userstateopen(L);
|
||||
}
|
||||
@@ -248,7 +248,7 @@ static void f_luaopen (lua_State *L, void *ud) {
|
||||
*/
|
||||
static void preinit_thread (lua_State *L, global_State *g) {
|
||||
G(L) = g;
|
||||
L->stack = NULL;
|
||||
L->stack.p = NULL;
|
||||
L->ci = NULL;
|
||||
L->nci = 0;
|
||||
L->twups = L; /* thread has no upvalues */
|
||||
@@ -269,8 +269,9 @@ static void preinit_thread (lua_State *L, global_State *g) {
|
||||
static void close_state (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
if (!completestate(g)) /* closing a partially built state? */
|
||||
luaC_freeallobjects(L); /* jucst collect its objects */
|
||||
luaC_freeallobjects(L); /* just collect its objects */
|
||||
else { /* closing a fully built state */
|
||||
L->ci = &L->base_ci; /* unwind CallInfo list */
|
||||
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
|
||||
luaC_freeallobjects(L); /* collect all objects */
|
||||
luai_userstateclose(L);
|
||||
@@ -283,20 +284,16 @@ static void close_state (lua_State *L) {
|
||||
|
||||
|
||||
LUA_API lua_State *lua_newthread (lua_State *L) {
|
||||
global_State *g;
|
||||
global_State *g = G(L);
|
||||
GCObject *o;
|
||||
lua_State *L1;
|
||||
lua_lock(L);
|
||||
g = G(L);
|
||||
luaC_checkGC(L);
|
||||
/* create new thread */
|
||||
L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
|
||||
L1->marked = luaC_white(g);
|
||||
L1->tt = LUA_VTHREAD;
|
||||
/* link it on list 'allgc' */
|
||||
L1->next = g->allgc;
|
||||
g->allgc = obj2gco(L1);
|
||||
o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
|
||||
L1 = gco2th(o);
|
||||
/* anchor it on L stack */
|
||||
setthvalue2s(L, L->top, L1);
|
||||
setthvalue2s(L, L->top.p, L1);
|
||||
api_incr_top(L);
|
||||
preinit_thread(L1, g);
|
||||
L1->hookmask = L->hookmask;
|
||||
@@ -315,7 +312,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
|
||||
|
||||
void luaE_freethread (lua_State *L, lua_State *L1) {
|
||||
LX *l = fromstate(L1);
|
||||
luaF_closeupval(L1, L1->stack); /* close all upvalues */
|
||||
luaF_closeupval(L1, L1->stack.p); /* close all upvalues */
|
||||
lua_assert(L1->openupval == NULL);
|
||||
luai_userstatefree(L, L1);
|
||||
freestack(L1);
|
||||
@@ -325,26 +322,27 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
|
||||
|
||||
int luaE_resetthread (lua_State *L, int status) {
|
||||
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
|
||||
setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
|
||||
ci->func = L->stack;
|
||||
setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
|
||||
ci->func.p = L->stack.p;
|
||||
ci->callstatus = CIST_C;
|
||||
if (status == LUA_YIELD)
|
||||
status = LUA_OK;
|
||||
L->status = LUA_OK; /* so it can run __close metamethods */
|
||||
status = luaD_closeprotected(L, 1, status);
|
||||
if (status != LUA_OK) /* errors? */
|
||||
luaD_seterrorobj(L, status, L->stack + 1);
|
||||
luaD_seterrorobj(L, status, L->stack.p + 1);
|
||||
else
|
||||
L->top = L->stack + 1;
|
||||
ci->top = L->top + LUA_MINSTACK;
|
||||
L->status = cast_byte(status);
|
||||
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
|
||||
L->top.p = L->stack.p + 1;
|
||||
ci->top.p = L->top.p + LUA_MINSTACK;
|
||||
luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
LUA_API int lua_resetthread (lua_State *L) {
|
||||
LUA_API int lua_resetthread (lua_State *L, lua_State *from) {
|
||||
int status;
|
||||
lua_lock(L);
|
||||
L->nCcalls = (from) ? getCcalls(from) : 0;
|
||||
status = luaE_resetthread(L, L->status);
|
||||
lua_unlock(L);
|
||||
return status;
|
||||
@@ -371,7 +369,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
||||
g->warnf = NULL;
|
||||
g->ud_warn = NULL;
|
||||
g->mainthread = L;
|
||||
g->gcrunning = 0; /* no GC while building state */
|
||||
g->gcstp = GCSTPGC; /* no GC while building state */
|
||||
g->strt.size = g->strt.nuse = 0;
|
||||
g->strt.hash = NULL;
|
||||
setnilvalue(&g->l_registry);
|
||||
@@ -424,7 +422,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
|
||||
** Generate a warning from an error message
|
||||
*/
|
||||
void luaE_warnerror (lua_State *L, const char *where) {
|
||||
TValue *errobj = s2v(L->top - 1); /* error object */
|
||||
TValue *errobj = s2v(L->top.p - 1); /* error object */
|
||||
const char *msg = (ttisstring(errobj))
|
||||
? svalue(errobj)
|
||||
: "error object is not a string";
|
||||
|
||||
@@ -139,7 +139,7 @@ struct lua_longjmp; /* defined in ldo.c */
|
||||
|
||||
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
|
||||
|
||||
#define stacksize(th) cast_int((th)->stack_last - (th)->stack)
|
||||
#define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
|
||||
|
||||
|
||||
/* kinds of Garbage Collection */
|
||||
@@ -165,13 +165,13 @@ typedef struct stringtable {
|
||||
** - field 'nyield' is used only while a function is "doing" an
|
||||
** yield (from the yield until the next resume);
|
||||
** - field 'nres' is used only while closing tbc variables when
|
||||
** returning from a C function;
|
||||
** returning from a function;
|
||||
** - field 'transferinfo' is used only during call/returnhooks,
|
||||
** before the function starts or after it ends.
|
||||
*/
|
||||
typedef struct CallInfo {
|
||||
StkId func; /* function index in the stack */
|
||||
StkId top; /* top for this function */
|
||||
StkIdRel func; /* function index in the stack */
|
||||
StkIdRel top; /* top for this function */
|
||||
struct CallInfo *previous, *next; /* dynamic call link */
|
||||
union {
|
||||
struct { /* only for Lua functions */
|
||||
@@ -209,7 +209,7 @@ typedef struct CallInfo {
|
||||
#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */
|
||||
#define CIST_TAIL (1<<5) /* call was tail called */
|
||||
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
|
||||
#define CIST_FIN (1<<7) /* call is running a finalizer */
|
||||
#define CIST_FIN (1<<7) /* function "called" a finalizer */
|
||||
#define CIST_TRAN (1<<8) /* 'ci' has transfer information */
|
||||
#define CIST_CLSRET (1<<9) /* function is closing tbc variables */
|
||||
/* Bits 10-12 are used for CIST_RECST (see below) */
|
||||
@@ -262,7 +262,7 @@ typedef struct global_State {
|
||||
lu_byte gcstopem; /* stops emergency collections */
|
||||
lu_byte genminormul; /* control for minor generational collections */
|
||||
lu_byte genmajormul; /* control for major generational collections */
|
||||
lu_byte gcrunning; /* true if GC is running */
|
||||
lu_byte gcstp; /* control whether GC is running */
|
||||
lu_byte gcemergency; /* true if this is an emergency collection */
|
||||
lu_byte gcpause; /* size of pause between successive GCs */
|
||||
lu_byte gcstepmul; /* GC "speed" */
|
||||
@@ -305,13 +305,13 @@ struct lua_State {
|
||||
lu_byte status;
|
||||
lu_byte allowhook;
|
||||
unsigned short nci; /* number of items in 'ci' list */
|
||||
StkId top; /* first free slot in the stack */
|
||||
StkIdRel top; /* first free slot in the stack */
|
||||
global_State *l_G;
|
||||
CallInfo *ci; /* call info for current function */
|
||||
StkId stack_last; /* end of stack (last element + 1) */
|
||||
StkId stack; /* stack base */
|
||||
StkIdRel stack_last; /* end of stack (last element + 1) */
|
||||
StkIdRel stack; /* stack base */
|
||||
UpVal *openupval; /* list of open upvalues in this stack */
|
||||
StkId tbclist; /* list of to-be-closed variables */
|
||||
StkIdRel tbclist; /* list of to-be-closed variables */
|
||||
GCObject *gclist;
|
||||
struct lua_State *twups; /* list of threads with open upvalues */
|
||||
struct lua_longjmp *errorJmp; /* current error recover point */
|
||||
|
||||
@@ -43,9 +43,10 @@ int luaS_eqlngstr (TString *a, TString *b) {
|
||||
}
|
||||
|
||||
int luaS_eqshrstr (TString *a, TString *b) {
|
||||
int r;
|
||||
lu_byte len = a->shrlen;
|
||||
lua_assert(b->tt == LUA_VSHRSTR);
|
||||
int r = len == b->shrlen && (memcmp(getstr(a), getstr(b), len) == 0);
|
||||
r = len == b->shrlen && (memcmp(getstr(a), getstr(b), len) == 0);
|
||||
if (r) {
|
||||
if (a->id < b->id) {
|
||||
a->id = b->id;
|
||||
@@ -161,10 +162,11 @@ static unsigned int luai_makeseed(lua_State *L) {
|
||||
void luaS_init (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
int i, j;
|
||||
stringtable *tb;
|
||||
if (STRSEED == 0) {
|
||||
STRSEED = luai_makeseed(L);
|
||||
}
|
||||
stringtable *tb = &G(L)->strt;
|
||||
tb = &G(L)->strt;
|
||||
tb->hash = luaM_newvector(L, MINSTRTABSIZE, TString*);
|
||||
tablerehash(tb->hash, 0, MINSTRTABSIZE); /* clear array */
|
||||
tb->size = MINSTRTABSIZE;
|
||||
|
||||
@@ -1090,13 +1090,31 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
|
||||
|
||||
|
||||
/* valid flags in a format specification */
|
||||
#if !defined(L_FMTFLAGS)
|
||||
#define L_FMTFLAGS "-+ #0"
|
||||
#if !defined(L_FMTFLAGSF)
|
||||
|
||||
/* valid flags for a, A, e, E, f, F, g, and G conversions */
|
||||
#define L_FMTFLAGSF "-+#0 "
|
||||
|
||||
/* valid flags for o, x, and X conversions */
|
||||
#define L_FMTFLAGSX "-#0"
|
||||
|
||||
/* valid flags for d and i conversions */
|
||||
#define L_FMTFLAGSI "-+0 "
|
||||
|
||||
/* valid flags for u conversions */
|
||||
#define L_FMTFLAGSU "-0"
|
||||
|
||||
/* valid flags for c, p, and s conversions */
|
||||
#define L_FMTFLAGSC "-"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** maximum size of each format specification (such as "%-099.99d")
|
||||
** Maximum size of each format specification (such as "%-099.99d"):
|
||||
** Initial '%', flags (up to 5), width (2), period, precision (2),
|
||||
** length modifier (8), conversion specifier, and final '\0', plus some
|
||||
** extra.
|
||||
*/
|
||||
#define MAX_FORMAT 32
|
||||
|
||||
@@ -1189,25 +1207,53 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
|
||||
}
|
||||
|
||||
|
||||
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
|
||||
const char *p = strfrmt;
|
||||
while (*p != '\0' && strchr(L_FMTFLAGS, *p) != NULL) p++; /* skip flags */
|
||||
if ((size_t)(p - strfrmt) >= sizeof(L_FMTFLAGS)/sizeof(char))
|
||||
luaL_error(L, "invalid format (repeated flags)");
|
||||
if (isdigit(uchar(*p))) p++; /* skip width */
|
||||
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
|
||||
if (*p == '.') {
|
||||
p++;
|
||||
if (isdigit(uchar(*p))) p++; /* skip precision */
|
||||
if (isdigit(uchar(*p))) p++; /* (2 digits at most) */
|
||||
static const char *get2digits (const char *s) {
|
||||
if (isdigit(uchar(*s))) {
|
||||
s++;
|
||||
if (isdigit(uchar(*s))) s++; /* (2 digits at most) */
|
||||
}
|
||||
if (isdigit(uchar(*p)))
|
||||
luaL_error(L, "invalid format (width or precision too long)");
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Check whether a conversion specification is valid. When called,
|
||||
** first character in 'form' must be '%' and last character must
|
||||
** be a valid conversion specifier. 'flags' are the accepted flags;
|
||||
** 'precision' signals whether to accept a precision.
|
||||
*/
|
||||
static void checkformat (lua_State *L, const char *form, const char *flags,
|
||||
int precision) {
|
||||
const char *spec = form + 1; /* skip '%' */
|
||||
spec += strspn(spec, flags); /* skip flags */
|
||||
if (*spec != '0') { /* a width cannot start with '0' */
|
||||
spec = get2digits(spec); /* skip width */
|
||||
if (*spec == '.' && precision) {
|
||||
spec++;
|
||||
spec = get2digits(spec); /* skip precision */
|
||||
}
|
||||
}
|
||||
if (!isalpha(uchar(*spec))) /* did not go to the end? */
|
||||
luaL_error(L, "invalid conversion specification: '%s'", form);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Get a conversion specification and copy it to 'form'.
|
||||
** Return the address of its last character.
|
||||
*/
|
||||
static const char *getformat (lua_State *L, const char *strfrmt,
|
||||
char *form) {
|
||||
/* spans flags, width, and precision ('0' is included as a flag) */
|
||||
size_t len = strspn(strfrmt, L_FMTFLAGSF "123456789.");
|
||||
len++; /* adds following character (should be the specifier) */
|
||||
/* still needs space for '%', '\0', plus a length modifier */
|
||||
if (len >= MAX_FORMAT - 10)
|
||||
luaL_error(L, "invalid format (too long)");
|
||||
*(form++) = '%';
|
||||
memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
|
||||
form += (p - strfrmt) + 1;
|
||||
*form = '\0';
|
||||
return p;
|
||||
memcpy(form, strfrmt, len * sizeof(char));
|
||||
*(form + len) = '\0';
|
||||
return strfrmt + len - 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1230,6 +1276,7 @@ static int str_format (lua_State *L) {
|
||||
size_t sfl;
|
||||
const char *strfrmt = luaL_checklstring(L, arg, &sfl);
|
||||
const char *strfrmt_end = strfrmt+sfl;
|
||||
const char *flags;
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
while (strfrmt < strfrmt_end) {
|
||||
@@ -1239,25 +1286,35 @@ static int str_format (lua_State *L) {
|
||||
luaL_addchar(&b, *strfrmt++); /* %% */
|
||||
else { /* format item */
|
||||
char form[MAX_FORMAT]; /* to store the format ('%...') */
|
||||
int maxitem = MAX_ITEM;
|
||||
char *buff = luaL_prepbuffsize(&b, maxitem); /* to put formatted item */
|
||||
int nb = 0; /* number of bytes in added item */
|
||||
int maxitem = MAX_ITEM; /* maximum length for the result */
|
||||
char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */
|
||||
int nb = 0; /* number of bytes in result */
|
||||
if (++arg > top)
|
||||
return luaL_argerror(L, arg, "no value");
|
||||
strfrmt = scanformat(L, strfrmt, form);
|
||||
strfrmt = getformat(L, strfrmt, form);
|
||||
switch (*strfrmt++) {
|
||||
case 'c': {
|
||||
checkformat(L, form, L_FMTFLAGSC, 0);
|
||||
nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg));
|
||||
break;
|
||||
}
|
||||
case 'd': case 'i':
|
||||
case 'o': case 'u': case 'x': case 'X': {
|
||||
flags = L_FMTFLAGSI;
|
||||
goto intcase;
|
||||
case 'u':
|
||||
flags = L_FMTFLAGSU;
|
||||
goto intcase;
|
||||
case 'o': case 'x': case 'X':
|
||||
flags = L_FMTFLAGSX;
|
||||
intcase: {
|
||||
lua_Integer n = luaL_checkinteger(L, arg);
|
||||
checkformat(L, form, flags, 1);
|
||||
addlenmod(form, LUA_INTEGER_FRMLEN);
|
||||
nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n);
|
||||
break;
|
||||
}
|
||||
case 'a': case 'A':
|
||||
checkformat(L, form, L_FMTFLAGSF, 1);
|
||||
addlenmod(form, LUA_NUMBER_FRMLEN);
|
||||
nb = lua_number2strx(L, buff, maxitem, form,
|
||||
luaL_checknumber(L, arg));
|
||||
@@ -1268,12 +1325,14 @@ static int str_format (lua_State *L) {
|
||||
/* FALLTHROUGH */
|
||||
case 'e': case 'E': case 'g': case 'G': {
|
||||
lua_Number n = luaL_checknumber(L, arg);
|
||||
checkformat(L, form, L_FMTFLAGSF, 1);
|
||||
addlenmod(form, LUA_NUMBER_FRMLEN);
|
||||
nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
const void *p = lua_topointer(L, arg);
|
||||
checkformat(L, form, L_FMTFLAGSC, 0);
|
||||
if (p == NULL) { /* avoid calling 'printf' with argument NULL */
|
||||
p = "(null)"; /* result */
|
||||
form[strlen(form) - 1] = 's'; /* format it as a string */
|
||||
@@ -1294,7 +1353,8 @@ static int str_format (lua_State *L) {
|
||||
luaL_addvalue(&b); /* keep entire string */
|
||||
else {
|
||||
luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
|
||||
if (!strchr(form, '.') && l >= 100) {
|
||||
checkformat(L, form, L_FMTFLAGSC, 1);
|
||||
if (strchr(form, '.') == NULL && l >= 100) {
|
||||
/* no precision and string is too long to be formatted */
|
||||
luaL_addvalue(&b); /* keep entire string */
|
||||
}
|
||||
@@ -1352,15 +1412,6 @@ static const union {
|
||||
} nativeendian = {1};
|
||||
|
||||
|
||||
/* dummy structure to get native alignment requirements */
|
||||
struct cD {
|
||||
char c;
|
||||
union { double d; void *p; lua_Integer i; lua_Number n; } u;
|
||||
};
|
||||
|
||||
#define MAXALIGN (offsetof(struct cD, u))
|
||||
|
||||
|
||||
/*
|
||||
** information to pack/unpack stuff
|
||||
*/
|
||||
@@ -1435,6 +1486,8 @@ static void initheader (lua_State *L, Header *h) {
|
||||
** Read and classify next option. 'size' is filled with option's size.
|
||||
*/
|
||||
static KOption getoption (Header *h, const char **fmt, int *size) {
|
||||
/* dummy structure to get native alignment requirements */
|
||||
struct cD { char c; union { LUAI_MAXALIGN; } u; };
|
||||
int opt = *((*fmt)++);
|
||||
*size = 0; /* default */
|
||||
switch (opt) {
|
||||
@@ -1465,7 +1518,11 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
|
||||
case '<': h->islittle = 1; break;
|
||||
case '>': h->islittle = 0; break;
|
||||
case '=': h->islittle = nativeendian.little; break;
|
||||
case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break;
|
||||
case '!': {
|
||||
const int maxalign = offsetof(struct cD, u);
|
||||
h->maxalign = getnumlimit(h, fmt, maxalign);
|
||||
break;
|
||||
}
|
||||
default: luaL_error(h->L, "invalid format option '%c'", opt);
|
||||
}
|
||||
return Knop;
|
||||
|
||||
@@ -84,8 +84,6 @@
|
||||
#define hashstr(t,str) hashpow2(t, (str)->hash)
|
||||
#define hashboolean(t,p) hashpow2(t, p)
|
||||
|
||||
#define hashint(t,i) hashpow2(t, i)
|
||||
|
||||
|
||||
#define hashpointer(t,p) hashmod(t, point2uint(p))
|
||||
|
||||
@@ -101,6 +99,20 @@ static const Node dummynode_ = {
|
||||
static const TValue absentkey = {ABSTKEYCONSTANT};
|
||||
|
||||
|
||||
/*
|
||||
** Hash for integers. To allow a good hash, use the remainder operator
|
||||
** ('%'). If integer fits as a non-negative int, compute an int
|
||||
** remainder, which is faster. Otherwise, use an unsigned-integer
|
||||
** remainder, which uses all bits and ensures a non-negative result.
|
||||
*/
|
||||
static Node *hashint (const Table *t, lua_Integer i) {
|
||||
lua_Unsigned ui = l_castS2U(i);
|
||||
if (ui <= cast_uint(INT_MAX))
|
||||
return hashmod(t, cast_int(ui));
|
||||
else
|
||||
return hashmod(t, ui);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Hash for floating-point numbers.
|
||||
@@ -134,26 +146,24 @@ static int l_hashfloat (lua_Number n) {
|
||||
|
||||
/*
|
||||
** returns the 'main' position of an element in a table (that is,
|
||||
** the index of its hash value). The key comes broken (tag in 'ktt'
|
||||
** and value in 'vkl') so that we can call it on keys inserted into
|
||||
** nodes.
|
||||
** the index of its hash value).
|
||||
*/
|
||||
static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
|
||||
switch (withvariant(ktt)) {
|
||||
static Node *mainpositionTV (const Table *t, const TValue *key) {
|
||||
switch (ttypetag(key)) {
|
||||
case LUA_VNUMINT: {
|
||||
lua_Integer key = ivalueraw(*kvl);
|
||||
return hashint(t, key);
|
||||
lua_Integer i = ivalue(key);
|
||||
return hashint(t, i);
|
||||
}
|
||||
case LUA_VNUMFLT: {
|
||||
lua_Number n = fltvalueraw(*kvl);
|
||||
lua_Number n = fltvalue(key);
|
||||
return hashmod(t, l_hashfloat(n));
|
||||
}
|
||||
case LUA_VSHRSTR: {
|
||||
TString *ts = tsvalueraw(*kvl);
|
||||
TString *ts = tsvalue(key);
|
||||
return hashstr(t, ts);
|
||||
}
|
||||
case LUA_VLNGSTR: {
|
||||
TString *ts = tsvalueraw(*kvl);
|
||||
TString *ts = tsvalue(key);
|
||||
return hashpow2(t, luaS_hashlongstr(ts));
|
||||
}
|
||||
case LUA_VFALSE:
|
||||
@@ -161,26 +171,25 @@ static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
|
||||
case LUA_VTRUE:
|
||||
return hashboolean(t, 1);
|
||||
case LUA_VLIGHTUSERDATA: {
|
||||
void *p = pvalueraw(*kvl);
|
||||
void *p = pvalue(key);
|
||||
return hashpointer(t, p);
|
||||
}
|
||||
case LUA_VLCF: {
|
||||
lua_CFunction f = fvalueraw(*kvl);
|
||||
lua_CFunction f = fvalue(key);
|
||||
return hashpointer(t, f);
|
||||
}
|
||||
default: {
|
||||
GCObject *o = gcvalueraw(*kvl);
|
||||
GCObject *o = gcvalue(key);
|
||||
return hashpointer(t, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Returns the main position of an element given as a 'TValue'
|
||||
*/
|
||||
static Node *mainpositionTV (const Table *t, const TValue *key) {
|
||||
return mainposition(t, rawtt(key), valraw(key));
|
||||
l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) {
|
||||
TValue key;
|
||||
getnodekey(cast(lua_State *, NULL), &key, nd);
|
||||
return mainpositionTV(t, &key);
|
||||
}
|
||||
|
||||
|
||||
@@ -481,7 +490,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
|
||||
luaG_runerror(L, "table overflow");
|
||||
size = twoto(lsize);
|
||||
t->node = luaM_newvector(L, size, Node);
|
||||
for (i = 0; i < (int)size; i++) {
|
||||
for (i = 0; i < cast_int(size); i++) {
|
||||
Node *n = gnode(t, i);
|
||||
gnext(n) = 0;
|
||||
setnilkey(n);
|
||||
@@ -683,7 +692,7 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
|
||||
return;
|
||||
}
|
||||
lua_assert(!isdummy(t));
|
||||
othern = mainposition(t, keytt(mp), &keyval(mp));
|
||||
othern = mainpositionfromnode(t, mp);
|
||||
if (othern != mp) { /* is colliding node out of its main position? */
|
||||
/* yes; move colliding node into free position */
|
||||
while (othern + gnext(othern) != mp) /* find previous */
|
||||
@@ -976,6 +985,4 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
|
||||
return mainpositionTV(t, key);
|
||||
}
|
||||
|
||||
int luaH_isdummy (const Table *t) { return isdummy(t); }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -59,7 +59,6 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t);
|
||||
|
||||
#if defined(LUA_DEBUG)
|
||||
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
|
||||
LUAI_FUNC int luaH_isdummy (const Table *t);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -59,8 +59,9 @@ static void checktab (lua_State *L, int arg, int what) {
|
||||
|
||||
|
||||
static int tinsert (lua_State *L) {
|
||||
lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
|
||||
lua_Integer pos; /* where to insert new element */
|
||||
lua_Integer e = aux_getn(L, 1, TAB_RW);
|
||||
e = luaL_intop(+, e, 1); /* first empty element */
|
||||
switch (lua_gettop(L)) {
|
||||
case 2: { /* called with only 2 arguments */
|
||||
pos = e; /* insert new element at the end */
|
||||
@@ -92,7 +93,7 @@ static int tremove (lua_State *L) {
|
||||
lua_Integer pos = luaL_optinteger(L, 2, size);
|
||||
if (pos != size) /* validate 'pos' if given */
|
||||
/* check whether 'pos' is in [1, size + 1] */
|
||||
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1,
|
||||
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
|
||||
"position out of bounds");
|
||||
lua_geti(L, 1, pos); /* result = t[pos] */
|
||||
for ( ; pos < size; pos++) {
|
||||
@@ -147,7 +148,7 @@ static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
|
||||
lua_geti(L, 1, i);
|
||||
if (l_unlikely(!lua_isstring(L, -1)))
|
||||
luaL_error(L, "invalid value (%s) at index %I in table for 'concat'",
|
||||
luaL_typename(L, -1), i);
|
||||
luaL_typename(L, -1), (LUAI_UACINT)i);
|
||||
luaL_addvalue(b);
|
||||
}
|
||||
|
||||
|
||||
1977
3rd/lua/ltests.c
Normal file
1977
3rd/lua/ltests.c
Normal file
File diff suppressed because it is too large
Load Diff
151
3rd/lua/ltests.h
Normal file
151
3rd/lua/ltests.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
** $Id: ltests.h $
|
||||
** Internal Header for Debugging of the Lua Implementation
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#ifndef ltests_h
|
||||
#define ltests_h
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* test Lua with compatibility code */
|
||||
#define LUA_COMPAT_MATHLIB
|
||||
#define LUA_COMPAT_LT_LE
|
||||
|
||||
|
||||
#define LUA_DEBUG
|
||||
|
||||
|
||||
/* turn on assertions */
|
||||
#define LUAI_ASSERT
|
||||
|
||||
|
||||
/* to avoid warnings, and to make sure value is really unused */
|
||||
#define UNUSED(x) (x=0, (void)(x))
|
||||
|
||||
|
||||
/* test for sizes in 'l_sprintf' (make sure whole buffer is available) */
|
||||
#undef l_sprintf
|
||||
#if !defined(LUA_USE_C89)
|
||||
#define l_sprintf(s,sz,f,i) (memset(s,0xAB,sz), snprintf(s,sz,f,i))
|
||||
#else
|
||||
#define l_sprintf(s,sz,f,i) (memset(s,0xAB,sz), sprintf(s,f,i))
|
||||
#endif
|
||||
|
||||
|
||||
/* get a chance to test code without jump tables */
|
||||
#define LUA_USE_JUMPTABLE 0
|
||||
|
||||
|
||||
/* use 32-bit integers in random generator */
|
||||
#define LUA_RAND32
|
||||
|
||||
|
||||
/* memory-allocator control variables */
|
||||
typedef struct Memcontrol {
|
||||
int failnext;
|
||||
unsigned long numblocks;
|
||||
unsigned long total;
|
||||
unsigned long maxmem;
|
||||
unsigned long memlimit;
|
||||
unsigned long countlimit;
|
||||
unsigned long objcount[LUA_NUMTYPES];
|
||||
} Memcontrol;
|
||||
|
||||
LUA_API Memcontrol l_memcontrol;
|
||||
|
||||
|
||||
/*
|
||||
** generic variable for debug tricks
|
||||
*/
|
||||
extern void *l_Trick;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** Function to traverse and check all memory used by Lua
|
||||
*/
|
||||
LUAI_FUNC int lua_checkmemory (lua_State *L);
|
||||
|
||||
/*
|
||||
** Function to print an object GC-friendly
|
||||
*/
|
||||
struct GCObject;
|
||||
LUAI_FUNC void lua_printobj (lua_State *L, struct GCObject *o);
|
||||
|
||||
|
||||
/* test for lock/unlock */
|
||||
|
||||
struct L_EXTRA { int lock; int *plock; };
|
||||
#undef LUA_EXTRASPACE
|
||||
#define LUA_EXTRASPACE sizeof(struct L_EXTRA)
|
||||
#define getlock(l) cast(struct L_EXTRA*, lua_getextraspace(l))
|
||||
#define luai_userstateopen(l) \
|
||||
(getlock(l)->lock = 0, getlock(l)->plock = &(getlock(l)->lock))
|
||||
#define luai_userstateclose(l) \
|
||||
lua_assert(getlock(l)->lock == 1 && getlock(l)->plock == &(getlock(l)->lock))
|
||||
#define luai_userstatethread(l,l1) \
|
||||
lua_assert(getlock(l1)->plock == getlock(l)->plock)
|
||||
#define luai_userstatefree(l,l1) \
|
||||
lua_assert(getlock(l)->plock == getlock(l1)->plock)
|
||||
#define lua_lock(l) lua_assert((*getlock(l)->plock)++ == 0)
|
||||
#define lua_unlock(l) lua_assert(--(*getlock(l)->plock) == 0)
|
||||
|
||||
|
||||
|
||||
LUA_API int luaB_opentests (lua_State *L);
|
||||
|
||||
LUA_API void *debug_realloc (void *ud, void *block,
|
||||
size_t osize, size_t nsize);
|
||||
|
||||
#if defined(lua_c)
|
||||
#define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol)
|
||||
#define luaL_openlibs(L) \
|
||||
{ (luaL_openlibs)(L); \
|
||||
luaL_requiref(L, "T", luaB_opentests, 1); \
|
||||
lua_pop(L, 1); }
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* change some sizes to give some bugs a chance */
|
||||
|
||||
#undef LUAL_BUFFERSIZE
|
||||
#define LUAL_BUFFERSIZE 23
|
||||
#define MINSTRTABSIZE 2
|
||||
#define MAXIWTHABS 3
|
||||
|
||||
#define STRCACHE_N 23
|
||||
#define STRCACHE_M 5
|
||||
|
||||
#undef LUAI_USER_ALIGNMENT_T
|
||||
#define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; }
|
||||
|
||||
|
||||
/*
|
||||
** This one is not compatible with tests for opcode optimizations,
|
||||
** as it blocks some optimizations
|
||||
#define MAXINDEXRK 0
|
||||
*/
|
||||
|
||||
|
||||
/* make stack-overflow tests run faster */
|
||||
#undef LUAI_MAXSTACK
|
||||
#define LUAI_MAXSTACK 50000
|
||||
|
||||
|
||||
/* test mode uses more stack space */
|
||||
#undef LUAI_MAXCCALLS
|
||||
#define LUAI_MAXCCALLS 180
|
||||
|
||||
|
||||
/* force Lua to use its own implementations */
|
||||
#undef lua_strx2number
|
||||
#undef lua_number2strx
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -102,12 +102,12 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
|
||||
|
||||
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
||||
const TValue *p2, const TValue *p3) {
|
||||
StkId func = L->top;
|
||||
StkId func = L->top.p;
|
||||
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
|
||||
setobj2s(L, func + 1, p1); /* 1st argument */
|
||||
setobj2s(L, func + 2, p2); /* 2nd argument */
|
||||
setobj2s(L, func + 3, p3); /* 3rd argument */
|
||||
L->top = func + 4;
|
||||
L->top.p = func + 4;
|
||||
/* metamethod may yield only when called from Lua code */
|
||||
if (isLuacode(L->ci))
|
||||
luaD_call(L, func, 0);
|
||||
@@ -119,18 +119,18 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
|
||||
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
|
||||
const TValue *p2, StkId res) {
|
||||
ptrdiff_t result = savestack(L, res);
|
||||
StkId func = L->top;
|
||||
StkId func = L->top.p;
|
||||
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
|
||||
setobj2s(L, func + 1, p1); /* 1st argument */
|
||||
setobj2s(L, func + 2, p2); /* 2nd argument */
|
||||
L->top += 3;
|
||||
L->top.p += 3;
|
||||
/* metamethod may yield only when called from Lua code */
|
||||
if (isLuacode(L->ci))
|
||||
luaD_call(L, func, 1);
|
||||
else
|
||||
luaD_callnoyield(L, func, 1);
|
||||
res = restorestack(L, result);
|
||||
setobjs2s(L, res, --L->top); /* move result to its place */
|
||||
setobjs2s(L, res, --L->top.p); /* move result to its place */
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||
|
||||
|
||||
void luaT_tryconcatTM (lua_State *L) {
|
||||
StkId top = L->top;
|
||||
StkId top = L->top.p;
|
||||
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
|
||||
TM_CONCAT)))
|
||||
luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
|
||||
@@ -200,15 +200,15 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
|
||||
*/
|
||||
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
|
||||
TMS event) {
|
||||
if (callbinTM(L, p1, p2, L->top, event)) /* try original event */
|
||||
return !l_isfalse(s2v(L->top));
|
||||
if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */
|
||||
return !l_isfalse(s2v(L->top.p));
|
||||
#if defined(LUA_COMPAT_LT_LE)
|
||||
else if (event == TM_LE) {
|
||||
/* try '!(p2 < p1)' for '(p1 <= p2)' */
|
||||
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
|
||||
if (callbinTM(L, p2, p1, L->top, TM_LT)) {
|
||||
if (callbinTM(L, p2, p1, L->top.p, TM_LT)) {
|
||||
L->ci->callstatus ^= CIST_LEQ; /* clear mark */
|
||||
return l_isfalse(s2v(L->top));
|
||||
return l_isfalse(s2v(L->top.p));
|
||||
}
|
||||
/* else error will remove this 'ci'; no need to clear mark */
|
||||
}
|
||||
@@ -238,20 +238,20 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
|
||||
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
|
||||
const Proto *p) {
|
||||
int i;
|
||||
int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */
|
||||
int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */
|
||||
int nextra = actual - nfixparams; /* number of extra arguments */
|
||||
ci->u.l.nextraargs = nextra;
|
||||
luaD_checkstack(L, p->maxstacksize + 1);
|
||||
/* copy function to the top of the stack */
|
||||
setobjs2s(L, L->top++, ci->func);
|
||||
setobjs2s(L, L->top.p++, ci->func.p);
|
||||
/* move fixed parameters to the top of the stack */
|
||||
for (i = 1; i <= nfixparams; i++) {
|
||||
setobjs2s(L, L->top++, ci->func + i);
|
||||
setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */
|
||||
setobjs2s(L, L->top.p++, ci->func.p + i);
|
||||
setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
|
||||
}
|
||||
ci->func += actual + 1;
|
||||
ci->top += actual + 1;
|
||||
lua_assert(L->top <= ci->top && ci->top <= L->stack_last);
|
||||
ci->func.p += actual + 1;
|
||||
ci->top.p += actual + 1;
|
||||
lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
|
||||
}
|
||||
|
||||
|
||||
@@ -261,10 +261,10 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
|
||||
if (wanted < 0) {
|
||||
wanted = nextra; /* get all extra arguments available */
|
||||
checkstackGCp(L, nextra, where); /* ensure stack space */
|
||||
L->top = where + nextra; /* next instruction will need top */
|
||||
L->top.p = where + nextra; /* next instruction will need top */
|
||||
}
|
||||
for (i = 0; i < wanted && i < nextra; i++)
|
||||
setobjs2s(L, where + i, ci->func - nextra + i);
|
||||
setobjs2s(L, where + i, ci->func.p - nextra + i);
|
||||
for (; i < wanted; i++) /* complete required results with nil */
|
||||
setnilvalue(s2v(where + i));
|
||||
}
|
||||
|
||||
@@ -89,14 +89,15 @@ static void print_usage (const char *badoption) {
|
||||
lua_writestringerror(
|
||||
"usage: %s [options] [script [args]]\n"
|
||||
"Available options are:\n"
|
||||
" -e stat execute string 'stat'\n"
|
||||
" -i enter interactive mode after executing 'script'\n"
|
||||
" -l name require library 'name' into global 'name'\n"
|
||||
" -v show version information\n"
|
||||
" -E ignore environment variables\n"
|
||||
" -W turn warnings on\n"
|
||||
" -- stop handling options\n"
|
||||
" - stop handling options and execute stdin\n"
|
||||
" -e stat execute string 'stat'\n"
|
||||
" -i enter interactive mode after executing 'script'\n"
|
||||
" -l mod require library 'mod' into global 'mod'\n"
|
||||
" -l g=mod require library 'mod' into global 'g'\n"
|
||||
" -v show version information\n"
|
||||
" -E ignore environment variables\n"
|
||||
" -W turn warnings on\n"
|
||||
" -- stop handling options\n"
|
||||
" - stop handling options and execute stdin\n"
|
||||
,
|
||||
progname);
|
||||
}
|
||||
@@ -176,10 +177,11 @@ static void print_version (void) {
|
||||
** to the script (everything after 'script') go to positive indices;
|
||||
** other arguments (before the script name) go to negative indices.
|
||||
** If there is no script name, assume interpreter's name as base.
|
||||
** (If there is no interpreter's name either, 'script' is -1, so
|
||||
** table sizes are zero.)
|
||||
*/
|
||||
static void createargtable (lua_State *L, char **argv, int argc, int script) {
|
||||
int i, narg;
|
||||
if (script == argc) script = 0; /* no script name? */
|
||||
narg = argc - (script + 1); /* number of positive indices */
|
||||
lua_createtable(L, narg, script + 1);
|
||||
for (i = 0; i < argc; i++) {
|
||||
@@ -207,16 +209,22 @@ static int dostring (lua_State *L, const char *s, const char *name) {
|
||||
|
||||
|
||||
/*
|
||||
** Calls 'require(name)' and stores the result in a global variable
|
||||
** with the given name.
|
||||
** Receives 'globname[=modname]' and runs 'globname = require(modname)'.
|
||||
*/
|
||||
static int dolibrary (lua_State *L, const char *name) {
|
||||
static int dolibrary (lua_State *L, char *globname) {
|
||||
int status;
|
||||
char *modname = strchr(globname, '=');
|
||||
if (modname == NULL) /* no explicit name? */
|
||||
modname = globname; /* module name is equal to global name */
|
||||
else {
|
||||
*modname = '\0'; /* global name ends here */
|
||||
modname++; /* module name starts after the '=' */
|
||||
}
|
||||
lua_getglobal(L, "require");
|
||||
lua_pushstring(L, name);
|
||||
status = docall(L, 1, 1); /* call 'require(name)' */
|
||||
lua_pushstring(L, modname);
|
||||
status = docall(L, 1, 1); /* call 'require(modname)' */
|
||||
if (status == LUA_OK)
|
||||
lua_setglobal(L, name); /* global[name] = require return */
|
||||
lua_setglobal(L, globname); /* globname = require(modname) */
|
||||
return report(L, status);
|
||||
}
|
||||
|
||||
@@ -261,14 +269,23 @@ static int handle_script (lua_State *L, char **argv) {
|
||||
|
||||
/*
|
||||
** Traverses all arguments from 'argv', returning a mask with those
|
||||
** needed before running any Lua code (or an error code if it finds
|
||||
** any invalid argument). 'first' returns the first not-handled argument
|
||||
** (either the script name or a bad argument in case of error).
|
||||
** needed before running any Lua code or an error code if it finds any
|
||||
** invalid argument. In case of error, 'first' is the index of the bad
|
||||
** argument. Otherwise, 'first' is -1 if there is no program name,
|
||||
** 0 if there is no script name, or the index of the script name.
|
||||
*/
|
||||
static int collectargs (char **argv, int *first) {
|
||||
int args = 0;
|
||||
int i;
|
||||
for (i = 1; argv[i] != NULL; i++) {
|
||||
if (argv[0] != NULL) { /* is there a program name? */
|
||||
if (argv[0][0]) /* not empty? */
|
||||
progname = argv[0]; /* save it */
|
||||
}
|
||||
else { /* no program name */
|
||||
*first = -1;
|
||||
return 0;
|
||||
}
|
||||
for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
|
||||
*first = i;
|
||||
if (argv[i][0] != '-') /* not an option? */
|
||||
return args; /* stop handling options */
|
||||
@@ -309,7 +326,7 @@ static int collectargs (char **argv, int *first) {
|
||||
return has_error;
|
||||
}
|
||||
}
|
||||
*first = i; /* no script name */
|
||||
*first = 0; /* no script name */
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -327,7 +344,7 @@ static int runargs (lua_State *L, char **argv, int n) {
|
||||
switch (option) {
|
||||
case 'e': case 'l': {
|
||||
int status;
|
||||
const char *extra = argv[i] + 2; /* both options need an argument */
|
||||
char *extra = argv[i] + 2; /* both options need an argument */
|
||||
if (*extra == '\0') extra = argv[++i];
|
||||
lua_assert(extra != NULL);
|
||||
status = (option == 'e')
|
||||
@@ -602,8 +619,8 @@ static int pmain (lua_State *L) {
|
||||
char **argv = (char **)lua_touserdata(L, 2);
|
||||
int script;
|
||||
int args = collectargs(argv, &script);
|
||||
int optlim = (script > 0) ? script : argc; /* first argv not an option */
|
||||
luaL_checkversion(L); /* check that interpreter has correct version */
|
||||
if (argv[0] && argv[0][0]) progname = argv[0];
|
||||
if (args == has_error) { /* bad arg? */
|
||||
print_usage(argv[script]); /* 'script' has index of bad arg. */
|
||||
return 0;
|
||||
@@ -621,14 +638,15 @@ static int pmain (lua_State *L) {
|
||||
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
|
||||
return 0; /* error running LUA_INIT */
|
||||
}
|
||||
if (!runargs(L, argv, script)) /* execute arguments -e and -l */
|
||||
if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */
|
||||
return 0; /* something failed */
|
||||
if (script < argc && /* execute main script (if there is one) */
|
||||
handle_script(L, argv + script) != LUA_OK)
|
||||
return 0;
|
||||
if (script > 0) { /* execute main script (if there is one) */
|
||||
if (handle_script(L, argv + script) != LUA_OK)
|
||||
return 0; /* interrupt in case of error */
|
||||
}
|
||||
if (args & has_i) /* -i option? */
|
||||
doREPL(L); /* do read-eval-print loop */
|
||||
else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */
|
||||
else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
|
||||
if (lua_stdin_is_tty()) { /* running in interactive mode? */
|
||||
print_version();
|
||||
doREPL(L); /* do read-eval-print loop */
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
|
||||
#define LUA_VERSION_MAJOR "5"
|
||||
#define LUA_VERSION_MINOR "4"
|
||||
#define LUA_VERSION_RELEASE "3"
|
||||
#define LUA_VERSION_RELEASE "5"
|
||||
|
||||
#define LUA_VERSION_NUM 504
|
||||
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 0)
|
||||
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 5)
|
||||
|
||||
#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-2021 Lua.org, PUC-Rio"
|
||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio"
|
||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ extern const char lua_ident[];
|
||||
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
|
||||
LUA_API void (lua_close) (lua_State *L);
|
||||
LUA_API lua_State *(lua_newthread) (lua_State *L);
|
||||
LUA_API int (lua_resetthread) (lua_State *L);
|
||||
LUA_API int (lua_resetthread) (lua_State *L, lua_State *from);
|
||||
|
||||
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
|
||||
|
||||
@@ -496,7 +496,7 @@ struct lua_Debug {
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright (C) 1994-2021 Lua.org, PUC-Rio.
|
||||
* Copyright (C) 1994-2022 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
|
||||
|
||||
724
3rd/lua/luac.c
724
3rd/lua/luac.c
@@ -1,724 +0,0 @@
|
||||
/*
|
||||
** $Id: luac.c $
|
||||
** Lua compiler (saves bytecodes to files; also lists bytecodes)
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
#define luac_c
|
||||
#define LUA_CORE
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
|
||||
#include "ldebug.h"
|
||||
#include "lobject.h"
|
||||
#include "lopcodes.h"
|
||||
#include "lopnames.h"
|
||||
#include "lstate.h"
|
||||
#include "lundump.h"
|
||||
|
||||
static void PrintFunction(const Proto* f, int full);
|
||||
#define luaU_print PrintFunction
|
||||
|
||||
#define PROGNAME "luac" /* default program name */
|
||||
#define OUTPUT PROGNAME ".out" /* default output file */
|
||||
|
||||
static int listing=0; /* list bytecodes? */
|
||||
static int dumping=1; /* dump bytecodes? */
|
||||
static int stripping=0; /* strip debug information? */
|
||||
static char Output[]={ OUTPUT }; /* default output file name */
|
||||
static const char* output=Output; /* actual output file name */
|
||||
static const char* progname=PROGNAME; /* actual program name */
|
||||
static TString **tmname;
|
||||
|
||||
static void fatal(const char* message)
|
||||
{
|
||||
fprintf(stderr,"%s: %s\n",progname,message);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void cannot(const char* what)
|
||||
{
|
||||
fprintf(stderr,"%s: cannot %s %s: %s\n",progname,what,output,strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void usage(const char* message)
|
||||
{
|
||||
if (*message=='-')
|
||||
fprintf(stderr,"%s: unrecognized option '%s'\n",progname,message);
|
||||
else
|
||||
fprintf(stderr,"%s: %s\n",progname,message);
|
||||
fprintf(stderr,
|
||||
"usage: %s [options] [filenames]\n"
|
||||
"Available options are:\n"
|
||||
" -l list (use -l -l for full listing)\n"
|
||||
" -o name output to file 'name' (default is \"%s\")\n"
|
||||
" -p parse only\n"
|
||||
" -s strip debug information\n"
|
||||
" -v show version information\n"
|
||||
" -- stop handling options\n"
|
||||
" - stop handling options and process stdin\n"
|
||||
,progname,Output);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define IS(s) (strcmp(argv[i],s)==0)
|
||||
|
||||
static int doargs(int argc, char* argv[])
|
||||
{
|
||||
int i;
|
||||
int version=0;
|
||||
if (argv[0]!=NULL && *argv[0]!=0) progname=argv[0];
|
||||
for (i=1; i<argc; i++)
|
||||
{
|
||||
if (*argv[i]!='-') /* end of options; keep it */
|
||||
break;
|
||||
else if (IS("--")) /* end of options; skip it */
|
||||
{
|
||||
++i;
|
||||
if (version) ++version;
|
||||
break;
|
||||
}
|
||||
else if (IS("-")) /* end of options; use stdin */
|
||||
break;
|
||||
else if (IS("-l")) /* list */
|
||||
++listing;
|
||||
else if (IS("-o")) /* output file */
|
||||
{
|
||||
output=argv[++i];
|
||||
if (output==NULL || *output==0 || (*output=='-' && output[1]!=0))
|
||||
usage("'-o' needs argument");
|
||||
if (IS("-")) output=NULL;
|
||||
}
|
||||
else if (IS("-p")) /* parse only */
|
||||
dumping=0;
|
||||
else if (IS("-s")) /* strip debug information */
|
||||
stripping=1;
|
||||
else if (IS("-v")) /* show version */
|
||||
++version;
|
||||
else /* unknown option */
|
||||
usage(argv[i]);
|
||||
}
|
||||
if (i==argc && (listing || !dumping))
|
||||
{
|
||||
dumping=0;
|
||||
argv[--i]=Output;
|
||||
}
|
||||
if (version)
|
||||
{
|
||||
printf("%s\n",LUA_COPYRIGHT);
|
||||
if (version==argc-1) exit(EXIT_SUCCESS);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
#define FUNCTION "(function()end)();"
|
||||
|
||||
static const char* reader(lua_State* L, void* ud, size_t* size)
|
||||
{
|
||||
UNUSED(L);
|
||||
if ((*(int*)ud)--)
|
||||
{
|
||||
*size=sizeof(FUNCTION)-1;
|
||||
return FUNCTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
*size=0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define toproto(L,i) getproto(s2v(L->top+(i)))
|
||||
|
||||
static const Proto* combine(lua_State* L, int n)
|
||||
{
|
||||
if (n==1)
|
||||
return toproto(L,-1);
|
||||
else
|
||||
{
|
||||
Proto* f;
|
||||
int i=n;
|
||||
if (lua_load(L,reader,&i,"=(" PROGNAME ")",NULL)!=LUA_OK) fatal(lua_tostring(L,-1));
|
||||
f=toproto(L,-1);
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
f->p[i]=toproto(L,i-n-1);
|
||||
if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
|
||||
}
|
||||
f->sizelineinfo=0;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
static int writer(lua_State* L, const void* p, size_t size, void* u)
|
||||
{
|
||||
UNUSED(L);
|
||||
return (fwrite(p,size,1,(FILE*)u)!=1) && (size!=0);
|
||||
}
|
||||
|
||||
static int pmain(lua_State* L)
|
||||
{
|
||||
int argc=(int)lua_tointeger(L,1);
|
||||
char** argv=(char**)lua_touserdata(L,2);
|
||||
const Proto* f;
|
||||
int i;
|
||||
tmname=G(L)->tmname;
|
||||
if (!lua_checkstack(L,argc)) fatal("too many input files");
|
||||
for (i=0; i<argc; i++)
|
||||
{
|
||||
const char* filename=IS("-") ? NULL : argv[i];
|
||||
if (luaL_loadfile(L,filename)!=LUA_OK) fatal(lua_tostring(L,-1));
|
||||
}
|
||||
f=combine(L,argc);
|
||||
if (listing) luaU_print(f,listing>1);
|
||||
if (dumping)
|
||||
{
|
||||
FILE* D= (output==NULL) ? stdout : fopen(output,"wb");
|
||||
if (D==NULL) cannot("open");
|
||||
lua_lock(L);
|
||||
luaU_dump(L,f,writer,D,stripping);
|
||||
lua_unlock(L);
|
||||
if (ferror(D)) cannot("write");
|
||||
if (fclose(D)) cannot("close");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
lua_State* L;
|
||||
int i=doargs(argc,argv);
|
||||
argc-=i; argv+=i;
|
||||
if (argc<=0) usage("no input files given");
|
||||
L=luaL_newstate();
|
||||
if (L==NULL) fatal("cannot create state: not enough memory");
|
||||
lua_pushcfunction(L,&pmain);
|
||||
lua_pushinteger(L,argc);
|
||||
lua_pushlightuserdata(L,argv);
|
||||
if (lua_pcall(L,2,0,0)!=LUA_OK) fatal(lua_tostring(L,-1));
|
||||
lua_close(L);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
** print bytecodes
|
||||
*/
|
||||
|
||||
#define UPVALNAME(x) ((f->upvalues[x].name) ? getstr(f->upvalues[x].name) : "-")
|
||||
#define VOID(p) ((const void*)(p))
|
||||
#define eventname(i) (getstr(tmname[i]))
|
||||
|
||||
static void PrintString(const TString* ts)
|
||||
{
|
||||
const char* s=getstr(ts);
|
||||
size_t i,n=tsslen(ts);
|
||||
printf("\"");
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
int c=(int)(unsigned char)s[i];
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
printf("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
printf("\\\\");
|
||||
break;
|
||||
case '\a':
|
||||
printf("\\a");
|
||||
break;
|
||||
case '\b':
|
||||
printf("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
printf("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
printf("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
printf("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
printf("\\t");
|
||||
break;
|
||||
case '\v':
|
||||
printf("\\v");
|
||||
break;
|
||||
default:
|
||||
if (isprint(c)) printf("%c",c); else printf("\\%03d",c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("\"");
|
||||
}
|
||||
|
||||
static void PrintType(const Proto* f, int i)
|
||||
{
|
||||
const TValue* o=&f->k[i];
|
||||
switch (ttypetag(o))
|
||||
{
|
||||
case LUA_VNIL:
|
||||
printf("N");
|
||||
break;
|
||||
case LUA_VFALSE:
|
||||
case LUA_VTRUE:
|
||||
printf("B");
|
||||
break;
|
||||
case LUA_VNUMFLT:
|
||||
printf("F");
|
||||
break;
|
||||
case LUA_VNUMINT:
|
||||
printf("I");
|
||||
break;
|
||||
case LUA_VSHRSTR:
|
||||
case LUA_VLNGSTR:
|
||||
printf("S");
|
||||
break;
|
||||
default: /* cannot happen */
|
||||
printf("?%d",ttypetag(o));
|
||||
break;
|
||||
}
|
||||
printf("\t");
|
||||
}
|
||||
|
||||
static void PrintConstant(const Proto* f, int i)
|
||||
{
|
||||
const TValue* o=&f->k[i];
|
||||
switch (ttypetag(o))
|
||||
{
|
||||
case LUA_VNIL:
|
||||
printf("nil");
|
||||
break;
|
||||
case LUA_VFALSE:
|
||||
printf("false");
|
||||
break;
|
||||
case LUA_VTRUE:
|
||||
printf("true");
|
||||
break;
|
||||
case LUA_VNUMFLT:
|
||||
{
|
||||
char buff[100];
|
||||
sprintf(buff,LUA_NUMBER_FMT,fltvalue(o));
|
||||
printf("%s",buff);
|
||||
if (buff[strspn(buff,"-0123456789")]=='\0') printf(".0");
|
||||
break;
|
||||
}
|
||||
case LUA_VNUMINT:
|
||||
printf(LUA_INTEGER_FMT,ivalue(o));
|
||||
break;
|
||||
case LUA_VSHRSTR:
|
||||
case LUA_VLNGSTR:
|
||||
PrintString(tsvalue(o));
|
||||
break;
|
||||
default: /* cannot happen */
|
||||
printf("?%d",ttypetag(o));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define COMMENT "\t; "
|
||||
#define EXTRAARG GETARG_Ax(code[pc+1])
|
||||
#define EXTRAARGC (EXTRAARG*(MAXARG_C+1))
|
||||
#define ISK (isk ? "k" : "")
|
||||
|
||||
static void PrintCode(const Proto* f)
|
||||
{
|
||||
const Instruction* code=f->code;
|
||||
int pc,n=f->sizecode;
|
||||
for (pc=0; pc<n; pc++)
|
||||
{
|
||||
Instruction i=code[pc];
|
||||
OpCode o=GET_OPCODE(i);
|
||||
int a=GETARG_A(i);
|
||||
int b=GETARG_B(i);
|
||||
int c=GETARG_C(i);
|
||||
int ax=GETARG_Ax(i);
|
||||
int bx=GETARG_Bx(i);
|
||||
int sb=GETARG_sB(i);
|
||||
int sc=GETARG_sC(i);
|
||||
int sbx=GETARG_sBx(i);
|
||||
int isk=GETARG_k(i);
|
||||
int line=luaG_getfuncline(f,pc);
|
||||
printf("\t%d\t",pc+1);
|
||||
if (line>0) printf("[%d]\t",line); else printf("[-]\t");
|
||||
printf("%-9s\t",opnames[o]);
|
||||
switch (o)
|
||||
{
|
||||
case OP_MOVE:
|
||||
printf("%d %d",a,b);
|
||||
break;
|
||||
case OP_LOADI:
|
||||
printf("%d %d",a,sbx);
|
||||
break;
|
||||
case OP_LOADF:
|
||||
printf("%d %d",a,sbx);
|
||||
break;
|
||||
case OP_LOADK:
|
||||
printf("%d %d",a,bx);
|
||||
printf(COMMENT); PrintConstant(f,bx);
|
||||
break;
|
||||
case OP_LOADKX:
|
||||
printf("%d",a);
|
||||
printf(COMMENT); PrintConstant(f,EXTRAARG);
|
||||
break;
|
||||
case OP_LOADFALSE:
|
||||
printf("%d",a);
|
||||
break;
|
||||
case OP_LFALSESKIP:
|
||||
printf("%d",a);
|
||||
break;
|
||||
case OP_LOADTRUE:
|
||||
printf("%d",a);
|
||||
break;
|
||||
case OP_LOADNIL:
|
||||
printf("%d %d",a,b);
|
||||
printf(COMMENT "%d out",b+1);
|
||||
break;
|
||||
case OP_GETUPVAL:
|
||||
printf("%d %d",a,b);
|
||||
printf(COMMENT "%s",UPVALNAME(b));
|
||||
break;
|
||||
case OP_SETUPVAL:
|
||||
printf("%d %d",a,b);
|
||||
printf(COMMENT "%s",UPVALNAME(b));
|
||||
break;
|
||||
case OP_GETTABUP:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT "%s",UPVALNAME(b));
|
||||
printf(" "); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_GETTABLE:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_GETI:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_GETFIELD:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_SETTABUP:
|
||||
printf("%d %d %d%s",a,b,c,ISK);
|
||||
printf(COMMENT "%s",UPVALNAME(a));
|
||||
printf(" "); PrintConstant(f,b);
|
||||
if (isk) { printf(" "); PrintConstant(f,c); }
|
||||
break;
|
||||
case OP_SETTABLE:
|
||||
printf("%d %d %d%s",a,b,c,ISK);
|
||||
if (isk) { printf(COMMENT); PrintConstant(f,c); }
|
||||
break;
|
||||
case OP_SETI:
|
||||
printf("%d %d %d%s",a,b,c,ISK);
|
||||
if (isk) { printf(COMMENT); PrintConstant(f,c); }
|
||||
break;
|
||||
case OP_SETFIELD:
|
||||
printf("%d %d %d%s",a,b,c,ISK);
|
||||
printf(COMMENT); PrintConstant(f,b);
|
||||
if (isk) { printf(" "); PrintConstant(f,c); }
|
||||
break;
|
||||
case OP_NEWTABLE:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT "%d",c+EXTRAARGC);
|
||||
break;
|
||||
case OP_SELF:
|
||||
printf("%d %d %d%s",a,b,c,ISK);
|
||||
if (isk) { printf(COMMENT); PrintConstant(f,c); }
|
||||
break;
|
||||
case OP_ADDI:
|
||||
printf("%d %d %d",a,b,sc);
|
||||
break;
|
||||
case OP_ADDK:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_SUBK:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_MULK:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_MODK:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_POWK:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_DIVK:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_IDIVK:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_BANDK:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_BORK:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_BXORK:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT); PrintConstant(f,c);
|
||||
break;
|
||||
case OP_SHRI:
|
||||
printf("%d %d %d",a,b,sc);
|
||||
break;
|
||||
case OP_SHLI:
|
||||
printf("%d %d %d",a,b,sc);
|
||||
break;
|
||||
case OP_ADD:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_SUB:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_MUL:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_MOD:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_POW:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_DIV:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_IDIV:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_BAND:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_BOR:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_BXOR:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_SHL:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_SHR:
|
||||
printf("%d %d %d",a,b,c);
|
||||
break;
|
||||
case OP_MMBIN:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT "%s",eventname(c));
|
||||
break;
|
||||
case OP_MMBINI:
|
||||
printf("%d %d %d %d",a,sb,c,isk);
|
||||
printf(COMMENT "%s",eventname(c));
|
||||
if (isk) printf(" flip");
|
||||
break;
|
||||
case OP_MMBINK:
|
||||
printf("%d %d %d %d",a,b,c,isk);
|
||||
printf(COMMENT "%s ",eventname(c)); PrintConstant(f,b);
|
||||
if (isk) printf(" flip");
|
||||
break;
|
||||
case OP_UNM:
|
||||
printf("%d %d",a,b);
|
||||
break;
|
||||
case OP_BNOT:
|
||||
printf("%d %d",a,b);
|
||||
break;
|
||||
case OP_NOT:
|
||||
printf("%d %d",a,b);
|
||||
break;
|
||||
case OP_LEN:
|
||||
printf("%d %d",a,b);
|
||||
break;
|
||||
case OP_CONCAT:
|
||||
printf("%d %d",a,b);
|
||||
break;
|
||||
case OP_CLOSE:
|
||||
printf("%d",a);
|
||||
break;
|
||||
case OP_TBC:
|
||||
printf("%d",a);
|
||||
break;
|
||||
case OP_JMP:
|
||||
printf("%d",GETARG_sJ(i));
|
||||
printf(COMMENT "to %d",GETARG_sJ(i)+pc+2);
|
||||
break;
|
||||
case OP_EQ:
|
||||
printf("%d %d %d",a,b,isk);
|
||||
break;
|
||||
case OP_LT:
|
||||
printf("%d %d %d",a,b,isk);
|
||||
break;
|
||||
case OP_LE:
|
||||
printf("%d %d %d",a,b,isk);
|
||||
break;
|
||||
case OP_EQK:
|
||||
printf("%d %d %d",a,b,isk);
|
||||
printf(COMMENT); PrintConstant(f,b);
|
||||
break;
|
||||
case OP_EQI:
|
||||
printf("%d %d %d",a,sb,isk);
|
||||
break;
|
||||
case OP_LTI:
|
||||
printf("%d %d %d",a,sb,isk);
|
||||
break;
|
||||
case OP_LEI:
|
||||
printf("%d %d %d",a,sb,isk);
|
||||
break;
|
||||
case OP_GTI:
|
||||
printf("%d %d %d",a,sb,isk);
|
||||
break;
|
||||
case OP_GEI:
|
||||
printf("%d %d %d",a,sb,isk);
|
||||
break;
|
||||
case OP_TEST:
|
||||
printf("%d %d",a,isk);
|
||||
break;
|
||||
case OP_TESTSET:
|
||||
printf("%d %d %d",a,b,isk);
|
||||
break;
|
||||
case OP_CALL:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT);
|
||||
if (b==0) printf("all in "); else printf("%d in ",b-1);
|
||||
if (c==0) printf("all out"); else printf("%d out",c-1);
|
||||
break;
|
||||
case OP_TAILCALL:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT "%d in",b-1);
|
||||
break;
|
||||
case OP_RETURN:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT);
|
||||
if (b==0) printf("all out"); else printf("%d out",b-1);
|
||||
break;
|
||||
case OP_RETURN0:
|
||||
break;
|
||||
case OP_RETURN1:
|
||||
printf("%d",a);
|
||||
break;
|
||||
case OP_FORLOOP:
|
||||
printf("%d %d",a,bx);
|
||||
printf(COMMENT "to %d",pc-bx+2);
|
||||
break;
|
||||
case OP_FORPREP:
|
||||
printf("%d %d",a,bx);
|
||||
printf(COMMENT "to %d",pc+bx+2);
|
||||
break;
|
||||
case OP_TFORPREP:
|
||||
printf("%d %d",a,bx);
|
||||
printf(COMMENT "to %d",pc+bx+2);
|
||||
break;
|
||||
case OP_TFORCALL:
|
||||
printf("%d %d",a,c);
|
||||
break;
|
||||
case OP_TFORLOOP:
|
||||
printf("%d %d",a,bx);
|
||||
printf(COMMENT "to %d",pc-bx+2);
|
||||
break;
|
||||
case OP_SETLIST:
|
||||
printf("%d %d %d",a,b,c);
|
||||
if (isk) printf(COMMENT "%d",c+EXTRAARGC);
|
||||
break;
|
||||
case OP_CLOSURE:
|
||||
printf("%d %d",a,bx);
|
||||
printf(COMMENT "%p",VOID(f->p[bx]));
|
||||
break;
|
||||
case OP_VARARG:
|
||||
printf("%d %d",a,c);
|
||||
printf(COMMENT);
|
||||
if (c==0) printf("all out"); else printf("%d out",c-1);
|
||||
break;
|
||||
case OP_VARARGPREP:
|
||||
printf("%d",a);
|
||||
break;
|
||||
case OP_EXTRAARG:
|
||||
printf("%d",ax);
|
||||
break;
|
||||
#if 0
|
||||
default:
|
||||
printf("%d %d %d",a,b,c);
|
||||
printf(COMMENT "not handled");
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define SS(x) ((x==1)?"":"s")
|
||||
#define S(x) (int)(x),SS(x)
|
||||
|
||||
static void PrintHeader(const Proto* f)
|
||||
{
|
||||
const char* s=f->source ? getstr(f->source) : "=?";
|
||||
if (*s=='@' || *s=='=')
|
||||
s++;
|
||||
else if (*s==LUA_SIGNATURE[0])
|
||||
s="(bstring)";
|
||||
else
|
||||
s="(string)";
|
||||
printf("\n%s <%s:%d,%d> (%d instruction%s at %p)\n",
|
||||
(f->linedefined==0)?"main":"function",s,
|
||||
f->linedefined,f->lastlinedefined,
|
||||
S(f->sizecode),VOID(f));
|
||||
printf("%d%s param%s, %d slot%s, %d upvalue%s, ",
|
||||
(int)(f->numparams),f->is_vararg?"+":"",SS(f->numparams),
|
||||
S(f->maxstacksize),S(f->sizeupvalues));
|
||||
printf("%d local%s, %d constant%s, %d function%s\n",
|
||||
S(f->sizelocvars),S(f->sizek),S(f->sizep));
|
||||
}
|
||||
|
||||
static void PrintDebug(const Proto* f)
|
||||
{
|
||||
int i,n;
|
||||
n=f->sizek;
|
||||
printf("constants (%d) for %p:\n",n,VOID(f));
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
printf("\t%d\t",i);
|
||||
PrintType(f,i);
|
||||
PrintConstant(f,i);
|
||||
printf("\n");
|
||||
}
|
||||
n=f->sizelocvars;
|
||||
printf("locals (%d) for %p:\n",n,VOID(f));
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
printf("\t%d\t%s\t%d\t%d\n",
|
||||
i,getstr(f->locvars[i].varname),f->locvars[i].startpc+1,f->locvars[i].endpc+1);
|
||||
}
|
||||
n=f->sizeupvalues;
|
||||
printf("upvalues (%d) for %p:\n",n,VOID(f));
|
||||
for (i=0; i<n; i++)
|
||||
{
|
||||
printf("\t%d\t%s\t%d\t%d\n",
|
||||
i,UPVALNAME(i),f->upvalues[i].instack,f->upvalues[i].idx);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintFunction(const Proto* f, int full)
|
||||
{
|
||||
int i,n=f->sizep;
|
||||
PrintHeader(f);
|
||||
PrintCode(f);
|
||||
if (full) PrintDebug(f);
|
||||
for (i=0; i<n; i++) PrintFunction(f->p[i],full);
|
||||
}
|
||||
@@ -485,7 +485,6 @@
|
||||
@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
|
||||
@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
|
||||
@@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED.
|
||||
@@ LUA_UNSIGNEDBITS is the number of bits in a LUA_UNSIGNED.
|
||||
@@ lua_integer2str converts an integer to a string.
|
||||
*/
|
||||
|
||||
@@ -506,9 +505,6 @@
|
||||
#define LUA_UNSIGNED unsigned LUAI_UACINT
|
||||
|
||||
|
||||
#define LUA_UNSIGNEDBITS (sizeof(LUA_UNSIGNED) * CHAR_BIT)
|
||||
|
||||
|
||||
/* now the variable definitions */
|
||||
|
||||
#if LUA_INT_TYPE == LUA_INT_INT /* { int */
|
||||
@@ -732,7 +728,7 @@
|
||||
** CHANGE it if you need a different limit. This limit is arbitrary;
|
||||
** its only purpose is to stop Lua from consuming unlimited stack
|
||||
** space (and to reserve some numbers for pseudo-indices).
|
||||
** (It must fit into max(size_t)/32.)
|
||||
** (It must fit into max(size_t)/32 and max(int)/2.)
|
||||
*/
|
||||
#if LUAI_IS32INT
|
||||
#define LUAI_MAXSTACK 1000000
|
||||
@@ -751,14 +747,15 @@
|
||||
|
||||
/*
|
||||
@@ LUA_IDSIZE gives the maximum size for the description of the source
|
||||
@@ of a function in debug information.
|
||||
** of a function in debug information.
|
||||
** CHANGE it if you want a different size.
|
||||
*/
|
||||
#define LUA_IDSIZE 60
|
||||
|
||||
|
||||
/*
|
||||
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
|
||||
@@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
|
||||
** buffer system.
|
||||
*/
|
||||
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
|
||||
|
||||
|
||||
@@ -120,10 +120,10 @@ static TString *loadStringN (LoadState *S, Proto *p) {
|
||||
}
|
||||
else { /* long string */
|
||||
ts = luaS_createlngstrobj(L, size); /* create string */
|
||||
setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */
|
||||
setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
|
||||
luaD_inctop(L);
|
||||
loadVector(S, getstr(ts), size); /* load directly in final place */
|
||||
L->top--; /* pop string */
|
||||
L->top.p--; /* pop string */
|
||||
}
|
||||
luaC_objbarrier(L, p, ts);
|
||||
return ts;
|
||||
@@ -321,7 +321,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
|
||||
S.Z = Z;
|
||||
checkHeader(&S);
|
||||
cl = luaF_newLclosure(L, loadByte(&S));
|
||||
setclLvalue2s(L, L->top, cl);
|
||||
setclLvalue2s(L, L->top.p, cl);
|
||||
luaD_inctop(L);
|
||||
cl->p = luaF_newproto(L);
|
||||
luaC_objbarrier(L, cl, cl->p);
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
|
||||
#define MAXUTF 0x7FFFFFFFu
|
||||
|
||||
|
||||
#define MSGInvalid "invalid UTF-8 code"
|
||||
|
||||
/*
|
||||
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
|
||||
*/
|
||||
@@ -35,7 +38,8 @@ typedef unsigned long utfint;
|
||||
#endif
|
||||
|
||||
|
||||
#define iscont(p) ((*(p) & 0xC0) == 0x80)
|
||||
#define iscont(c) (((c) & 0xC0) == 0x80)
|
||||
#define iscontp(p) iscont(*(p))
|
||||
|
||||
|
||||
/* from strlib */
|
||||
@@ -65,7 +69,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
|
||||
int count = 0; /* to count number of continuation bytes */
|
||||
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
|
||||
unsigned int cc = (unsigned char)s[++count]; /* read next byte */
|
||||
if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
|
||||
if (!iscont(cc)) /* not a continuation byte? */
|
||||
return NULL; /* invalid byte sequence */
|
||||
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
|
||||
}
|
||||
@@ -140,7 +144,7 @@ static int codepoint (lua_State *L) {
|
||||
utfint code;
|
||||
s = utf8_decode(s, &code, !lax);
|
||||
if (s == NULL)
|
||||
return luaL_error(L, "invalid UTF-8 code");
|
||||
return luaL_error(L, MSGInvalid);
|
||||
lua_pushinteger(L, code);
|
||||
n++;
|
||||
}
|
||||
@@ -190,16 +194,16 @@ static int byteoffset (lua_State *L) {
|
||||
"position out of bounds");
|
||||
if (n == 0) {
|
||||
/* find beginning of current byte sequence */
|
||||
while (posi > 0 && iscont(s + posi)) posi--;
|
||||
while (posi > 0 && iscontp(s + posi)) posi--;
|
||||
}
|
||||
else {
|
||||
if (iscont(s + posi))
|
||||
if (iscontp(s + posi))
|
||||
return luaL_error(L, "initial position is a continuation byte");
|
||||
if (n < 0) {
|
||||
while (n < 0 && posi > 0) { /* move back */
|
||||
do { /* find beginning of previous character */
|
||||
posi--;
|
||||
} while (posi > 0 && iscont(s + posi));
|
||||
} while (posi > 0 && iscontp(s + posi));
|
||||
n++;
|
||||
}
|
||||
}
|
||||
@@ -208,7 +212,7 @@ static int byteoffset (lua_State *L) {
|
||||
while (n > 0 && posi < (lua_Integer)len) {
|
||||
do { /* find beginning of next character */
|
||||
posi++;
|
||||
} while (iscont(s + posi)); /* (cannot pass final '\0') */
|
||||
} while (iscontp(s + posi)); /* (cannot pass final '\0') */
|
||||
n--;
|
||||
}
|
||||
}
|
||||
@@ -224,20 +228,17 @@ static int byteoffset (lua_State *L) {
|
||||
static int iter_aux (lua_State *L, int strict) {
|
||||
size_t len;
|
||||
const char *s = luaL_checklstring(L, 1, &len);
|
||||
lua_Integer n = lua_tointeger(L, 2) - 1;
|
||||
if (n < 0) /* first iteration? */
|
||||
n = 0; /* start from here */
|
||||
else if (n < (lua_Integer)len) {
|
||||
n++; /* skip current byte */
|
||||
while (iscont(s + n)) n++; /* and its continuations */
|
||||
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
|
||||
if (n < len) {
|
||||
while (iscontp(s + n)) n++; /* go to next character */
|
||||
}
|
||||
if (n >= (lua_Integer)len)
|
||||
if (n >= len) /* (also handles original 'n' being negative) */
|
||||
return 0; /* no more codepoints */
|
||||
else {
|
||||
utfint code;
|
||||
const char *next = utf8_decode(s + n, &code, strict);
|
||||
if (next == NULL)
|
||||
return luaL_error(L, "invalid UTF-8 code");
|
||||
if (next == NULL || iscontp(next))
|
||||
return luaL_error(L, MSGInvalid);
|
||||
lua_pushinteger(L, n + 1);
|
||||
lua_pushinteger(L, code);
|
||||
return 2;
|
||||
@@ -256,7 +257,8 @@ static int iter_auxlax (lua_State *L) {
|
||||
|
||||
static int iter_codes (lua_State *L) {
|
||||
int lax = lua_toboolean(L, 2);
|
||||
luaL_checkstring(L, 1);
|
||||
const char *s = luaL_checkstring(L, 1);
|
||||
luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
|
||||
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
|
||||
lua_pushvalue(L, 1);
|
||||
lua_pushinteger(L, 0);
|
||||
|
||||
279
3rd/lua/lvm.c
279
3rd/lua/lvm.c
@@ -408,7 +408,7 @@ static int l_strcmp (const TString *ls, const TString *rs) {
|
||||
** from float to int.)
|
||||
** When 'f' is NaN, comparisons must result in false.
|
||||
*/
|
||||
static int LTintfloat (lua_Integer i, lua_Number f) {
|
||||
l_sinline int LTintfloat (lua_Integer i, lua_Number f) {
|
||||
if (l_intfitsf(i))
|
||||
return luai_numlt(cast_num(i), f); /* compare them as floats */
|
||||
else { /* i < f <=> i < ceil(f) */
|
||||
@@ -425,7 +425,7 @@ static int LTintfloat (lua_Integer i, lua_Number f) {
|
||||
** Check whether integer 'i' is less than or equal to float 'f'.
|
||||
** See comments on previous function.
|
||||
*/
|
||||
static int LEintfloat (lua_Integer i, lua_Number f) {
|
||||
l_sinline int LEintfloat (lua_Integer i, lua_Number f) {
|
||||
if (l_intfitsf(i))
|
||||
return luai_numle(cast_num(i), f); /* compare them as floats */
|
||||
else { /* i <= f <=> i <= floor(f) */
|
||||
@@ -442,7 +442,7 @@ static int LEintfloat (lua_Integer i, lua_Number f) {
|
||||
** Check whether float 'f' is less than integer 'i'.
|
||||
** See comments on previous function.
|
||||
*/
|
||||
static int LTfloatint (lua_Number f, lua_Integer i) {
|
||||
l_sinline int LTfloatint (lua_Number f, lua_Integer i) {
|
||||
if (l_intfitsf(i))
|
||||
return luai_numlt(f, cast_num(i)); /* compare them as floats */
|
||||
else { /* f < i <=> floor(f) < i */
|
||||
@@ -459,7 +459,7 @@ static int LTfloatint (lua_Number f, lua_Integer i) {
|
||||
** Check whether float 'f' is less than or equal to integer 'i'.
|
||||
** See comments on previous function.
|
||||
*/
|
||||
static int LEfloatint (lua_Number f, lua_Integer i) {
|
||||
l_sinline int LEfloatint (lua_Number f, lua_Integer i) {
|
||||
if (l_intfitsf(i))
|
||||
return luai_numle(f, cast_num(i)); /* compare them as floats */
|
||||
else { /* f <= i <=> ceil(f) <= i */
|
||||
@@ -475,7 +475,7 @@ static int LEfloatint (lua_Number f, lua_Integer i) {
|
||||
/*
|
||||
** Return 'l < r', for numbers.
|
||||
*/
|
||||
static int LTnum (const TValue *l, const TValue *r) {
|
||||
l_sinline int LTnum (const TValue *l, const TValue *r) {
|
||||
lua_assert(ttisnumber(l) && ttisnumber(r));
|
||||
if (ttisinteger(l)) {
|
||||
lua_Integer li = ivalue(l);
|
||||
@@ -497,7 +497,7 @@ static int LTnum (const TValue *l, const TValue *r) {
|
||||
/*
|
||||
** Return 'l <= r', for numbers.
|
||||
*/
|
||||
static int LEnum (const TValue *l, const TValue *r) {
|
||||
l_sinline int LEnum (const TValue *l, const TValue *r) {
|
||||
lua_assert(ttisnumber(l) && ttisnumber(r));
|
||||
if (ttisinteger(l)) {
|
||||
lua_Integer li = ivalue(l);
|
||||
@@ -610,8 +610,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
|
||||
if (tm == NULL) /* no TM? */
|
||||
return 0; /* objects are different */
|
||||
else {
|
||||
luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */
|
||||
return !l_isfalse(s2v(L->top));
|
||||
luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
|
||||
return !l_isfalse(s2v(L->top.p));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,17 +635,17 @@ static void copy2buff (StkId top, int n, char *buff) {
|
||||
|
||||
/*
|
||||
** Main operation for concatenation: concat 'total' values in the stack,
|
||||
** from 'L->top - total' up to 'L->top - 1'.
|
||||
** from 'L->top.p - total' up to 'L->top.p - 1'.
|
||||
*/
|
||||
void luaV_concat (lua_State *L, int total) {
|
||||
if (total == 1)
|
||||
return; /* "all" values already concatenated */
|
||||
do {
|
||||
StkId top = L->top;
|
||||
StkId top = L->top.p;
|
||||
int n = 2; /* number of elements handled in this pass (at least 2) */
|
||||
if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) ||
|
||||
!tostring(L, s2v(top - 1)))
|
||||
luaT_tryconcatTM(L);
|
||||
luaT_tryconcatTM(L); /* may invalidate 'top' */
|
||||
else if (isemptystr(s2v(top - 1))) /* second operand is empty? */
|
||||
cast_void(tostring(L, s2v(top - 2))); /* result is first operand */
|
||||
else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */
|
||||
@@ -658,8 +658,10 @@ void luaV_concat (lua_State *L, int total) {
|
||||
/* collect total length and number of strings */
|
||||
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
|
||||
size_t l = vslen(s2v(top - n - 1));
|
||||
if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
|
||||
if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) {
|
||||
L->top.p = top - total; /* pop strings to avoid wasting stack */
|
||||
luaG_runerror(L, "string length overflow");
|
||||
}
|
||||
tl += l;
|
||||
}
|
||||
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
|
||||
@@ -673,8 +675,8 @@ void luaV_concat (lua_State *L, int total) {
|
||||
}
|
||||
setsvalue2s(L, top - n, ts); /* create result */
|
||||
}
|
||||
total -= n-1; /* got 'n' strings to create 1 new */
|
||||
L->top -= n-1; /* popped 'n' strings and pushed one */
|
||||
total -= n - 1; /* got 'n' strings to create one new */
|
||||
L->top.p -= n - 1; /* popped 'n' strings and pushed one */
|
||||
} while (total > 1); /* repeat until only 1 result left */
|
||||
}
|
||||
|
||||
@@ -765,11 +767,10 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
|
||||
/* number of bits in an integer */
|
||||
#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
|
||||
|
||||
|
||||
/*
|
||||
** Shift left operation. (Shift right just negates 'y'.)
|
||||
*/
|
||||
#define luaV_shiftr(x,y) luaV_shiftl(x,-(y))
|
||||
|
||||
lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
|
||||
if (y < 0) { /* shift right? */
|
||||
if (y <= -NBITS) return 0;
|
||||
@@ -809,26 +810,26 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
|
||||
*/
|
||||
void luaV_finishOp (lua_State *L) {
|
||||
CallInfo *ci = L->ci;
|
||||
StkId base = ci->func + 1;
|
||||
StkId base = ci->func.p + 1;
|
||||
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
|
||||
OpCode op = GET_OPCODE(inst);
|
||||
switch (op) { /* finish its execution */
|
||||
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
|
||||
setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top);
|
||||
setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p);
|
||||
break;
|
||||
}
|
||||
case OP_UNM: case OP_BNOT: case OP_LEN:
|
||||
case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
|
||||
case OP_GETFIELD: case OP_SELF: {
|
||||
setobjs2s(L, base + GETARG_A(inst), --L->top);
|
||||
setobjs2s(L, base + GETARG_A(inst), --L->top.p);
|
||||
break;
|
||||
}
|
||||
case OP_LT: case OP_LE:
|
||||
case OP_LTI: case OP_LEI:
|
||||
case OP_GTI: case OP_GEI:
|
||||
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
|
||||
int res = !l_isfalse(s2v(L->top - 1));
|
||||
L->top--;
|
||||
int res = !l_isfalse(s2v(L->top.p - 1));
|
||||
L->top.p--;
|
||||
#if defined(LUA_COMPAT_LT_LE)
|
||||
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
|
||||
ci->callstatus ^= CIST_LEQ; /* clear mark */
|
||||
@@ -841,18 +842,27 @@ void luaV_finishOp (lua_State *L) {
|
||||
break;
|
||||
}
|
||||
case OP_CONCAT: {
|
||||
StkId top = L->top - 1; /* top when 'luaT_tryconcatTM' was called */
|
||||
StkId top = L->top.p - 1; /* top when 'luaT_tryconcatTM' was called */
|
||||
int a = GETARG_A(inst); /* first element to concatenate */
|
||||
int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
|
||||
setobjs2s(L, top - 2, top); /* put TM result in proper position */
|
||||
L->top = top - 1; /* top is one after last element (at top-2) */
|
||||
L->top.p = top - 1; /* top is one after last element (at top-2) */
|
||||
luaV_concat(L, total); /* concat them (may yield again) */
|
||||
break;
|
||||
}
|
||||
case OP_CLOSE: case OP_RETURN: { /* yielded closing variables */
|
||||
case OP_CLOSE: { /* yielded closing variables */
|
||||
ci->u.l.savedpc--; /* repeat instruction to close other vars. */
|
||||
break;
|
||||
}
|
||||
case OP_RETURN: { /* yielded closing variables */
|
||||
StkId ra = base + GETARG_A(inst);
|
||||
/* adjust top to signal correct number of returns, in case the
|
||||
return is "up to top" ('isIT') */
|
||||
L->top.p = ra + ci->u2.nres;
|
||||
/* repeat instruction to close other vars. and complete the return */
|
||||
ci->u.l.savedpc--;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
/* only these other opcodes can yield */
|
||||
lua_assert(op == OP_TFORCALL || op == OP_CALL ||
|
||||
@@ -890,6 +900,7 @@ void luaV_finishOp (lua_State *L) {
|
||||
** operation, 'fop' is the float operation.
|
||||
*/
|
||||
#define op_arithI(L,iop,fop) { \
|
||||
StkId ra = RA(i); \
|
||||
TValue *v1 = vRB(i); \
|
||||
int imm = GETARG_sC(i); \
|
||||
if (ttisinteger(v1)) { \
|
||||
@@ -918,6 +929,7 @@ void luaV_finishOp (lua_State *L) {
|
||||
** Arithmetic operations over floats and others with register operands.
|
||||
*/
|
||||
#define op_arithf(L,fop) { \
|
||||
StkId ra = RA(i); \
|
||||
TValue *v1 = vRB(i); \
|
||||
TValue *v2 = vRC(i); \
|
||||
op_arithf_aux(L, v1, v2, fop); }
|
||||
@@ -927,6 +939,7 @@ void luaV_finishOp (lua_State *L) {
|
||||
** Arithmetic operations with K operands for floats.
|
||||
*/
|
||||
#define op_arithfK(L,fop) { \
|
||||
StkId ra = RA(i); \
|
||||
TValue *v1 = vRB(i); \
|
||||
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
|
||||
op_arithf_aux(L, v1, v2, fop); }
|
||||
@@ -936,6 +949,7 @@ void luaV_finishOp (lua_State *L) {
|
||||
** Arithmetic operations over integers and floats.
|
||||
*/
|
||||
#define op_arith_aux(L,v1,v2,iop,fop) { \
|
||||
StkId ra = RA(i); \
|
||||
if (ttisinteger(v1) && ttisinteger(v2)) { \
|
||||
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
|
||||
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
|
||||
@@ -965,6 +979,7 @@ void luaV_finishOp (lua_State *L) {
|
||||
** Bitwise operations with constant operand.
|
||||
*/
|
||||
#define op_bitwiseK(L,op) { \
|
||||
StkId ra = RA(i); \
|
||||
TValue *v1 = vRB(i); \
|
||||
TValue *v2 = KC(i); \
|
||||
lua_Integer i1; \
|
||||
@@ -978,6 +993,7 @@ void luaV_finishOp (lua_State *L) {
|
||||
** Bitwise operations with register operands.
|
||||
*/
|
||||
#define op_bitwise(L,op) { \
|
||||
StkId ra = RA(i); \
|
||||
TValue *v1 = vRB(i); \
|
||||
TValue *v2 = vRC(i); \
|
||||
lua_Integer i1; lua_Integer i2; \
|
||||
@@ -992,18 +1008,19 @@ void luaV_finishOp (lua_State *L) {
|
||||
** integers.
|
||||
*/
|
||||
#define op_order(L,opi,opn,other) { \
|
||||
int cond; \
|
||||
TValue *rb = vRB(i); \
|
||||
if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
|
||||
lua_Integer ia = ivalue(s2v(ra)); \
|
||||
lua_Integer ib = ivalue(rb); \
|
||||
cond = opi(ia, ib); \
|
||||
} \
|
||||
else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
|
||||
cond = opn(s2v(ra), rb); \
|
||||
else \
|
||||
Protect(cond = other(L, s2v(ra), rb)); \
|
||||
docondjump(); }
|
||||
StkId ra = RA(i); \
|
||||
int cond; \
|
||||
TValue *rb = vRB(i); \
|
||||
if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
|
||||
lua_Integer ia = ivalue(s2v(ra)); \
|
||||
lua_Integer ib = ivalue(rb); \
|
||||
cond = opi(ia, ib); \
|
||||
} \
|
||||
else if (ttisnumber(s2v(ra)) && ttisnumber(rb)) \
|
||||
cond = opn(s2v(ra), rb); \
|
||||
else \
|
||||
Protect(cond = other(L, s2v(ra), rb)); \
|
||||
docondjump(); }
|
||||
|
||||
|
||||
/*
|
||||
@@ -1011,20 +1028,21 @@ void luaV_finishOp (lua_State *L) {
|
||||
** always small enough to have an exact representation as a float.)
|
||||
*/
|
||||
#define op_orderI(L,opi,opf,inv,tm) { \
|
||||
int cond; \
|
||||
int im = GETARG_sB(i); \
|
||||
if (ttisinteger(s2v(ra))) \
|
||||
cond = opi(ivalue(s2v(ra)), im); \
|
||||
else if (ttisfloat(s2v(ra))) { \
|
||||
lua_Number fa = fltvalue(s2v(ra)); \
|
||||
lua_Number fim = cast_num(im); \
|
||||
cond = opf(fa, fim); \
|
||||
} \
|
||||
else { \
|
||||
int isf = GETARG_C(i); \
|
||||
Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
|
||||
} \
|
||||
docondjump(); }
|
||||
StkId ra = RA(i); \
|
||||
int cond; \
|
||||
int im = GETARG_sB(i); \
|
||||
if (ttisinteger(s2v(ra))) \
|
||||
cond = opi(ivalue(s2v(ra)), im); \
|
||||
else if (ttisfloat(s2v(ra))) { \
|
||||
lua_Number fa = fltvalue(s2v(ra)); \
|
||||
lua_Number fim = cast_num(im); \
|
||||
cond = opf(fa, fim); \
|
||||
} \
|
||||
else { \
|
||||
int isf = GETARG_C(i); \
|
||||
Protect(cond = luaT_callorderiTM(L, s2v(ra), im, inv, isf, tm)); \
|
||||
} \
|
||||
docondjump(); }
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
@@ -1053,7 +1071,7 @@ void luaV_finishOp (lua_State *L) {
|
||||
|
||||
#define updatetrap(ci) (trap = ci->u.l.trap)
|
||||
|
||||
#define updatebase(ci) (base = ci->func + 1)
|
||||
#define updatebase(ci) (base = ci->func.p + 1)
|
||||
|
||||
|
||||
#define updatestack(ci) \
|
||||
@@ -1088,7 +1106,7 @@ void luaV_finishOp (lua_State *L) {
|
||||
** Whenever code can raise errors, the global 'pc' and the global
|
||||
** 'top' must be correct to report occasional errors.
|
||||
*/
|
||||
#define savestate(L,ci) (savepc(L), L->top = ci->top)
|
||||
#define savestate(L,ci) (savepc(L), L->top.p = ci->top.p)
|
||||
|
||||
|
||||
/*
|
||||
@@ -1101,14 +1119,14 @@ void luaV_finishOp (lua_State *L) {
|
||||
#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci))
|
||||
|
||||
/*
|
||||
** Protect code that can only raise errors. (That is, it cannnot change
|
||||
** Protect code that can only raise errors. (That is, it cannot change
|
||||
** the stack or hooks.)
|
||||
*/
|
||||
#define halfProtect(exp) (savestate(L,ci), (exp))
|
||||
|
||||
/* 'c' is the limit of live values in the stack */
|
||||
#define checkGC(L,c) \
|
||||
{ luaC_condGC(L, (savepc(L), L->top = (c)), \
|
||||
{ luaC_condGC(L, (savepc(L), L->top.p = (c)), \
|
||||
updatetrap(ci)); \
|
||||
luai_threadyield(L); }
|
||||
|
||||
@@ -1120,7 +1138,6 @@ void luaV_finishOp (lua_State *L) {
|
||||
updatebase(ci); /* correct stack */ \
|
||||
} \
|
||||
i = *(pc++); \
|
||||
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
|
||||
}
|
||||
|
||||
#define vmdispatch(o) switch(o)
|
||||
@@ -1140,7 +1157,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
startfunc:
|
||||
trap = L->hookmask;
|
||||
returning: /* trap already set */
|
||||
cl = clLvalue(s2v(ci->func));
|
||||
cl = clLvalue(s2v(ci->func.p));
|
||||
k = cl->p->k;
|
||||
pc = ci->u.l.savedpc;
|
||||
if (l_unlikely(trap)) {
|
||||
@@ -1152,58 +1169,68 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
}
|
||||
ci->u.l.trap = 1; /* assume trap is on, for now */
|
||||
}
|
||||
base = ci->func + 1;
|
||||
base = ci->func.p + 1;
|
||||
/* main loop of interpreter */
|
||||
for (;;) {
|
||||
Instruction i; /* instruction being executed */
|
||||
StkId ra; /* instruction's A register */
|
||||
vmfetch();
|
||||
// low-level line tracing for debugging Lua
|
||||
// printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
|
||||
lua_assert(base == ci->func + 1);
|
||||
lua_assert(base <= L->top && L->top < L->stack_last);
|
||||
#if 0
|
||||
/* low-level line tracing for debugging Lua */
|
||||
printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
|
||||
#endif
|
||||
lua_assert(base == ci->func.p + 1);
|
||||
lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p);
|
||||
/* invalidate top for instructions not expecting it */
|
||||
lua_assert(isIT(i) || (cast_void(L->top = base), 1));
|
||||
lua_assert(isIT(i) || (cast_void(L->top.p = base), 1));
|
||||
vmdispatch (GET_OPCODE(i)) {
|
||||
vmcase(OP_MOVE) {
|
||||
StkId ra = RA(i);
|
||||
setobjs2s(L, ra, RB(i));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LOADI) {
|
||||
StkId ra = RA(i);
|
||||
lua_Integer b = GETARG_sBx(i);
|
||||
setivalue(s2v(ra), b);
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LOADF) {
|
||||
StkId ra = RA(i);
|
||||
int b = GETARG_sBx(i);
|
||||
setfltvalue(s2v(ra), cast_num(b));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LOADK) {
|
||||
StkId ra = RA(i);
|
||||
TValue *rb = k + GETARG_Bx(i);
|
||||
setobj2s(L, ra, rb);
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LOADKX) {
|
||||
StkId ra = RA(i);
|
||||
TValue *rb;
|
||||
rb = k + GETARG_Ax(*pc); pc++;
|
||||
setobj2s(L, ra, rb);
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LOADFALSE) {
|
||||
StkId ra = RA(i);
|
||||
setbfvalue(s2v(ra));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LFALSESKIP) {
|
||||
StkId ra = RA(i);
|
||||
setbfvalue(s2v(ra));
|
||||
pc++; /* skip next instruction */
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LOADTRUE) {
|
||||
StkId ra = RA(i);
|
||||
setbtvalue(s2v(ra));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LOADNIL) {
|
||||
StkId ra = RA(i);
|
||||
int b = GETARG_B(i);
|
||||
do {
|
||||
setnilvalue(s2v(ra++));
|
||||
@@ -1211,19 +1238,22 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_GETUPVAL) {
|
||||
StkId ra = RA(i);
|
||||
int b = GETARG_B(i);
|
||||
setobj2s(L, ra, cl->upvals[b]->v);
|
||||
setobj2s(L, ra, cl->upvals[b]->v.p);
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_SETUPVAL) {
|
||||
StkId ra = RA(i);
|
||||
UpVal *uv = cl->upvals[GETARG_B(i)];
|
||||
setobj(L, uv->v, s2v(ra));
|
||||
setobj(L, uv->v.p, s2v(ra));
|
||||
luaC_barrier(L, uv, s2v(ra));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_GETTABUP) {
|
||||
StkId ra = RA(i);
|
||||
const TValue *slot;
|
||||
TValue *upval = cl->upvals[GETARG_B(i)]->v;
|
||||
TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
|
||||
TValue *rc = KC(i);
|
||||
TString *key = tsvalue(rc); /* key must be a string */
|
||||
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
|
||||
@@ -1234,6 +1264,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_GETTABLE) {
|
||||
StkId ra = RA(i);
|
||||
const TValue *slot;
|
||||
TValue *rb = vRB(i);
|
||||
TValue *rc = vRC(i);
|
||||
@@ -1248,6 +1279,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_GETI) {
|
||||
StkId ra = RA(i);
|
||||
const TValue *slot;
|
||||
TValue *rb = vRB(i);
|
||||
int c = GETARG_C(i);
|
||||
@@ -1262,6 +1294,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_GETFIELD) {
|
||||
StkId ra = RA(i);
|
||||
const TValue *slot;
|
||||
TValue *rb = vRB(i);
|
||||
TValue *rc = KC(i);
|
||||
@@ -1275,7 +1308,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
}
|
||||
vmcase(OP_SETTABUP) {
|
||||
const TValue *slot;
|
||||
TValue *upval = cl->upvals[GETARG_A(i)]->v;
|
||||
TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
|
||||
TValue *rb = KB(i);
|
||||
TValue *rc = RKC(i);
|
||||
TString *key = tsvalue(rb); /* key must be a string */
|
||||
@@ -1287,6 +1320,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_SETTABLE) {
|
||||
StkId ra = RA(i);
|
||||
const TValue *slot;
|
||||
TValue *rb = vRB(i); /* key (table is in 'ra') */
|
||||
TValue *rc = RKC(i); /* value */
|
||||
@@ -1301,6 +1335,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_SETI) {
|
||||
StkId ra = RA(i);
|
||||
const TValue *slot;
|
||||
int c = GETARG_B(i);
|
||||
TValue *rc = RKC(i);
|
||||
@@ -1315,6 +1350,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_SETFIELD) {
|
||||
StkId ra = RA(i);
|
||||
const TValue *slot;
|
||||
TValue *rb = KB(i);
|
||||
TValue *rc = RKC(i);
|
||||
@@ -1327,6 +1363,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_NEWTABLE) {
|
||||
StkId ra = RA(i);
|
||||
int b = GETARG_B(i); /* log2(hash size) + 1 */
|
||||
int c = GETARG_C(i); /* array size */
|
||||
Table *t;
|
||||
@@ -1336,7 +1373,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
if (TESTARG_k(i)) /* non-zero extra argument? */
|
||||
c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */
|
||||
pc++; /* skip extra argument */
|
||||
L->top = ra + 1; /* correct top in case of emergency GC */
|
||||
L->top.p = ra + 1; /* correct top in case of emergency GC */
|
||||
t = luaH_new(L); /* memory allocation */
|
||||
sethvalue2s(L, ra, t);
|
||||
if (b != 0 || c != 0)
|
||||
@@ -1345,6 +1382,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_SELF) {
|
||||
StkId ra = RA(i);
|
||||
const TValue *slot;
|
||||
TValue *rb = vRB(i);
|
||||
TValue *rc = RKC(i);
|
||||
@@ -1402,6 +1440,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_SHRI) {
|
||||
StkId ra = RA(i);
|
||||
TValue *rb = vRB(i);
|
||||
int ic = GETARG_sC(i);
|
||||
lua_Integer ib;
|
||||
@@ -1411,6 +1450,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_SHLI) {
|
||||
StkId ra = RA(i);
|
||||
TValue *rb = vRB(i);
|
||||
int ic = GETARG_sC(i);
|
||||
lua_Integer ib;
|
||||
@@ -1468,6 +1508,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_MMBIN) {
|
||||
StkId ra = RA(i);
|
||||
Instruction pi = *(pc - 2); /* original arith. expression */
|
||||
TValue *rb = vRB(i);
|
||||
TMS tm = (TMS)GETARG_C(i);
|
||||
@@ -1477,6 +1518,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_MMBINI) {
|
||||
StkId ra = RA(i);
|
||||
Instruction pi = *(pc - 2); /* original arith. expression */
|
||||
int imm = GETARG_sB(i);
|
||||
TMS tm = (TMS)GETARG_C(i);
|
||||
@@ -1486,6 +1528,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_MMBINK) {
|
||||
StkId ra = RA(i);
|
||||
Instruction pi = *(pc - 2); /* original arith. expression */
|
||||
TValue *imm = KB(i);
|
||||
TMS tm = (TMS)GETARG_C(i);
|
||||
@@ -1495,6 +1538,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_UNM) {
|
||||
StkId ra = RA(i);
|
||||
TValue *rb = vRB(i);
|
||||
lua_Number nb;
|
||||
if (ttisinteger(rb)) {
|
||||
@@ -1509,6 +1553,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_BNOT) {
|
||||
StkId ra = RA(i);
|
||||
TValue *rb = vRB(i);
|
||||
lua_Integer ib;
|
||||
if (tointegerns(rb, &ib)) {
|
||||
@@ -1519,6 +1564,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_NOT) {
|
||||
StkId ra = RA(i);
|
||||
TValue *rb = vRB(i);
|
||||
if (l_isfalse(rb))
|
||||
setbtvalue(s2v(ra));
|
||||
@@ -1527,21 +1573,25 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_LEN) {
|
||||
StkId ra = RA(i);
|
||||
Protect(luaV_objlen(L, ra, vRB(i)));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_CONCAT) {
|
||||
StkId ra = RA(i);
|
||||
int n = GETARG_B(i); /* number of elements to concatenate */
|
||||
L->top = ra + n; /* mark the end of concat operands */
|
||||
L->top.p = ra + n; /* mark the end of concat operands */
|
||||
ProtectNT(luaV_concat(L, n));
|
||||
checkGC(L, L->top); /* 'luaV_concat' ensures correct top */
|
||||
checkGC(L, L->top.p); /* 'luaV_concat' ensures correct top */
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_CLOSE) {
|
||||
StkId ra = RA(i);
|
||||
Protect(luaF_close(L, ra, LUA_OK, 1));
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_TBC) {
|
||||
StkId ra = RA(i);
|
||||
/* create new to-be-closed upvalue */
|
||||
halfProtect(luaF_newtbcupval(L, ra));
|
||||
vmbreak;
|
||||
@@ -1551,6 +1601,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_EQ) {
|
||||
StkId ra = RA(i);
|
||||
int cond;
|
||||
TValue *rb = vRB(i);
|
||||
Protect(cond = luaV_equalobj(L, s2v(ra), rb));
|
||||
@@ -1566,6 +1617,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_EQK) {
|
||||
StkId ra = RA(i);
|
||||
TValue *rb = KB(i);
|
||||
/* basic types do not use '__eq'; we can use raw equality */
|
||||
int cond = luaV_rawequalobj(s2v(ra), rb);
|
||||
@@ -1573,6 +1625,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_EQI) {
|
||||
StkId ra = RA(i);
|
||||
int cond;
|
||||
int im = GETARG_sB(i);
|
||||
if (ttisinteger(s2v(ra)))
|
||||
@@ -1601,11 +1654,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_TEST) {
|
||||
StkId ra = RA(i);
|
||||
int cond = !l_isfalse(s2v(ra));
|
||||
docondjump();
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_TESTSET) {
|
||||
StkId ra = RA(i);
|
||||
TValue *rb = vRB(i);
|
||||
if (l_isfalse(rb) == GETARG_k(i))
|
||||
pc++;
|
||||
@@ -1616,78 +1671,74 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_CALL) {
|
||||
StkId ra = RA(i);
|
||||
CallInfo *newci;
|
||||
int b = GETARG_B(i);
|
||||
int nresults = GETARG_C(i) - 1;
|
||||
if (b != 0) /* fixed number of arguments? */
|
||||
L->top = ra + b; /* top signals number of arguments */
|
||||
L->top.p = ra + b; /* top signals number of arguments */
|
||||
/* else previous instruction set top */
|
||||
savepc(L); /* in case of errors */
|
||||
if ((newci = luaD_precall(L, ra, nresults)) == NULL)
|
||||
updatetrap(ci); /* C call; nothing else to be done */
|
||||
else { /* Lua call: run function in this same C frame */
|
||||
ci = newci;
|
||||
ci->callstatus = 0; /* call re-uses 'luaV_execute' */
|
||||
goto startfunc;
|
||||
}
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_TAILCALL) {
|
||||
StkId ra = RA(i);
|
||||
int b = GETARG_B(i); /* number of arguments + 1 (function) */
|
||||
int n; /* number of results when calling a C function */
|
||||
int nparams1 = GETARG_C(i);
|
||||
/* delta is virtual 'func' - real 'func' (vararg functions) */
|
||||
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
|
||||
if (b != 0)
|
||||
L->top = ra + b;
|
||||
L->top.p = ra + b;
|
||||
else /* previous instruction set top */
|
||||
b = cast_int(L->top - ra);
|
||||
b = cast_int(L->top.p - ra);
|
||||
savepc(ci); /* several calls here can raise errors */
|
||||
if (TESTARG_k(i)) {
|
||||
luaF_closeupval(L, base); /* close upvalues from current call */
|
||||
lua_assert(L->tbclist < base); /* no pending tbc variables */
|
||||
lua_assert(base == ci->func + 1);
|
||||
lua_assert(L->tbclist.p < base); /* no pending tbc variables */
|
||||
lua_assert(base == ci->func.p + 1);
|
||||
}
|
||||
while (!ttisfunction(s2v(ra))) { /* not a function? */
|
||||
luaD_tryfuncTM(L, ra); /* try '__call' metamethod */
|
||||
b++; /* there is now one extra argument */
|
||||
checkstackGCp(L, 1, ra);
|
||||
}
|
||||
if (!ttisLclosure(s2v(ra))) { /* C function? */
|
||||
luaD_precall(L, ra, LUA_MULTRET); /* call it */
|
||||
updatetrap(ci);
|
||||
updatestack(ci); /* stack may have been relocated */
|
||||
ci->func -= delta; /* restore 'func' (if vararg) */
|
||||
luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */
|
||||
if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
|
||||
goto startfunc; /* execute the callee */
|
||||
else { /* C function? */
|
||||
ci->func.p -= delta; /* restore 'func' (if vararg) */
|
||||
luaD_poscall(L, ci, n); /* finish caller */
|
||||
updatetrap(ci); /* 'luaD_poscall' can change hooks */
|
||||
goto ret; /* caller returns after the tail call */
|
||||
}
|
||||
ci->func -= delta; /* restore 'func' (if vararg) */
|
||||
luaD_pretailcall(L, ci, ra, b); /* prepare call frame */
|
||||
goto startfunc; /* execute the callee */
|
||||
}
|
||||
vmcase(OP_RETURN) {
|
||||
StkId ra = RA(i);
|
||||
int n = GETARG_B(i) - 1; /* number of results */
|
||||
int nparams1 = GETARG_C(i);
|
||||
if (n < 0) /* not fixed? */
|
||||
n = cast_int(L->top - ra); /* get what is available */
|
||||
n = cast_int(L->top.p - ra); /* get what is available */
|
||||
savepc(ci);
|
||||
if (TESTARG_k(i)) { /* may there be open upvalues? */
|
||||
if (L->top < ci->top)
|
||||
L->top = ci->top;
|
||||
ci->u2.nres = n; /* save number of returns */
|
||||
if (L->top.p < ci->top.p)
|
||||
L->top.p = ci->top.p;
|
||||
luaF_close(L, base, CLOSEKTOP, 1);
|
||||
updatetrap(ci);
|
||||
updatestack(ci);
|
||||
}
|
||||
if (nparams1) /* vararg function? */
|
||||
ci->func -= ci->u.l.nextraargs + nparams1;
|
||||
L->top = ra + n; /* set call for 'luaD_poscall' */
|
||||
ci->func.p -= ci->u.l.nextraargs + nparams1;
|
||||
L->top.p = ra + n; /* set call for 'luaD_poscall' */
|
||||
luaD_poscall(L, ci, n);
|
||||
updatetrap(ci); /* 'luaD_poscall' can change hooks */
|
||||
goto ret;
|
||||
}
|
||||
vmcase(OP_RETURN0) {
|
||||
if (l_unlikely(L->hookmask)) {
|
||||
L->top = ra;
|
||||
StkId ra = RA(i);
|
||||
L->top.p = ra;
|
||||
savepc(ci);
|
||||
luaD_poscall(L, ci, 0); /* no hurry... */
|
||||
trap = 1;
|
||||
@@ -1695,15 +1746,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
else { /* do the 'poscall' here */
|
||||
int nres;
|
||||
L->ci = ci->previous; /* back to caller */
|
||||
L->top = base - 1;
|
||||
L->top.p = base - 1;
|
||||
for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
|
||||
setnilvalue(s2v(L->top++)); /* all results are nil */
|
||||
setnilvalue(s2v(L->top.p++)); /* all results are nil */
|
||||
}
|
||||
goto ret;
|
||||
}
|
||||
vmcase(OP_RETURN1) {
|
||||
if (l_unlikely(L->hookmask)) {
|
||||
L->top = ra + 1;
|
||||
StkId ra = RA(i);
|
||||
L->top.p = ra + 1;
|
||||
savepc(ci);
|
||||
luaD_poscall(L, ci, 1); /* no hurry... */
|
||||
trap = 1;
|
||||
@@ -1712,12 +1764,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
int nres = ci->nresults;
|
||||
L->ci = ci->previous; /* back to caller */
|
||||
if (nres == 0)
|
||||
L->top = base - 1; /* asked for no results */
|
||||
L->top.p = base - 1; /* asked for no results */
|
||||
else {
|
||||
StkId ra = RA(i);
|
||||
setobjs2s(L, base - 1, ra); /* at least this result */
|
||||
L->top = base;
|
||||
L->top.p = base;
|
||||
for (; l_unlikely(nres > 1); nres--)
|
||||
setnilvalue(s2v(L->top++)); /* complete missing results */
|
||||
setnilvalue(s2v(L->top.p++)); /* complete missing results */
|
||||
}
|
||||
}
|
||||
ret: /* return from a Lua function */
|
||||
@@ -1729,6 +1782,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
}
|
||||
}
|
||||
vmcase(OP_FORLOOP) {
|
||||
StkId ra = RA(i);
|
||||
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
|
||||
lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
|
||||
if (count > 0) { /* still more iterations? */
|
||||
@@ -1747,12 +1801,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_FORPREP) {
|
||||
StkId ra = RA(i);
|
||||
savestate(L, ci); /* in case of errors */
|
||||
if (forprep(L, ra))
|
||||
pc += GETARG_Bx(i) + 1; /* skip the loop */
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_TFORPREP) {
|
||||
StkId ra = RA(i);
|
||||
/* create to-be-closed upvalue (if needed) */
|
||||
halfProtect(luaF_newtbcupval(L, ra + 3));
|
||||
pc += GETARG_Bx(i);
|
||||
@@ -1761,7 +1817,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
goto l_tforcall;
|
||||
}
|
||||
vmcase(OP_TFORCALL) {
|
||||
l_tforcall:
|
||||
l_tforcall: {
|
||||
StkId ra = RA(i);
|
||||
/* 'ra' has the iterator function, 'ra + 1' has the state,
|
||||
'ra + 2' has the control variable, and 'ra + 3' has the
|
||||
to-be-closed variable. The call will use the stack after
|
||||
@@ -1769,29 +1826,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
*/
|
||||
/* push function, state, and control variable */
|
||||
memcpy(ra + 4, ra, 3 * sizeof(*ra));
|
||||
L->top = ra + 4 + 3;
|
||||
L->top.p = ra + 4 + 3;
|
||||
ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
|
||||
updatestack(ci); /* stack may have changed */
|
||||
i = *(pc++); /* go to next instruction */
|
||||
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
|
||||
goto l_tforloop;
|
||||
}
|
||||
}}
|
||||
vmcase(OP_TFORLOOP) {
|
||||
l_tforloop:
|
||||
l_tforloop: {
|
||||
StkId ra = RA(i);
|
||||
if (!ttisnil(s2v(ra + 4))) { /* continue loop? */
|
||||
setobjs2s(L, ra + 2, ra + 4); /* save control variable */
|
||||
pc -= GETARG_Bx(i); /* jump back */
|
||||
}
|
||||
vmbreak;
|
||||
}
|
||||
}}
|
||||
vmcase(OP_SETLIST) {
|
||||
StkId ra = RA(i);
|
||||
int n = GETARG_B(i);
|
||||
unsigned int last = GETARG_C(i);
|
||||
Table *h = hvalue(s2v(ra));
|
||||
if (n == 0)
|
||||
n = cast_int(L->top - ra) - 1; /* get up to the top */
|
||||
n = cast_int(L->top.p - ra) - 1; /* get up to the top */
|
||||
else
|
||||
L->top = ci->top; /* correct top in case of emergency GC */
|
||||
L->top.p = ci->top.p; /* correct top in case of emergency GC */
|
||||
last += n;
|
||||
if (TESTARG_k(i)) {
|
||||
last += GETARG_Ax(*pc) * (MAXARG_C + 1);
|
||||
@@ -1808,12 +1867,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_CLOSURE) {
|
||||
StkId ra = RA(i);
|
||||
Proto *p = cl->p->p[GETARG_Bx(i)];
|
||||
halfProtect(pushclosure(L, p, cl->upvals, base, ra));
|
||||
checkGC(L, ra + 1);
|
||||
vmbreak;
|
||||
}
|
||||
vmcase(OP_VARARG) {
|
||||
StkId ra = RA(i);
|
||||
int n = GETARG_C(i) - 1; /* required results */
|
||||
Protect(luaT_getvarargs(L, ci, ra, n));
|
||||
vmbreak;
|
||||
|
||||
@@ -112,6 +112,11 @@ typedef enum {
|
||||
luaC_barrierback(L, gcvalue(t), v); }
|
||||
|
||||
|
||||
/*
|
||||
** Shift right is the same as shift left with a negative 'y'
|
||||
*/
|
||||
#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
|
||||
|
||||
|
||||
|
||||
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
|
||||
|
||||
@@ -26,7 +26,7 @@ MYLIBS=
|
||||
MYOBJS=
|
||||
|
||||
# Special flags for compiler modules; -Os reduces code size.
|
||||
CMCFLAGS= -Os
|
||||
CMCFLAGS=
|
||||
|
||||
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
|
||||
|
||||
@@ -44,7 +44,7 @@ LUAC_T= luac
|
||||
LUAC_O= luac.o
|
||||
|
||||
ALL_O= $(BASE_O) $(LUA_O) $(LUAC_O)
|
||||
ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
|
||||
ALL_T= $(LUA_A) $(LUA_T)
|
||||
ALL_A= $(LUA_A)
|
||||
|
||||
# Targets start here.
|
||||
@@ -67,7 +67,7 @@ $(LUAC_T): $(LUAC_O) $(LUA_A)
|
||||
$(CC) -o $@ $(LDFLAGS) $(LUAC_O) $(LUA_A) $(LIBS)
|
||||
|
||||
test:
|
||||
./lua -v
|
||||
./$(LUA_T) -v
|
||||
|
||||
clean:
|
||||
$(RM) $(ALL_T) $(ALL_O)
|
||||
@@ -79,7 +79,7 @@ echo:
|
||||
@echo "PLAT= $(PLAT)"
|
||||
@echo "CC= $(CC)"
|
||||
@echo "CFLAGS= $(CFLAGS)"
|
||||
@echo "LDFLAGS= $(SYSLDFLAGS)"
|
||||
@echo "LDFLAGS= $(LDFLAGS)"
|
||||
@echo "LIBS= $(LIBS)"
|
||||
@echo "AR= $(AR)"
|
||||
@echo "RANLIB= $(RANLIB)"
|
||||
@@ -108,6 +108,8 @@ c89:
|
||||
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_C89" CC="gcc -std=c89"
|
||||
@echo ''
|
||||
@echo '*** C89 does not guarantee 64-bit integers for Lua.'
|
||||
@echo '*** Make sure to compile all external Lua libraries'
|
||||
@echo '*** with LUA_USE_C89 to ensure consistency'
|
||||
@echo ''
|
||||
|
||||
FreeBSD NetBSD OpenBSD freebsd:
|
||||
107
3rd/lua/onelua.c
Normal file
107
3rd/lua/onelua.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* one.c -- Lua core, libraries, and interpreter in a single file
|
||||
*/
|
||||
|
||||
/* default is to build the full interpreter */
|
||||
#ifndef MAKE_LIB
|
||||
#ifndef MAKE_LUAC
|
||||
#ifndef MAKE_LUA
|
||||
#define MAKE_LUA
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* choose suitable platform-specific features */
|
||||
/* some of these may need extra libraries such as -ldl -lreadline -lncurses */
|
||||
#if 0
|
||||
#define LUA_USE_LINUX
|
||||
#define LUA_USE_MACOSX
|
||||
#define LUA_USE_POSIX
|
||||
#define LUA_ANSI
|
||||
#endif
|
||||
|
||||
/* no need to change anything below this line ----------------------------- */
|
||||
|
||||
#include "lprefix.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
/* setup for luaconf.h */
|
||||
#define LUA_CORE
|
||||
#define LUA_LIB
|
||||
#define ltable_c
|
||||
#define lvm_c
|
||||
#include "luaconf.h"
|
||||
|
||||
/* do not export internal symbols */
|
||||
#undef LUAI_FUNC
|
||||
#undef LUAI_DDEC
|
||||
#undef LUAI_DDEF
|
||||
#define LUAI_FUNC static
|
||||
#define LUAI_DDEC(def) /* empty */
|
||||
#define LUAI_DDEF static
|
||||
|
||||
/* core -- used by all */
|
||||
#include "lzio.c"
|
||||
#include "lctype.c"
|
||||
#include "lopcodes.c"
|
||||
#include "lmem.c"
|
||||
#include "lundump.c"
|
||||
#include "ldump.c"
|
||||
#include "lstate.c"
|
||||
#include "lgc.c"
|
||||
#include "llex.c"
|
||||
#include "lcode.c"
|
||||
#include "lparser.c"
|
||||
#include "ldebug.c"
|
||||
#include "lfunc.c"
|
||||
#include "lobject.c"
|
||||
#include "ltm.c"
|
||||
#include "lstring.c"
|
||||
#include "ltable.c"
|
||||
#include "ldo.c"
|
||||
#include "lvm.c"
|
||||
#include "lapi.c"
|
||||
|
||||
/* auxiliary library -- used by all */
|
||||
#include "lauxlib.c"
|
||||
|
||||
/* standard library -- not used by luac */
|
||||
#ifndef MAKE_LUAC
|
||||
#include "lbaselib.c"
|
||||
#include "lcorolib.c"
|
||||
#include "ldblib.c"
|
||||
#include "liolib.c"
|
||||
#include "lmathlib.c"
|
||||
#include "loadlib.c"
|
||||
#include "loslib.c"
|
||||
#include "lstrlib.c"
|
||||
#include "ltablib.c"
|
||||
#include "lutf8lib.c"
|
||||
#include "linit.c"
|
||||
#endif
|
||||
|
||||
/* lua */
|
||||
#ifdef MAKE_LUA
|
||||
#include "lua.c"
|
||||
#endif
|
||||
|
||||
/* luac */
|
||||
#ifdef MAKE_LUAC
|
||||
#include "luac.c"
|
||||
#endif
|
||||
@@ -1,3 +1,12 @@
|
||||
v1.6.0 (2022-11-16)
|
||||
-----------
|
||||
* Update Lua to 5.4.4 (github Nov 8, 2022)
|
||||
* Update jemalloc to 5.3.0
|
||||
* Update lpeg to 1.0.2 (For sproto)
|
||||
* Update mongo driver to support the newest wire protocol
|
||||
* socket.listen()/cluster.open() returns ip address and port
|
||||
* Add service.close()
|
||||
|
||||
v1.5.0 (2021-11-9)
|
||||
-----------
|
||||
* Update Lua to 5.4.3
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2020 codingnow.com
|
||||
Copyright (c) 2012-2022 codingnow.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
@@ -32,7 +32,7 @@ Run these in different consoles:
|
||||
|
||||
## About Lua version
|
||||
|
||||
Skynet now uses a modified version of lua 5.4.3 ( https://github.com/ejoy/lua/tree/skynet54 ) for multiple lua states.
|
||||
Skynet now uses a modified version of lua 5.4.4 ( https://github.com/ejoy/lua/tree/skynet54 ) for multiple lua states.
|
||||
|
||||
Official Lua versions can also be used as long as the Makefile is edited.
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ skynet.start(function()
|
||||
-- register name "sdb" for simpledb, you can use cluster.query() later.
|
||||
-- See cluster2.lua
|
||||
cluster.register("sdb", sdb)
|
||||
cluster.unregister("sdb")
|
||||
cluster.register("sdb", sdb)
|
||||
|
||||
print(skynet.call(sdb, "lua", "SET", "a", "foobar"))
|
||||
print(skynet.call(sdb, "lua", "SET", "b", "foobar2"))
|
||||
|
||||
10
examples/config.handle
Normal file
10
examples/config.handle
Normal file
@@ -0,0 +1,10 @@
|
||||
include "config.path"
|
||||
|
||||
thread = 8
|
||||
logger = "skynet.log"
|
||||
logpath = "."
|
||||
harbor = 0
|
||||
start = "testhandle" -- main script
|
||||
bootstrap = "snlua bootstrap" -- The service for bootstrap
|
||||
cpath = root.."cservice/?.so"
|
||||
--daemon = "./skynet.pid"
|
||||
@@ -12,11 +12,11 @@ skynet.start(function()
|
||||
skynet.newservice("debug_console",8000)
|
||||
skynet.newservice("simpledb")
|
||||
local watchdog = skynet.newservice("watchdog")
|
||||
skynet.call(watchdog, "lua", "start", {
|
||||
local addr,port = skynet.call(watchdog, "lua", "start", {
|
||||
port = 8888,
|
||||
maxclient = max_client,
|
||||
nodelay = true,
|
||||
})
|
||||
skynet.error("Watchdog listen on", 8888)
|
||||
skynet.error("Watchdog listen on " .. addr .. ":" .. port)
|
||||
skynet.exit()
|
||||
end)
|
||||
|
||||
@@ -40,7 +40,7 @@ function SOCKET.data(fd, msg)
|
||||
end
|
||||
|
||||
function CMD.start(conf)
|
||||
skynet.call(gate, "lua", "open" , conf)
|
||||
return skynet.call(gate, "lua", "open" , conf)
|
||||
end
|
||||
|
||||
function CMD.close(fd)
|
||||
|
||||
@@ -263,11 +263,11 @@ lsha1(lua_State *L) {
|
||||
#define BLOCKSIZE 64
|
||||
|
||||
static inline void
|
||||
xor_key(uint8_t key[BLOCKSIZE], uint32_t xor) {
|
||||
xor_key(uint8_t key[BLOCKSIZE], uint32_t xor_) {
|
||||
int i;
|
||||
for (i=0;i<BLOCKSIZE;i+=sizeof(uint32_t)) {
|
||||
uint32_t * k = (uint32_t *)&key[i];
|
||||
*k ^= xor;
|
||||
*k ^= xor_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -219,14 +219,17 @@ _ltls_context_read(lua_State* L) {
|
||||
|
||||
do {
|
||||
read = SSL_read(tls_p->ssl, outbuff, sizeof(outbuff));
|
||||
if(read <= 0) {
|
||||
if(read < 0) {
|
||||
int err = SSL_get_error(tls_p->ssl, read);
|
||||
ERR_clear_error();
|
||||
if(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
|
||||
break;
|
||||
}
|
||||
luaL_error(L, "SSL_read error:%d", err);
|
||||
}else if(read <= sizeof(outbuff)) {
|
||||
}else if(read == 0){
|
||||
break;
|
||||
}
|
||||
else if(read <= sizeof(outbuff)) {
|
||||
luaL_addlstring(&b, outbuff, read);
|
||||
}else {
|
||||
luaL_error(L, "invalid SSL_read:%d", read);
|
||||
|
||||
@@ -85,10 +85,10 @@ bson_reserve(struct bson *b, int sz) {
|
||||
} while (b->cap <= b->size + sz);
|
||||
|
||||
if (b->ptr == b->buffer) {
|
||||
b->ptr = malloc(b->cap);
|
||||
b->ptr = (uint8_t*)malloc(b->cap);
|
||||
memcpy(b->ptr, b->buffer, b->size);
|
||||
} else {
|
||||
b->ptr = realloc(b->ptr, b->cap);
|
||||
b->ptr = (uint8_t*)realloc(b->ptr, b->cap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ append_one(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth)
|
||||
break;
|
||||
case LUA_TUSERDATA: {
|
||||
append_key(bs, L, BSON_DOCUMENT, key, sz);
|
||||
int32_t * doc = lua_touserdata(L,-1);
|
||||
int32_t * doc = (int32_t*)lua_touserdata(L,-1);
|
||||
int32_t sz = *doc;
|
||||
bson_reserve(bs,sz);
|
||||
memcpy(bs->ptr + bs->size, doc, sz);
|
||||
@@ -574,7 +574,7 @@ static int
|
||||
ltostring(lua_State *L) {
|
||||
size_t sz = lua_rawlen(L, 1);
|
||||
void * ud = lua_touserdata(L,1);
|
||||
lua_pushlstring(L, ud, sz);
|
||||
lua_pushlstring(L, (const char*)ud, sz);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -591,7 +591,7 @@ make_object(lua_State *L, int type, const void * ptr, size_t len) {
|
||||
luaL_buffinit(L, &b);
|
||||
luaL_addchar(&b, 0);
|
||||
luaL_addchar(&b, type);
|
||||
luaL_addlstring(&b, ptr, len);
|
||||
luaL_addlstring(&b, (const char*)ptr, len);
|
||||
luaL_pushresult(&b);
|
||||
}
|
||||
|
||||
@@ -600,7 +600,7 @@ unpack_dict(lua_State *L, struct bson_reader *br, bool array) {
|
||||
luaL_checkstack(L, 16, NULL); // reserve enough stack space to unpack table
|
||||
int sz = read_int32(L, br);
|
||||
const void * bytes = read_bytes(L, br, sz-5);
|
||||
struct bson_reader t = { bytes, sz-5 };
|
||||
struct bson_reader t = { (const uint8_t*)bytes, sz-5 };
|
||||
int end = read_byte(L, br);
|
||||
if (end != '\0') {
|
||||
luaL_error(L, "Invalid document end");
|
||||
@@ -632,7 +632,7 @@ unpack_dict(lua_State *L, struct bson_reader *br, bool array) {
|
||||
if (sz <= 0) {
|
||||
luaL_error(L, "Invalid bson string , length = %d", sz);
|
||||
}
|
||||
lua_pushlstring(L, read_bytes(L, &t, sz), sz-1);
|
||||
lua_pushlstring(L, (const char*)read_bytes(L, &t, sz), sz-1);
|
||||
break;
|
||||
}
|
||||
case BSON_DOCUMENT:
|
||||
@@ -650,7 +650,7 @@ unpack_dict(lua_State *L, struct bson_reader *br, bool array) {
|
||||
luaL_addchar(&b, 0);
|
||||
luaL_addchar(&b, BSON_BINARY);
|
||||
luaL_addchar(&b, subtype);
|
||||
luaL_addlstring(&b, read_bytes(L, &t, sz), sz);
|
||||
luaL_addlstring(&b, (const char*)read_bytes(L, &t, sz), sz);
|
||||
luaL_pushresult(&b);
|
||||
break;
|
||||
}
|
||||
@@ -666,7 +666,7 @@ unpack_dict(lua_State *L, struct bson_reader *br, bool array) {
|
||||
case BSON_MINKEY:
|
||||
case BSON_MAXKEY:
|
||||
case BSON_NULL: {
|
||||
char key[] = { 0, bt };
|
||||
char key[] = { 0, (char)bt };
|
||||
lua_pushlstring(L, key, sizeof(key));
|
||||
break;
|
||||
}
|
||||
@@ -739,7 +739,7 @@ unpack_dict(lua_State *L, struct bson_reader *br, bool array) {
|
||||
|
||||
static int
|
||||
lmakeindex(lua_State *L) {
|
||||
int32_t *bson = luaL_checkudata(L,1,"bson");
|
||||
int32_t *bson = (int32_t*)luaL_checkudata(L,1,"bson");
|
||||
const uint8_t * start = (const uint8_t *)bson;
|
||||
struct bson_reader br = { start+4, get_length(start) - 5 };
|
||||
lua_newtable(L);
|
||||
@@ -871,7 +871,7 @@ lreplace(lua_State *L) {
|
||||
int id = lua_tointeger(L, -1);
|
||||
int type = id & ((1<<(BSON_TYPE_SHIFT)) - 1);
|
||||
int offset = id >> BSON_TYPE_SHIFT;
|
||||
uint8_t * start = lua_touserdata(L,1);
|
||||
uint8_t * start = (uint8_t*)lua_touserdata(L,1);
|
||||
struct bson b = { 0,16, start + offset };
|
||||
switch (type) {
|
||||
case BSON_REAL:
|
||||
@@ -910,7 +910,7 @@ lreplace(lua_State *L) {
|
||||
|
||||
static int
|
||||
ldecode(lua_State *L) {
|
||||
const int32_t * data = lua_touserdata(L,1);
|
||||
const int32_t * data = (const int32_t*)lua_touserdata(L,1);
|
||||
if (data == NULL) {
|
||||
return 0;
|
||||
}
|
||||
@@ -945,7 +945,7 @@ bson_meta(lua_State *L) {
|
||||
|
||||
static int
|
||||
encode_bson(lua_State *L) {
|
||||
struct bson *b = lua_touserdata(L, 2);
|
||||
struct bson *b = (struct bson*)lua_touserdata(L, 2);
|
||||
lua_settop(L, 1);
|
||||
if (luaL_getmetafield(L, -1, "__pairs") != LUA_TNIL) {
|
||||
pack_meta_dict(L, b, 0);
|
||||
@@ -978,7 +978,7 @@ lencode(lua_State *L) {
|
||||
static int
|
||||
encode_bson_byorder(lua_State *L) {
|
||||
int n = lua_gettop(L);
|
||||
struct bson *b = lua_touserdata(L, n);
|
||||
struct bson *b = (struct bson*)lua_touserdata(L, n);
|
||||
lua_settop(L, --n);
|
||||
pack_ordered_dict(L, b, n, 0);
|
||||
lua_settop(L,0);
|
||||
@@ -1106,7 +1106,7 @@ lsubtype(lua_State *L, int subtype, const uint8_t * buf, size_t sz) {
|
||||
char oid[24];
|
||||
int i;
|
||||
const uint8_t * id = buf;
|
||||
static char *hex = "0123456789abcdef";
|
||||
static const char *hex = "0123456789abcdef";
|
||||
for (i=0;i<12;i++) {
|
||||
oid[i*2] = hex[id[i] >> 4];
|
||||
oid[i*2+1] = hex[id[i] & 0xf];
|
||||
@@ -1219,7 +1219,7 @@ ltype(lua_State *L) {
|
||||
|
||||
static void
|
||||
typeclosure(lua_State *L) {
|
||||
static const char * typename[] = {
|
||||
static const char * typename_[] = {
|
||||
"number", // 1
|
||||
"boolean", // 2
|
||||
"table", // 3
|
||||
@@ -1236,9 +1236,9 @@ typeclosure(lua_State *L) {
|
||||
"unsupported", // 14
|
||||
};
|
||||
int i;
|
||||
int n = sizeof(typename)/sizeof(typename[0]);
|
||||
int n = sizeof(typename_)/sizeof(typename_[0]);
|
||||
for (i=0;i<n;i++) {
|
||||
lua_pushstring(L,typename[i]);
|
||||
lua_pushstring(L, typename_[i]);
|
||||
}
|
||||
lua_pushcclosure(L, ltype, n);
|
||||
}
|
||||
@@ -1347,7 +1347,7 @@ luaopen_bson(lua_State *L) {
|
||||
char null[] = { 0, BSON_NULL };
|
||||
lua_pushlstring(L, null, sizeof(null));
|
||||
lua_setfield(L,-2,"null");
|
||||
char minkey[] = { 0, BSON_MINKEY };
|
||||
char minkey[] = { 0, (char)BSON_MINKEY };
|
||||
lua_pushlstring(L, minkey, sizeof(minkey));
|
||||
lua_setfield(L,-2,"minkey");
|
||||
char maxkey[] = { 0, BSON_MAXKEY };
|
||||
|
||||
@@ -603,6 +603,11 @@ lnodename(lua_State *L) {
|
||||
pid_t pid = getpid();
|
||||
char hostname[256];
|
||||
if (gethostname(hostname, sizeof(hostname))==0) {
|
||||
int i;
|
||||
for (i=0; hostname[i]; i++) {
|
||||
if (hostname[i] <= ' ')
|
||||
hostname[i] = '_';
|
||||
}
|
||||
lua_pushfstring(L, "%s%d", hostname, (int)pid);
|
||||
} else {
|
||||
lua_pushfstring(L, "noname%d", (int)pid);
|
||||
|
||||
@@ -455,7 +455,7 @@ des_key(lua_State *L, uint32_t SK[32]) {
|
||||
if (keysz != 8) {
|
||||
luaL_error(L, "Invalid key size %d, need 8 bytes", (int)keysz);
|
||||
}
|
||||
des_main_ks(SK, key);
|
||||
des_main_ks(SK, (const uint8_t*)key);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -470,7 +470,7 @@ ldesencode(lua_State *L) {
|
||||
uint8_t tmp[SMALL_CHUNK];
|
||||
uint8_t *buffer = tmp;
|
||||
if (chunksz > SMALL_CHUNK) {
|
||||
buffer = lua_newuserdatauv(L, chunksz, 0);
|
||||
buffer = (uint8_t*)lua_newuserdatauv(L, chunksz, 0);
|
||||
}
|
||||
int i;
|
||||
for (i=0;i<(int)textsz-7;i+=8) {
|
||||
@@ -503,7 +503,7 @@ ldesdecode(lua_State *L) {
|
||||
uint8_t tmp[SMALL_CHUNK];
|
||||
uint8_t *buffer = tmp;
|
||||
if (textsz > SMALL_CHUNK) {
|
||||
buffer = lua_newuserdatauv(L, textsz, 0);
|
||||
buffer = (uint8_t*)lua_newuserdatauv(L, textsz, 0);
|
||||
}
|
||||
for (i=0;i<textsz;i+=8) {
|
||||
des_crypt(SK, text+i, buffer+i);
|
||||
@@ -558,7 +558,7 @@ ltohex(lua_State *L) {
|
||||
char tmp[SMALL_CHUNK];
|
||||
char *buffer = tmp;
|
||||
if (sz > SMALL_CHUNK/2) {
|
||||
buffer = lua_newuserdatauv(L, sz * 2, 0);
|
||||
buffer = (char*)lua_newuserdatauv(L, sz * 2, 0);
|
||||
}
|
||||
int i;
|
||||
for (i=0;i<sz;i++) {
|
||||
@@ -581,7 +581,7 @@ lfromhex(lua_State *L) {
|
||||
char tmp[SMALL_CHUNK];
|
||||
char *buffer = tmp;
|
||||
if (sz > SMALL_CHUNK*2) {
|
||||
buffer = lua_newuserdatauv(L, sz / 2, 0);
|
||||
buffer = (char*)lua_newuserdatauv(L, sz / 2, 0);
|
||||
}
|
||||
int i;
|
||||
for (i=0;i<sz;i+=2) {
|
||||
@@ -898,7 +898,7 @@ lb64encode(lua_State *L) {
|
||||
char tmp[SMALL_CHUNK];
|
||||
char *buffer = tmp;
|
||||
if (encode_sz > SMALL_CHUNK) {
|
||||
buffer = lua_newuserdatauv(L, encode_sz, 0);
|
||||
buffer = (char*)lua_newuserdatauv(L, encode_sz, 0);
|
||||
}
|
||||
int i,j;
|
||||
j=0;
|
||||
@@ -953,7 +953,7 @@ lb64decode(lua_State *L) {
|
||||
char tmp[SMALL_CHUNK];
|
||||
char *buffer = tmp;
|
||||
if (decode_sz > SMALL_CHUNK) {
|
||||
buffer = lua_newuserdatauv(L, decode_sz, 0);
|
||||
buffer = (char*)lua_newuserdatauv(L, decode_sz, 0);
|
||||
}
|
||||
int i,j;
|
||||
int output = 0;
|
||||
@@ -961,10 +961,12 @@ lb64decode(lua_State *L) {
|
||||
int padding = 0;
|
||||
int c[4];
|
||||
for (j=0;j<4;) {
|
||||
if (i>=sz) {
|
||||
return luaL_error(L, "Invalid base64 text");
|
||||
if (i>=sz && 4>j){
|
||||
/*To improve compatibility, there may not be enough equal signs */
|
||||
c[j] = -2;
|
||||
}else{
|
||||
c[j] = b64index(text[i]);
|
||||
}
|
||||
c[j] = b64index(text[i]);
|
||||
if (c[j] == -1) {
|
||||
++i;
|
||||
continue;
|
||||
|
||||
@@ -10,21 +10,17 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define OP_REPLY 1
|
||||
#define OP_MSG 1000
|
||||
#define OP_UPDATE 2001
|
||||
#define OP_INSERT 2002
|
||||
#define OP_QUERY 2004
|
||||
#define OP_GET_MORE 2005
|
||||
#define OP_DELETE 2006
|
||||
#define OP_KILL_CURSORS 2007
|
||||
#define OP_COMPRESSED 2012
|
||||
#define OP_MSG 2013
|
||||
|
||||
typedef enum {
|
||||
MSG_CHECKSUM_PRESENT = 1 << 0,
|
||||
MSG_MORE_TO_COME = 1 << 1,
|
||||
MSG_EXHAUST_ALLOWED = 1 << 16,
|
||||
} msg_flags_t;
|
||||
|
||||
#define REPLY_CURSORNOTFOUND 1
|
||||
#define REPLY_QUERYFAILURE 2
|
||||
#define REPLY_AWAITCAPABLE 8 // ignore because mongo 1.6+ always set it
|
||||
|
||||
#define DEFAULT_CAP 128
|
||||
|
||||
struct connection {
|
||||
int sock;
|
||||
int id;
|
||||
@@ -89,10 +85,10 @@ buffer_reserve(struct buffer *b, int sz) {
|
||||
} while (b->cap <= b->size + sz);
|
||||
|
||||
if (b->ptr == b->buffer) {
|
||||
b->ptr = skynet_malloc(b->cap);
|
||||
b->ptr = (uint8_t*)malloc(b->cap);
|
||||
memcpy(b->ptr, b->buffer, b->size);
|
||||
} else {
|
||||
b->ptr = skynet_realloc(b->ptr, b->cap);
|
||||
b->ptr = (uint8_t*)realloc(b->ptr, b->cap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +102,14 @@ write_int32(struct buffer *b, int32_t v) {
|
||||
b->ptr[b->size++] = (uv >> 24)&0xff;
|
||||
}
|
||||
|
||||
static inline void
|
||||
write_int8(struct buffer *b, int8_t v) {
|
||||
uint8_t uv = (uint8_t)v;
|
||||
buffer_reserve(b, 1);
|
||||
b->ptr[b->size++] = uv;
|
||||
}
|
||||
|
||||
/*
|
||||
static inline void
|
||||
write_bytes(struct buffer *b, const void * buf, int sz) {
|
||||
buffer_reserve(b,sz);
|
||||
@@ -120,6 +124,7 @@ write_string(struct buffer *b, const char *key, size_t sz) {
|
||||
b->ptr[b->size+sz] = '\0';
|
||||
b->size+=sz+1;
|
||||
}
|
||||
*/
|
||||
|
||||
static inline int
|
||||
reserve_length(struct buffer *b) {
|
||||
@@ -138,388 +143,69 @@ write_length(struct buffer *b, int32_t v, int off) {
|
||||
b->ptr[off++] = (uv >> 24)&0xff;
|
||||
}
|
||||
|
||||
// 1 integer id
|
||||
// 2 integer flags
|
||||
// 3 string collection name
|
||||
// 4 integer skip
|
||||
// 5 integer return number
|
||||
// 6 document query
|
||||
// 7 document selector (optional)
|
||||
// return string package
|
||||
static int
|
||||
op_query(lua_State *L) {
|
||||
int id = luaL_checkinteger(L,1);
|
||||
document query = lua_touserdata(L,6);
|
||||
if (query == NULL) {
|
||||
return luaL_error(L, "require query document");
|
||||
}
|
||||
document selector = lua_touserdata(L,7);
|
||||
int flags = luaL_checkinteger(L, 2);
|
||||
size_t nsz = 0;
|
||||
const char *name = luaL_checklstring(L,3,&nsz);
|
||||
int skip = luaL_checkinteger(L, 4);
|
||||
int number = luaL_checkinteger(L, 5);
|
||||
struct header_t {
|
||||
//int32_t message_length; // total message size, include this
|
||||
int32_t request_id; // identifier for this message
|
||||
int32_t response_to; // requestID from the original request(used in responses from the database)
|
||||
int32_t opcode; // message type
|
||||
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L,&b);
|
||||
|
||||
struct buffer buf;
|
||||
buffer_create(&buf);
|
||||
int len = reserve_length(&buf);
|
||||
write_int32(&buf, id);
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, OP_QUERY);
|
||||
write_int32(&buf, flags);
|
||||
write_string(&buf, name, nsz);
|
||||
write_int32(&buf, skip);
|
||||
write_int32(&buf, number);
|
||||
|
||||
int32_t query_len = get_length(query);
|
||||
int total = buf.size + query_len;
|
||||
int32_t selector_len = 0;
|
||||
if (selector) {
|
||||
selector_len = get_length(selector);
|
||||
total += selector_len;
|
||||
}
|
||||
|
||||
write_length(&buf, total, len);
|
||||
luaL_addlstring(&b, (const char *)buf.ptr, buf.size);
|
||||
buffer_destroy(&buf);
|
||||
|
||||
luaL_addlstring(&b, (const char *)query, query_len);
|
||||
|
||||
if (selector) {
|
||||
luaL_addlstring(&b, (const char *)selector, selector_len);
|
||||
}
|
||||
|
||||
luaL_pushresult(&b);
|
||||
|
||||
return 1;
|
||||
}
|
||||
int32_t flags;
|
||||
};
|
||||
|
||||
// 1 string data
|
||||
// 2 result document table
|
||||
// return boolean succ (false -> request id, error document)
|
||||
// number request_id
|
||||
// document first
|
||||
// string cursor_id
|
||||
// integer startfrom
|
||||
static int
|
||||
op_reply(lua_State *L) {
|
||||
unpack_reply(lua_State *L) {
|
||||
size_t data_len = 0;
|
||||
const char * data = luaL_checklstring(L,1,&data_len);
|
||||
struct {
|
||||
// int32_t length; // total message size, including this
|
||||
int32_t request_id; // identifier for this message
|
||||
int32_t response_id; // requestID from the original request
|
||||
// (used in reponses from db)
|
||||
int32_t opcode; // request type
|
||||
int32_t flags;
|
||||
int32_t cursor_id[2];
|
||||
int32_t starting;
|
||||
int32_t number;
|
||||
} const *reply = (const void *)data;
|
||||
const struct header_t* h = (const struct header_t*)data;
|
||||
|
||||
if (data_len < sizeof(*reply)) {
|
||||
if (data_len < sizeof(*h)) {
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int id = little_endian(reply->response_id);
|
||||
int flags = little_endian(reply->flags);
|
||||
if (flags & REPLY_QUERYFAILURE) {
|
||||
lua_pushboolean(L,0);
|
||||
lua_pushinteger(L, id);
|
||||
lua_pushlightuserdata(L, (void *)(reply+1));
|
||||
return 3;
|
||||
int opcode = little_endian(h->opcode);
|
||||
if (opcode != OP_MSG) {
|
||||
return luaL_error(L, "Unsupported opcode:%d", opcode);
|
||||
}
|
||||
|
||||
int starting_from = little_endian(reply->starting);
|
||||
int number = little_endian(reply->number);
|
||||
int sz = (int)data_len - sizeof(*reply);
|
||||
const uint8_t * doc = (const uint8_t *)(reply+1);
|
||||
int id = little_endian(h->response_to);
|
||||
int flags = little_endian(h->flags);
|
||||
|
||||
if (lua_istable(L,2)) {
|
||||
int i = 1;
|
||||
while (sz > 4) {
|
||||
lua_pushlightuserdata(L, (void *)doc);
|
||||
lua_rawseti(L, 2, i);
|
||||
|
||||
int32_t doc_len = get_length((document)doc);
|
||||
if (doc_len <= 0) {
|
||||
return luaL_error(L, "Invalid result bson document");
|
||||
}
|
||||
|
||||
doc += doc_len;
|
||||
sz -= doc_len;
|
||||
|
||||
++i;
|
||||
if (flags != 0) {
|
||||
if ((flags & MSG_CHECKSUM_PRESENT) != 0) {
|
||||
return luaL_error(L, "Unsupported OP_MSG flag checksumPresent");
|
||||
}
|
||||
if (i != number + 1) {
|
||||
lua_pushboolean(L,0);
|
||||
lua_pushinteger(L, id);
|
||||
return 2;
|
||||
}
|
||||
int c = lua_rawlen(L, 2);
|
||||
for (;i<=c;i++) {
|
||||
lua_pushnil(L);
|
||||
lua_rawseti(L, 2, i);
|
||||
}
|
||||
} else {
|
||||
if (sz >= 4) {
|
||||
sz -= get_length((document)doc);
|
||||
|
||||
if ((flags ^ MSG_MORE_TO_COME) != 0) {
|
||||
return luaL_error(L, "Unsupported OP_MSG flag:%d", flags);
|
||||
}
|
||||
}
|
||||
if (sz != 0) {
|
||||
return luaL_error(L, "Invalid result bson document");
|
||||
|
||||
int sz = (int)data_len - sizeof(*h);
|
||||
|
||||
const uint8_t * section = (const uint8_t *)(h+1);
|
||||
|
||||
uint8_t payload_type = *section;
|
||||
const uint8_t * doc = section+1;
|
||||
|
||||
if (payload_type != 0) {
|
||||
return luaL_error(L, "Unsupported OP_MSG payload type: %d", payload_type);
|
||||
}
|
||||
lua_pushboolean(L,1);
|
||||
|
||||
int32_t doc_sz = get_length((document)(doc));
|
||||
if ((sz - 1) != doc_sz) {
|
||||
return luaL_error(L, "Unsupported OP_MSG reply: >1 section");
|
||||
}
|
||||
|
||||
lua_pushboolean(L, 1);
|
||||
lua_pushinteger(L, id);
|
||||
if (number == 0)
|
||||
lua_pushnil(L);
|
||||
else
|
||||
lua_pushlightuserdata(L, (void *)(reply+1));
|
||||
if (reply->cursor_id[0] == 0 && reply->cursor_id[1]==0) {
|
||||
// closed cursor
|
||||
lua_pushnil(L);
|
||||
} else {
|
||||
lua_pushlstring(L, (const char *)(reply->cursor_id), 8);
|
||||
}
|
||||
lua_pushinteger(L, starting_from);
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
/*
|
||||
1 string cursor_id
|
||||
return string package
|
||||
*/
|
||||
static int
|
||||
op_kill(lua_State *L) {
|
||||
size_t cursor_len = 0;
|
||||
const char * cursor_id = luaL_tolstring(L, 1, &cursor_len);
|
||||
if (cursor_len != 8) {
|
||||
return luaL_error(L, "Invalid cursor id");
|
||||
}
|
||||
|
||||
struct buffer buf;
|
||||
buffer_create(&buf);
|
||||
|
||||
int len = reserve_length(&buf);
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, OP_KILL_CURSORS);
|
||||
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, 1);
|
||||
write_bytes(&buf, cursor_id, 8);
|
||||
|
||||
write_length(&buf, buf.size, len);
|
||||
|
||||
lua_pushlstring(L, (const char *)buf.ptr, buf.size);
|
||||
buffer_destroy(&buf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
1 string collection
|
||||
2 integer single remove
|
||||
3 document selector
|
||||
|
||||
return string package
|
||||
*/
|
||||
static int
|
||||
op_delete(lua_State *L) {
|
||||
document selector = lua_touserdata(L,3);
|
||||
if (selector == NULL) {
|
||||
luaL_error(L, "Invalid param");
|
||||
}
|
||||
size_t sz = 0;
|
||||
const char * name = luaL_checklstring(L,1,&sz);
|
||||
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L,&b);
|
||||
|
||||
struct buffer buf;
|
||||
buffer_create(&buf);
|
||||
int len = reserve_length(&buf);
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, OP_DELETE);
|
||||
write_int32(&buf, 0);
|
||||
write_string(&buf, name, sz);
|
||||
write_int32(&buf, lua_tointeger(L,2));
|
||||
|
||||
int32_t selector_len = get_length(selector);
|
||||
int total = buf.size + selector_len;
|
||||
write_length(&buf, total, len);
|
||||
|
||||
luaL_addlstring(&b, (const char *)buf.ptr, buf.size);
|
||||
buffer_destroy(&buf);
|
||||
|
||||
luaL_addlstring(&b, (const char *)selector, selector_len);
|
||||
luaL_pushresult(&b);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
1 integer id
|
||||
2 string collection
|
||||
3 integer number
|
||||
4 cursor_id (8 bytes string/ 64bit)
|
||||
|
||||
return string package
|
||||
*/
|
||||
static int
|
||||
op_get_more(lua_State *L) {
|
||||
int id = luaL_checkinteger(L, 1);
|
||||
size_t sz = 0;
|
||||
const char * name = luaL_checklstring(L,2,&sz);
|
||||
int number = luaL_checkinteger(L, 3);
|
||||
size_t cursor_len = 0;
|
||||
const char * cursor_id = luaL_tolstring(L, 4, &cursor_len);
|
||||
if (cursor_len != 8) {
|
||||
return luaL_error(L, "Invalid cursor id");
|
||||
}
|
||||
|
||||
struct buffer buf;
|
||||
buffer_create(&buf);
|
||||
int len = reserve_length(&buf);
|
||||
write_int32(&buf, id);
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, OP_GET_MORE);
|
||||
write_int32(&buf, 0);
|
||||
write_string(&buf, name, sz);
|
||||
write_int32(&buf, number);
|
||||
write_bytes(&buf, cursor_id, 8);
|
||||
write_length(&buf, buf.size, len);
|
||||
|
||||
lua_pushlstring(L, (const char *)buf.ptr, buf.size);
|
||||
buffer_destroy(&buf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 1 string collection
|
||||
// 2 integer flags
|
||||
// 3 document selector
|
||||
// 4 document update
|
||||
// return string package
|
||||
static int
|
||||
op_update(lua_State *L) {
|
||||
document selector = lua_touserdata(L,3);
|
||||
document update = lua_touserdata(L,4);
|
||||
if (selector == NULL || update == NULL) {
|
||||
luaL_error(L, "Invalid param");
|
||||
}
|
||||
size_t sz = 0;
|
||||
const char * name = luaL_checklstring(L,1,&sz);
|
||||
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
|
||||
struct buffer buf;
|
||||
buffer_create(&buf);
|
||||
// make package header, don't raise L error
|
||||
int len = reserve_length(&buf);
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, OP_UPDATE);
|
||||
write_int32(&buf, 0);
|
||||
write_string(&buf, name, sz);
|
||||
write_int32(&buf, lua_tointeger(L,2));
|
||||
|
||||
int32_t selector_len = get_length(selector);
|
||||
int32_t update_len = get_length(update);
|
||||
|
||||
int total = buf.size + selector_len + update_len;
|
||||
write_length(&buf, total, len);
|
||||
|
||||
luaL_addlstring(&b, (const char *)buf.ptr, buf.size);
|
||||
buffer_destroy(&buf);
|
||||
|
||||
luaL_addlstring(&b, (const char *)selector, selector_len);
|
||||
luaL_addlstring(&b, (const char *)update, update_len);
|
||||
|
||||
luaL_pushresult(&b);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
document_length(lua_State *L) {
|
||||
if (lua_isuserdata(L, 3)) {
|
||||
document doc = lua_touserdata(L,3);
|
||||
return get_length(doc);
|
||||
}
|
||||
if (lua_istable(L,3)) {
|
||||
int total = 0;
|
||||
int s = lua_rawlen(L,3);
|
||||
int i;
|
||||
for (i=1;i<=s;i++) {
|
||||
lua_rawgeti(L, 3, i);
|
||||
document doc = lua_touserdata(L,-1);
|
||||
if (doc == NULL) {
|
||||
lua_pop(L,1);
|
||||
return luaL_error(L, "Invalid document at %d", i);
|
||||
} else {
|
||||
total += get_length(doc);
|
||||
lua_pop(L,1);
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
return luaL_error(L, "Insert need documents");
|
||||
}
|
||||
|
||||
// 1 integer flags
|
||||
// 2 string collection
|
||||
// 3 documents
|
||||
// return string package
|
||||
static int
|
||||
op_insert(lua_State *L) {
|
||||
size_t sz = 0;
|
||||
const char * name = luaL_checklstring(L,2,&sz);
|
||||
int dsz = document_length(L);
|
||||
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
|
||||
struct buffer buf;
|
||||
buffer_create(&buf);
|
||||
// make package header, don't raise L error
|
||||
int len = reserve_length(&buf);
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, OP_INSERT);
|
||||
write_int32(&buf, lua_tointeger(L,1));
|
||||
write_string(&buf, name, sz);
|
||||
|
||||
int total = buf.size + dsz;
|
||||
write_length(&buf, total, len);
|
||||
|
||||
luaL_addlstring(&b, (const char *)buf.ptr, buf.size);
|
||||
buffer_destroy(&buf);
|
||||
|
||||
if (lua_isuserdata(L,3)) {
|
||||
document doc = lua_touserdata(L,3);
|
||||
luaL_addlstring(&b, (const char *)doc, get_length(doc));
|
||||
} else {
|
||||
int s = lua_rawlen(L, 3);
|
||||
int i;
|
||||
for (i=1;i<=s;i++) {
|
||||
lua_rawgeti(L,3,i);
|
||||
document doc = lua_touserdata(L,-1);
|
||||
lua_pop(L,1); // must call lua_pop before luaL_addlstring, because addlstring may change stack top
|
||||
luaL_addlstring(&b, (const char *)doc, get_length(doc));
|
||||
}
|
||||
}
|
||||
|
||||
luaL_pushresult(&b);
|
||||
|
||||
return 1;
|
||||
lua_pushlightuserdata(L, (void *)(doc));
|
||||
return 3;
|
||||
}
|
||||
|
||||
// string 4 bytes length
|
||||
@@ -534,21 +220,55 @@ reply_length(lua_State *L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// @param 1 request_id int
|
||||
// @param 2 flags int
|
||||
// @param 3 command bson document
|
||||
// @return
|
||||
static int
|
||||
op_msg(lua_State *L) {
|
||||
int id = luaL_checkinteger(L, 1);
|
||||
int flags = luaL_checkinteger(L, 2);
|
||||
document cmd = lua_touserdata(L, 3);
|
||||
|
||||
if (cmd == NULL) {
|
||||
return luaL_error(L, "opmsg require cmd document");
|
||||
}
|
||||
|
||||
luaL_Buffer b;
|
||||
luaL_buffinit(L, &b);
|
||||
|
||||
struct buffer buf;
|
||||
buffer_create(&buf);
|
||||
int len = reserve_length(&buf);
|
||||
write_int32(&buf, id);
|
||||
write_int32(&buf, 0);
|
||||
write_int32(&buf, OP_MSG);
|
||||
write_int32(&buf, flags);
|
||||
write_int8(&buf, 0);
|
||||
|
||||
int32_t cmd_len = get_length(cmd);
|
||||
int total = buf.size + cmd_len;
|
||||
|
||||
write_length(&buf, total, len);
|
||||
luaL_addlstring(&b, (const char *)buf.ptr, buf.size);
|
||||
buffer_destroy(&buf);
|
||||
|
||||
luaL_addlstring(&b, (const char *)cmd, cmd_len);
|
||||
luaL_pushresult(&b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
LUAMOD_API int
|
||||
luaopen_skynet_mongo_driver(lua_State *L) {
|
||||
luaL_checkversion(L);
|
||||
luaL_Reg l[] ={
|
||||
{ "query", op_query },
|
||||
{ "reply", op_reply },
|
||||
{ "kill", op_kill },
|
||||
{ "delete", op_delete },
|
||||
{ "more", op_get_more },
|
||||
{ "update", op_update },
|
||||
{ "insert", op_insert },
|
||||
{ "reply", unpack_reply }, // 接收响应
|
||||
{ "length", reply_length },
|
||||
{ "op_msg", op_msg},
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
luaL_newlib(L,l);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
#define TYPE_OPEN 4
|
||||
#define TYPE_CLOSE 5
|
||||
#define TYPE_WARNING 6
|
||||
#define TYPE_INIT 7
|
||||
|
||||
/*
|
||||
Each package is uint16 + data , uint16 (serialized in big-endian) is the number of bytes comprising the data .
|
||||
@@ -354,8 +355,11 @@ lfilter(lua_State *L) {
|
||||
assert(size == -1); // never padding string
|
||||
return filter_data(L, message->id, (uint8_t *)buffer, message->ud);
|
||||
case SKYNET_SOCKET_TYPE_CONNECT:
|
||||
// ignore listen fd connect
|
||||
return 1;
|
||||
lua_pushvalue(L, lua_upvalueindex(TYPE_INIT));
|
||||
lua_pushinteger(L, message->id);
|
||||
lua_pushlstring(L, buffer, size);
|
||||
lua_pushinteger(L, message->ud);
|
||||
return 5;
|
||||
case SKYNET_SOCKET_TYPE_CLOSE:
|
||||
// no more data in fd (message->id)
|
||||
close_uncomplete(L, message->id);
|
||||
@@ -483,8 +487,9 @@ luaopen_skynet_netpack(lua_State *L) {
|
||||
lua_pushliteral(L, "open");
|
||||
lua_pushliteral(L, "close");
|
||||
lua_pushliteral(L, "warning");
|
||||
lua_pushliteral(L, "init");
|
||||
|
||||
lua_pushcclosure(L, lfilter, 6);
|
||||
lua_pushcclosure(L, lfilter, 7);
|
||||
lua_setfield(L, -2, "filter");
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -256,17 +256,19 @@ wb_table_hash(lua_State *L, struct write_block * wb, int index, int depth, int a
|
||||
wb_nil(wb);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
wb_table_metapairs(lua_State *L, struct write_block *wb, int index, int depth) {
|
||||
uint8_t n = COMBINE_TYPE(TYPE_TABLE, 0);
|
||||
wb_push(wb, &n, 1);
|
||||
lua_pushvalue(L, index);
|
||||
lua_call(L, 1, 3);
|
||||
if (lua_pcall(L, 1, 3,0) != LUA_OK)
|
||||
return 1;
|
||||
for(;;) {
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_copy(L, -5, -3);
|
||||
lua_call(L, 2, 2);
|
||||
if (lua_pcall(L, 2, 2, 0) != LUA_OK)
|
||||
return 1;
|
||||
int type = lua_type(L, -2);
|
||||
if (type == LUA_TNIL) {
|
||||
lua_pop(L, 4);
|
||||
@@ -277,19 +279,24 @@ wb_table_metapairs(lua_State *L, struct write_block *wb, int index, int depth) {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
wb_nil(wb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
wb_table(lua_State *L, struct write_block *wb, int index, int depth) {
|
||||
luaL_checkstack(L, LUA_MINSTACK, NULL);
|
||||
if (!lua_checkstack(L, LUA_MINSTACK)) {
|
||||
lua_pushstring(L, "out of memory");
|
||||
return 1;
|
||||
}
|
||||
if (index < 0) {
|
||||
index = lua_gettop(L) + index + 1;
|
||||
}
|
||||
if (luaL_getmetafield(L, index, "__pairs") != LUA_TNIL) {
|
||||
wb_table_metapairs(L, wb, index, depth);
|
||||
return wb_table_metapairs(L, wb, index, depth);
|
||||
} else {
|
||||
int array_size = wb_table_array(L, wb, index, depth);
|
||||
wb_table_hash(L, wb, index, depth, array_size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,7 +337,10 @@ pack_one(lua_State *L, struct write_block *b, int index, int depth) {
|
||||
if (index < 0) {
|
||||
index = lua_gettop(L) + index + 1;
|
||||
}
|
||||
wb_table(L, b, index, depth+1);
|
||||
if (wb_table(L, b, index, depth+1)) {
|
||||
wb_free(b);
|
||||
lua_error(L);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -35,12 +35,6 @@ get_time() {
|
||||
#endif
|
||||
}
|
||||
|
||||
struct snlua {
|
||||
lua_State * L;
|
||||
struct skynet_context * ctx;
|
||||
const char * preload;
|
||||
};
|
||||
|
||||
static int
|
||||
traceback (lua_State *L) {
|
||||
const char *msg = lua_tostring(L, 1);
|
||||
@@ -52,18 +46,16 @@ traceback (lua_State *L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct callback_context {
|
||||
lua_State *L;
|
||||
};
|
||||
|
||||
static int
|
||||
_cb(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
|
||||
lua_State *L = ud;
|
||||
struct callback_context *cb_ctx = (struct callback_context *)ud;
|
||||
lua_State *L = cb_ctx->L;
|
||||
int trace = 1;
|
||||
int r;
|
||||
int top = lua_gettop(L);
|
||||
if (top == 0) {
|
||||
lua_pushcfunction(L, traceback);
|
||||
lua_rawgetp(L, LUA_REGISTRYINDEX, _cb);
|
||||
} else {
|
||||
assert(top == 2);
|
||||
}
|
||||
lua_pushvalue(L,2);
|
||||
|
||||
lua_pushinteger(L, type);
|
||||
@@ -108,15 +100,17 @@ lcallback(lua_State *L) {
|
||||
int forward = lua_toboolean(L, 2);
|
||||
luaL_checktype(L,1,LUA_TFUNCTION);
|
||||
lua_settop(L,1);
|
||||
lua_rawsetp(L, LUA_REGISTRYINDEX, _cb);
|
||||
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_MAINTHREAD);
|
||||
lua_State *gL = lua_tothread(L,-1);
|
||||
struct callback_context *cb_ctx = (struct callback_context *)lua_newuserdata(L, sizeof(*cb_ctx));
|
||||
cb_ctx->L = lua_newthread(L);
|
||||
lua_pushcfunction(cb_ctx->L, traceback);
|
||||
lua_setuservalue(L, -2);
|
||||
lua_setfield(L, LUA_REGISTRYINDEX, "callback_context");
|
||||
lua_xmove(L, cb_ctx->L, 1);
|
||||
|
||||
if (forward) {
|
||||
skynet_callback(context, gL, forward_cb);
|
||||
skynet_callback(context, cb_ctx, forward_cb);
|
||||
} else {
|
||||
skynet_callback(context, gL, _cb);
|
||||
skynet_callback(context, cb_ctx, _cb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -168,8 +168,8 @@ function M.request(interface, method, host, url, recvheader, header, content)
|
||||
local write = interface.write
|
||||
local header_content = ""
|
||||
if header then
|
||||
if not header.host then
|
||||
header.host = host
|
||||
if not header.Host then
|
||||
header.Host = host
|
||||
end
|
||||
for k,v in pairs(header) do
|
||||
header_content = string.format("%s%s:%s\r\n", header_content, k, v)
|
||||
|
||||
@@ -139,6 +139,9 @@ local function read_handshake(self, upgrade_ops)
|
||||
end
|
||||
end
|
||||
|
||||
-- read 'x-real-ip' header from nginx
|
||||
self.real_ip = header["x-real-ip"]
|
||||
|
||||
-- response handshake
|
||||
local accept = crypt.base64encode(crypt.sha1(sw_key .. self.guid))
|
||||
local resp = "HTTP/1.1 101 Switching Protocols\r\n"..
|
||||
@@ -184,7 +187,7 @@ local function write_frame(self, op, payload_data, masking_key)
|
||||
-- mask set to 0
|
||||
if payload_len < 126 then
|
||||
s = string.pack("I1I1", v1, mask | payload_len)
|
||||
elseif payload_len < 0xffff then
|
||||
elseif payload_len <= 0xffff then
|
||||
s = string.pack("I1I1>I2", v1, mask | 126, payload_len)
|
||||
else
|
||||
s = string.pack("I1I1>I8", v1, mask | 127, payload_len)
|
||||
@@ -497,6 +500,11 @@ function M.addrinfo(id)
|
||||
return ws_obj.addr
|
||||
end
|
||||
|
||||
function M.real_ip(id)
|
||||
local ws_obj = assert(ws_pool[id])
|
||||
return ws_obj.real_ip
|
||||
end
|
||||
|
||||
function M.close(id, code ,reason)
|
||||
local ws_obj = ws_pool[id]
|
||||
if not ws_obj then
|
||||
|
||||
@@ -545,6 +545,7 @@ function skynet.exit()
|
||||
for address in pairs(tmp) do
|
||||
c.send(address, skynet.PTYPE_ERROR, 0, "")
|
||||
end
|
||||
c.callback(function() end)
|
||||
c.command("EXIT")
|
||||
-- quit service
|
||||
coroutine_yield "QUIT"
|
||||
|
||||
@@ -77,9 +77,9 @@ end
|
||||
|
||||
function cluster.open(port)
|
||||
if type(port) == "string" then
|
||||
skynet.call(clusterd, "lua", "listen", port)
|
||||
return skynet.call(clusterd, "lua", "listen", port)
|
||||
else
|
||||
skynet.call(clusterd, "lua", "listen", "0.0.0.0", port)
|
||||
return skynet.call(clusterd, "lua", "listen", "0.0.0.0", port)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -106,6 +106,11 @@ function cluster.register(name, addr)
|
||||
return skynet.call(clusterd, "lua", "register", name, addr)
|
||||
end
|
||||
|
||||
function cluster.unregister(name)
|
||||
assert(type(name) == "string")
|
||||
return skynet.call(clusterd, "lua", "unregister", name)
|
||||
end
|
||||
|
||||
function cluster.query(node, name)
|
||||
return skynet.call(get_sender(node), "lua", "req", 0, skynet.pack(name))
|
||||
end
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
local bson = require "bson"
|
||||
local socket = require "skynet.socket"
|
||||
|
||||
require "skynet.socket"
|
||||
|
||||
local socketchannel = require "skynet.socketchannel"
|
||||
local skynet = require "skynet"
|
||||
local driver = require "skynet.mongo.driver"
|
||||
@@ -12,6 +14,7 @@ local table = table
|
||||
local bson_encode = bson.encode
|
||||
local bson_encode_order = bson.encode_order
|
||||
local bson_decode = bson.decode
|
||||
local bson_int64 = bson.int64
|
||||
local empty_bson = bson_encode {}
|
||||
|
||||
local mongo = {}
|
||||
@@ -68,11 +71,9 @@ local collection_meta = {
|
||||
local function dispatch_reply(so)
|
||||
local len_reply = so:read(4)
|
||||
local reply = so:read(driver.length(len_reply))
|
||||
local result = { result = {} }
|
||||
local succ, reply_id, document, cursor_id, startfrom = driver.reply(reply, result.result)
|
||||
local result = {}
|
||||
local succ, reply_id, document = driver.reply(reply)
|
||||
result.document = document
|
||||
result.cursor_id = cursor_id
|
||||
result.startfrom = startfrom
|
||||
result.data = reply
|
||||
return reply_id, succ, result
|
||||
end
|
||||
@@ -298,17 +299,37 @@ function mongo_db:runCommand(cmd,cmd_v,...)
|
||||
local sock = conn.__sock
|
||||
local bson_cmd
|
||||
if not cmd_v then
|
||||
bson_cmd = bson_encode_order(cmd,1)
|
||||
-- ensure cmd remains in first place
|
||||
bson_cmd = bson_encode_order(cmd,1, "$db", self.name)
|
||||
else
|
||||
bson_cmd = bson_encode_order(cmd,cmd_v,...)
|
||||
bson_cmd = bson_encode_order(cmd,cmd_v, "$db", self.name, ...)
|
||||
end
|
||||
local pack = driver.query(request_id, 0, self.__cmd, 0, 1, bson_cmd)
|
||||
|
||||
local pack = driver.op_msg(request_id, 0, bson_cmd)
|
||||
-- we must hold req (req.data), because req.document is a lightuserdata, it's a pointer to the string (req.data)
|
||||
local req = sock:request(pack, request_id)
|
||||
local doc = req.document
|
||||
return bson_decode(doc)
|
||||
end
|
||||
|
||||
--- send command without response
|
||||
function mongo_db:send_command(cmd, cmd_v, ...)
|
||||
local conn = self.connection
|
||||
local request_id = conn:genId()
|
||||
local sock = conn.__sock
|
||||
local bson_cmd
|
||||
if not cmd_v then
|
||||
-- ensure cmd remains in first place
|
||||
bson_cmd = bson_encode_order(cmd, 1, "$db", self.name, "writeConcern", {w=0})
|
||||
else
|
||||
bson_cmd = bson_encode_order(cmd, cmd_v, "$db", self.name, "writeConcern", {w=0}, ...)
|
||||
end
|
||||
|
||||
local pack = driver.op_msg(request_id, 2, bson_cmd)
|
||||
sock:request(pack)
|
||||
return {ok=1} -- fake successful response
|
||||
end
|
||||
|
||||
function mongo_db:getCollection(collection)
|
||||
local col = {
|
||||
connection = self.connection,
|
||||
@@ -326,10 +347,7 @@ function mongo_collection:insert(doc)
|
||||
if doc._id == nil then
|
||||
doc._id = bson.objectid()
|
||||
end
|
||||
local sock = self.connection.__sock
|
||||
local pack = driver.insert(0, self.full_name, bson_encode(doc))
|
||||
-- flags support 1: ContinueOnError
|
||||
sock:request(pack)
|
||||
self.database:send_command("insert", self.name, "documents", {bson_encode(doc)})
|
||||
end
|
||||
|
||||
local function werror(r)
|
||||
@@ -353,6 +371,11 @@ function mongo_collection:safe_insert(doc)
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:raw_safe_insert(doc)
|
||||
local r = self.database:runCommand("insert", self.name, "documents", {doc})
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:batch_insert(docs)
|
||||
for i=1,#docs do
|
||||
if docs[i]._id == nil then
|
||||
@@ -360,11 +383,12 @@ function mongo_collection:batch_insert(docs)
|
||||
end
|
||||
docs[i] = bson_encode(docs[i])
|
||||
end
|
||||
local sock = self.connection.__sock
|
||||
local pack = driver.insert(0, self.full_name, docs)
|
||||
sock:request(pack)
|
||||
|
||||
self.database:send_command("insert", self.name, "documents", docs)
|
||||
end
|
||||
|
||||
mongo_collection.insert_many = mongo_collection.batch_insert
|
||||
|
||||
function mongo_collection:safe_batch_insert(docs)
|
||||
for i = 1, #docs do
|
||||
if docs[i]._id == nil then
|
||||
@@ -377,16 +401,20 @@ function mongo_collection:safe_batch_insert(docs)
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:update(selector,update,upsert,multi)
|
||||
local flags = (upsert and 1 or 0) + (multi and 2 or 0)
|
||||
local sock = self.connection.__sock
|
||||
local pack = driver.update(self.full_name, flags, bson_encode(selector), bson_encode(update))
|
||||
sock:request(pack)
|
||||
mongo_collection.safe_insert_many = mongo_collection.safe_batch_insert
|
||||
|
||||
function mongo_collection:update(query,update,upsert,multi)
|
||||
self.database:send_command("update", self.name, "updates", {bson_encode({
|
||||
q = query,
|
||||
u = update,
|
||||
upsert = upsert,
|
||||
multi = multi
|
||||
})})
|
||||
end
|
||||
|
||||
function mongo_collection:safe_update(selector, update, upsert, multi)
|
||||
function mongo_collection:safe_update(query, update, upsert, multi)
|
||||
local r = self.database:runCommand("update", self.name, "updates", {bson_encode({
|
||||
q = selector,
|
||||
q = query,
|
||||
u = update,
|
||||
upsert = upsert,
|
||||
multi = multi,
|
||||
@@ -394,44 +422,93 @@ function mongo_collection:safe_update(selector, update, upsert, multi)
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:delete(selector, single)
|
||||
local sock = self.connection.__sock
|
||||
local pack = driver.delete(self.full_name, single, bson_encode(selector))
|
||||
sock:request(pack)
|
||||
function mongo_collection:batch_update(updates)
|
||||
local updates_tb = {}
|
||||
for i = 1, #updates do
|
||||
updates_tb[i] = bson_encode({
|
||||
q = updates[i].query,
|
||||
u = updates[i].update,
|
||||
upsert = updates[i].upsert,
|
||||
multi = updates[i].multi,
|
||||
})
|
||||
end
|
||||
|
||||
self.database:send_command("update", self.name, "updates", updates_tb)
|
||||
end
|
||||
|
||||
function mongo_collection:safe_delete(selector, single)
|
||||
function mongo_collection:safe_batch_update(updates)
|
||||
local updates_tb = {}
|
||||
for i = 1, #updates do
|
||||
updates_tb[i] = bson_encode({
|
||||
q = updates[i].query,
|
||||
u = updates[i].update,
|
||||
upsert = updates[i].upsert,
|
||||
multi = updates[i].multi,
|
||||
})
|
||||
end
|
||||
|
||||
local r = self.database:runCommand("update", self.name, "updates", updates_tb)
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:raw_safe_update(update)
|
||||
local r = self.database:runCommand("update", self.name, "updates", {update})
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:delete(query, single)
|
||||
self.database:runCommand("delete", self.name, "deletes", {bson_encode({
|
||||
q = query,
|
||||
limit = single and 1 or 0,
|
||||
})})
|
||||
end
|
||||
|
||||
function mongo_collection:safe_delete(query, single)
|
||||
local r = self.database:runCommand("delete", self.name, "deletes", {bson_encode({
|
||||
q = selector,
|
||||
q = query,
|
||||
limit = single and 1 or 0,
|
||||
})})
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:findOne(query, selector)
|
||||
local conn = self.connection
|
||||
local request_id = conn:genId()
|
||||
local sock = conn.__sock
|
||||
local pack = driver.query(request_id, 0, self.full_name, 0, 1, query and bson_encode(query) or empty_bson, selector and bson_encode(selector))
|
||||
-- we must hold req (req.data), because req.document is a lightuserdata, it's a pointer to the string (req.data)
|
||||
local req = sock:request(pack, request_id)
|
||||
local doc = req.document
|
||||
return bson_decode(doc)
|
||||
function mongo_collection:safe_batch_delete(deletes, single)
|
||||
local delete_tb = {}
|
||||
for i = 1, #deletes do
|
||||
delete_tb[i] = bson_encode({
|
||||
q = deletes[i],
|
||||
limit = single and 1 or 0,
|
||||
})
|
||||
end
|
||||
local r = self.database:runCommand("delete", self.name, "deletes", delete_tb)
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:find(query, selector)
|
||||
function mongo_collection:raw_safe_delete(delete)
|
||||
local r = self.database:runCommand("delete", self.name, "deletes", {delete})
|
||||
return werror(r)
|
||||
end
|
||||
|
||||
function mongo_collection:findOne(query, projection)
|
||||
local cursor = self:find(query, projection)
|
||||
if cursor:hasNext() then
|
||||
return cursor:next()
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function mongo_collection:find(query, projection)
|
||||
return setmetatable( {
|
||||
__collection = self,
|
||||
__query = query and bson_encode(query) or empty_bson,
|
||||
__selector = selector and bson_encode(selector),
|
||||
__projection = projection and bson_encode(projection) or empty_bson,
|
||||
__ptr = nil,
|
||||
__data = nil,
|
||||
__cursor = nil,
|
||||
__document = {},
|
||||
__flags = 0,
|
||||
__skip = 0,
|
||||
__sortquery = nil,
|
||||
__limit = 0,
|
||||
__sort = empty_bson,
|
||||
} , cursor_meta)
|
||||
end
|
||||
|
||||
@@ -452,7 +529,7 @@ function mongo_cursor:sort(key, key_v, ...)
|
||||
local key_list = unfold({}, key, key_v , ...)
|
||||
key = bson_encode_order(table.unpack(key_list))
|
||||
end
|
||||
self.__sortquery = bson_encode {['$query'] = self.__query, ['$orderby'] = key}
|
||||
self.__sort = key
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -583,21 +660,37 @@ function mongo_collection:findAndModify(doc)
|
||||
return self.database:runCommand(table.unpack(cmd))
|
||||
end
|
||||
|
||||
-- https://docs.mongodb.com/manual/reference/command/aggregate/
|
||||
-- collection:aggregate({ { ["$project"] = {tags = 1} } }, {cursor={}})
|
||||
-- @param pipeline: array
|
||||
-- @param options: map
|
||||
-- @return
|
||||
function mongo_collection:aggregate(pipeline, options)
|
||||
assert(pipeline)
|
||||
local cmd = {"aggregate", self.name, "pipeline", pipeline}
|
||||
for k, v in pairs(options) do
|
||||
table.insert(cmd, k)
|
||||
table.insert(cmd, v)
|
||||
end
|
||||
return self.database:runCommand(table.unpack(cmd))
|
||||
end
|
||||
|
||||
function mongo_cursor:hasNext()
|
||||
if self.__ptr == nil then
|
||||
if self.__document == nil then
|
||||
return false
|
||||
end
|
||||
local conn = self.__collection.connection
|
||||
local request_id = conn:genId()
|
||||
local sock = conn.__sock
|
||||
local pack
|
||||
local response
|
||||
|
||||
local database = self.__collection.database
|
||||
if self.__data == nil then
|
||||
local query = self.__sortquery or self.__query
|
||||
pack = driver.query(request_id, self.__flags, self.__collection.full_name, self.__skip, self.__limit, query, self.__selector)
|
||||
local name = self.__collection.name
|
||||
response = database:runCommand("find", name, "filter", self.__query, "sort", self.__sort,
|
||||
"skip", self.__skip, "limit", self.__limit, "projection", self.__projection)
|
||||
else
|
||||
if self.__cursor then
|
||||
pack = driver.more(request_id, self.__collection.full_name, self.__limit, self.__cursor)
|
||||
if self.__cursor and self.__cursor > 0 then
|
||||
local name = self.__collection.name
|
||||
response = database:runCommand("getMore", bson_int64(self.__cursor), "collection", name)
|
||||
else
|
||||
-- no more
|
||||
self.__document = nil
|
||||
@@ -606,45 +699,35 @@ function mongo_cursor:hasNext()
|
||||
end
|
||||
end
|
||||
|
||||
local ok, result = pcall(sock.request,sock,pack, request_id)
|
||||
|
||||
local doc = result.document
|
||||
local cursor = result.cursor_id
|
||||
|
||||
if ok then
|
||||
if doc then
|
||||
local doc = result.result
|
||||
self.__document = doc
|
||||
self.__data = result.data
|
||||
self.__ptr = 1
|
||||
self.__cursor = cursor
|
||||
local limit = self.__limit
|
||||
if cursor and limit > 0 then
|
||||
limit = limit - #doc
|
||||
if limit <= 0 then
|
||||
-- reach limit
|
||||
self:close()
|
||||
end
|
||||
self.__limit = limit
|
||||
end
|
||||
return true
|
||||
else
|
||||
self.__document = nil
|
||||
self.__data = nil
|
||||
self.__cursor = nil
|
||||
return false
|
||||
end
|
||||
else
|
||||
if response.ok ~= 1 then
|
||||
self.__document = nil
|
||||
self.__data = nil
|
||||
self.__cursor = nil
|
||||
if doc then
|
||||
local err = bson_decode(doc)
|
||||
error(err["$err"])
|
||||
else
|
||||
error("Reply from mongod error")
|
||||
end
|
||||
error(response["$err"] or "Reply from mongod error")
|
||||
end
|
||||
|
||||
local cursor = response.cursor
|
||||
self.__document = cursor.firstBatch or cursor.nextBatch
|
||||
self.__data = response
|
||||
self.__ptr = 1
|
||||
self.__cursor = cursor.id
|
||||
|
||||
local limit = self.__limit
|
||||
if cursor.id > 0 and limit > 0 then
|
||||
limit = limit - #self.__document
|
||||
if limit <= 0 then
|
||||
-- reach limit
|
||||
self:close()
|
||||
end
|
||||
|
||||
self.__limit = limit
|
||||
end
|
||||
|
||||
if cursor.id == 0 and #self.__document == 0 then -- nomore
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return true
|
||||
@@ -654,7 +737,7 @@ function mongo_cursor:next()
|
||||
if self.__ptr == nil then
|
||||
error "Call hasNext first"
|
||||
end
|
||||
local r = bson_decode(self.__document[self.__ptr])
|
||||
local r = self.__document[self.__ptr]
|
||||
self.__ptr = self.__ptr + 1
|
||||
if self.__ptr > #self.__document then
|
||||
self.__ptr = nil
|
||||
@@ -664,10 +747,9 @@ function mongo_cursor:next()
|
||||
end
|
||||
|
||||
function mongo_cursor:close()
|
||||
if self.__cursor then
|
||||
local sock = self.__collection.connection.__sock
|
||||
local pack = driver.kill(self.__cursor)
|
||||
sock:request(pack)
|
||||
if self.__cursor and self.__cursor > 0 then
|
||||
local coll = self.__collection
|
||||
coll.database:send_command("killCursors", coll.name, "cursors", {bson_int64(self.__cursor)})
|
||||
self.__cursor = nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -165,25 +165,25 @@ local function _set_byte2(n)
|
||||
return strpack("<I2", n)
|
||||
end
|
||||
|
||||
local function _set_byte3(n)
|
||||
return strpack("<I3", n)
|
||||
end
|
||||
-- local function _set_byte3(n)
|
||||
-- return strpack("<I3", n)
|
||||
-- end
|
||||
|
||||
local function _set_byte4(n)
|
||||
return strpack("<I4", n)
|
||||
end
|
||||
-- local function _set_byte4(n)
|
||||
-- return strpack("<I4", n)
|
||||
-- end
|
||||
|
||||
local function _set_byte8(n)
|
||||
return strpack("<I8", n)
|
||||
end
|
||||
-- local function _set_byte8(n)
|
||||
-- return strpack("<I8", n)
|
||||
-- end
|
||||
|
||||
local function _set_int8(n)
|
||||
return strpack("<i8", n)
|
||||
end
|
||||
|
||||
local function _set_float(n)
|
||||
return strpack("<f", n)
|
||||
end
|
||||
-- local function _set_float(n)
|
||||
-- return strpack("<f", n)
|
||||
-- end
|
||||
|
||||
local function _set_double(n)
|
||||
return strpack("<d", n)
|
||||
@@ -193,12 +193,12 @@ local function _from_cstring(data, i)
|
||||
return strunpack("z", data, i)
|
||||
end
|
||||
|
||||
local function _dumphex(bytes)
|
||||
return strgsub(bytes, ".",
|
||||
function(x)
|
||||
return strformat("%02x ", strbyte(x))
|
||||
end)
|
||||
end
|
||||
-- local function _dumphex(bytes)
|
||||
-- return strgsub(bytes, ".",
|
||||
-- function(x)
|
||||
-- return strformat("%02x ", strbyte(x))
|
||||
-- end)
|
||||
-- end
|
||||
|
||||
local function _compute_token(password, scramble)
|
||||
if password == "" then
|
||||
@@ -565,7 +565,7 @@ store_types["nil"] = function(v)
|
||||
end
|
||||
|
||||
local function _compose_stmt_execute(self, stmt, cursor_type, args)
|
||||
local arg_num = #args
|
||||
local arg_num = args.n
|
||||
if arg_num ~= stmt.param_count then
|
||||
error("require stmt.param_count " .. stmt.param_count .. " get arg_num " .. arg_num)
|
||||
end
|
||||
@@ -599,7 +599,7 @@ local function _compose_stmt_execute(self, stmt, cursor_type, args)
|
||||
local v = args[i]
|
||||
f = store_types[type(v)]
|
||||
if not f then
|
||||
error("invalid parameter type", type(v))
|
||||
error("invalid parameter type " .. type(v))
|
||||
end
|
||||
ts, vs = f(v)
|
||||
types_buf = types_buf .. ts
|
||||
@@ -741,7 +741,7 @@ function _M.connect(opts)
|
||||
local user = opts.user or ""
|
||||
local password = opts.password or ""
|
||||
local charset = CHARSET_MAP[opts.charset or "_default"]
|
||||
local channel =
|
||||
local channel =
|
||||
socketchannel.channel {
|
||||
host = opts.host,
|
||||
port = opts.port or 3306,
|
||||
@@ -947,7 +947,7 @@ local function read_execute_result(self, sock)
|
||||
|
||||
-- typ == 'DATA'
|
||||
|
||||
local field_count, extra = _parse_result_set_header_packet(packet)
|
||||
-- local field_count, extra = _parse_result_set_header_packet(packet)
|
||||
|
||||
local cols = {}
|
||||
local col
|
||||
@@ -1034,7 +1034,7 @@ end
|
||||
err
|
||||
]]
|
||||
function _M.execute(self, stmt, ...)
|
||||
local querypacket, er = _compose_stmt_execute(self, stmt, CURSOR_TYPE_NO_CURSOR, {...})
|
||||
local querypacket, er = _compose_stmt_execute(self, stmt, CURSOR_TYPE_NO_CURSOR, table.pack(...))
|
||||
if not querypacket then
|
||||
return {
|
||||
badresult = true,
|
||||
|
||||
@@ -34,6 +34,16 @@ function service.new(name, mainfunc, ...)
|
||||
return address
|
||||
end
|
||||
|
||||
function service.close(name)
|
||||
local addr = skynet.call(get_provider(), "lua", "close", name)
|
||||
if addr then
|
||||
cache[name] = nil
|
||||
skynet.kill(addr)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function service.query(name)
|
||||
if not cache[name] then
|
||||
cache[name] = skynet.call(get_provider(), "lua", "query", name)
|
||||
|
||||
@@ -92,6 +92,30 @@ local function sharetable_service()
|
||||
skynet.ret(skynet.pack(ptr))
|
||||
end
|
||||
|
||||
local function querylist(source, filenamelist)
|
||||
local ptrList = {}
|
||||
for _, filename in ipairs(filenamelist) do
|
||||
if files[filename] then
|
||||
ptrList[filename] = query_file(source, filename)
|
||||
end
|
||||
end
|
||||
return ptrList
|
||||
end
|
||||
|
||||
local function queryall(source)
|
||||
local ptrList = {}
|
||||
for filename in pairs(files) do
|
||||
ptrList[filename] = query_file(source, filename)
|
||||
end
|
||||
return ptrList
|
||||
end
|
||||
|
||||
function sharetable.queryall(source, filenamelist)
|
||||
local queryFunc = filenamelist and querylist or queryall
|
||||
local ptrList = queryFunc(source, filenamelist)
|
||||
skynet.ret(skynet.pack(ptrList))
|
||||
end
|
||||
|
||||
function sharetable.close(source)
|
||||
local list = clients[source]
|
||||
if list then
|
||||
@@ -208,6 +232,21 @@ function sharetable.query(filename)
|
||||
end
|
||||
end
|
||||
|
||||
function sharetable.queryall(filenamelist)
|
||||
local list, t, map = {}
|
||||
local ptrList = skynet.call(sharetable.address, "lua", "queryall", filenamelist)
|
||||
for filename, ptr in pairs(ptrList) do
|
||||
t = core.clone(ptr)
|
||||
map = RECORD[filename]
|
||||
if not map then
|
||||
map = {}
|
||||
RECORD[filename] = map
|
||||
end
|
||||
map[t] = true
|
||||
list[filename] = t
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
local pairs = pairs
|
||||
local type = type
|
||||
|
||||
@@ -103,13 +103,17 @@ socket_message[1] = function(id, size, data)
|
||||
end
|
||||
|
||||
-- SKYNET_SOCKET_TYPE_CONNECT = 2
|
||||
socket_message[2] = function(id, _ , addr)
|
||||
socket_message[2] = function(id, ud , addr)
|
||||
local s = socket_pool[id]
|
||||
if s == nil then
|
||||
return
|
||||
end
|
||||
-- log remote addr
|
||||
if not s.connected then -- resume may also post connect message
|
||||
if s.listen then
|
||||
s.addr = addr
|
||||
s.port = ud
|
||||
end
|
||||
s.connected = true
|
||||
wakeup(s)
|
||||
end
|
||||
@@ -220,7 +224,10 @@ local function connect(id, func)
|
||||
protocol = "TCP",
|
||||
}
|
||||
assert(not socket_onclose[id], "socket has onclose callback")
|
||||
assert(not socket_pool[id], "socket is not closed")
|
||||
local s2 = socket_pool[id]
|
||||
if s2 and not s2.listen then
|
||||
error("socket is not closed")
|
||||
end
|
||||
socket_pool[id] = s
|
||||
suspend(s)
|
||||
local err = s.connecting
|
||||
@@ -404,7 +411,16 @@ function socket.listen(host, port, backlog)
|
||||
host, port = string.match(host, "([^:]+):(.+)$")
|
||||
port = tonumber(port)
|
||||
end
|
||||
return driver.listen(host, port, backlog)
|
||||
local id = driver.listen(host, port, backlog)
|
||||
local s = {
|
||||
id = id,
|
||||
connected = false,
|
||||
listen = true,
|
||||
}
|
||||
assert(socket_pool[id] == nil)
|
||||
socket_pool[id] = s
|
||||
suspend(s)
|
||||
return id, s.addr, s.port
|
||||
end
|
||||
|
||||
-- abandon use to forward socket id to other service
|
||||
|
||||
@@ -321,7 +321,10 @@ local function connect_once(self)
|
||||
|
||||
self.__sock = setmetatable( {fd} , channel_socket_meta )
|
||||
self.__dispatch_thread = skynet.fork(function()
|
||||
pcall(dispatch_function(self), self)
|
||||
if self.__sock then
|
||||
-- self.__sock can be false (socket closed) if error during connecting, See #1513
|
||||
pcall(dispatch_function(self), self)
|
||||
end
|
||||
-- clear dispatch_thread
|
||||
self.__dispatch_thread = nil
|
||||
end)
|
||||
@@ -388,13 +391,17 @@ end
|
||||
|
||||
local function check_connection(self)
|
||||
if self.__sock then
|
||||
local authco = self.__authcoroutine
|
||||
if socket.disconnected(self.__sock[1]) then
|
||||
-- closed by peer
|
||||
skynet.error("socket: disconnect detected ", self.__host, self.__port)
|
||||
close_channel_socket(self)
|
||||
if authco and authco == coroutine.running() then
|
||||
-- disconnected during auth, See #1513
|
||||
return false
|
||||
end
|
||||
return
|
||||
end
|
||||
local authco = self.__authcoroutine
|
||||
if not authco then
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -34,6 +34,8 @@ function gateserver.start(handler)
|
||||
assert(handler.message)
|
||||
assert(handler.connect)
|
||||
|
||||
local listen_context = {}
|
||||
|
||||
function CMD.open( source, conf )
|
||||
assert(not socket)
|
||||
local address = conf.address or "0.0.0.0"
|
||||
@@ -42,6 +44,12 @@ function gateserver.start(handler)
|
||||
nodelay = conf.nodelay
|
||||
skynet.error(string.format("Listen on %s:%d", address, port))
|
||||
socket = socketdriver.listen(address, port)
|
||||
listen_context.co = coroutine.running()
|
||||
listen_context.fd = socket
|
||||
skynet.wait(listen_context.co)
|
||||
conf.address = listen_context.addr
|
||||
conf.port = listen_context.port
|
||||
listen_context = nil
|
||||
socketdriver.start(socket)
|
||||
if handler.open then
|
||||
return handler.open(source, conf)
|
||||
@@ -125,6 +133,19 @@ function gateserver.start(handler)
|
||||
end
|
||||
end
|
||||
|
||||
function MSG.init(id, addr, port)
|
||||
if listen_context then
|
||||
local co = listen_context.co
|
||||
if co then
|
||||
assert(id == listen_context.fd)
|
||||
listen_context.addr = addr
|
||||
listen_context.port = port
|
||||
skynet.wakeup(co)
|
||||
listen_context.co = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
skynet.register_protocol {
|
||||
name = "socket",
|
||||
id = skynet.PTYPE_SOCKET, -- PTYPE_SOCKET = 6
|
||||
|
||||
@@ -26,7 +26,7 @@ return function (name , G, loader)
|
||||
error (string.format("%s method only support string", group))
|
||||
end
|
||||
if type(func) ~= "function" then
|
||||
error (string.format("%s.%s must be function"), group, name)
|
||||
error (string.format("%s.%s must be function", group, name))
|
||||
end
|
||||
if tmp[name] then
|
||||
error (string.format("%s.%s duplicate definition", group, name))
|
||||
|
||||
@@ -177,7 +177,7 @@ local function launch_master(conf)
|
||||
skynet.error(string.format("invalid client (fd = %d) error = %s", fd, err))
|
||||
end
|
||||
end
|
||||
socket.close_fd(fd) -- We haven't call socket.start, so use socket.close_fd rather than socket.close.
|
||||
socket.close(fd)
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
@@ -100,8 +100,10 @@ function server.logout(username)
|
||||
local u = user_online[username]
|
||||
user_online[username] = nil
|
||||
if u.fd then
|
||||
gateserver.closeclient(u.fd)
|
||||
connection[u.fd] = nil
|
||||
if connection[u.fd] then
|
||||
gateserver.closeclient(u.fd)
|
||||
connection[u.fd] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -153,11 +155,15 @@ function server.start(conf)
|
||||
handshake[fd] = nil
|
||||
local c = connection[fd]
|
||||
if c then
|
||||
c.fd = nil
|
||||
connection[fd] = nil
|
||||
if conf.disconnect_handler then
|
||||
conf.disconnect_handler(c.username)
|
||||
end
|
||||
-- double check, conf.disconnect_handler may close fd
|
||||
if connection[fd] then
|
||||
c.fd = nil
|
||||
connection[fd] = nil
|
||||
gateserver.closeclient(fd)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -107,6 +107,7 @@ local function queryproto(self, pname)
|
||||
|
||||
return v
|
||||
end
|
||||
sproto.queryproto = queryproto
|
||||
|
||||
function sproto:exist_proto(pname)
|
||||
local v = self.__pcache[pname]
|
||||
|
||||
@@ -233,6 +233,7 @@ close_harbor(struct harbor *h, int id) {
|
||||
s->status = STATUS_DOWN;
|
||||
if (s->fd) {
|
||||
skynet_socket_close(h->ctx, s->fd);
|
||||
s->fd = 0;
|
||||
}
|
||||
if (s->queue) {
|
||||
release_queue(s->queue);
|
||||
@@ -256,17 +257,20 @@ harbor_create(void) {
|
||||
return h;
|
||||
}
|
||||
|
||||
void
|
||||
harbor_release(struct harbor *h) {
|
||||
|
||||
static void
|
||||
close_all_remotes(struct harbor *h) {
|
||||
int i;
|
||||
for (i=1;i<REMOTE_MAX;i++) {
|
||||
struct slave *s = &h->s[i];
|
||||
if (s->fd && s->status != STATUS_DOWN) {
|
||||
close_harbor(h,i);
|
||||
// don't call report_harbor_down.
|
||||
// never call skynet_send during module exit, because of dead lock
|
||||
}
|
||||
close_harbor(h,i);
|
||||
// don't call report_harbor_down.
|
||||
// never call skynet_send during module exit, because of dead lock
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
harbor_release(struct harbor *h) {
|
||||
close_all_remotes(h);
|
||||
hash_delete(h->map);
|
||||
skynet_free(h);
|
||||
}
|
||||
@@ -534,7 +538,7 @@ remote_send_handle(struct harbor *h, uint32_t source, uint32_t destination, int
|
||||
if (s->status == STATUS_DOWN) {
|
||||
// throw an error return to source
|
||||
// report the destination is dead
|
||||
skynet_send(context, destination, source, PTYPE_ERROR, 0 , NULL, 0);
|
||||
skynet_send(context, destination, source, PTYPE_ERROR, session, NULL, 0);
|
||||
skynet_error(context, "Drop message to harbor %d from %x to %x (session = %d, msgsz = %d)",harbor_id, source, destination,session,(int)sz);
|
||||
} else {
|
||||
if (s->queue == NULL) {
|
||||
@@ -735,6 +739,9 @@ harbor_init(struct harbor *h, struct skynet_context *ctx, const char * args) {
|
||||
}
|
||||
h->id = harbor_id;
|
||||
h->slave = slave;
|
||||
if (harbor_id == 0) {
|
||||
close_all_remotes(h);
|
||||
}
|
||||
skynet_callback(ctx, h, mainloop);
|
||||
skynet_harbor_start(ctx);
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ static int luaB_auxwrap (lua_State *L) {
|
||||
if (r < 0) {
|
||||
int stat = lua_status(co);
|
||||
if (stat != LUA_OK && stat != LUA_YIELD)
|
||||
lua_resetthread(co); /* close variables in case of errors */
|
||||
lua_resetthread(co, L); /* close variables in case of errors */
|
||||
if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
|
||||
luaL_where(L, 1); /* add extra info, if available */
|
||||
lua_insert(L, -2);
|
||||
@@ -521,14 +521,12 @@ snlua_signal(struct snlua *l, int signal) {
|
||||
skynet_error(l->ctx, "recv a signal %d", signal);
|
||||
if (signal == 0) {
|
||||
if (ATOM_LOAD(&l->trap) == 0) {
|
||||
int zero = 0;
|
||||
// only one thread can set trap ( l->trap 0->1 )
|
||||
if (!ATOM_CAS(&l->trap, zero, 1))
|
||||
if (!ATOM_CAS(&l->trap, 0, 1))
|
||||
return;
|
||||
lua_sethook (l->activeL, signal_hook, LUA_MASKCOUNT, 1);
|
||||
// finish set ( l->trap 1 -> -1 )
|
||||
int one = 1;
|
||||
ATOM_CAS(&l->trap, one, -1);
|
||||
ATOM_CAS(&l->trap, 1, -1);
|
||||
}
|
||||
} else if (signal == 1) {
|
||||
skynet_error(l->ctx, "Current Memory %.3fK", (float)l->mem / 1024);
|
||||
|
||||
@@ -5,6 +5,7 @@ local cluster = require "skynet.cluster.core"
|
||||
local config_name = skynet.getenv "cluster"
|
||||
local node_address = {}
|
||||
local node_sender = {}
|
||||
local node_sender_closed = {}
|
||||
local command = {}
|
||||
local config = {}
|
||||
local nodename = cluster.nodename()
|
||||
@@ -56,17 +57,21 @@ local function open_channel(t, key)
|
||||
if succ then
|
||||
t[key] = c
|
||||
ct.channel = c
|
||||
node_sender_closed[key] = nil
|
||||
else
|
||||
err = string.format("changenode [%s] (%s:%s) failed", key, host, port)
|
||||
end
|
||||
elseif address == false then
|
||||
c = node_sender[key]
|
||||
if c == nil then
|
||||
-- no sender, always succ
|
||||
if c == nil or node_sender_closed[key] then
|
||||
-- no sender or closed, always succ
|
||||
succ = true
|
||||
else
|
||||
-- trun off the sender
|
||||
succ, err = pcall(skynet.call, c, "lua", "changenode", false)
|
||||
if succ then --trun off failed, wait next index todo turn off
|
||||
node_sender_closed[key] = true
|
||||
end
|
||||
end
|
||||
else
|
||||
err = string.format("cluster node [%s] is absent.", key)
|
||||
@@ -141,10 +146,15 @@ function command.listen(source, addr, port)
|
||||
local gate = skynet.newservice("gate")
|
||||
if port == nil then
|
||||
local address = assert(node_address[addr], addr .. " is down")
|
||||
addr, port = string.match(address, "([^:]+):(.*)$")
|
||||
addr, port = string.match(address, "(.+):([^:]+)$")
|
||||
port = tonumber(port)
|
||||
assert(port ~= 0)
|
||||
skynet.call(gate, "lua", "open", { address = addr, port = port })
|
||||
skynet.ret(skynet.pack(addr, port))
|
||||
else
|
||||
local realaddr, realport = skynet.call(gate, "lua", "open", { address = addr, port = port })
|
||||
skynet.ret(skynet.pack(realaddr, realport))
|
||||
end
|
||||
skynet.call(gate, "lua", "open", { address = addr, port = port })
|
||||
skynet.ret(skynet.pack(nil))
|
||||
end
|
||||
|
||||
function command.sender(source, node)
|
||||
@@ -204,6 +214,18 @@ function command.register(source, name, addr)
|
||||
skynet.error(string.format("Register [%s] :%08x", name, addr))
|
||||
end
|
||||
|
||||
function command.unregister(_, name)
|
||||
if not register_name[name] then
|
||||
return skynet.ret(nil)
|
||||
end
|
||||
local addr = register_name[name]
|
||||
register_name[addr] = nil
|
||||
register_name[name] = nil
|
||||
clearnamecache()
|
||||
skynet.ret(nil)
|
||||
skynet.error(string.format("Unregister [%s] :%08x", name, addr))
|
||||
end
|
||||
|
||||
function command.queryname(source, name)
|
||||
skynet.ret(skynet.pack(register_name[name]))
|
||||
end
|
||||
|
||||
@@ -263,11 +263,8 @@ skynet.start(function()
|
||||
end
|
||||
end)
|
||||
skynet.wait()
|
||||
socket.close(slave_fd)
|
||||
else
|
||||
-- slave_fd does not start, so use close_fd.
|
||||
socket.close_fd(slave_fd)
|
||||
end
|
||||
socket.close(slave_fd)
|
||||
skynet.error("Shakehand ready")
|
||||
skynet.fork(ready)
|
||||
end)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user