From 3afe85b2ce9ffdc8eca819ddc1c05414701606fd Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 14 Feb 2000 14:51:08 -0200 Subject: [PATCH] new version for INSTRUCTION formats --- lobject.h | 16 ++- lopcodes.h | 147 ++++++++++-------------- lparser.c | 332 ++++++++++++++++++++--------------------------------- lvm.c | 235 ++++++++++++++++--------------------- 4 files changed, 295 insertions(+), 435 deletions(-) diff --git a/lobject.h b/lobject.h index a325d235..0236aac8 100644 --- a/lobject.h +++ b/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 1.45 2000/01/28 16:53:00 roberto Exp roberto $ +** $Id: lobject.h,v 1.46 2000/02/11 16:52:54 roberto Exp roberto $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -36,11 +36,14 @@ #define LUA_NUM_TYPE double #endif - typedef LUA_NUM_TYPE real; -#define Byte lua_Byte /* some systems have Byte as a predefined type */ -typedef unsigned char Byte; /* unsigned 8 bits */ + +/* +** type for virtual-machine instructions +** must be an unsigned with 4 bytes (see details in lopcodes.h) +*/ +typedef unsigned long Instruction; #define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */ @@ -157,9 +160,12 @@ typedef struct TProtoFunc { int nknum; /* size of `knum' */ struct TProtoFunc **kproto; /* functions defined inside the function */ int nkproto; /* size of `kproto' */ - Byte *code; /* ends with opcode ENDCODE */ + Instruction *code; /* ends with opcode ENDCODE */ int lineDefined; TaggedString *source; + short numparams; + short is_vararg; + short maxstacksize; struct LocVar *locvars; /* ends with line = -1 */ } TProtoFunc; diff --git a/lopcodes.h b/lopcodes.h index 6da468f5..2094b2d3 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.38 2000/01/28 16:53:00 roberto Exp roberto $ +** $Id: lopcodes.h,v 1.39 2000/02/11 16:52:54 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -8,67 +8,79 @@ #define lopcodes_h + +/*=========================================================================== + We assume that instructions are unsigned numbers with 4 bytes. + All instructions have an opcode in the lower byte. Moreover, + an instruction can have 0, 1, or 2 arguments. There are 4 types of + Instructions: + type 0: no arguments + type 1: 1 unsigned argument in the higher 24 bits (called `U') + type 2: 1 signed argument in the higher 24 bits (`S') + type 3: 1st unsigned argument in the higher 16 bits (`A') + 2nd unsigned argument in the middle 8 bits (`B') + + The signed argument is represented in excess 2^23; that is, the real value + is 2^23 minus the usigned value. +===========================================================================*/ + /* -** NOTICE: variants of the same opcode must be consecutive: First, those -** with word parameter, then with byte parameter. +** the following macros help to manipulate instructions */ +#define MAXARG_U ((1<<24)-1) +#define MAXARG_S ((1<<23)-1) +#define MAXARG_A ((1<<16)-1) +#define MAXARG_B ((1<<8)-1) + +#define GET_OPCODE(i) ((OpCode)((i)&0xFF)) +#define GETARG_U(i) ((int)((i)>>8)) +#define GETARG_S(i) ((int)((i)>>8)-(1<<23)) +#define GETARG_A(i) ((int)((i)>>16)) +#define GETARG_B(i) ((int)(((i)>>8) & 0xFF)) + +#define SET_OPCODE(i,o) (((i)&0xFFFFFF00u) | (Instruction)(o)) +#define SETARG_U(i,u) (((i)&0x000000FFu) | ((Instruction)(u)<<8)) +#define SETARG_S(i,s) (((i)&0x000000FFu) | ((Instruction)((s)+(1<<23))<<8)) +#define SETARG_A(i,a) (((i)&0x0000FFFFu) | ((Instruction)(a)<<16)) +#define SETARG_B(i,b) (((i)&0xFFFF00FFu) | ((Instruction)(b)<<8)) + + typedef enum { /* name parm before after side effect -----------------------------------------------------------------------------*/ ENDCODE,/* - - (return) */ -RETCODE,/* b - (return) */ +RETCODE,/* U - (return) */ -CALL,/* b c v_n-v_1 f(at c) r_b-r_1 f(v1,...,v_n) */ +CALL,/* A B v_n-v_1 f(at a) r_b-r_1 f(v1,...,v_n) */ +TAILCALL,/* A B v_a-v_1 f (return) f(v1,...,v_a) */ -TAILCALL,/* b c v_c-v_1 f (return) f(v1,...,v_c) */ +PUSHNIL,/* U - nil_0-nil_u */ +POP,/* U a_u-a_1 - */ -PUSHNIL,/* b - nil_0-nil_b */ -POP,/* b a_b-a_1 - */ +PUSHINT,/* S - (real)s */ +PUSHSTRING,/* U - KSTR[u] */ +PUSHNUMBER,/* U - KNUM[u] */ -PUSHINTW,/* w - (float)w */ -PUSHINT,/* b - (float)b */ +PUSHUPVALUE,/* U - Closure[u] */ -PUSHINTNEGW,/* w - (float)-w */ -PUSHINTNEG,/* b - (float)-b */ - -PUSHSTRINGW,/* w - KSTR[w] */ -PUSHSTRING,/* b - KSTR[b] */ -PUSHNUMBERW,/* w - KNUM[w] */ -PUSHNUMBER,/* b - KNUM[b] */ - -PUSHUPVALUE,/* b - Closure[b] */ - -PUSHLOCAL,/* b - LOC[b] */ - -GETGLOBALW,/* w - VAR[CNST[w]] */ -GETGLOBAL,/* b - VAR[CNST[b]] */ +PUSHLOCAL,/* U - LOC[u] */ +GETGLOBAL,/* U - VAR[CNST[u]] */ GETTABLE,/* - i t t[i] */ +GETDOTTED,/* U t t[CNST[u]] */ +PUSHSELF,/* U t t t[CNST[u]] */ -GETDOTTEDW,/* w t t[CNST[w]] */ -GETDOTTED,/* b t t[CNST[b]] */ - -PUSHSELFW,/* w t t t[CNST[w]] */ -PUSHSELF,/* b t t t[CNST[b]] */ - -CREATEARRAYW,/* w - newarray(size = w) */ -CREATEARRAY,/* b - newarray(size = b) */ - -SETLOCAL,/* b x - LOC[b]=x */ - -SETGLOBALW,/* w x - VAR[CNST[w]]=x */ -SETGLOBAL,/* b x - VAR[CNST[b]]=x */ +CREATETABLE,/* U - newarray(size = u) */ +SETLOCAL,/* U x - LOC[u]=x */ +SETGLOBAL,/* U x - VAR[CNST[u]]=x */ SETTABLEPOP,/* - v i t - t[i]=v */ +SETTABLE,/* U v a_u-a_1 i t a_u-a_1 i t t[i]=v */ -SETTABLE,/* b v a_b-a_1 i t a_b-a_1 i t t[i]=v */ - -SETLISTW,/* w c v_c-v_1 t t t[i+w*FPF]=v_i */ -SETLIST,/* b c v_c-v_1 t t t[i+b*FPF]=v_i */ - -SETMAP,/* b v_b k_b - v_0 k_0 t t t[k_i]=v_i */ +SETLIST,/* A B v_b-v_0 t t t[i+a*FPF]=v_i */ +SETMAP,/* U v_u k_u - v_0 k_0 t t t[k_i]=v_i */ NEQOP,/* - y x (x~=y)? 1 : nil */ EQOP,/* - y x (x==y)? 1 : nil */ @@ -85,54 +97,21 @@ CONCOP,/* - y x x..y */ MINUSOP,/* - x -x */ NOTOP,/* - x (x==nil)? 1 : nil */ -ONTJMPW,/* w x (x!=nil)? x : - (x!=nil)? PC+=w */ -ONTJMP,/* b x (x!=nil)? x : - (x!=nil)? PC+=b */ -ONFJMPW,/* w x (x==nil)? x : - (x==nil)? PC+=w */ -ONFJMP,/* b x (x==nil)? x : - (x==nil)? PC+=b */ -JMPW,/* w - - PC+=w */ -JMP,/* b - - PC+=b */ -IFFJMPW,/* w x - (x==nil)? PC+=w */ -IFFJMP,/* b x - (x==nil)? PC+=b */ -IFTUPJMPW,/* w x - (x!=nil)? PC-=w */ -IFTUPJMP,/* b x - (x!=nil)? PC-=b */ -IFFUPJMPW,/* w x - (x==nil)? PC-=w */ -IFFUPJMP,/* b x - (x==nil)? PC-=b */ +ONTJMP,/* S x (x!=nil)? x : - (x!=nil)? PC+=s */ +ONFJMP,/* S x (x==nil)? x : - (x==nil)? PC+=s */ +JMP,/* S - - PC+=s */ +IFTJMP,/* S x - (x!=nil)? PC+=s */ +IFFJMP,/* S x - (x==nil)? PC+=s */ -CLOSUREW,/* w c v_c-v_1 closure(CNST[w], v_c-v_1) */ -CLOSURE,/* b c v_c-v_1 closure(CNST[b], v_c-v_1) */ +CLOSURE,/* A B v_b-v_1 closure(CNST[a], v_b-v_1) */ -SETLINEW,/* w - - LINE=w */ -SETLINE,/* b - - LINE=b */ - -LONGARGW,/* w (add w*(1<<16) to arg of next instruction) */ -LONGARG /* b (add b*(1<<16) to arg of next instruction) */ +SETLINE/* U - - LINE=u */ } OpCode; #define RFIELDS_PER_FLUSH 32 /* records (SETMAP) */ -#define LFIELDS_PER_FLUSH 64 /* FPF - lists (SETLIST) */ - -#define ZEROVARARG 128 - - -/* maximum value of an arg of 3 bytes; must fit in an "int" */ -#if MAX_INT < (1<<24) -#define MAX_ARG MAX_INT -#else -#define MAX_ARG ((1<<24)-1) -#endif - -/* maximum value of a word of 2 bytes; cannot be larger than MAX_ARG */ -#if MAX_ARG < (1<<16) -#define MAX_WORD MAX_ARG -#else -#define MAX_WORD ((1<<16)-1) -#endif - - -/* maximum value of a byte */ -#define MAX_BYTE ((1<<8)-1) +#define LFIELDS_PER_FLUSH 64 /* FPF - lists (SETLIST) (locvars (-1 if no debug information) */ @@ -131,89 +127,63 @@ static void checklimit (LexState *ls, int val, int limit, const char *msg) { } -static void check_pc (LexState *ls, int n) { - luaM_growvector(ls->L, ls->fs->f->code, ls->fs->pc, n, - Byte, codeEM, MAX_INT); +static int code_instruction (LexState *ls, Instruction i) { + FuncState *fs = ls->fs; + luaM_growvector(ls->L, fs->f->code, fs->pc, 1, Instruction, codeEM, MAXARG_S); + fs->f->code[fs->pc] = i; + return fs->pc++; } -static void code_byte (LexState *ls, Byte c) { - check_pc(ls, 1); - ls->fs->f->code[ls->fs->pc++] = c; +static void fix_jump (LexState *ls, int pc, int dest) { + Instruction *jmp = &ls->fs->f->code[pc]; + /* jump is relative to position following jump instruction */ + *jmp = SETARG_S(*jmp, dest-(pc+1)); } static void deltastack (LexState *ls, int delta) { FuncState *fs = ls->fs; fs->stacksize += delta; - if (fs->stacksize > fs->maxstacksize) { - if (fs->stacksize > MAX_BYTE) - luaY_error(ls, "function or expression too complex"); - fs->maxstacksize = fs->stacksize; + if (delta > 0 && fs->stacksize > fs->f->maxstacksize) { + fs->f->maxstacksize = fs->stacksize; } } -static void code_oparg_at (LexState *ls, int pc, OpCode op, - int arg, int delta) { - Byte *code = ls->fs->f->code; +static int aux_code (LexState *ls, OpCode op, Instruction i, int delta) { deltastack(ls, delta); - if (arg <= MAX_BYTE) { - code[pc] = (Byte)op; - code[pc+1] = (Byte)arg; - } - else if (arg > MAX_ARG) - luaY_error(ls, "code too long"); - else { /* MAX_BYTE < arg < MAX_ARG */ - if (arg > MAX_WORD) { - code[pc] = (Byte)LONGARG; - code[pc+1] = (Byte)(arg>>16); - pc += 2; - } - code[pc] = (Byte)(op-1); /* opcode for word argument */ - code[pc+1] = (Byte)((arg&0xFFFF)>>8); - code[pc+2] = (Byte)(arg&0xFF); - } + return code_instruction(ls, SET_OPCODE(i, op)); } -static int codesize (int arg) { - if (arg <= MAX_BYTE) return 2; /* opcode + 1 byte */ - else if (arg <= MAX_WORD) return 3; /* opcode + 1 word (2 bytes) */ - else return 5; /* LONGARG + 1 byte + opcode + 1 word (2 bytes) */ +static int code_0 (LexState *ls, OpCode op, int delta) { + return aux_code(ls, op, 0, delta); } -static int fix_opcode (LexState *ls, int pc, OpCode op, int arg) { - int tomove = codesize(arg)-2; - if (tomove > 0) { /* need to open space? */ - FuncState *fs = ls->fs; - TProtoFunc *f = fs->f; - check_pc(ls, tomove); - luaO_memup(f->code+pc+tomove, f->code+pc, fs->pc-pc); - fs->pc += tomove; - } - code_oparg_at(ls, pc, op, arg, 0); - return tomove; + +static int code_U (LexState *ls, OpCode op, int u, int delta) { + Instruction i = SETARG_U(0, u); + return aux_code(ls, op, i, delta); } -static void code_oparg (LexState *ls, OpCode op, int arg, int delta) { - int size = codesize(arg); - check_pc(ls, size); - code_oparg_at(ls, ls->fs->pc, op, arg, delta); - ls->fs->pc += size; +static int code_S (LexState *ls, OpCode op, int s, int delta) { + Instruction i = SETARG_S(0, s); + return aux_code(ls, op, i, delta); } -static void code_opcode (LexState *ls, OpCode op, int delta) { - deltastack(ls, delta); - code_byte(ls, (Byte)op); +static int code_AB (LexState *ls, OpCode op, int a, int b, int delta) { + Instruction i = SETARG_A(0, a); + i = SETARG_B(i, b); + return aux_code(ls, op, i, delta); } static void code_kstr (LexState *ls, int c) { - code_oparg(ls, PUSHSTRING, c, 1); + code_U(ls, PUSHSTRING, c, 1); } @@ -226,8 +196,8 @@ static int string_constant (LexState *ls, FuncState *fs, TaggedString *s) { TProtoFunc *f = fs->f; int c = s->constindex; if (c >= f->nkstr || f->kstr[c] != s) { - luaM_growvector(ls->L, f->kstr, f->nkstr, 1, - TaggedString *, constantEM, MAX_ARG); + luaM_growvector(ls->L, f->kstr, f->nkstr, 1, TaggedString *, + constantEM, MAXARG_U); c = f->nkstr++; f->kstr[c] = s; s->constindex = c; /* hint for next time */ @@ -250,8 +220,7 @@ static int real_constant (LexState *ls, real r) { while (--c >= lim) if (f->knum[c] == r) return c; /* not found; create a new entry */ - luaM_growvector(ls->L, f->knum, f->nknum, 1, - real, constantEM, MAX_ARG); + luaM_growvector(ls->L, f->knum, f->nknum, 1, real, constantEM, MAXARG_U); c = f->nknum++; f->knum[c] = r; return c; @@ -259,27 +228,10 @@ static int real_constant (LexState *ls, real r) { static void code_number (LexState *ls, real f) { - real af = (f<0) ? -f : f; - if (0 <= af && af <= (real)MAX_WORD && (int)af == af) { - /* abs(f) has a short integer value */ - code_oparg(ls, (f<0) ? PUSHINTNEG : PUSHINT, (int)af, 1); - } + if ((real)(-MAXARG_S) <= f && f <= (real)MAXARG_S && (int)f == f) + code_S(ls, PUSHINT, (int)f, 1); /* f has a short integer value */ else - code_oparg(ls, PUSHNUMBER, real_constant(ls, f), 1); -} - - -static void flush_record (LexState *ls, int n) { - if (n > 0) - code_oparg(ls, SETMAP, n-1, -2*n); -} - - -static void flush_list (LexState *ls, int m, int n) { - if (n > 0) { - code_oparg(ls, SETLIST, m, -n); - code_byte(ls, (Byte)n); - } + code_U(ls, PUSHNUMBER, real_constant(ls, f), 1); } @@ -371,14 +323,14 @@ static void pushupvalue (LexState *ls, TaggedString *n) { luaX_syntaxerror(ls, "cannot access upvalue in main", n->str); if (aux_localname(ls->fs, n) >= 0) luaX_syntaxerror(ls, "cannot access an upvalue in current scope", n->str); - code_oparg(ls, PUSHUPVALUE, indexupvalue(ls, n), 1); + code_U(ls, PUSHUPVALUE, indexupvalue(ls, n), 1); } static void check_debugline (LexState *ls) { if (ls->L->debug && ls->linenumber != ls->fs->lastsetline) { - code_oparg(ls, SETLINE, ls->linenumber, 0); + code_U(ls, SETLINE, ls->linenumber, 0); ls->fs->lastsetline = ls->linenumber; } } @@ -386,16 +338,16 @@ static void check_debugline (LexState *ls) { static void adjuststack (LexState *ls, int n) { if (n > 0) - code_oparg(ls, POP, n, -n); + code_U(ls, POP, n, -n); else if (n < 0) - code_oparg(ls, PUSHNIL, (-n)-1, -n); + code_U(ls, PUSHNIL, (-n)-1, -n); } static void close_exp (LexState *ls, int pc, int nresults) { if (pc > 0) { /* expression is an open function call? */ - Byte *code = ls->fs->f->code; - code[pc-1] = (Byte)nresults; /* set nresults */ + Instruction *i = &ls->fs->f->code[pc]; + *i = SETARG_B(*i, nresults); /* set nresults */ if (nresults != MULT_RET) deltastack(ls, nresults); /* push results */ } @@ -426,13 +378,12 @@ static void code_args (LexState *ls, int nparams, int dots) { FuncState *fs = ls->fs; adjustlocalvars(ls, nparams, 0); checklimit(ls, fs->nlocalvar, MAXPARAMS, "parameters"); - nparams = fs->nlocalvar; - if (!dots) { - fs->f->code[1] = (Byte)nparams; /* fill-in arg information */ + nparams = fs->nlocalvar; /* `self' could be there already */ + fs->f->numparams = nparams; + fs->f->is_vararg = dots; + if (!dots) deltastack(ls, nparams); - } else { - fs->f->code[1] = (Byte)(nparams+ZEROVARARG); deltastack(ls, nparams+1); add_localvar(ls, luaS_newfixed(ls->L, "arg")); } @@ -451,17 +402,17 @@ static void unloaddot (LexState *ls, vardesc *v) { static void lua_pushvar (LexState *ls, vardesc *var) { switch (var->k) { case VLOCAL: - code_oparg(ls, PUSHLOCAL, var->info, 1); + code_U(ls, PUSHLOCAL, var->info, 1); break; case VGLOBAL: - code_oparg(ls, GETGLOBAL, var->info, 1); + code_U(ls, GETGLOBAL, var->info, 1); assertglobal(ls, var->info); /* make sure that there is a global */ break; case VDOT: - code_oparg(ls, GETDOTTED, var->info, 0); + code_U(ls, GETDOTTED, var->info, 0); break; case VINDEXED: - code_opcode(ls, GETTABLE, -1); + code_0(ls, GETTABLE, -1); break; case VEXP: close_exp(ls, var->info, 1); /* function must return 1 value */ @@ -475,14 +426,14 @@ static void lua_pushvar (LexState *ls, vardesc *var) { static void storevar (LexState *ls, const vardesc *var) { switch (var->k) { case VLOCAL: - code_oparg(ls, SETLOCAL, var->info, -1); + code_U(ls, SETLOCAL, var->info, -1); break; case VGLOBAL: - code_oparg(ls, SETGLOBAL, var->info, -1); + code_U(ls, SETGLOBAL, var->info, -1); assertglobal(ls, var->info); /* make sure that there is a global */ break; case VINDEXED: - code_opcode(ls, SETTABLEPOP, -3); + code_0(ls, SETTABLEPOP, -3); break; default: LUA_INTERNALERROR(ls->L, "invalid var kind to store"); @@ -490,43 +441,16 @@ static void storevar (LexState *ls, const vardesc *var) { } -static int fix_jump (LexState *ls, int pc, OpCode op, int n) { - /* jump is relative to position following jump instruction */ - return fix_opcode(ls, pc, op, n-(pc+JMPSIZE)); -} - - -static void fix_upjmp (LexState *ls, OpCode op, int pos) { - int delta = ls->fs->pc+JMPSIZE - pos; /* jump is relative */ - code_oparg(ls, op, delta+(codesize(delta)-2), 0); -} - - -static void codeIf (LexState *ls, int thenAdd, int elseAdd) { - FuncState *fs = ls->fs; - int elseinit = elseAdd+JMPSIZE; - if (fs->pc == elseinit) { /* no else part? */ - fs->pc -= JMPSIZE; - elseinit = fs->pc; - } - else - elseinit += fix_jump(ls, elseAdd, JMP, fs->pc); - fix_jump(ls, thenAdd, IFFJMP, elseinit); -} - - static void func_onstack (LexState *ls, FuncState *func) { - FuncState *fs = ls->fs; - TProtoFunc *f = fs->f; + TProtoFunc *f = ls->fs->f; int i; - luaM_growvector(ls->L, f->kproto, f->nkproto, 1, - TProtoFunc *, constantEM, MAX_ARG); - f->kproto[f->nkproto] = func->f; for (i=0; inupvalues; i++) lua_pushvar(ls, &func->upvalues[i]); + luaM_growvector(ls->L, f->kproto, f->nkproto, 1, TProtoFunc *, + constantEM, MAXARG_A); + f->kproto[f->nkproto++] = func->f; deltastack(ls, 1); /* CLOSURE puts one extra element (before popping) */ - code_oparg(ls, CLOSURE, f->nkproto++, -func->nupvalues); - code_byte(ls, (Byte)func->nupvalues); + code_AB(ls, CLOSURE, f->nkproto-1, func->nupvalues, -func->nupvalues); } @@ -536,7 +460,6 @@ static void init_state (LexState *ls, FuncState *fs, TaggedString *source) { fs->prev = ls->fs; /* linked list of funcstates */ ls->fs = fs; fs->stacksize = 0; - fs->maxstacksize = 0; fs->nlocalvar = 0; fs->nupvalues = 0; fs->lastsetline = 0; @@ -544,9 +467,10 @@ static void init_state (LexState *ls, FuncState *fs, TaggedString *source) { f->source = source; fs->pc = 0; f->code = NULL; + f->maxstacksize = 0; + f->numparams = 0; /* default for main chunk */ + f->is_vararg = 0; /* default for main chunk */ fs->nvars = (L->debug) ? 0 : -1; /* flag no debug information? */ - code_byte(ls, 0); /* to be filled with maxstacksize */ - code_byte(ls, 0); /* to be filled with arg information */ /* push function (to avoid GC) */ tfvalue(L->top) = f; ttype(L->top) = LUA_T_LPROTO; @@ -557,9 +481,8 @@ static void init_state (LexState *ls, FuncState *fs, TaggedString *source) { static void close_func (LexState *ls) { FuncState *fs = ls->fs; TProtoFunc *f = fs->f; - code_opcode(ls, ENDCODE, 0); - f->code[0] = (Byte)fs->maxstacksize; - luaM_reallocvector(ls->L, f->code, fs->pc, Byte); + code_0(ls, ENDCODE, 0); + luaM_reallocvector(ls->L, f->code, fs->pc, Instruction); luaM_reallocvector(ls->L, f->kstr, f->nkstr, TaggedString *); luaM_reallocvector(ls->L, f->knum, f->nknum, real); luaM_reallocvector(ls->L, f->kproto, f->nkproto, TProtoFunc *); @@ -662,28 +585,6 @@ TProtoFunc *luaY_parser (lua_State *L, ZIO *z) { /*============================================================*/ - -static int SaveWord (LexState *ls) { - int res = ls->fs->pc; - check_pc(ls, JMPSIZE); - ls->fs->pc += JMPSIZE; /* open space */ - return res; -} - - -static int SaveWordPop (LexState *ls) { - deltastack(ls, -1); /* pop condition */ - return SaveWord(ls); -} - - -static int cond (LexState *ls) { - /* cond -> exp1 */ - exp1(ls); - return SaveWordPop(ls); -} - - static void explist1 (LexState *ls, listdesc *d) { vardesc v; expr(ls, &v); @@ -744,11 +645,8 @@ static int funcparams (LexState *ls, int slf) { luaY_error(ls, "function arguments expected"); break; } - code_byte(ls, CALL); - code_byte(ls, 0); /* save space for nresult */ - code_byte(ls, (Byte)slevel); fs->stacksize = slevel; /* call will remove func and params */ - return fs->pc-1; + return code_AB(ls, CALL, slevel, 0, 0); } @@ -775,7 +673,7 @@ static void var_or_func_tail (LexState *ls, vardesc *v) { next(ls); name = checkname(ls); lua_pushvar(ls, v); /* `v' must be on stack */ - code_oparg(ls, PUSHSELF, name, 1); + code_U(ls, PUSHSELF, name, 1); v->k = VEXP; v->info = funcparams(ls, 1); break; @@ -836,16 +734,20 @@ static void recfield (LexState *ls) { static int recfields (LexState *ls) { /* recfields -> { ',' recfield } [','] */ int n = 1; /* one has been read before */ + int mod_n = 1; /* mod_n == n%RFIELDS_PER_FLUSH */ while (ls->token == ',') { next(ls); if (ls->token == ';' || ls->token == '}') break; recfield(ls); n++; - if (n%RFIELDS_PER_FLUSH == 0) - flush_record(ls, RFIELDS_PER_FLUSH); + if (++mod_n == RFIELDS_PER_FLUSH) { + code_U(ls, SETMAP, RFIELDS_PER_FLUSH-1, -2*RFIELDS_PER_FLUSH); + mod_n = 0; + } } - flush_record(ls, n%RFIELDS_PER_FLUSH); + if (mod_n) + code_U(ls, SETMAP, mod_n-1, -2*mod_n); return n; } @@ -853,16 +755,23 @@ static int recfields (LexState *ls) { static int listfields (LexState *ls) { /* listfields -> { ',' exp1 } [','] */ int n = 1; /* one has been read before */ + int mod_n = 1; /* mod_n == n%LFIELDS_PER_FLUSH */ while (ls->token == ',') { next(ls); if (ls->token == ';' || ls->token == '}') break; exp1(ls); n++; - if (n%LFIELDS_PER_FLUSH == 0) - flush_list(ls, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH); + checklimit(ls, n, MAXARG_A*LFIELDS_PER_FLUSH, + "items in a list initializer"); + if (++mod_n == LFIELDS_PER_FLUSH) { + code_AB(ls, SETLIST, n/LFIELDS_PER_FLUSH - 1, LFIELDS_PER_FLUSH-1, + -LFIELDS_PER_FLUSH); + mod_n = 0; + } } - flush_list(ls, n/LFIELDS_PER_FLUSH, n%LFIELDS_PER_FLUSH); + if (mod_n > 0) + code_AB(ls, SETLIST, n/LFIELDS_PER_FLUSH, mod_n-1, -mod_n); return n; } @@ -920,10 +829,9 @@ static void constructor_part (LexState *ls, constdesc *cd) { static void constructor (LexState *ls) { /* constructor -> '{' constructor_part [';' constructor_part] '}' */ int line = ls->linenumber; - int pc = SaveWord(ls); + int pc = code_U(ls, CREATETABLE, 0, 1); int nelems; constdesc cd; - deltastack(ls, 1); check(ls, '{'); constructor_part(ls, &cd); nelems = cd.n; @@ -936,7 +844,8 @@ static void constructor (LexState *ls) { nelems += other_cd.n; } check_match(ls, '}', '{', line); - fix_opcode(ls, pc, CREATEARRAY, nelems); + /* set initial table size */ + ls->fs->f->code[pc] = SETARG_U(ls->fs->f->code[pc], nelems); } /* }====================================================================== */ @@ -1009,7 +918,7 @@ static void push (LexState *ls, stack_op *s, int op) { static void pop_to (LexState *ls, stack_op *s, int prio) { int op; while (s->top > 0 && priority[(op=s->ops[s->top-1])] >= prio) { - code_opcode(ls, opcodes[op], optop--; } } @@ -1113,10 +1022,10 @@ static void expr (LexState *ls, vardesc *v) { int pc; lua_pushvar(ls, v); next(ls); - pc = SaveWordPop(ls); + pc = code_S(ls, op, 0, -1); arith_exp(ls, v); lua_pushvar(ls, v); - fix_jump(ls, pc, op, ls->fs->pc); + fix_jump(ls, pc, ls->fs->pc); } } @@ -1167,7 +1076,7 @@ static int assignment (LexState *ls, vardesc *v, int nvars) { storevar(ls, v); } else { /* indexed var with values in between*/ - code_oparg(ls, SETTABLE, left+(nvars-1), -1); + code_U(ls, SETTABLE, left+(nvars-1), -1); left += 2; /* table&index are not popped, because they aren't on top */ } return left; @@ -1175,22 +1084,18 @@ static int assignment (LexState *ls, vardesc *v, int nvars) { static void whilestat (LexState *ls, int line) { - /* whilestat -> WHILE cond DO block END */ + /* whilestat -> WHILE exp1 DO block END */ FuncState *fs = ls->fs; - TProtoFunc *f = fs->f; int while_init = fs->pc; - int cond_end, cond_size; + int j1; next(ls); - cond_end = cond(ls); + exp1(ls); + j1 = code_U(ls, IFFJMP, 0, -1); /* jump to exit loop */ check(ls, DO); block(ls); check_match(ls, END, WHILE, line); - cond_size = cond_end-while_init; - check_pc(ls, cond_size); - memcpy(f->code+fs->pc, f->code+while_init, cond_size); - luaO_memdown(f->code+while_init, f->code+cond_end, fs->pc-while_init); - while_init += JMPSIZE + fix_jump(ls, while_init, JMP, fs->pc-cond_size); - fix_upjmp(ls, IFTUPJMP, while_init); + fix_jump(ls, code_U(ls, JMP, 0, 0), while_init); /* jump to keep loop */ + fix_jump(ls, j1, fs->pc); } @@ -1202,8 +1107,7 @@ static void repeatstat (LexState *ls, int line) { block(ls); check_match(ls, UNTIL, REPEAT, line); exp1(ls); - fix_upjmp(ls, IFFUPJMP, repeat_init); - deltastack(ls, -1); /* pops condition */ + fix_jump(ls, code_U(ls, IFFJMP, 0, -1), repeat_init); } @@ -1295,21 +1199,29 @@ static void namestat (LexState *ls) { static void ifpart (LexState *ls, int line) { /* ifpart -> cond THEN block [ELSE block | ELSEIF ifpart] */ + FuncState *fs = ls->fs; int c; - int e; + int je; next(ls); /* skip IF or ELSEIF */ - c = cond(ls); + exp1(ls); /* cond */ + c = code_U(ls, IFFJMP, 0, -1); /* jump `then' if `cond' is false */ check(ls, THEN); - block(ls); - e = SaveWord(ls); + block(ls); /* `then' part */ + je = code_U(ls, JMP, 0, 0); /* jump `else' part after `then' */ if (ls->token == ELSEIF) ifpart(ls, line); else { if (optional(ls, ELSE)) - block(ls); + block(ls); /* `else' part */ check_match(ls, END, IF, line); } - codeIf(ls, c, e); + if (fs->pc == je+1) { /* `else' part empty? */ + fs->pc--; /* remove last jump */ + je--; /* first jump will be smaller */ + } + else + fix_jump(ls, je, fs->pc); /* fix last jump */ + fix_jump(ls, c, je+1); /* fix first jump to beginning of `else' part */ } @@ -1395,9 +1307,9 @@ static void parlist (LexState *ls) { static void body (LexState *ls, int needself, int line) { /* body -> '(' parlist ')' chunk END */ - FuncState newfs; - init_state(ls, &newfs, ls->fs->f->source); - newfs.f->lineDefined = line; + FuncState new_fs; + init_state(ls, &new_fs, ls->fs->f->source); + new_fs.f->lineDefined = line; check(ls, '('); if (needself) add_localvar(ls, luaS_newfixed(ls->L, "self")); @@ -1406,7 +1318,7 @@ static void body (LexState *ls, int needself, int line) { chunk(ls); check_match(ls, END, FUNCTION, line); close_func(ls); - func_onstack(ls, &newfs); + func_onstack(ls, &new_fs); } @@ -1418,12 +1330,12 @@ static void ret (LexState *ls) { next(ls); explist(ls, &e); if (e.pc > 0) { /* expression is an open function call? */ - Byte *code = ls->fs->f->code; - code[e.pc-2] = TAILCALL; /* instead of a conventional CALL */ - code[e.pc-1] = (Byte)ls->fs->nlocalvar; + Instruction *i = &ls->fs->f->code[e.pc]; + *i = SET_OPCODE(*i, TAILCALL); /* instead of a conventional CALL */ + *i = SETARG_B(*i, ls->fs->nlocalvar); } else - code_oparg(ls, RETCODE, ls->fs->nlocalvar, 0); + code_U(ls, RETCODE, ls->fs->nlocalvar, 0); ls->fs->stacksize = ls->fs->nlocalvar; /* removes all temp values */ optional(ls, ';'); } diff --git a/lvm.c b/lvm.c index f8c46ec0..f1c1ee83 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.85 2000/02/08 16:39:42 roberto Exp roberto $ +** $Id: lvm.c,v 1.86 2000/02/11 16:52:54 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -280,6 +280,11 @@ void luaV_comparison (lua_State *L) { } +#define setbool(o,cond) if (cond) { \ + ttype(o) = LUA_T_NUMBER; nvalue(o) = 1.0; } \ + else ttype(o) = LUA_T_NIL + + void luaV_pack (lua_State *L, StkId firstelem, int nvararg, TObject *tab) { int i; Hash *htab; @@ -313,90 +318,80 @@ static void adjust_varargs (lua_State *L, StkId base, int nfixargs) { StkId luaV_execute (lua_State *L, const Closure *cl, const TProtoFunc *tf, register StkId base) { register StkId top; /* keep top local, for performance */ - register const Byte *pc = tf->code; + register const Instruction *pc = tf->code; TaggedString **kstr = tf->kstr; if (L->callhook) luaD_callHook(L, base-1, L->callhook, "call"); - luaD_checkstack(L, (*pc++)+EXTRA_STACK); - if (*pc < ZEROVARARG) - luaD_adjusttop(L, base, *(pc++)); - else { /* varargs */ - adjust_varargs(L, base, (*pc++)-ZEROVARARG); + luaD_checkstack(L, tf->maxstacksize+EXTRA_STACK); + if (tf->is_vararg) { /* varargs? */ + adjust_varargs(L, base, tf->numparams); luaC_checkGC(L); } + else + luaD_adjusttop(L, base, tf->numparams); top = L->top; for (;;) { - register int aux = 0; - switchentry: - switch ((OpCode)*pc++) { + register Instruction i = *pc++; + switch (GET_OPCODE(i)) { case ENDCODE: return L->top; /* no results */ case RETCODE: L->top = top; - return base+(*pc++); + return base+GETARG_U(i); - case CALL: aux = *pc++; + case CALL: L->top = top; - luaD_call(L, base+(*pc++), aux); + luaD_call(L, base+GETARG_A(i), GETARG_B(i)); top = L->top; break; - case TAILCALL: aux = *pc++; + case TAILCALL: L->top = top; - luaD_call(L, base+(*pc++), MULT_RET); - return base+aux; + luaD_call(L, base+GETARG_A(i), MULT_RET); + return base+GETARG_B(i); - case PUSHNIL: aux = *pc++; + case PUSHNIL: { + register int n = GETARG_U(i); do { ttype(top++) = LUA_T_NIL; - } while (aux--); + } while (n--); + break; + } + + case POP: + top -= GETARG_U(i); break; - case POP: aux = *pc++; - top -= aux; - break; - - case PUSHINTW: aux += highbyte(L, *pc++); - case PUSHINT: aux += *pc++; + case PUSHINT: ttype(top) = LUA_T_NUMBER; - nvalue(top) = aux; + nvalue(top) = (real)GETARG_S(i); top++; break; - case PUSHINTNEGW: aux += highbyte(L, *pc++); - case PUSHINTNEG: aux += *pc++; - ttype(top) = LUA_T_NUMBER; - nvalue(top) = -aux; - top++; - break; - - case PUSHSTRINGW: aux += highbyte(L, *pc++); - case PUSHSTRING: aux += *pc++; + case PUSHSTRING: ttype(top) = LUA_T_STRING; - tsvalue(top) = kstr[aux]; + tsvalue(top) = kstr[GETARG_U(i)]; top++; break; - case PUSHNUMBERW: aux += highbyte(L, *pc++); - case PUSHNUMBER: aux += *pc++; + case PUSHNUMBER: ttype(top) = LUA_T_NUMBER; - nvalue(top) = tf->knum[aux]; + nvalue(top) = tf->knum[GETARG_U(i)]; top++; break; - case PUSHUPVALUE: aux = *pc++; - *top++ = cl->consts[aux+1]; + case PUSHUPVALUE: + *top++ = cl->consts[GETARG_U(i)+1]; break; - case PUSHLOCAL: aux = *pc++; - *top++ = *(base+aux); + case PUSHLOCAL: + *top++ = *(base+GETARG_U(i)); break; - case GETGLOBALW: aux += highbyte(L, *pc++); - case GETGLOBAL: aux += *pc++; - luaV_getglobal(L, kstr[aux]->u.s.gv, top); + case GETGLOBAL: + luaV_getglobal(L, kstr[GETARG_U(i)]->u.s.gv, top); top++; break; @@ -405,41 +400,37 @@ StkId luaV_execute (lua_State *L, const Closure *cl, const TProtoFunc *tf, top--; break; - case GETDOTTEDW: aux += highbyte(L, *pc++); - case GETDOTTED: aux += *pc++; + case GETDOTTED: ttype(top) = LUA_T_STRING; - tsvalue(top++) = kstr[aux]; + tsvalue(top++) = kstr[GETARG_U(i)]; luaV_gettable(L, top); top--; break; - case PUSHSELFW: aux += highbyte(L, *pc++); - case PUSHSELF: aux += *pc++; { + case PUSHSELF: { TObject receiver; receiver = *(top-1); ttype(top) = LUA_T_STRING; - tsvalue(top++) = kstr[aux]; + tsvalue(top++) = kstr[GETARG_U(i)]; luaV_gettable(L, top); *(top-1) = receiver; break; } - case CREATEARRAYW: aux += highbyte(L, *pc++); - case CREATEARRAY: aux += *pc++; + case CREATETABLE: L->top = top; luaC_checkGC(L); - avalue(top) = luaH_new(L, aux); + avalue(top) = luaH_new(L, GETARG_U(i)); ttype(top) = LUA_T_ARRAY; top++; break; - case SETLOCAL: aux = *pc++; - *(base+aux) = *(--top); + case SETLOCAL: + *(base+GETARG_U(i)) = *(--top); break; - case SETGLOBALW: aux += highbyte(L, *pc++); - case SETGLOBAL: aux += *pc++; - luaV_setglobal(L, kstr[aux]->u.s.gv, top); + case SETGLOBAL: + luaV_setglobal(L, kstr[GETARG_U(i)]->u.s.gv, top); top--; break; @@ -449,91 +440,81 @@ StkId luaV_execute (lua_State *L, const Closure *cl, const TProtoFunc *tf, break; case SETTABLE: - luaV_settable(L, top-3-(*pc++), top); + luaV_settable(L, top-3-GETARG_U(i), top); top--; /* pop value */ break; - case SETLISTW: aux += highbyte(L, *pc++); - case SETLIST: aux += *pc++; { - int n = *(pc++); + case SETLIST: { + int aux = GETARG_A(i) * LFIELDS_PER_FLUSH; + int n = GETARG_B(i)+1; Hash *arr = avalue(top-n-1); L->top = top-n; /* final value of `top' (in case of errors) */ - aux *= LFIELDS_PER_FLUSH; for (; n; n--) luaH_setint(L, arr, n+aux, --top); break; } - case SETMAP: aux = *pc++; { - StkId finaltop = top-2*(aux+1); + case SETMAP: { + int n = GETARG_U(i); + StkId finaltop = top-2*(n+1); Hash *arr = avalue(finaltop-1); L->top = finaltop; /* final value of `top' (in case of errors) */ do { luaH_set(L, arr, top-2, top-1); top-=2; - } while (aux--); + } while (n--); break; } - case NEQOP: aux = 1; + case NEQOP: + top--; + setbool(top-1, !luaO_equalObj(top-1, top)); + break; + case EQOP: top--; - aux = (luaO_equalObj(top-1, top) != aux); - booleanresult: - if (aux) { - ttype(top-1) = LUA_T_NUMBER; - nvalue(top-1) = 1.0; - } - else ttype(top-1) = LUA_T_NIL; + setbool(top-1, luaO_equalObj(top-1, top)); break; case LTOP: top--; if (ttype(top-1) == LUA_T_NUMBER && ttype(top) == LUA_T_NUMBER) - aux = nvalue(top-1) < nvalue(top); + setbool(top-1, nvalue(top-1) < nvalue(top)); else if (ttype(top-1) == LUA_T_STRING && ttype(top) == LUA_T_STRING) - aux = luaV_strcomp(tsvalue(top-1), tsvalue(top)) < 0; - else { + setbool(top-1, luaV_strcomp(tsvalue(top-1), tsvalue(top)) < 0); + else call_binTM(L, top+1, IM_LT, "unexpected type in comparison"); - break; - } - goto booleanresult; + break; case LEOP: top--; if (ttype(top-1) == LUA_T_NUMBER && ttype(top) == LUA_T_NUMBER) - aux = nvalue(top-1) <= nvalue(top); + setbool(top-1, nvalue(top-1) <= nvalue(top)); else if (ttype(top-1) == LUA_T_STRING && ttype(top) == LUA_T_STRING) - aux = luaV_strcomp(tsvalue(top-1), tsvalue(top)) <= 0; - else { + setbool(top-1, luaV_strcomp(tsvalue(top-1), tsvalue(top)) <= 0); + else call_binTM(L, top+1, IM_LE, "unexpected type in comparison"); - break; - } - goto booleanresult; + break; case GTOP: top--; if (ttype(top-1) == LUA_T_NUMBER && ttype(top) == LUA_T_NUMBER) - aux = nvalue(top-1) > nvalue(top); + setbool(top-1, nvalue(top-1) > nvalue(top)); else if (ttype(top-1) == LUA_T_STRING && ttype(top) == LUA_T_STRING) - aux = luaV_strcomp(tsvalue(top-1), tsvalue(top)) > 0; - else { + setbool(top-1, luaV_strcomp(tsvalue(top-1), tsvalue(top)) > 0); + else call_binTM(L, top+1, IM_GT, "unexpected type in comparison"); - break; - } - goto booleanresult; + break; case GEOP: top--; if (ttype(top-1) == LUA_T_NUMBER && ttype(top) == LUA_T_NUMBER) - aux = nvalue(top-1) >= nvalue(top); + setbool(top-1, nvalue(top-1) >= nvalue(top)); else if (ttype(top-1) == LUA_T_STRING && ttype(top) == LUA_T_STRING) - aux = luaV_strcomp(tsvalue(top-1), tsvalue(top)) >= 0; - else { + setbool(top-1, luaV_strcomp(tsvalue(top-1), tsvalue(top)) >= 0); + else call_binTM(L, top+1, IM_GE, "unexpected type in comparison"); - break; - } - goto booleanresult; + break; case ADDOP: if (tonumber(top-1) || tonumber(top-2)) @@ -597,71 +578,53 @@ StkId luaV_execute (lua_State *L, const Closure *cl, const TProtoFunc *tf, nvalue(top-1) = 1; break; - case ONTJMPW: aux += highbyte(L, *pc++); - case ONTJMP: aux += *pc++; - if (ttype(top-1) != LUA_T_NIL) pc += aux; + case ONTJMP: + if (ttype(top-1) != LUA_T_NIL) pc += GETARG_S(i); else top--; break; - case ONFJMPW: aux += highbyte(L, *pc++); - case ONFJMP: aux += *pc++; - if (ttype(top-1) == LUA_T_NIL) pc += aux; + case ONFJMP: + if (ttype(top-1) == LUA_T_NIL) pc += GETARG_S(i); else top--; break; - case JMPW: aux += highbyte(L, *pc++); - case JMP: aux += *pc++; - pc += aux; + case JMP: + pc += GETARG_S(i); break; - case IFFJMPW: aux += highbyte(L, *pc++); - case IFFJMP: aux += *pc++; - if (ttype(--top) == LUA_T_NIL) pc += aux; + case IFTJMP: + if (ttype(--top) != LUA_T_NIL) pc += GETARG_S(i); break; - case IFTUPJMPW: aux += highbyte(L, *pc++); - case IFTUPJMP: aux += *pc++; - if (ttype(--top) != LUA_T_NIL) pc -= aux; + case IFFJMP: + if (ttype(--top) == LUA_T_NIL) pc += GETARG_S(i); break; - case IFFUPJMPW: aux += highbyte(L, *pc++); - case IFFUPJMP: aux += *pc++; - if (ttype(--top) == LUA_T_NIL) pc -= aux; - break; - - case CLOSUREW: aux += highbyte(L, *pc++); - case CLOSURE: aux += *pc++; + case CLOSURE: ttype(top) = LUA_T_LPROTO; - tfvalue(top) = tf->kproto[aux]; + tfvalue(top) = tf->kproto[GETARG_A(i)]; L->top = ++top; - aux = *pc++; /* number of upvalues */ - luaV_closure(L, aux); + luaV_closure(L, GETARG_B(i)); + top -= GETARG_B(i); luaC_checkGC(L); - top -= aux; break; - case SETLINEW: aux += highbyte(L, *pc++); - case SETLINE: aux += *pc++; + case SETLINE: if ((base-1)->ttype != LUA_T_LINE) { /* open space for LINE value */ - int i = top-base; - while (i--) base[i+1] = base[i]; + int n = top-base; + while (n--) base[n+1] = base[n]; base++; top++; (base-1)->ttype = LUA_T_LINE; } - (base-1)->value.i = aux; + (base-1)->value.i = GETARG_U(i); if (L->linehook) { L->top = top; - luaD_lineHook(L, base-2, aux); + luaD_lineHook(L, base-2, GETARG_U(i)); } break; - case LONGARGW: aux += highbyte(L, *pc++); - case LONGARG: aux += *pc++; - aux = highbyte(L, highbyte(L, aux)); - goto switchentry; /* do not reset `aux' */ - } } }