Browse Source

better error messages

Roberto Ierusalimschy 25 years ago
parent
commit
014a09c509
10 changed files with 230 additions and 104 deletions
  1. 53 55
      lcode.c
  2. 5 2
      lcode.h
  3. 136 12
      ldebug.c
  4. 4 4
      ldebug.h
  5. 4 4
      ldo.c
  6. 2 2
      ldo.h
  7. 4 4
      lobject.h
  8. 4 4
      lparser.c
  9. 2 1
      lparser.h
  10. 16 16
      lvm.c

+ 53 - 55
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 1.38 2000/06/21 18:13:56 roberto Exp roberto $
+** $Id: lcode.c,v 1.39 2000/06/26 19:28:31 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -423,12 +423,9 @@ int luaK_code1 (FuncState *fs, OpCode o, int arg1) {
 }
 
 
-#define VD	100	/* flag for variable delta */
-
-
 int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
   Instruction i = previous_instruction(fs);
-  int delta = luaK_opproperties[o].delta;
+  int delta = luaK_opproperties[o].push - luaK_opproperties[o].pop;
   int optm = 0;  /* 1 when there is an optimization */
   switch (o) {
     case OP_CLOSURE: {
@@ -621,7 +618,7 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
     case iS: i = CREATE_S(o, arg1); break;
     case iAB: i = CREATE_AB(o, arg1, arg2); break;
   }
-  if (fs->f->debug) {
+  if (fs->debug) {
     LexState *ls = fs->ls;
     luaX_checklimit(ls, ls->lastline, MAXARG_U, "lines in a chunk");
     luaM_growvector(fs->L, fs->f->lines, fs->pc, 1, int, "??", MAXARG_U);
@@ -636,53 +633,54 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
 
 
 const struct OpProperties luaK_opproperties[NUM_OPCODES] = {
-  {iO, 0},	/* OP_END */
-  {iU, 0},	/* OP_RETURN */
-  {iAB, 0},	/* OP_CALL */
-  {iAB, 0},	/* OP_TAILCALL */
-  {iU, VD},	/* OP_PUSHNIL */
-  {iU, VD},	/* OP_POP */
-  {iS, 1},	/* OP_PUSHINT */
-  {iU, 1},	/* OP_PUSHSTRING */
-  {iU, 1},	/* OP_PUSHNUM */
-  {iU, 1},	/* OP_PUSHNEGNUM */
-  {iU, 1},	/* OP_PUSHUPVALUE */
-  {iU, 1},	/* OP_GETLOCAL */
-  {iU, 1},	/* OP_GETGLOBAL */
-  {iO, -1},	/* OP_GETTABLE */
-  {iU, 0},	/* OP_GETDOTTED */
-  {iU, 0},	/* OP_GETINDEXED */
-  {iU, 1},	/* OP_PUSHSELF */
-  {iU, 1},	/* OP_CREATETABLE */
-  {iU, -1},	/* OP_SETLOCAL */
-  {iU, -1},	/* OP_SETGLOBAL */
-  {iAB, VD},	/* OP_SETTABLE */
-  {iAB, VD},	/* OP_SETLIST */
-  {iU, VD},	/* OP_SETMAP */
-  {iO, -1},	/* OP_ADD */
-  {iS, 0},	/* OP_ADDI */
-  {iO, -1},	/* OP_SUB */
-  {iO, -1},	/* OP_MULT */
-  {iO, -1},	/* OP_DIV */
-  {iO, -1},	/* OP_POW */
-  {iU, VD},	/* OP_CONCAT */
-  {iO, 0},	/* OP_MINUS */
-  {iO, 0},	/* OP_NOT */
-  {iS, -2},	/* OP_JMPNE */
-  {iS, -2},	/* OP_JMPEQ */
-  {iS, -2},	/* OP_JMPLT */
-  {iS, -2},	/* OP_JMPLE */
-  {iS, -2},	/* OP_JMPGT */
-  {iS, -2},	/* OP_JMPGE */
-  {iS, -1},	/* OP_JMPT */
-  {iS, -1},	/* OP_JMPF */
-  {iS, -1},	/* OP_JMPONT */
-  {iS, -1},	/* OP_JMPONF */
-  {iS, 0},	/* OP_JMP */
-  {iO, 1},	/* OP_PUSHNILJMP */
-  {iS, 0},	/* OP_FORPREP */
-  {iS, -3},	/* OP_FORLOOP */
-  {iS, 3},	/* OP_LFORPREP */
-  {iS, -4},	/* OP_LFORLOOP */
-  {iAB, VD}	/* OP_CLOSURE */
+  {iO, 0, 0},	/* OP_END */
+  {iU, 0, 0},	/* OP_RETURN */
+  {iAB, 0, 0},	/* OP_CALL */
+  {iAB, 0, 0},	/* OP_TAILCALL */
+  {iU, VD, 0},	/* OP_PUSHNIL */
+  {iU, VD, 0},	/* OP_POP */
+  {iS, 1, 0},	/* OP_PUSHINT */
+  {iU, 1, 0},	/* OP_PUSHSTRING */
+  {iU, 1, 0},	/* OP_PUSHNUM */
+  {iU, 1, 0},	/* OP_PUSHNEGNUM */
+  {iU, 1, 0},	/* OP_PUSHUPVALUE */
+  {iU, 1, 0},	/* OP_GETLOCAL */
+  {iU, 1, 0},	/* OP_GETGLOBAL */
+  {iO, 1, 2},	/* OP_GETTABLE */
+  {iU, 1, 1},	/* OP_GETDOTTED */
+  {iU, 1, 1},	/* OP_GETINDEXED */
+  {iU, 2, 1},	/* OP_PUSHSELF */
+  {iU, 1, 0},	/* OP_CREATETABLE */
+  {iU, 0, 1},	/* OP_SETLOCAL */
+  {iU, 0, 1},	/* OP_SETGLOBAL */
+  {iAB, VD, 0},	/* OP_SETTABLE */
+  {iAB, VD, 0},	/* OP_SETLIST */
+  {iU, VD, 0},	/* OP_SETMAP */
+  {iO, 1, 2},	/* OP_ADD */
+  {iS, 1, 1},	/* OP_ADDI */
+  {iO, 1, 2},	/* OP_SUB */
+  {iO, 1, 2},	/* OP_MULT */
+  {iO, 1, 2},	/* OP_DIV */
+  {iO, 1, 2},	/* OP_POW */
+  {iU, VD, 0},	/* OP_CONCAT */
+  {iO, 1, 1},	/* OP_MINUS */
+  {iO, 1, 1},	/* OP_NOT */
+  {iS, 0, 2},	/* OP_JMPNE */
+  {iS, 0, 2},	/* OP_JMPEQ */
+  {iS, 0, 2},	/* OP_JMPLT */
+  {iS, 0, 2},	/* OP_JMPLE */
+  {iS, 0, 2},	/* OP_JMPGT */
+  {iS, 0, 2},	/* OP_JMPGE */
+  {iS, 0, 1},	/* OP_JMPT */
+  {iS, 0, 1},	/* OP_JMPF */
+  {iS, 0, 1},	/* OP_JMPONT */
+  {iS, 0, 1},	/* OP_JMPONF */
+  {iS, 0, 0},	/* OP_JMP */
+  {iO, 1, 0},	/* OP_PUSHNILJMP */
+  {iS, 0, 0},	/* OP_FORPREP */
+  {iS, 0, 3},	/* OP_FORLOOP */
+  {iS, 3, 0},	/* OP_LFORPREP */
+  {iS, 0, 4},	/* OP_LFORLOOP */
+  {iAB, VD, 0}	/* OP_CLOSURE */
 };
+

+ 5 - 2
lcode.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.h,v 1.13 2000/05/22 18:44:46 roberto Exp roberto $
+** $Id: lcode.h,v 1.14 2000/06/16 17:51:40 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -22,9 +22,12 @@
 
 enum Mode {iO, iU, iS, iAB};  /* instruction format */
 
+#define VD	100	/* flag for variable delta */
+
 extern const struct OpProperties {
   char mode;
-  signed char delta;
+  unsigned char push;
+  unsigned char pop;
 } luaK_opproperties[];
 
 

+ 136 - 12
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 1.23 2000/06/12 13:52:05 roberto Exp roberto $
+** $Id: ldebug.c,v 1.24 2000/06/26 19:28:31 roberto Exp roberto $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -13,10 +13,12 @@
 
 #include "lapi.h"
 #include "lauxlib.h"
+#include "lcode.h"
 #include "ldebug.h"
 #include "ldo.h"
 #include "lfunc.h"
 #include "lobject.h"
+#include "lopcodes.h"
 #include "lstate.h"
 #include "ltable.h"
 #include "ltm.h"
@@ -97,6 +99,13 @@ static int lua_nups (StkId f) {
 }
 
 
+static int lua_currentpc (StkId f) {
+  CallInfo *ci = infovalue(f);
+  LUA_ASSERT(L, ttype(f) == TAG_LMARK, "function has no pc");
+  return (*ci->pc - 1) - ci->func->f.l->code;
+}
+
+
 static int lua_currentline (StkId f) {
   if (ttype(f) != TAG_LMARK)
     return -1;  /* only active lua functions have current-line information */
@@ -104,15 +113,11 @@ static int lua_currentline (StkId f) {
     CallInfo *ci = infovalue(f);
     int *lines = ci->func->f.l->lines;
     if (!lines) return -1;  /* no static debug information */
-    else return lines[ci->pc];
+    else return lines[lua_currentpc(f)];
   }
 }
 
 
-static int lua_currentpc (StkId f) {
-  return infovalue(f)->pc;
-}
-
 
 static Proto *getluaproto (StkId f) {
   return (ttype(f) == TAG_LMARK) ?  infovalue(f)->func->f.l : NULL;
@@ -225,17 +230,136 @@ int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
 }
 
 
+/*
+** {======================================================
+** Symbolic Execution
+** =======================================================
+*/
+
+static Instruction luaG_symbexec (const Proto *pt, int lastpc, int stackpos) {
+  int stack[MAXSTACK];  /* stores last instruction that changes each value */
+  const Instruction *code = pt->code;
+  int top = pt->numparams;
+  int pc = 0;
+  if (pt->is_vararg)  /* varargs? */
+    top++;  /* `arg' */
+  while (pc < lastpc) {
+    const Instruction i = code[pc++];
+    switch (GET_OPCODE(i)) {
+      case OP_CALL: {
+        int nresults = GETARG_B(i);
+        if (nresults == MULT_RET) nresults = 1;
+        top = GETARG_A(i);
+        while (nresults--)
+          stack[top++] = pc-1;
+        break;
+      }
+      case OP_PUSHNIL: {
+        int n;
+        for (n=0; n<GETARG_U(i); n++)
+          stack[top++] = pc-1;
+        break;
+      }
+      case OP_POP: {
+        top -= GETARG_U(i);
+        break;
+      }
+      case OP_SETTABLE:
+      case OP_SETLIST: {
+        top -= GETARG_B(i);
+        break;
+      }
+      case OP_SETMAP: {
+        top -= 2*GETARG_U(i);
+        break;
+      }
+      case OP_CONCAT: {
+        top -= GETARG_U(i);
+        stack[top++] = pc-1;
+        break;
+      }
+      case OP_JMPONT:
+      case OP_JMPONF: {
+        int newpc = pc + GETARG_S(i);
+        if (newpc >= lastpc) {
+          stack[top-1] = pc-1;  /* value generated by or-and */
+          pc = newpc;  /* do the jump */
+        }
+        else
+          top--;  /* original code did not jump; condition was false */
+        break;
+      }
+      case OP_PUSHNILJMP: {
+        break;  /* do not `push', to compensate next instruction */
+      }
+      case OP_CLOSURE: {
+        top -= GETARG_B(i);
+        stack[top++] = pc-1;
+        break;
+      }
+      default: {
+        int n;
+        LUA_ASSERT(NULL, luaK_opproperties[GET_OPCODE(i)].push != VD,
+                   "invalid opcode for default");
+        top -= luaK_opproperties[GET_OPCODE(i)].pop;
+        for (n=0; n<luaK_opproperties[GET_OPCODE(i)].push; n++)
+          stack[top++] = pc-1;
+      }
+    }
+  }
+  return code[stack[stackpos]];
+}
+
+
+static const char *getname (lua_State *L, StkId obj, const char **name) {
+  StkId func = aux_stackedfunction(L, 0, obj);
+  if (func == NULL || ttype(func) != TAG_LMARK)
+    return NULL;  /* not a Lua function */
+  else {
+    Proto *p = infovalue(func)->func->f.l;
+    int pc = lua_currentpc(func);
+    int stackpos = obj - (func+1);  /* func+1 == function base */
+    Instruction i = luaG_symbexec(p, pc, stackpos);
+    switch (GET_OPCODE(i)) {
+      case OP_GETGLOBAL: {
+        *name = p->kstr[GETARG_U(i)]->str;
+        return "global";
+      }
+      case OP_GETLOCAL: {
+        *name = luaF_getlocalname(p, GETARG_U(i)+1, pc);
+        return (*name) ? "local" : NULL;
+      }
+      case OP_PUSHSELF:
+      case OP_GETDOTTED: {
+        *name = p->kstr[GETARG_U(i)]->str;
+        return "field";
+      }
+      default:
+        return NULL;  /* no usefull name found */
+    }
+  }
+}
+
+
+/* }====================================================== */
+
 
-static void call_index_error (lua_State *L, TObject *o, const char *v) {
-  luaL_verror(L, "attempt to %.10s a %.10s value", v, lua_type(L, o));
+static void call_index_error (lua_State *L, StkId o, const char *op,
+                              const char *tp) {
+  const char *name;
+  const char *kind = getname(L, o, &name);
+  if (kind)
+    luaL_verror(L, "%s `%s' is not a %s", kind, name, tp);
+  else
+    luaL_verror(L, "attempt to %.10s a %.10s value", op, lua_type(L, o));
 }
 
 
-void luaG_callerror (lua_State *L, TObject *func) {
-  call_index_error(L, func, "call");
+void luaG_callerror (lua_State *L, StkId func) {
+  call_index_error(L, func, "call", "function");
 }
 
 
-void luaG_indexerror (lua_State *L, TObject *t) {
-  call_index_error(L, t, "index");
+void luaG_indexerror (lua_State *L, StkId t) {
+  call_index_error(L, t, "index", "table");
 }

+ 4 - 4
ldebug.h

@@ -1,5 +1,5 @@
 /*
-** $Id: $
+** $Id: ldebug.h,v 1.1 2000/01/14 17:15:44 roberto Exp roberto $
 ** Auxiliary functions from Debug Interface module
 ** See Copyright Notice in lua.h
 */
@@ -8,12 +8,12 @@
 #define ldebug_h
 
 
-#include "lobject.h"
+#include "lstate.h"
 #include "luadebug.h"
 
 
-void luaG_callerror (lua_State *L, TObject *func);
-void luaG_indexerror (lua_State *L, TObject *t);
+void luaG_callerror (lua_State *L, StkId func);
+void luaG_indexerror (lua_State *L, StkId t);
 
 
 #endif

+ 4 - 4
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 1.79 2000/06/16 17:16:34 roberto Exp roberto $
+** $Id: ldo.c,v 1.80 2000/06/26 19:28:31 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -103,7 +103,7 @@ void luaD_openstack (lua_State *L, StkId pos) {
 }
 
 
-void luaD_lineHook (lua_State *L, StkId func, int line) {
+void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook) {
   if (L->allowhooks) {
     lua_Debug ar;
     struct C_Lua_Stack oldCLS = L->Cstack;
@@ -113,7 +113,7 @@ void luaD_lineHook (lua_State *L, StkId func, int line) {
     ar.event = "line";
     ar.currentline = line;
     L->allowhooks = 0;  /* cannot call hooks inside a hook */
-    (*L->linehook)(L, &ar);
+    (*linehook)(L, &ar);
     L->allowhooks = 1;
     L->top = old_top;
     L->Cstack = oldCLS;
@@ -187,7 +187,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) {
     case TAG_LCLOSURE: {
       CallInfo ci;
       ci.func = clvalue(func);
-      ci.pc = 0;
+      ci.line = 0;
       ttype(func) = TAG_LMARK;
       infovalue(func) = &ci;
       if (callhook)

+ 2 - 2
ldo.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.h,v 1.19 2000/03/29 20:19:20 roberto Exp roberto $
+** $Id: ldo.h,v 1.20 2000/04/14 18:12:35 roberto Exp $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -22,7 +22,7 @@
 void luaD_init (lua_State *L, int stacksize);
 void luaD_adjusttop (lua_State *L, StkId base, int extra);
 void luaD_openstack (lua_State *L, StkId pos);
-void luaD_lineHook (lua_State *L, StkId func, int line);
+void luaD_lineHook (lua_State *L, StkId func, int line, lua_Hook linehook);
 void luaD_call (lua_State *L, StkId func, int nResults);
 void luaD_callTM (lua_State *L, const TObject *f, int nParams, int nResults);
 int luaD_protectedrun (lua_State *L);

+ 4 - 4
lobject.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.h,v 1.67 2000/06/08 18:27:13 roberto Exp roberto $
+** $Id: lobject.h,v 1.68 2000/06/26 19:28:31 roberto Exp roberto $
 ** Type definitions for Lua objects
 ** See Copyright Notice in lua.h
 */
@@ -122,7 +122,6 @@ typedef struct Proto {
   int *lines;  /* source line that generated each opcode */
   int lineDefined;
   TString  *source;
-  int debug;  /* flag for debug information */
   int numparams;
   int is_vararg;
   int maxstacksize;
@@ -171,9 +170,10 @@ typedef struct Hash {
 ** informations about a call (for debugging)
 */
 typedef struct CallInfo {
-  int pc;  /* current pc of called function */
-  int line;  /* current line */
   struct Closure *func;  /* function being called */
+  const Instruction **pc;  /* current pc of called function */
+  int lastpc;  /* last pc traced */
+  int line;  /* current line */
 } CallInfo;
 
 

+ 4 - 4
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 1.99 2000/06/26 19:28:31 roberto Exp roberto $
+** $Id: lparser.c,v 1.100 2000/06/28 17:06:07 roberto Exp roberto $
 ** LL(1) Parser and code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -154,7 +154,7 @@ static int checkname (LexState *ls) {
 
 static void luaI_registerlocalvar (LexState *ls, TString *varname, int pc) {
   FuncState *fs = ls->fs;
-  if (fs->f->debug) {
+  if (fs->debug) {
     Proto *f = fs->f;
     luaM_growvector(ls->L, f->locvars, fs->nvars, 1, LocVar, "", MAX_INT);
     f->locvars[fs->nvars].varname = varname;
@@ -359,7 +359,7 @@ Proto *luaY_parser (lua_State *L, ZIO *z) {
   luaX_setinput(L, &lexstate, z, luaS_new(L, zname(z)));
   open_func(&lexstate, &funcstate);
   next(&lexstate);  /* read first token */
-  funcstate.f->debug = L->debug;  /* previous `next' may scan a pragma */
+  funcstate.debug = L->debug;  /* previous `next' may scan a pragma */
   chunk(&lexstate);
   check_condition(&lexstate, (lexstate.t.token == TK_EOS), "<eof> expected");
   close_func(&lexstate);
@@ -1085,7 +1085,7 @@ static void body (LexState *ls, int needself, int line) {
   FuncState new_fs;
   open_func(ls, &new_fs);
   new_fs.f->lineDefined = line;
-  new_fs.f->debug = ls->L->debug;
+  new_fs.debug = ls->L->debug;
   check(ls, '(');
   if (needself) {
     new_localvarstr(ls, "self", 0);

+ 2 - 1
lparser.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.h,v 1.18 2000/06/21 18:13:56 roberto Exp roberto $
+** $Id: lparser.h,v 1.19 2000/06/26 19:28:31 roberto Exp roberto $
 ** LL(1) Parser and code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -47,6 +47,7 @@ typedef struct FuncState {
   int stacklevel;  /* number of values on activation register */
   int nlocalvar;  /* number of active local variables */
   int nupvalues;  /* number of upvalues */
+  int debug;  /* flag for debug information */
   int nvars;  /* number of entries in f->locvars */
   struct Breaklabel *bl;  /* chain of breakable blocks */
   expdesc upvalues[MAXUPVALUES];  /* upvalues */

+ 16 - 16
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 1.117 2000/06/26 19:28:31 roberto Exp roberto $
+** $Id: lvm.c,v 1.118 2000/06/27 19:00:36 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -67,20 +67,19 @@ int luaV_tostring (lua_State *L, TObject *obj) {  /* LUA_NUMBER */
 }
 
 
-static void traceexec (lua_State *L, StkId base, int pc, StkId top) {
+static void traceexec (lua_State *L, StkId base, StkId top, lua_Hook linehook) {
   CallInfo *ci = infovalue(base-1);
-  int oldpc = ci->pc;
-  ci->pc = pc;
-  if (L->linehook && ci->func->f.l->debug) {
-    int *lines = ci->func->f.l->lines;
-    LUA_ASSERT(L, lines, "must have debug information");
-    /* calls linehook when jumps back (loop) or enters a new line */
-    if (pc <= oldpc || lines[pc] != ci->line) {
+  int *lines = ci->func->f.l->lines;
+  int pc = (*ci->pc - 1) - ci->func->f.l->code;
+  if (lines) {
+    /* calls linehook when enters a new line or jumps back (loop) */
+    if (lines[pc] != ci->line || pc <= ci->lastpc) {
       ci->line = lines[pc];
       L->top = top;
-      luaD_lineHook(L, base-2, lines[pc]);
+      luaD_lineHook(L, base-2, lines[pc], linehook);
     }
   }
+  ci->lastpc = pc;
 }
 
 
@@ -113,7 +112,7 @@ void luaV_Lclosure (lua_State *L, Proto *l, int nelems) {
 ** Receives the table at top-2 and the index at top-1.
 */
 void luaV_gettable (lua_State *L, StkId top) {
-  TObject *table = top-2;
+  StkId table = top-2;
   const TObject *im;
   if (ttype(table) != TAG_TABLE) {  /* not a table, get gettable TM */
     im = luaT_getimbyObj(L, table, IM_GETTABLE);
@@ -348,7 +347,8 @@ StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) {
   StkId top;  /* keep top local, for performance */
   const Instruction *pc = tf->code;
   TString **kstr = tf->kstr;
-  int debug = tf->debug;
+  lua_Hook linehook = L->linehook;
+  infovalue(base-1)->pc = &pc;
   luaD_checkstack(L, tf->maxstacksize+EXTRA_STACK);
   if (tf->is_vararg) {  /* varargs? */
     adjust_varargs(L, base, tf->numparams);
@@ -359,9 +359,9 @@ StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) {
   top = L->top;
   /* main loop of interpreter */
   for (;;) {
-    if (debug)
-      traceexec(L, base, pc - tf->code, top);
-   {const Instruction i = *pc++;
+    const Instruction i = *pc++;
+    if (linehook)
+      traceexec(L, base, top, linehook);
     switch (GET_OPCODE(i)) {
 
       case OP_END:
@@ -705,5 +705,5 @@ StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) {
         break;
 
     }
-  }}
+  }
 }