summaryrefslogtreecommitdiff
path: root/src/luac
diff options
context:
space:
mode:
authorLua Team <team@lua.org>1999-07-08 12:00:00 +0000
committerrepogen <>1999-07-08 12:00:00 +0000
commitafb67002d94ef22c14741910ba83da262a6e9338 (patch)
treeb51ab3502813f590a4b115997f6fe41da43b6586 /src/luac
parent377347776f1f3d820f92151f70bec667f96d5e6b (diff)
downloadlua-github-3.2.tar.gz
Lua 3.23.2
Diffstat (limited to 'src/luac')
-rw-r--r--src/luac/Makefile6
-rw-r--r--src/luac/README31
-rw-r--r--src/luac/dump.c126
-rw-r--r--src/luac/luac.c99
-rw-r--r--src/luac/luac.h43
-rw-r--r--src/luac/opcode.c85
-rw-r--r--src/luac/opcode.h196
-rw-r--r--src/luac/opt.c241
-rw-r--r--src/luac/print.c182
-rw-r--r--src/luac/stubs.c91
-rw-r--r--src/luac/test.c253
11 files changed, 835 insertions, 518 deletions
diff --git a/src/luac/Makefile b/src/luac/Makefile
index 195b5cc4..e2950e60 100644
--- a/src/luac/Makefile
+++ b/src/luac/Makefile
@@ -5,8 +5,8 @@ LUA= ../..
include $(LUA)/config
INCS= -I$(INC) $(EXTRA_INCS) -I..
-OBJS= dump.o luac.o opcode.o opt.o print.o stubs.o
-SRCS= dump.c luac.c opcode.c opt.c print.c stubs.c luac.h opcode.h
+OBJS= dump.o luac.o opcode.o opt.o print.o stubs.o test.o
+SRCS= dump.c luac.c opcode.c opt.c print.c stubs.c test.c luac.h opcode.h
T= $(BIN)/luac
@@ -16,7 +16,7 @@ $T: $(OBJS) $(LIB)/liblua.a
$(CC) -o $@ $(OBJS) -L$(LIB) -llua
$(LIB)/liblua.a:
- cd ..; make
+ cd ..; $(MAKE)
clean:
rm -f $(OBJS) $T
diff --git a/src/luac/README b/src/luac/README
index 1fd49cc2..9fba74bb 100644
--- a/src/luac/README
+++ b/src/luac/README
@@ -2,24 +2,27 @@ luac translates Lua programs into binary files that can be loaded and executed
with lua_dofile in C or with dofile in Lua.
The main advantages of pre-compiling chunks are: faster loading,
protecting source code from user changes, off-line syntax error detection.
-
luac can also be used to learn about the Lua virtual machine.
-Here are the options it understands:
+Here are the options that luac understands:
- -c compile (default)
- -u undump
- -d generate debugging information
- -D predefine symbol for conditional compilation
- -l list (default for -u)
- -o output file for -c (default is "luac.out")
- -O optimize
- -p parse only
- -q quiet (default for -c)
- -v show version information
- -V verbose
- - compile "stdin"
+ -c compile (default)
+ -d generate debugging information
+ -D name predefine 'name' for conditional compilation
+ -l list (default for -u)
+ -n save numbers in native format (file may not be portable)
+ -o file output file for -c (default is "luac.out")
+ -O optimize
+ -p parse only
+ -q quiet (default for -c)
+ -t test code integrity
+ -u undump
+ -U name undefine 'name' for conditional compilation
+ -v show version information
+ -V verbose
+ - compile "stdin"
Finally, luac is an example of how to use the internals of Lua (politely).
Also, luac does not need the runtime code and stubs.c makes sure it is not
linked into luac. This file also shows how to avoid linking the parser.
+
diff --git a/src/luac/dump.c b/src/luac/dump.c
index ce9551e6..479ce5d4 100644
--- a/src/luac/dump.c
+++ b/src/luac/dump.c
@@ -1,16 +1,20 @@
/*
-** $Id: dump.c,v 1.11 1998/07/12 00:17:37 lhf Exp $
+** $Id: dump.c,v 1.20 1999/07/02 19:34:26 lhf Exp $
** save bytecodes to file
** See Copyright Notice in lua.h
*/
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "luac.h"
-#define NotWord(x) ((unsigned short)x!=x)
+#ifdef OLD_ANSI
+#define strerror(e) "(no error message provided by operating system)"
+#endif
+
#define DumpBlock(b,size,D) fwrite(b,size,1,D)
-#define DumpNative(t,D) DumpBlock(&t,sizeof(t),D)
+#define DumpInt DumpLong
static void DumpWord(int i, FILE* D)
{
@@ -28,43 +32,24 @@ static void DumpLong(long i, FILE* D)
DumpWord(lo,D);
}
-#if ID_NUMBER==ID_REAL4
-/* LUA_NUMBER */
-/* assumes sizeof(long)==4 and sizeof(float)==4 (IEEE) */
-static void DumpFloat(float f, FILE* D)
+static void DumpNumber(real x, FILE* D, int native, TProtoFunc* tf)
{
- long l=*(long*)&f;
- DumpLong(l,D);
-}
-#endif
-
-#if ID_NUMBER==ID_REAL8
-/* LUA_NUMBER */
-/* assumes sizeof(long)==4 and sizeof(double)==8 (IEEE) */
-static void DumpDouble(double f, FILE* D)
-{
- long* l=(long*)&f;
- int x=1;
- if (*(char*)&x==1) /* little-endian */
- {
- DumpLong(l[1],D);
- DumpLong(l[0],D);
- }
- else /* big-endian */
+ if (native)
+ DumpBlock(&x,sizeof(x),D);
+ else
{
- DumpLong(l[0],D);
- DumpLong(l[1],D);
+ char b[256];
+ int n;
+ sprintf(b,NUMBER_FMT"%n",x,&n);
+ luaU_str2d(b,tf->source->str); /* help lundump not to fail */
+ fputc(n,D);
+ DumpBlock(b,n,D);
}
}
-#endif
static void DumpCode(TProtoFunc* tf, FILE* D)
{
- int size=CodeSize(tf);
- if (NotWord(size))
- fprintf(stderr,"luac: warning: "
- "\"%s\":%d code too long for 16-bit machines (%d bytes)\n",
- fileName(tf),tf->lineDefined,size);
+ int size=luaU_codesize(tf);
DumpLong(size,D);
DumpBlock(tf->code,size,D);
}
@@ -72,87 +57,98 @@ static void DumpCode(TProtoFunc* tf, FILE* D)
static void DumpString(char* s, int size, FILE* D)
{
if (s==NULL)
- DumpWord(0,D);
+ DumpLong(0,D);
else
{
- if (NotWord(size))
- luaL_verror("string too long (%d bytes): \"%.32s...\"",size,s);
- DumpWord(size,D);
+ DumpLong(size,D);
DumpBlock(s,size,D);
}
}
static void DumpTString(TaggedString* s, FILE* D)
{
- if (s==NULL) DumpString(NULL,0,D); else DumpString(s->str,s->u.s.len+1,D);
+ if (s==NULL)
+ DumpString(NULL,0,D);
+ else
+ DumpString(s->str,s->u.s.len+1,D);
}
static void DumpLocals(TProtoFunc* tf, FILE* D)
{
- int n;
- LocVar* lv;
- for (n=0,lv=tf->locvars; lv && lv->line>=0; lv++) ++n;
- DumpWord(n,D);
- for (lv=tf->locvars; lv && lv->line>=0; lv++)
+ if (tf->locvars==NULL)
+ DumpInt(0,D);
+ else
{
- DumpWord(lv->line,D);
- DumpTString(lv->varname,D);
+ LocVar* v;
+ int n=0;
+ for (v=tf->locvars; v->line>=0; v++)
+ ++n;
+ DumpInt(n,D);
+ for (v=tf->locvars; v->line>=0; v++)
+ {
+ DumpInt(v->line,D);
+ DumpTString(v->varname,D);
+ }
}
}
-static void DumpFunction(TProtoFunc* tf, FILE* D);
+static void DumpFunction(TProtoFunc* tf, FILE* D, int native);
-static void DumpConstants(TProtoFunc* tf, FILE* D)
+static void DumpConstants(TProtoFunc* tf, FILE* D, int native)
{
int i,n=tf->nconsts;
- DumpWord(n,D);
+ DumpInt(n,D);
for (i=0; i<n; i++)
{
TObject* o=tf->consts+i;
- fputc(-ttype(o),D);
+ fputc(-ttype(o),D); /* ttype(o) is negative - ORDER LUA_T */
switch (ttype(o))
{
case LUA_T_NUMBER:
- DumpNumber(nvalue(o),D);
+ DumpNumber(nvalue(o),D,native,tf);
break;
case LUA_T_STRING:
DumpTString(tsvalue(o),D);
break;
case LUA_T_PROTO:
- DumpFunction(tfvalue(o),D);
+ DumpFunction(tfvalue(o),D,native);
break;
case LUA_T_NIL:
break;
default: /* cannot happen */
- luaL_verror("cannot dump constant #%d: type=%d [%s]",
- i,ttype(o),luaO_typename(o));
+ luaU_badconstant("dump",i,o,tf);
break;
}
}
}
-static void DumpFunction(TProtoFunc* tf, FILE* D)
+static void DumpFunction(TProtoFunc* tf, FILE* D, int native)
{
- DumpWord(tf->lineDefined,D);
- DumpTString(tf->fileName,D);
+ DumpInt(tf->lineDefined,D);
+ DumpTString(tf->source,D);
DumpCode(tf,D);
DumpLocals(tf,D);
- DumpConstants(tf,D);
+ DumpConstants(tf,D,native);
+ if (ferror(D))
+ luaL_verror("write error" IN ": %s (errno=%d)",INLOC,strerror(errno),errno);
}
-static void DumpHeader(TProtoFunc* Main, FILE* D)
+static void DumpHeader(TProtoFunc* Main, FILE* D, int native)
{
- real t=TEST_NUMBER;
fputc(ID_CHUNK,D);
fputs(SIGNATURE,D);
fputc(VERSION,D);
- fputc(ID_NUMBER,D);
- fputc(sizeof(t),D);
- DumpNumber(t,D);
+ if (native)
+ {
+ fputc(sizeof(real),D);
+ DumpNumber(TEST_NUMBER,D,native,Main);
+ }
+ else
+ fputc(0,D);
}
-void DumpChunk(TProtoFunc* Main, FILE* D)
+void luaU_dumpchunk(TProtoFunc* Main, FILE* D, int native)
{
- DumpHeader(Main,D);
- DumpFunction(Main,D);
+ DumpHeader(Main,D,native);
+ DumpFunction(Main,D,native);
}
diff --git a/src/luac/luac.c b/src/luac/luac.c
index c4619153..68af1c76 100644
--- a/src/luac/luac.c
+++ b/src/luac/luac.c
@@ -1,5 +1,5 @@
/*
-** $Id: luac.c,v 1.10 1998/07/12 00:38:30 lhf Exp $
+** $Id: luac.c,v 1.17 1999/07/02 19:34:26 lhf Exp $
** lua compiler (saves bytecodes to files; also list binary files)
** See Copyright Notice in lua.h
*/
@@ -9,43 +9,45 @@
#include <string.h>
#include "luac.h"
#include "lparser.h"
+#include "lstate.h"
#include "lzio.h"
-#include "luadebug.h"
#define OUTPUT "luac.out" /* default output file */
-extern void DumpChunk(TProtoFunc* Main, FILE* D);
-extern void PrintChunk(TProtoFunc* Main);
-extern void OptChunk(TProtoFunc* Main);
-
static FILE* efopen(char* name, char* mode);
static void doit(int undump, char* filename);
static int listing=0; /* list bytecodes? */
-static int debugging=0; /* debug? */
+static int debugging=0; /* emit debug information? */
static int dumping=1; /* dump bytecodes? */
static int undumping=0; /* undump bytecodes? */
static int optimizing=0; /* optimize? */
static int parsing=0; /* parse only? */
+static int testing=0; /* test integrity? */
static int verbose=0; /* tell user what is done */
+static int native=0; /* save numbers in native format? */
static FILE* D; /* output file */
-static void usage(void)
+static void usage(char* op)
{
- fprintf(stderr,"usage: "
- "luac [-c | -u] [-D name] [-d] [-l] [-o output] [-O] [-p] [-q] [-v] [-V] [files]\n"
- " -c\tcompile (default)\n"
- " -u\tundump\n"
- " -d\tgenerate debugging information\n"
- " -D\tpredefine symbol for conditional compilation\n"
- " -l\tlist (default for -u)\n"
- " -o\toutput file for -c (default is \"" OUTPUT "\")\n"
- " -O\toptimize\n"
- " -p\tparse only\n"
- " -q\tquiet (default for -c)\n"
- " -v\tshow version information\n"
- " -V\tverbose\n"
- " -\tcompile \"stdin\"\n"
+ if (op) fprintf(stderr,"luac: unrecognized option '%s'\n",op);
+ fprintf(stderr,
+ "usage: luac [options] [filenames]. Available options are:\n"
+ " -c\t\tcompile (default)\n"
+ " -d\t\tgenerate debugging information\n"
+ " -D name\tpredefine 'name' for conditional compilation\n"
+ " -l\t\tlist (default for -u)\n"
+ " -n\t\tsave numbers in native format (file may not be portable)\n"
+ " -o file\toutput file for -c (default is \"" OUTPUT "\")\n"
+ " -O\t\toptimize\n"
+ " -p\t\tparse only\n"
+ " -q\t\tquiet (default for -c)\n"
+ " -t\t\ttest code integrity\n"
+ " -u\t\tundump\n"
+ " -U name\tundefine 'name' for conditional compilation\n"
+ " -v\t\tshow version information\n"
+ " -V\t\tverbose\n"
+ " -\t\tcompile \"stdin\"\n"
);
exit(1);
}
@@ -61,7 +63,7 @@ int main(int argc, char* argv[])
{
if (argv[i][0]!='-') /* end of options */
break;
- else if (IS("-")) /* use stdin */
+ else if (IS("-")) /* end of options; use stdin */
break;
else if (IS("-c")) /* compile (and dump) */
{
@@ -78,6 +80,8 @@ int main(int argc, char* argv[])
debugging=1;
else if (IS("-l")) /* list */
listing=1;
+ else if (IS("-n")) /* native */
+ native=1;
else if (IS("-o")) /* output file */
d=argv[++i];
else if (IS("-O")) /* optimize */
@@ -89,34 +93,37 @@ int main(int argc, char* argv[])
}
else if (IS("-q")) /* quiet */
listing=0;
+ else if (IS("-t")) /* test */
+ testing=1;
else if (IS("-u")) /* undump */
{
dumping=0;
undumping=1;
listing=1;
}
+ else if (IS("-U")) /* undefine */
+ {
+ TaggedString* s=luaS_new(argv[++i]);
+ s->u.s.globalval.ttype=LUA_T_NIL;
+ }
else if (IS("-v")) /* show version */
printf("%s %s\n(written by %s)\n\n",LUA_VERSION,LUA_COPYRIGHT,LUA_AUTHORS);
else if (IS("-V")) /* verbose */
verbose=1;
else /* unknown option */
- usage();
+ usage(argv[i]);
}
--i; /* fake new argv[0] */
argc-=i;
argv+=i;
if (dumping || parsing)
{
- if (argc<2) usage();
+ if (argc<2) usage(NULL);
if (dumping)
{
for (i=1; i<argc; i++) /* play safe with output file */
if (IS(d)) luaL_verror("will not overwrite input file \"%s\"",d);
D=efopen(d,"wb"); /* must open in binary mode */
-#if ID_NUMBER==ID_NATIVE
- if (verbose) fprintf(stderr,"luac: warning: "
- "saving numbers in native format. file may not be portable.\n");
-#endif
}
for (i=1; i<argc; i++) doit(0,IS("-")? NULL : argv[i]);
if (dumping) fclose(D);
@@ -134,39 +141,35 @@ int main(int argc, char* argv[])
static void do_compile(ZIO* z)
{
TProtoFunc* Main;
- if (optimizing) lua_debug=0; /* set debugging before parsing */
- if (debugging) lua_debug=1;
+ if (optimizing) L->debug=0;
+ if (debugging) L->debug=1;
Main=luaY_parser(z);
- if (optimizing) OptChunk(Main);
- if (listing) PrintChunk(Main);
- if (dumping) DumpChunk(Main,D);
+ if (optimizing) luaU_optchunk(Main);
+ if (listing) luaU_printchunk(Main);
+ if (testing) luaU_testchunk(Main);
+ if (dumping) luaU_dumpchunk(Main,D,native);
}
static void do_undump(ZIO* z)
{
- while (1)
+ for (;;)
{
TProtoFunc* Main=luaU_undump1(z);
if (Main==NULL) break;
- if (optimizing) OptChunk(Main);
- if (listing) PrintChunk(Main);
+ if (optimizing) luaU_optchunk(Main);
+ if (listing) luaU_printchunk(Main);
+ if (testing) luaU_testchunk(Main);
}
}
static void doit(int undump, char* filename)
{
- FILE* f;
+ FILE* f= (filename==NULL) ? stdin : efopen(filename, undump ? "rb" : "r");
ZIO z;
- if (filename==NULL)
- {
- f=stdin; filename="(stdin)";
- }
- else
- {
- f=efopen(filename, undump ? "rb" : "r");
- }
- zFopen(&z,f,filename);
- if (verbose) fprintf(stderr,"%s\n",filename);
+ char source[255+2]; /* +2 for '@' and '\0' */
+ luaL_filesource(source,filename,sizeof(source));
+ zFopen(&z,f,source);
+ if (verbose) fprintf(stderr,"%s\n",source+1);
if (undump) do_undump(&z); else do_compile(&z);
if (f!=stdin) fclose(f);
}
diff --git a/src/luac/luac.h b/src/luac/luac.h
index c3d8d73a..1ae5267b 100644
--- a/src/luac/luac.h
+++ b/src/luac/luac.h
@@ -1,11 +1,12 @@
/*
-** $Id: luac.h,v 1.6 1998/07/12 00:17:37 lhf Exp $
+** $Id: luac.h,v 1.11 1999/07/02 19:34:26 lhf Exp $
** definitions for luac
** See Copyright Notice in lua.h
*/
#include "lauxlib.h"
#include "lfunc.h"
+#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lstring.h"
@@ -13,21 +14,35 @@
typedef struct
{
- char* name;
- int size;
- int op;
- int class;
- int arg;
- int arg2;
+ char* name; /* name of opcode */
+ int op; /* value of opcode */
+ int class; /* class of opcode (byte variant) */
+ int args; /* types of arguments (operands) */
+ int arg; /* arg #1 */
+ int arg2; /* arg #2 */
} Opcode;
-int OpcodeInfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE);
-int CodeSize(TProtoFunc* tf);
+/* from dump.c */
+void luaU_dumpchunk(TProtoFunc* Main, FILE* D, int native);
-#define INFO(tf,p,I) OpcodeInfo(tf,p,I,__FILE__,__LINE__)
-#define fileName(tf) ( (tf->fileName)==NULL ? NULL : tf->fileName->str )
+/* from opcode.c */
+int luaU_opcodeinfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE);
+int luaU_codesize(TProtoFunc* tf);
+/* from opt.c */
+void luaU_optchunk(TProtoFunc* Main);
+
+/* from print.c */
+void luaU_printchunk(TProtoFunc* Main);
+
+/* from test.c */
+void luaU_testchunk(TProtoFunc* Main);
+TObject* luaU_getconstant(TProtoFunc* tf, int i, int at);
+
+#define INFO(tf,p,I) luaU_opcodeinfo(tf,p,I,__FILE__,__LINE__)
+
+/* fake (but convenient) opcodes */
#define NOP 255
-#define STACK -1
-#define ARGS -2
-#define VARARGS -3
+#define STACK (-1)
+#define ARGS (-2)
+#define VARARGS (-3)
diff --git a/src/luac/opcode.c b/src/luac/opcode.c
index c97e46a5..c2d4ae7d 100644
--- a/src/luac/opcode.c
+++ b/src/luac/opcode.c
@@ -1,83 +1,98 @@
/*
-** $Id: opcode.c,v 1.4 1998/07/12 00:17:37 lhf Exp $
+** $Id: opcode.c,v 1.9 1999/05/25 19:58:55 lhf Exp $
** opcode information
** See Copyright Notice in lua.h
*/
#include "luac.h"
+enum { /* for Opcode.args */
+ ARGS_NONE,
+ ARGS_B,
+ ARGS_W,
+ ARGS_BB,
+ ARGS_WB
+};
+
static Opcode Info[]= /* ORDER lopcodes.h */
{
#include "opcode.h"
};
+static Opcode Fake[]= /* ORDER luac.h */
+{
+{ "NOP", NOP, NOP, ARGS_NONE, -1, -1 },
+{ "STACK", STACK, STACK, ARGS_B, -1, -1 },
+{ "ARGS", ARGS, ARGS, ARGS_B, -1, -1 },
+{ "VARARGS", VARARGS, VARARGS, ARGS_B, -1, -1 },
+};
+
#define NOPCODES (sizeof(Info)/sizeof(Info[0]))
-int OpcodeInfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE)
+int luaU_opcodeinfo(TProtoFunc* tf, Byte* p, Opcode* I, char* xFILE, int xLINE)
{
Opcode OP;
Byte* code=tf->code;
int op=*p;
- if (p==code)
+ int size=1;
+ if (p==code) /* first byte is STACK */
{
- OP.name="STACK";
- OP.size=1;
- OP.op=STACK;
- OP.class=STACK;
+ OP=Fake[-STACK];
OP.arg=op;
}
- else if (p==code+1)
+ else if (p==code+1) /* second byte is ARGS or VARARGS */
{
- OP.size=1;
- if (op>=ZEROVARARG)
+ if (op<ZEROVARARG)
{
- OP.name="VARARGS";
- OP.op=VARARGS;
- OP.class=VARARGS;
- OP.arg=op-ZEROVARARG;
+ OP=Fake[-ARGS];
+ OP.arg=op;
}
else
{
- OP.name="ARGS";
- OP.op=ARGS;
- OP.class=ARGS;
- OP.arg=op;
+ OP=Fake[-VARARGS];
+ OP.arg=op-ZEROVARARG;
}
}
- else if (op==NOP)
+ else if (op==NOP) /* NOP is fake */
{
- OP.name="NOP";
- OP.size=1;
- OP.op=NOP;
- OP.class=NOP;
+ OP=Fake[0];
}
else if (op>=NOPCODES) /* cannot happen */
{
- luaL_verror("internal error at %s:%d: bad opcode %d at %d in tf=%p",
- xFILE, xLINE,op,(int)(p-code),tf);
+ luaL_verror("[%s:%d] bad opcode %d at pc=%d" IN,
+ xFILE,xLINE,op,(int)(p-code),INLOC);
return 0;
}
- else
+ else /* ordinary opcode */
{
OP=Info[op];
- if (op==SETLIST || op==CLOSURE || op==CALLFUNC)
+ switch (OP.args)
{
- OP.arg=p[1];
- OP.arg2=p[2];
+ case ARGS_NONE: size=1;
+ break;
+ case ARGS_B: size=2; OP.arg=p[1];
+ break;
+ case ARGS_W: size=3; OP.arg=(p[1]<<8)+p[2];
+ break;
+ case ARGS_BB: size=3; OP.arg=p[1]; OP.arg2=p[2];
+ break;
+ case ARGS_WB: size=4; OP.arg=(p[1]<<8)+p[2]; OP.arg2=p[3];
+ break;
+ default: /* cannot happen */
+ luaL_verror("[%s:%d] bad args %d for %s at pc=%d" IN,
+ __FILE__,__LINE__,OP.args,OP.name,(int)(p-code),INLOC);
+ break;
}
- else if (OP.size==2) OP.arg=p[1];
- else if (OP.size>=3) OP.arg=(p[1]<<8)+p[2];
- if (op==SETLISTW || op==CLOSUREW) OP.arg2=p[3];
}
*I=OP;
- return OP.size;
+ return size;
}
-int CodeSize(TProtoFunc* tf)
+int luaU_codesize(TProtoFunc* tf)
{
Byte* code=tf->code;
Byte* p=code;
- while (1)
+ for (;;)
{
Opcode OP;
p+=INFO(tf,p,&OP);
diff --git a/src/luac/opcode.h b/src/luac/opcode.h
index 805933c7..4ae910f5 100644
--- a/src/luac/opcode.h
+++ b/src/luac/opcode.h
@@ -1,134 +1,70 @@
/*
-** $Id: opcode.h,v 1.3 1998/06/25 15:50:09 lhf Exp $
+** $Id: opcode.h,v 1.1 1999/03/25 13:43:05 lhf Exp $
** opcode info to be #included into opcode.c
-** extracted automatically from lopcodes.h by mkopcodeh
+** extracted automatically from lopcodes.h by mkopcodeh -- DO NOT EDIT
** See Copyright Notice in lua.h
*/
-{ "ENDCODE", 1, ENDCODE, ENDCODE, ENDCODE-ENDCODE-1, 0 },
-{ "PUSHNIL", 2, PUSHNIL, PUSHNIL, PUSHNIL-PUSHNIL-1, 0 },
-{ "PUSHNIL0", 1, PUSHNIL0, PUSHNIL, PUSHNIL0-PUSHNIL-1, 0 },
-{ "PUSHNUMBER", 2, PUSHNUMBER, PUSHNUMBER, PUSHNUMBER-PUSHNUMBER-1, 0 },
-{ "PUSHNUMBER0", 1, PUSHNUMBER0, PUSHNUMBER, PUSHNUMBER0-PUSHNUMBER-1, 0 },
-{ "PUSHNUMBER1", 1, PUSHNUMBER1, PUSHNUMBER, PUSHNUMBER1-PUSHNUMBER-1, 0 },
-{ "PUSHNUMBER2", 1, PUSHNUMBER2, PUSHNUMBER, PUSHNUMBER2-PUSHNUMBER-1, 0 },
-{ "PUSHNUMBERW", 3, PUSHNUMBERW, PUSHNUMBER, PUSHNUMBERW-PUSHNUMBER-1, 0 },
-{ "PUSHCONSTANT", 2, PUSHCONSTANT, PUSHCONSTANT, PUSHCONSTANT-PUSHCONSTANT-1, 0 },
-{ "PUSHCONSTANT0", 1, PUSHCONSTANT0, PUSHCONSTANT, PUSHCONSTANT0-PUSHCONSTANT-1, 0 },
-{ "PUSHCONSTANT1", 1, PUSHCONSTANT1, PUSHCONSTANT, PUSHCONSTANT1-PUSHCONSTANT-1, 0 },
-{ "PUSHCONSTANT2", 1, PUSHCONSTANT2, PUSHCONSTANT, PUSHCONSTANT2-PUSHCONSTANT-1, 0 },
-{ "PUSHCONSTANT3", 1, PUSHCONSTANT3, PUSHCONSTANT, PUSHCONSTANT3-PUSHCONSTANT-1, 0 },
-{ "PUSHCONSTANT4", 1, PUSHCONSTANT4, PUSHCONSTANT, PUSHCONSTANT4-PUSHCONSTANT-1, 0 },
-{ "PUSHCONSTANT5", 1, PUSHCONSTANT5, PUSHCONSTANT, PUSHCONSTANT5-PUSHCONSTANT-1, 0 },
-{ "PUSHCONSTANT6", 1, PUSHCONSTANT6, PUSHCONSTANT, PUSHCONSTANT6-PUSHCONSTANT-1, 0 },
-{ "PUSHCONSTANT7", 1, PUSHCONSTANT7, PUSHCONSTANT, PUSHCONSTANT7-PUSHCONSTANT-1, 0 },
-{ "PUSHCONSTANTW", 3, PUSHCONSTANTW, PUSHCONSTANT, PUSHCONSTANTW-PUSHCONSTANT-1, 0 },
-{ "PUSHUPVALUE", 2, PUSHUPVALUE, PUSHUPVALUE, PUSHUPVALUE-PUSHUPVALUE-1, 0 },
-{ "PUSHUPVALUE0", 1, PUSHUPVALUE0, PUSHUPVALUE, PUSHUPVALUE0-PUSHUPVALUE-1, 0 },
-{ "PUSHUPVALUE1", 1, PUSHUPVALUE1, PUSHUPVALUE, PUSHUPVALUE1-PUSHUPVALUE-1, 0 },
-{ "PUSHLOCAL", 2, PUSHLOCAL, PUSHLOCAL, PUSHLOCAL-PUSHLOCAL-1, 0 },
-{ "PUSHLOCAL0", 1, PUSHLOCAL0, PUSHLOCAL, PUSHLOCAL0-PUSHLOCAL-1, 0 },
-{ "PUSHLOCAL1", 1, PUSHLOCAL1, PUSHLOCAL, PUSHLOCAL1-PUSHLOCAL-1, 0 },
-{ "PUSHLOCAL2", 1, PUSHLOCAL2, PUSHLOCAL, PUSHLOCAL2-PUSHLOCAL-1, 0 },
-{ "PUSHLOCAL3", 1, PUSHLOCAL3, PUSHLOCAL, PUSHLOCAL3-PUSHLOCAL-1, 0 },
-{ "PUSHLOCAL4", 1, PUSHLOCAL4, PUSHLOCAL, PUSHLOCAL4-PUSHLOCAL-1, 0 },
-{ "PUSHLOCAL5", 1, PUSHLOCAL5, PUSHLOCAL, PUSHLOCAL5-PUSHLOCAL-1, 0 },
-{ "PUSHLOCAL6", 1, PUSHLOCAL6, PUSHLOCAL, PUSHLOCAL6-PUSHLOCAL-1, 0 },
-{ "PUSHLOCAL7", 1, PUSHLOCAL7, PUSHLOCAL, PUSHLOCAL7-PUSHLOCAL-1, 0 },
-{ "GETGLOBAL", 2, GETGLOBAL, GETGLOBAL, GETGLOBAL-GETGLOBAL-1, 0 },
-{ "GETGLOBAL0", 1, GETGLOBAL0, GETGLOBAL, GETGLOBAL0-GETGLOBAL-1, 0 },
-{ "GETGLOBAL1", 1, GETGLOBAL1, GETGLOBAL, GETGLOBAL1-GETGLOBAL-1, 0 },
-{ "GETGLOBAL2", 1, GETGLOBAL2, GETGLOBAL, GETGLOBAL2-GETGLOBAL-1, 0 },
-{ "GETGLOBAL3", 1, GETGLOBAL3, GETGLOBAL, GETGLOBAL3-GETGLOBAL-1, 0 },
-{ "GETGLOBAL4", 1, GETGLOBAL4, GETGLOBAL, GETGLOBAL4-GETGLOBAL-1, 0 },
-{ "GETGLOBAL5", 1, GETGLOBAL5, GETGLOBAL, GETGLOBAL5-GETGLOBAL-1, 0 },
-{ "GETGLOBAL6", 1, GETGLOBAL6, GETGLOBAL, GETGLOBAL6-GETGLOBAL-1, 0 },
-{ "GETGLOBAL7", 1, GETGLOBAL7, GETGLOBAL, GETGLOBAL7-GETGLOBAL-1, 0 },
-{ "GETGLOBALW", 3, GETGLOBALW, GETGLOBAL, GETGLOBALW-GETGLOBAL-1, 0 },
-{ "GETTABLE", 1, GETTABLE, GETTABLE, GETTABLE-GETTABLE-1, 0 },
-{ "GETDOTTED", 2, GETDOTTED, GETDOTTED, GETDOTTED-GETDOTTED-1, 0 },
-{ "GETDOTTED0", 1, GETDOTTED0, GETDOTTED, GETDOTTED0-GETDOTTED-1, 0 },
-{ "GETDOTTED1", 1, GETDOTTED1, GETDOTTED, GETDOTTED1-GETDOTTED-1, 0 },
-{ "GETDOTTED2", 1, GETDOTTED2, GETDOTTED, GETDOTTED2-GETDOTTED-1, 0 },
-{ "GETDOTTED3", 1, GETDOTTED3, GETDOTTED, GETDOTTED3-GETDOTTED-1, 0 },
-{ "GETDOTTED4", 1, GETDOTTED4, GETDOTTED, GETDOTTED4-GETDOTTED-1, 0 },
-{ "GETDOTTED5", 1, GETDOTTED5, GETDOTTED, GETDOTTED5-GETDOTTED-1, 0 },
-{ "GETDOTTED6", 1, GETDOTTED6, GETDOTTED, GETDOTTED6-GETDOTTED-1, 0 },
-{ "GETDOTTED7", 1, GETDOTTED7, GETDOTTED, GETDOTTED7-GETDOTTED-1, 0 },
-{ "GETDOTTEDW", 3, GETDOTTEDW, GETDOTTED, GETDOTTEDW-GETDOTTED-1, 0 },
-{ "PUSHSELF", 2, PUSHSELF, PUSHSELF, PUSHSELF-PUSHSELF-1, 0 },
-{ "PUSHSELF0", 1, PUSHSELF0, PUSHSELF, PUSHSELF0-PUSHSELF-1, 0 },
-{ "PUSHSELF1", 1, PUSHSELF1, PUSHSELF, PUSHSELF1-PUSHSELF-1, 0 },
-{ "PUSHSELF2", 1, PUSHSELF2, PUSHSELF, PUSHSELF2-PUSHSELF-1, 0 },
-{ "PUSHSELF3", 1, PUSHSELF3, PUSHSELF, PUSHSELF3-PUSHSELF-1, 0 },
-{ "PUSHSELF4", 1, PUSHSELF4, PUSHSELF, PUSHSELF4-PUSHSELF-1, 0 },
-{ "PUSHSELF5", 1, PUSHSELF5, PUSHSELF, PUSHSELF5-PUSHSELF-1, 0 },
-{ "PUSHSELF6", 1, PUSHSELF6, PUSHSELF, PUSHSELF6-PUSHSELF-1, 0 },
-{ "PUSHSELF7", 1, PUSHSELF7, PUSHSELF, PUSHSELF7-PUSHSELF-1, 0 },
-{ "PUSHSELFW", 3, PUSHSELFW, PUSHSELF, PUSHSELFW-PUSHSELF-1, 0 },
-{ "CREATEARRAY", 2, CREATEARRAY, CREATEARRAY, CREATEARRAY-CREATEARRAY-1, 0 },
-{ "CREATEARRAY0", 1, CREATEARRAY0, CREATEARRAY, CREATEARRAY0-CREATEARRAY-1, 0 },
-{ "CREATEARRAY1", 1, CREATEARRAY1, CREATEARRAY, CREATEARRAY1-CREATEARRAY-1, 0 },
-{ "CREATEARRAYW", 3, CREATEARRAYW, CREATEARRAY, CREATEARRAYW-CREATEARRAY-1, 0 },
-{ "SETLOCAL", 2, SETLOCAL, SETLOCAL, SETLOCAL-SETLOCAL-1, 0 },
-{ "SETLOCAL0", 1, SETLOCAL0, SETLOCAL, SETLOCAL0-SETLOCAL-1, 0 },
-{ "SETLOCAL1", 1, SETLOCAL1, SETLOCAL, SETLOCAL1-SETLOCAL-1, 0 },
-{ "SETLOCAL2", 1, SETLOCAL2, SETLOCAL, SETLOCAL2-SETLOCAL-1, 0 },
-{ "SETLOCAL3", 1, SETLOCAL3, SETLOCAL, SETLOCAL3-SETLOCAL-1, 0 },
-{ "SETLOCAL4", 1, SETLOCAL4, SETLOCAL, SETLOCAL4-SETLOCAL-1, 0 },
-{ "SETLOCAL5", 1, SETLOCAL5, SETLOCAL, SETLOCAL5-SETLOCAL-1, 0 },
-{ "SETLOCAL6", 1, SETLOCAL6, SETLOCAL, SETLOCAL6-SETLOCAL-1, 0 },
-{ "SETLOCAL7", 1, SETLOCAL7, SETLOCAL, SETLOCAL7-SETLOCAL-1, 0 },
-{ "SETGLOBAL", 2, SETGLOBAL, SETGLOBAL, SETGLOBAL-SETGLOBAL-1, 0 },
-{ "SETGLOBAL0", 1, SETGLOBAL0, SETGLOBAL, SETGLOBAL0-SETGLOBAL-1, 0 },
-{ "SETGLOBAL1", 1, SETGLOBAL1, SETGLOBAL, SETGLOBAL1-SETGLOBAL-1, 0 },
-{ "SETGLOBAL2", 1, SETGLOBAL2, SETGLOBAL, SETGLOBAL2-SETGLOBAL-1, 0 },
-{ "SETGLOBAL3", 1, SETGLOBAL3, SETGLOBAL, SETGLOBAL3-SETGLOBAL-1, 0 },
-{ "SETGLOBAL4", 1, SETGLOBAL4, SETGLOBAL, SETGLOBAL4-SETGLOBAL-1, 0 },
-{ "SETGLOBAL5", 1, SETGLOBAL5, SETGLOBAL, SETGLOBAL5-SETGLOBAL-1, 0 },
-{ "SETGLOBAL6", 1, SETGLOBAL6, SETGLOBAL, SETGLOBAL6-SETGLOBAL-1, 0 },
-{ "SETGLOBAL7", 1, SETGLOBAL7, SETGLOBAL, SETGLOBAL7-SETGLOBAL-1, 0 },
-{ "SETGLOBALW", 3, SETGLOBALW, SETGLOBAL, SETGLOBALW-SETGLOBAL-1, 0 },
-{ "SETTABLE0", 1, SETTABLE0, SETTABLE0, SETTABLE0-SETTABLE0-1, 0 },
-{ "SETTABLE", 2, SETTABLE, SETTABLE, SETTABLE-SETTABLE-1, 0 },
-{ "SETLIST", 3, SETLIST, SETLIST, SETLIST-SETLIST-1, 0 },
-{ "SETLIST0", 2, SETLIST0, SETLIST, SETLIST0-SETLIST-1, 0 },
-{ "SETLISTW", 4, SETLISTW, SETLIST, SETLISTW-SETLIST-1, 0 },
-{ "SETMAP", 2, SETMAP, SETMAP, SETMAP-SETMAP-1, 0 },
-{ "SETMAP0", 1, SETMAP0, SETMAP, SETMAP0-SETMAP-1, 0 },
-{ "EQOP", 1, EQOP, EQOP, EQOP-EQOP-1, 0 },
-{ "NEQOP", 1, NEQOP, NEQOP, NEQOP-NEQOP-1, 0 },
-{ "LTOP", 1, LTOP, LTOP, LTOP-LTOP-1, 0 },
-{ "LEOP", 1, LEOP, LEOP, LEOP-LEOP-1, 0 },
-{ "GTOP", 1, GTOP, GTOP, GTOP-GTOP-1, 0 },
-{ "GEOP", 1, GEOP, GEOP, GEOP-GEOP-1, 0 },
-{ "ADDOP", 1, ADDOP, ADDOP, ADDOP-ADDOP-1, 0 },
-{ "SUBOP", 1, SUBOP, SUBOP, SUBOP-SUBOP-1, 0 },
-{ "MULTOP", 1, MULTOP, MULTOP, MULTOP-MULTOP-1, 0 },
-{ "DIVOP", 1, DIVOP, DIVOP, DIVOP-DIVOP-1, 0 },
-{ "POWOP", 1, POWOP, POWOP, POWOP-POWOP-1, 0 },
-{ "CONCOP", 1, CONCOP, CONCOP, CONCOP-CONCOP-1, 0 },
-{ "MINUSOP", 1, MINUSOP, MINUSOP, MINUSOP-MINUSOP-1, 0 },
-{ "NOTOP", 1, NOTOP, NOTOP, NOTOP-NOTOP-1, 0 },
-{ "ONTJMP", 2, ONTJMP, ONTJMP, ONTJMP-ONTJMP-1, 0 },
-{ "ONTJMPW", 3, ONTJMPW, ONTJMP, ONTJMPW-ONTJMP-1, 0 },
-{ "ONFJMP", 2, ONFJMP, ONFJMP, ONFJMP-ONFJMP-1, 0 },
-{ "ONFJMPW", 3, ONFJMPW, ONFJMP, ONFJMPW-ONFJMP-1, 0 },
-{ "JMP", 2, JMP, JMP, JMP-JMP-1, 0 },
-{ "JMPW", 3, JMPW, JMP, JMPW-JMP-1, 0 },
-{ "IFFJMP", 2, IFFJMP, IFFJMP, IFFJMP-IFFJMP-1, 0 },
-{ "IFFJMPW", 3, IFFJMPW, IFFJMP, IFFJMPW-IFFJMP-1, 0 },
-{ "IFTUPJMP", 2, IFTUPJMP, IFTUPJMP, IFTUPJMP-IFTUPJMP-1, 0 },
-{ "IFTUPJMPW", 3, IFTUPJMPW, IFTUPJMP, IFTUPJMPW-IFTUPJMP-1, 0 },
-{ "IFFUPJMP", 2, IFFUPJMP, IFFUPJMP, IFFUPJMP-IFFUPJMP-1, 0 },
-{ "IFFUPJMPW", 3, IFFUPJMPW, IFFUPJMP, IFFUPJMPW-IFFUPJMP-1, 0 },
-{ "CLOSURE", 3, CLOSURE, CLOSURE, CLOSURE-CLOSURE-1, 0 },
-{ "CLOSUREW", 4, CLOSUREW, CLOSURE, CLOSUREW-CLOSURE-1, 0 },
-{ "CALLFUNC", 3, CALLFUNC, CALLFUNC, CALLFUNC-CALLFUNC-1, 0 },
-{ "CALLFUNC0", 2, CALLFUNC0, CALLFUNC, CALLFUNC0-CALLFUNC-1, 0 },
-{ "CALLFUNC1", 2, CALLFUNC1, CALLFUNC, CALLFUNC1-CALLFUNC-1, 0 },
-{ "RETCODE", 2, RETCODE, RETCODE, RETCODE-RETCODE-1, 0 },
-{ "SETLINE", 2, SETLINE, SETLINE, SETLINE-SETLINE-1, 0 },
-{ "SETLINEW", 3, SETLINEW, SETLINE, SETLINEW-SETLINE-1, 0 },
-{ "POP", 2, POP, POP, POP-POP-1, 0 },
-{ "POP0", 1, POP0, POP, POP0-POP-1, 0 },
-{ "POP1", 1, POP1, POP, POP1-POP-1, 0 },
+{ "ENDCODE", ENDCODE, ENDCODE, ARGS_NONE, -1, -1 },
+{ "RETCODE", RETCODE, RETCODE, ARGS_B, -1, -1 },
+{ "CALL", CALL, CALL, ARGS_BB, -1, -1 },
+{ "TAILCALL", TAILCALL, TAILCALL, ARGS_BB, -1, -1 },
+{ "PUSHNIL", PUSHNIL, PUSHNIL, ARGS_B, -1, -1 },
+{ "POP", POP, POP, ARGS_B, -1, -1 },
+{ "PUSHNUMBERW", PUSHNUMBERW, PUSHNUMBER, ARGS_W, -1, -1 },
+{ "PUSHNUMBER", PUSHNUMBER, PUSHNUMBER, ARGS_B, -1, -1 },
+{ "PUSHNUMBERNEGW", PUSHNUMBERNEGW, PUSHNUMBERNEG, ARGS_W, -1, -1 },
+{ "PUSHNUMBERNEG", PUSHNUMBERNEG, PUSHNUMBERNEG, ARGS_B, -1, -1 },
+{ "PUSHCONSTANTW", PUSHCONSTANTW, PUSHCONSTANT, ARGS_W, -1, -1 },
+{ "PUSHCONSTANT", PUSHCONSTANT, PUSHCONSTANT, ARGS_B, -1, -1 },
+{ "PUSHUPVALUE", PUSHUPVALUE, PUSHUPVALUE, ARGS_B, -1, -1 },
+{ "PUSHLOCAL", PUSHLOCAL, PUSHLOCAL, ARGS_B, -1, -1 },
+{ "GETGLOBALW", GETGLOBALW, GETGLOBAL, ARGS_W, -1, -1 },
+{ "GETGLOBAL", GETGLOBAL, GETGLOBAL, ARGS_B, -1, -1 },
+{ "GETTABLE", GETTABLE, GETTABLE, ARGS_NONE, -1, -1 },
+{ "GETDOTTEDW", GETDOTTEDW, GETDOTTED, ARGS_W, -1, -1 },
+{ "GETDOTTED", GETDOTTED, GETDOTTED, ARGS_B, -1, -1 },
+{ "PUSHSELFW", PUSHSELFW, PUSHSELF, ARGS_W, -1, -1 },
+{ "PUSHSELF", PUSHSELF, PUSHSELF, ARGS_B, -1, -1 },
+{ "CREATEARRAYW", CREATEARRAYW, CREATEARRAY, ARGS_W, -1, -1 },
+{ "CREATEARRAY", CREATEARRAY, CREATEARRAY, ARGS_B, -1, -1 },
+{ "SETLOCAL", SETLOCAL, SETLOCAL, ARGS_B, -1, -1 },
+{ "SETGLOBALW", SETGLOBALW, SETGLOBAL, ARGS_W, -1, -1 },
+{ "SETGLOBAL", SETGLOBAL, SETGLOBAL, ARGS_B, -1, -1 },
+{ "SETTABLEPOP", SETTABLEPOP, SETTABLEPOP, ARGS_NONE, -1, -1 },
+{ "SETTABLE", SETTABLE, SETTABLE, ARGS_B, -1, -1 },
+{ "SETLISTW", SETLISTW, SETLIST, ARGS_WB, -1, -1 },
+{ "SETLIST", SETLIST, SETLIST, ARGS_BB, -1, -1 },
+{ "SETMAP", SETMAP, SETMAP, ARGS_B, -1, -1 },
+{ "NEQOP", NEQOP, NEQOP, ARGS_NONE, -1, -1 },
+{ "EQOP", EQOP, EQOP, ARGS_NONE, -1, -1 },
+{ "LTOP", LTOP, LTOP, ARGS_NONE, -1, -1 },
+{ "LEOP", LEOP, LEOP, ARGS_NONE, -1, -1 },
+{ "GTOP", GTOP, GTOP, ARGS_NONE, -1, -1 },
+{ "GEOP", GEOP, GEOP, ARGS_NONE, -1, -1 },
+{ "ADDOP", ADDOP, ADDOP, ARGS_NONE, -1, -1 },
+{ "SUBOP", SUBOP, SUBOP, ARGS_NONE, -1, -1 },
+{ "MULTOP", MULTOP, MULTOP, ARGS_NONE, -1, -1 },
+{ "DIVOP", DIVOP, DIVOP, ARGS_NONE, -1, -1 },
+{ "POWOP", POWOP, POWOP, ARGS_NONE, -1, -1 },
+{ "CONCOP", CONCOP, CONCOP, ARGS_NONE, -1, -1 },
+{ "MINUSOP", MINUSOP, MINUSOP, ARGS_NONE, -1, -1 },
+{ "NOTOP", NOTOP, NOTOP, ARGS_NONE, -1, -1 },
+{ "ONTJMPW", ONTJMPW, ONTJMP, ARGS_W, -1, -1 },
+{ "ONTJMP", ONTJMP, ONTJMP, ARGS_B, -1, -1 },
+{ "ONFJMPW", ONFJMPW, ONFJMP, ARGS_W, -1, -1 },
+{ "ONFJMP", ONFJMP, ONFJMP, ARGS_B, -1, -1 },
+{ "JMPW", JMPW, JMP, ARGS_W, -1, -1 },
+{ "JMP", JMP, JMP, ARGS_B, -1, -1 },
+{ "IFFJMPW", IFFJMPW, IFFJMP, ARGS_W, -1, -1 },
+{ "IFFJMP", IFFJMP, IFFJMP, ARGS_B, -1, -1 },
+{ "IFTUPJMPW", IFTUPJMPW, IFTUPJMP, ARGS_W, -1, -1 },
+{ "IFTUPJMP", IFTUPJMP, IFTUPJMP, ARGS_B, -1, -1 },
+{ "IFFUPJMPW", IFFUPJMPW, IFFUPJMP, ARGS_W, -1, -1 },
+{ "IFFUPJMP", IFFUPJMP, IFFUPJMP, ARGS_B, -1, -1 },
+{ "CLOSUREW", CLOSUREW, CLOSURE, ARGS_WB, -1, -1 },
+{ "CLOSURE", CLOSURE, CLOSURE, ARGS_BB, -1, -1 },
+{ "SETLINEW", SETLINEW, SETLINE, ARGS_W, -1, -1 },
+{ "SETLINE", SETLINE, SETLINE, ARGS_B, -1, -1 },
+{ "LONGARGW", LONGARGW, LONGARG, ARGS_W, -1, -1 },
+{ "LONGARG", LONGARG, LONGARG, ARGS_B, -1, -1 },
+{ "CHECKSTACK", CHECKSTACK, CHECKSTACK, ARGS_B, -1, -1 },
diff --git a/src/luac/opt.c b/src/luac/opt.c
index 5084ddee..e2becc2a 100644
--- a/src/luac/opt.c
+++ b/src/luac/opt.c
@@ -1,70 +1,126 @@
/*
-** $Id: opt.c,v 1.4 1998/04/02 20:44:08 lhf Exp $
+** $Id: opt.c,v 1.12 1999/07/02 19:34:26 lhf Exp $
** optimize bytecodes
** See Copyright Notice in lua.h
*/
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "luac.h"
-#include "lmem.h"
+
+static void FixArg(Byte* p, int i, int j, int isconst)
+{
+ if (j==i)
+ ;
+ else if (i<=MAX_BYTE) /* j<i, so j fits where i did */
+ p[1]=j;
+ else if (i<=MAX_WORD)
+ {
+ if (isconst && j<=MAX_BYTE) /* may use byte variant instead */
+ {
+ p[0]++; /* byte variant follows word variant */
+ p[1]=j;
+ p[2]=NOP;
+ }
+ else /* stuck with word variant */
+ {
+ p[1]=j>>8;
+ p[2]=j;
+ }
+ }
+ else /* previous instruction must've been LONGARG */
+ {
+ if (isconst && j<=MAX_WORD) p[-2]=p[-1]=NOP; else p[-1]=j>>16;
+ p[1]=j>>8;
+ p[2]=j;
+ }
+}
static void FixConstants(TProtoFunc* tf, int* C)
{
Byte* code=tf->code;
Byte* p=code;
- while (1)
+ int longarg=0;
+ for (;;)
{
Opcode OP;
int n=INFO(tf,p,&OP);
int op=OP.class;
- int i=OP.arg;
- if (op==ENDCODE) break;
- if ( op==PUSHCONSTANT || op==GETDOTTED || op==PUSHSELF ||
- op==GETGLOBAL || op==SETGLOBAL)
+ int i=OP.arg+longarg;
+ longarg=0;
+ if (op==PUSHCONSTANT || op==GETGLOBAL || op==GETDOTTED ||
+ op==PUSHSELF || op==SETGLOBAL || op==CLOSURE)
+ FixArg(p,i,C[i],1);
+ else if (op==LONGARG) longarg=i<<16;
+ else if (op==ENDCODE) break;
+ p+=n;
+ }
+}
+
+#define UNREF 1 /* "type" of unused constants */
+#define BIAS 128 /* mark for used constants */
+
+static void NoUnrefs(TProtoFunc* tf)
+{
+ int i,n=tf->nconsts;
+ Byte* code=tf->code;
+ Byte* p=code;
+ int longarg=0;
+ for (;;) /* mark all used constants */
+ {
+ Opcode OP;
+ int n=INFO(tf,p,&OP);
+ int op=OP.class;
+ int i=OP.arg+longarg;
+ longarg=0;
+ if (op==PUSHCONSTANT || op==GETGLOBAL || op==GETDOTTED ||
+ op==PUSHSELF || op==SETGLOBAL || op==CLOSURE)
{
- int j=C[i];
- if (j==i)
- ;
- else if (n==1)
- {
- p[0]=op+j+1;
- }
- else if (n==2)
- {
- if (j<8) { p[0]=op+j+1; p[1]=NOP; } else p[1]=j;
- }
- else
- {
- if (j<=255)
- {
- p[0]=op;
- p[1]=j;
- p[2]=NOP;
- }
- else
- {
- p[1]= 0x0000FF & (j>>8);
- p[2]= 0x0000FF & j;
- }
- }
+ TObject* o=tf->consts+i;
+ if (ttype(o)<=0) ttype(o)+=BIAS; /* mark as used */
}
+ else if (op==LONGARG) longarg=i<<16;
+ else if (op==ENDCODE) break;
p+=n;
}
+ for (i=0; i<n; i++) /* mark all unused constants */
+ {
+ TObject* o=tf->consts+i;
+ if (ttype(o)<=0)
+ ttype(o)=UNREF; /* mark as unused */
+ else
+ ttype(o)-=BIAS; /* unmark used constant */
+ }
}
-static TProtoFunc* TF;
+#define CMP(oa,ob,f) memcmp(&f(oa),&f(ob),sizeof(f(oa)))
-static int compare(const void* a, const void *b)
+static int compare(TProtoFunc* tf, int ia, int ib)
+{
+ TObject* oa=tf->consts+ia;
+ TObject* ob=tf->consts+ib;
+ int t=ttype(oa)-ttype(ob);
+ if (t) return t;
+ switch (ttype(oa))
+ {
+ case LUA_T_NUMBER: return CMP(oa,ob,nvalue);
+ case LUA_T_STRING: return CMP(oa,ob,tsvalue);
+ case LUA_T_PROTO: return CMP(oa,ob,tfvalue);
+ case LUA_T_NIL: return 0;
+ case UNREF: return 0;
+ default: return ia-ib; /* cannot happen */
+ }
+}
+
+static TProtoFunc* TF; /* for sort */
+
+static int compare1(const void* a, const void* b)
{
int ia=*(int*)a;
int ib=*(int*)b;
- int t;
- TObject* oa=TF->consts+ia;
- TObject* ob=TF->consts+ib;
- t=ttype(oa)-ttype(ob); if (t) return t;
- t=oa->value.i-ob->value.i; if (t) return t;
- return ia-ib;
+ int t=compare(TF,ia,ib);
+ return (t) ? t : ia-ib;
}
static void OptConstants(TProtoFunc* tf)
@@ -74,43 +130,60 @@ static void OptConstants(TProtoFunc* tf)
int i,k;
int n=tf->nconsts;
if (n==0) return;
- C=luaM_reallocvector(C,n,int);
- D=luaM_reallocvector(D,n,int);
+ luaM_reallocvector(C,n,int);
+ luaM_reallocvector(D,n,int);
+ NoUnrefs(tf);
for (i=0; i<n; i++) C[i]=D[i]=i; /* group duplicates */
- TF=tf; qsort(C,n,sizeof(C[0]),compare);
+ TF=tf; qsort(C,n,sizeof(C[0]),compare1);
k=C[0]; /* build duplicate table */
for (i=1; i<n; i++)
{
int j=C[i];
- TObject* oa=tf->consts+k;
- TObject* ob=tf->consts+j;
- if (ttype(oa)==ttype(ob) && oa->value.i==ob->value.i) D[j]=k; else k=j;
+ if (compare(tf,k,j)==0) D[j]=k; else k=j;
}
k=0; /* build rename map & pack constants */
for (i=0; i<n; i++)
{
- if (D[i]==i) { tf->consts[k]=tf->consts[i]; C[i]=k++; } else C[i]=C[D[i]];
+ if (D[i]==i) /* new value */
+ {
+ TObject* o=tf->consts+i;
+ if (ttype(o)!=UNREF)
+ {
+ tf->consts[k]=tf->consts[i];
+ C[i]=k++;
+ }
+ }
+ else C[i]=C[D[i]];
+ }
+ if (k<n)
+ {
+printf("\t" SOURCE " reduced constants from %d to %d\n",
+ tf->source->str,tf->lineDefined,n,k);
+ FixConstants(tf,C);
+ tf->nconsts=k;
}
- if (k>=n) return;
-printf("\t\"%s\":%d reduced constants from %d to %d\n",
- tf->fileName->str,tf->lineDefined,n,k);
- tf->nconsts=k;
- FixConstants(tf,C);
}
static int NoDebug(TProtoFunc* tf)
{
Byte* code=tf->code;
Byte* p=code;
+ int lop=NOP; /* last opcode */
int nop=0;
- while (1) /* change SETLINE to NOP */
+ for (;;) /* change SETLINE to NOP */
{
Opcode OP;
int n=INFO(tf,p,&OP);
int op=OP.class;
- if (op==ENDCODE) break;
if (op==NOP) ++nop;
- if (op==SETLINE) { nop+=n; memset(p,NOP,n); }
+ else if (op==SETLINE)
+ {
+ int m;
+ if (lop==LONGARG) m=2; else if (lop==LONGARGW) m=3; else m=0;
+ nop+=n+m; memset(p-m,NOP,n+m);
+ }
+ else if (op==ENDCODE) break;
+ lop=OP.op;
p+=n;
}
return nop;
@@ -125,8 +198,8 @@ static int FixJump(TProtoFunc* tf, Byte* a, Byte* b)
Opcode OP;
int n=INFO(tf,p,&OP);
int op=OP.class;
- if (op==ENDCODE) break;
if (op==NOP) ++nop;
+ else if (op==ENDCODE) break;
p+=n;
}
return nop;
@@ -136,42 +209,22 @@ static void FixJumps(TProtoFunc* tf)
{
Byte* code=tf->code;
Byte* p=code;
- while (1)
+ int longarg=0;
+ for (;;)
{
Opcode OP;
int n=INFO(tf,p,&OP);
int op=OP.class;
- int i=OP.arg;
- int nop;
+ int i=OP.arg+longarg;
+ int nop=0;
+ longarg=0;
if (op==ENDCODE) break;
- nop=0;
- if (op==IFTUPJMP || op==IFFUPJMP) nop=FixJump(tf,p-i+n,p); else
- if (op==ONTJMP || op==ONFJMP || op==JMP || op==IFFJMP) nop=FixJump(tf,p,p+i+n);
- if (nop>0)
- {
- int j=i-nop;
- if (n==2)
- p[1]=j;
- else
-#if 0
- {
- if (j<=255) /* does NOT work for nested loops */
- {
- if (op==IFTUPJMP || op==IFFUPJMP) --j;
- p[0]=OP.op-1; /* *JMP and *JMPW are consecutive */
- p[1]=j;
- p[2]=NOP;
- }
- else
-#endif
- {
- p[1]= 0x0000FF & (j>>8);
- p[2]= 0x0000FF & j;
- }
-#if 0
- }
-#endif
- }
+ else if (op==IFTUPJMP || op==IFFUPJMP)
+ nop=FixJump(tf,p-i+n,p);
+ else if (op==ONTJMP || op==ONFJMP || op==JMP || op==IFFJMP)
+ nop=FixJump(tf,p,p+i+n);
+ else if (op==LONGARG) longarg=i<<16;
+ if (nop>0) FixArg(p,i,i-nop,0);
p+=n;
}
}
@@ -181,7 +234,7 @@ static void PackCode(TProtoFunc* tf)
Byte* code=tf->code;
Byte* p=code;
Byte* q=code;
- while (1)
+ for (;;)
{
Opcode OP;
int n=INFO(tf,p,&OP);
@@ -190,14 +243,13 @@ static void PackCode(TProtoFunc* tf)
p+=n;
if (op==ENDCODE) break;
}
-printf("\t\"%s\":%d reduced code from %d to %d\n",
- tf->fileName->str,tf->lineDefined,(int)(p-code),(int)(q-code));
+printf("\t" SOURCE " reduced code from %d to %d\n",
+ tf->source->str,tf->lineDefined,(int)(p-code),(int)(q-code));
}
static void OptCode(TProtoFunc* tf)
{
- int nop=NoDebug(tf);
- if (nop==0) return; /* cannot improve code */
+ if (NoDebug(tf)==0) return; /* cannot improve code */
FixJumps(tf);
PackCode(tf);
}
@@ -216,13 +268,14 @@ static void OptFunctions(TProtoFunc* tf)
static void OptFunction(TProtoFunc* tf)
{
- tf->locvars=NULL; /* remove local variables table */
OptConstants(tf);
OptCode(tf);
OptFunctions(tf);
+ tf->source=luaS_new("");
+ tf->locvars=NULL;
}
-void OptChunk(TProtoFunc* Main)
+void luaU_optchunk(TProtoFunc* Main)
{
OptFunction(Main);
}
diff --git a/src/luac/print.c b/src/luac/print.c
index ce985390..b1ee8934 100644
--- a/src/luac/print.c
+++ b/src/luac/print.c
@@ -1,5 +1,5 @@
/*
-** $Id: print.c,v 1.13 1998/07/12 00:17:37 lhf Exp $
+** $Id: print.c,v 1.21 1999/05/25 19:58:55 lhf Exp $
** print bytecodes
** See Copyright Notice in lua.h
*/
@@ -9,88 +9,81 @@
#include "luac.h"
#ifdef DEBUG
-void PrintConstant1(TProtoFunc* tf, int i)
-{
- TObject* o=tf->consts+i;
- printf("%6d ",i);
- if (i<0 || i>=tf->nconsts)
- printf("(bad constant #%d: max=%d)",i,tf->nconsts);
- else
- switch (ttype(o))
- {
- case LUA_T_NUMBER:
- printf("N " NUMBER_FMT "\n",nvalue(o)); /* LUA_NUMBER */
- break;
- case LUA_T_STRING:
- printf("S %p\t\"%s\"\n",(void*)tsvalue(o),svalue(o));
- break;
- case LUA_T_PROTO:
- printf("F %p\n",(void*)tfvalue(o));
- break;
- default: /* cannot happen */
- printf("? %d\n",ttype(o));
- break;
- }
-}
-
static void PrintConstants(TProtoFunc* tf)
{
int i,n=tf->nconsts;
- printf("constants (%d):\n",n);
- for (i=0; i<n; i++) PrintConstant1(tf,i);
-}
-#endif
-
-static void PrintConstant(TProtoFunc* tf, int i)
-{
- if (i<0 || i>=tf->nconsts)
- printf("(bad constant #%d: max=%d)",i,tf->nconsts);
- else
+ printf("constants (%d) for %p:\n",n,tf);
+ for (i=0; i<n; i++)
{
TObject* o=tf->consts+i;
+ printf("%6d ",i);
switch (ttype(o))
{
case LUA_T_NUMBER:
- printf(NUMBER_FMT,nvalue(o)); /* LUA_NUMBER */
+ printf("N " NUMBER_FMT "\n",(double)nvalue(o));
break;
case LUA_T_STRING:
- printf("\"%s\"",svalue(o));
+ printf("S %p\t\"%s\"\n",tsvalue(o),svalue(o));
break;
case LUA_T_PROTO:
- printf("function at %p",(void*)tfvalue(o));
+ printf("F %p\n",tfvalue(o));
break;
case LUA_T_NIL:
- printf("(nil)");
+ printf("nil\n");
break;
default: /* cannot happen */
- printf("(bad constant #%d: type=%d [%s])\n",i,ttype(o),luaO_typename(o));
+ printf("? type=%d\n",ttype(o));
break;
}
}
}
+#endif
-#define VarStr(i) svalue(tf->consts+i)
+static void PrintConstant(TProtoFunc* tf, int i, int at)
+{
+ TObject* o=luaU_getconstant(tf,i,at);
+ switch (ttype(o))
+ {
+ case LUA_T_NUMBER:
+ printf(NUMBER_FMT,(double)nvalue(o));
+ break;
+ case LUA_T_STRING:
+ printf("\"%s\"",svalue(o));
+ break;
+ case LUA_T_PROTO:
+ printf("function at %p",(void*)tfvalue(o));
+ break;
+ case LUA_T_NIL:
+ printf("(nil)");
+ break;
+ default: /* cannot happen */
+ luaU_badconstant("print",i,o,tf);
+ break;
+ }
+}
static void PrintCode(TProtoFunc* tf)
{
Byte* code=tf->code;
Byte* p=code;
int line=0;
- while (1)
+ int longarg=0;
+ for (;;)
{
Opcode OP;
int n=INFO(tf,p,&OP);
- int op=OP.op;
- int i=OP.arg;
- printf("%6d ",(int)(p-code));
+ int i=OP.arg+longarg;
+ int at=p-code;
+ longarg=0;
+ printf("%6d ",at);
{
Byte* q=p;
int j=n;
while (j--) printf("%02X",*q++);
}
- printf("%*s%-13s",2*(5-n),"",OP.name);
-
- if (n!=1 || op<0) printf("\t%d",i); else if (i>=0) printf("\t");
+ printf("%*s%-14s ",2*(5-n),"",OP.name);
+ if (OP.arg >=0) printf("%d",i);
+ if (OP.arg2>=0) printf(" %d",OP.arg2);
switch (OP.class)
{
@@ -99,13 +92,14 @@ static void PrintCode(TProtoFunc* tf)
printf("\n");
return;
- case CLOSURE:
- printf(" %d",OP.arg2);
case PUSHCONSTANT:
+ case GETGLOBAL:
+ case SETGLOBAL:
case GETDOTTED:
case PUSHSELF:
+ case CLOSURE:
printf("\t; ");
- PrintConstant(tf,i);
+ PrintConstant(tf,i,at);
break;
case PUSHLOCAL:
@@ -116,29 +110,24 @@ static void PrintCode(TProtoFunc* tf)
break;
}
- case GETGLOBAL:
- case SETGLOBAL:
- printf("\t; %s",VarStr(i));
- break;
-
- case SETLIST:
- case CALLFUNC:
- if (n>=3) printf(" %d",OP.arg2);
+ case SETLINE:
+ printf("\t; " SOURCE,tf->source->str,line=i);
break;
- case SETLINE:
- printf("\t; \"%s\":%d",fileName(tf),line=i);
+ case LONGARG:
+ longarg=i<<16;
break;
/* suggested by Norman Ramsey <nr@cs.virginia.edu> */
- case IFTUPJMP:
- case IFFUPJMP:
- i=-i;
case ONTJMP:
case ONFJMP:
case JMP:
case IFFJMP:
- printf("\t; to %d",(int)(p-code)+i+n);
+ printf("\t; to %d",at+i+n);
+ break;
+ case IFTUPJMP:
+ case IFFUPJMP:
+ printf("\t; to %d",at-i+n);
break;
}
@@ -150,47 +139,44 @@ static void PrintCode(TProtoFunc* tf)
static void PrintLocals(TProtoFunc* tf)
{
LocVar* v=tf->locvars;
- int n,i=0;
- if (v==NULL || v->varname==NULL) return;
+ int n,i;
+ if (v==NULL || v->line<0) return;
n=tf->code[1]; if (n>=ZEROVARARG) n-=ZEROVARARG;
-
printf("locals:");
- if (n>0)
- {
- for (i=0; i<n; v++,i++) printf(" %s",v->varname->str);
- }
- if (v->varname!=NULL)
+ for (i=0; i<n; v++,i++) /* arguments */
+ printf(" %s",v->varname->str);
+ for (; v->line>=0; v++)
{
- for (; v->line>=0; v++)
+ if (v->varname==NULL)
{
- if (v->varname==NULL)
- {
- printf(")"); --i;
- }
- else
- {
- printf(" (%s",v->varname->str); i++;
- }
+ --i; if (i<0) luaL_verror("bad locvars[%d]",v-tf->locvars); else printf(")");
+ }
+ else
+ {
+ ++i; printf(" (%s",v->varname->str);
}
- i-=n;
- while (i--) printf(")");
}
+ i-=n;
+ while (i--) printf(")");
printf("\n");
}
+#define IsMain(tf) (tf->lineDefined==0)
+
static void PrintHeader(TProtoFunc* tf, TProtoFunc* Main, int at)
{
- int size=CodeSize(tf);
+ int size=luaU_codesize(tf);
if (IsMain(tf))
- printf("\nmain of \"%s\" (%d bytes at %p)\n",fileName(tf),size,(void*)tf);
- else if (Main)
+ printf("\nmain " SOURCE " (%d bytes at %p)\n",
+ tf->source->str,tf->lineDefined,size,tf);
+ else
{
- printf("\nfunction defined at \"%s\":%d (%d bytes at %p); used at ",
- fileName(tf),tf->lineDefined,size,(void*)tf);
- if (IsMain(Main))
+ printf("\nfunction " SOURCE " (%d bytes at %p); used at ",
+ tf->source->str,tf->lineDefined,size,tf);
+ if (Main && IsMain(Main))
printf("main");
else
- printf("%p",(void*)Main);
+ printf("%p",Main);
printf("+%d\n",at);
}
}
@@ -201,17 +187,21 @@ static void PrintFunctions(TProtoFunc* Main)
{
Byte* code=Main->code;
Byte* p=code;
- while (1)
+ int longarg=0;
+ for (;;)
{
Opcode OP;
int n=INFO(Main,p,&OP);
- if (OP.class==ENDCODE) break;
- if (OP.class==PUSHCONSTANT || OP.class==CLOSURE)
+ int op=OP.class;
+ int i=OP.arg+longarg;
+ longarg=0;
+ if (op==PUSHCONSTANT || op==CLOSURE)
{
- int i=OP.arg;
TObject* o=Main->consts+i;
if (ttype(o)==LUA_T_PROTO) PrintFunction(tfvalue(o),Main,(int)(p-code));
}
+ else if (op==LONGARG) longarg=i<<16;
+ else if (op==ENDCODE) break;
p+=n;
}
}
@@ -227,7 +217,7 @@ static void PrintFunction(TProtoFunc* tf, TProtoFunc* Main, int at)
PrintFunctions(tf);
}
-void PrintChunk(TProtoFunc* Main)
+void luaU_printchunk(TProtoFunc* Main)
{
PrintFunction(Main,0,0);
}
diff --git a/src/luac/stubs.c b/src/luac/stubs.c
index d42bec25..5f38940e 100644
--- a/src/luac/stubs.c
+++ b/src/luac/stubs.c
@@ -1,9 +1,17 @@
/*
-** $Id: stubs.c,v 1.8 1998/07/12 00:17:37 lhf Exp $
+** $Id: stubs.c,v 1.11 1999/03/11 17:09:10 lhf Exp $
** avoid runtime modules in luac
** See Copyright Notice in lua.h
*/
+#ifdef NOSTUBS
+
+/* according to gcc, ANSI C forbids an empty source file */
+void luaU_dummy(void);
+void luaU_dummy(void){}
+
+#else
+
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -22,32 +30,34 @@ void lua_error(char* s)
}
/* copied from lauxlib.c */
-void luaL_verror(char* fmt, ...)
+void luaL_verror (char *fmt, ...)
{
- char buff[500];
- va_list argp;
- va_start(argp,fmt);
- vsprintf(buff,fmt,argp);
- va_end(argp);
- lua_error(buff);
+ char buff[500];
+ va_list argp;
+ va_start(argp, fmt);
+ vsprintf(buff, fmt, argp);
+ va_end(argp);
+ lua_error(buff);
}
/* copied from lauxlib.c */
-int luaL_findstring (char* name, char* list[])
-{
- int i;
- for (i=0; list[i]; i++)
- if (strcmp(list[i], name) == 0)
- return i;
- return -1;
+void luaL_filesource (char *out, char *filename, int len) {
+ if (filename == NULL) filename = "(stdin)";
+ sprintf(out, "@%.*s", len-2, filename); /* -2 for '@' and '\0' */
}
/* avoid runtime modules in lstate.c */
+
+#include "lbuiltin.h"
+#include "ldo.h"
+#include "lgc.h"
+#include "ltable.h"
+#include "ltm.h"
+
void luaB_predefine(void){}
void luaC_hashcallIM(Hash *l){}
void luaC_strcallIM(TaggedString *l){}
void luaD_gcIM(TObject *o){}
-void luaD_init(void){}
void luaH_free(Hash *frees){}
void luaT_init(void){}
@@ -59,10 +69,53 @@ void luaT_init(void){}
#ifdef NOPARSER
-int lua_debug=0;
+#include "llex.h"
+#include "lparser.h"
void luaX_init(void){}
-void luaY_init(void){}
-void luaY_parser(void) { lua_error("parser not loaded"); }
+void luaD_init(void){}
+
+TProtoFunc* luaY_parser(ZIO *z) {
+ lua_error("parser not loaded");
+ return NULL;
+}
+
+#else
+/* copied from lauxlib.c */
+int luaL_findstring (char *name, char *list[]) {
+ int i;
+ for (i=0; list[i]; i++)
+ if (strcmp(list[i], name) == 0)
+ return i;
+ return -1; /* name not found */
+}
+
+/* copied from lauxlib.c */
+void luaL_chunkid (char *out, char *source, int len) {
+ len -= 13; /* 13 = strlen("string ''...\0") */
+ if (*source == '@')
+ sprintf(out, "file `%.*s'", len, source+1);
+ else if (*source == '(')
+ strcpy(out, "(C code)");
+ else {
+ char *b = strchr(source , '\n'); /* stop string at first new line */
+ int lim = (b && (b-source)<len) ? b-source : len;
+ sprintf(out, "string `%.*s'", lim, source);
+ strcpy(out+lim+(13-5), "...'"); /* 5 = strlen("...'\0") */
+ }
+}
+
+void luaD_checkstack(int n){}
+
+#define STACK_UNIT 128
+
+/* copied from ldo.c */
+void luaD_init (void) {
+ L->stack.stack = luaM_newvector(STACK_UNIT, TObject);
+ L->stack.top = L->stack.stack;
+ L->stack.last = L->stack.stack+(STACK_UNIT-1);
+}
+
+#endif
#endif
diff --git a/src/luac/test.c b/src/luac/test.c
new file mode 100644
index 00000000..78ba4556
--- /dev/null
+++ b/src/luac/test.c
@@ -0,0 +1,253 @@
+/*
+** $Id: test.c,v 1.10 1999/07/02 19:34:26 lhf Exp $
+** test integrity
+** See Copyright Notice in lua.h
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "luac.h"
+
+#define AT "pc=%d"
+#define ATLOC 0)
+#define UNSAFE(s) \
+ luaL_verror("unsafe code at " AT IN "\n " s,at,INLOC
+
+TObject* luaU_getconstant(TProtoFunc* tf, int i, int at)
+{
+ if (i>=tf->nconsts) UNSAFE("bad constant #%d (max=%d)"),i,tf->nconsts-1,ATLOC;
+ return tf->consts+i;
+}
+
+static int check(int n, TProtoFunc* tf, int at, int sp, int ss)
+{
+ if (n==0) return sp;
+ sp+=n;
+ if (sp<00) UNSAFE("stack underflow (sp=%d)"),sp,ATLOC;
+ if (sp>ss) UNSAFE("stack overflow (sp=%d ss=%d)"),sp,ss,ATLOC;
+ return sp;
+}
+
+#define CHECK(before,after) \
+ sp=check(-(before),tf,at,sp,ss), sp=check(after,tf,at,sp,ss)
+
+static int jmpok(TProtoFunc* tf, int size, int at, int d)
+{
+ int to=at+d;
+ if (to<2 || to>=size)
+ UNSAFE("invalid jump to %d (valid range is 2..%d)"),to,size-1,ATLOC;
+ return to;
+}
+
+static void TestStack(TProtoFunc* tf, int size, int* SP, int* JP)
+{
+ Byte* code=tf->code;
+ Byte* p=code;
+ int longarg=0;
+ int ss=0;
+ int sp=0;
+ for (;;)
+ {
+ Opcode OP;
+ int n=INFO(tf,p,&OP);
+ int op=OP.class;
+ int i=OP.arg+longarg;
+ int at=p-code;
+ longarg=0;
+ switch (op) /* test sanity of operands */
+ {
+ case PUSHCONSTANT:
+ case GETGLOBAL:
+ case GETDOTTED:
+ case PUSHSELF:
+ case SETGLOBAL:
+ case CLOSURE:
+ {
+ TObject* o=luaU_getconstant(tf,i,at);
+ if ((op==CLOSURE && ttype(o)!=LUA_T_PROTO)
+ || (op==GETGLOBAL && ttype(o)!=LUA_T_STRING)
+ || (op==SETGLOBAL && ttype(o)!=LUA_T_STRING))
+ UNSAFE("bad operand to %s"),OP.name,ATLOC;
+ break;
+ }
+ case PUSHLOCAL:
+ if (i>=sp) UNSAFE("bad local #%d (max=%d)"),i,sp-1,ATLOC;
+ break;
+ case SETLOCAL:
+ if (i>=(sp-1)) UNSAFE("bad local #%d (max=%d)"),i,sp-2,ATLOC;
+ break;
+ case ONTJMP:
+ case ONFJMP: /* negate to remember ON?JMP */
+ JP[at]=-jmpok(tf,size,at,i+n);
+ break;
+ case JMP: /* remember JMP targets */
+ case IFFJMP:
+ JP[at]= jmpok(tf,size,at,i+n);
+ break;
+ case IFTUPJMP:
+ case IFFUPJMP:
+ JP[at]= jmpok(tf,size,at,-i+n);
+ break;
+ }
+
+ SP[at]=sp; /* remember depth before instruction */
+
+ switch (op)
+ {
+ case STACK: ss=i; break;
+ case ARGS: CHECK(0,i); break;
+ case VARARGS: break;
+ case ENDCODE: return;
+ case RETCODE: CHECK(i,0); sp=i; break;
+ case CALL: CHECK(OP.arg2+1,i); break;
+ case TAILCALL: CHECK(OP.arg2,0); sp=i; break;
+ case PUSHNIL: CHECK(0,i+1); break;
+ case POP: CHECK(0,-i); break;
+ case PUSHNUMBER:
+ case PUSHNUMBERNEG:
+ case PUSHCONSTANT:
+ case PUSHUPVALUE:
+ case PUSHLOCAL:
+ case GETGLOBAL: CHECK(0,1); break;
+ case GETTABLE: CHECK(2,1); break;
+ case GETDOTTED: CHECK(1,1); break;
+ case PUSHSELF: CHECK(1,2); break;
+ case CREATEARRAY: CHECK(0,1); break;
+ case SETLOCAL: CHECK(1,0); break;
+ case SETGLOBAL: CHECK(1,0); break;
+ case SETTABLEPOP: CHECK(3,0); break;
+ case SETTABLE: CHECK(i+3,i+2); break;
+ case SETLIST: CHECK(OP.arg2+1,1); break;
+ case SETMAP: CHECK(2*(i+1)+1,1); break;
+ case NEQOP:
+ case EQOP:
+ case LTOP:
+ case LEOP:
+ case GTOP:
+ case GEOP:
+ case ADDOP:
+ case SUBOP:
+ case MULTOP:
+ case DIVOP:
+ case POWOP:
+ case CONCOP: CHECK(2,1); break;
+ case MINUSOP:
+ case NOTOP: CHECK(1,1); break;
+ case ONTJMP:
+ case ONFJMP:
+ case IFFJMP:
+ case IFTUPJMP:
+ case IFFUPJMP: CHECK(1,0); break;
+ case JMP: break;
+ case CLOSURE: CHECK(OP.arg2,1); break;
+ case SETLINE: break;
+ case LONGARG:
+ longarg=i<<16;
+ if (longarg<0) UNSAFE("longarg overflow"),ATLOC;
+ break;
+ case CHECKSTACK: break;
+ default: /* cannot happen */
+ UNSAFE("cannot test opcode %d [%s]"),OP.op,OP.name,ATLOC;
+ break;
+ }
+ p+=n;
+ }
+}
+
+static void TestJumps(TProtoFunc* tf, int size, int* SP, int* JP)
+{
+ int i;
+ for (i=0; i<size; i++)
+ {
+ int to=JP[i];
+ if (to!=0)
+ {
+ int at=i; /* for ATLOC */
+ int a,b,j;
+ int on=(to<0); /* ON?JMP */
+ if (on) to=-to;
+ a=SP[to];
+ if (a<0)
+ UNSAFE("invalid jump to %d (not an instruction)"),to,ATLOC;
+ for (j=i; SP[++j]<0; ) /* find next instruction */
+ ;
+ b=SP[j]+on;
+ if (a!=b)
+ UNSAFE("stack inconsistency in jump to %d (expected %d, found %d)"),
+ to,a,b,ATLOC;
+ }
+ }
+}
+
+static void TestCode(TProtoFunc* tf)
+{
+ static int* SP=NULL;
+ static int* JP=NULL;
+ int size=luaU_codesize(tf);
+ luaM_reallocvector(SP,size,int); memset(SP,-1,size*sizeof(int));
+ luaM_reallocvector(JP,size,int); memset(JP, 0,size*sizeof(int));
+ TestStack(tf,size,SP,JP);
+ TestJumps(tf,size,SP,JP);
+}
+
+#undef AT
+#define AT "locvars[%d]"
+static void TestLocals(TProtoFunc* tf)
+{
+ LocVar* v;
+ int l=1;
+ int d=0;
+ if (tf->locvars==NULL) return;
+ for (v=tf->locvars; v->line>=0; v++)
+ {
+ int at=v-tf->locvars; /* for ATLOC */
+ if (l>v->line)
+ UNSAFE("bad line number %d; expected at least %d"),v->line,l,ATLOC;
+ l=v->line;
+ if (v->varname==NULL)
+ {
+ if (--d<0) UNSAFE("no scope to close"),ATLOC;
+ }
+ else
+ ++d;
+ }
+}
+
+static void TestFunction(TProtoFunc* tf);
+
+static void TestConstants(TProtoFunc* tf)
+{
+ int i,n=tf->nconsts;
+ for (i=0; i<n; i++)
+ {
+ TObject* o=tf->consts+i;
+ switch (ttype(o))
+ {
+ case LUA_T_NUMBER:
+ break;
+ case LUA_T_STRING:
+ break;
+ case LUA_T_PROTO:
+ TestFunction(tfvalue(o));
+ break;
+ case LUA_T_NIL:
+ break;
+ default: /* cannot happen */
+ luaU_badconstant("print",i,o,tf);
+ break;
+ }
+ }
+}
+
+static void TestFunction(TProtoFunc* tf)
+{
+ TestCode(tf);
+ TestLocals(tf);
+ TestConstants(tf);
+}
+
+void luaU_testchunk(TProtoFunc* Main)
+{
+ TestFunction(Main);
+}