Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
diff --git a/src/ldblib.c b/src/ldblib.c
index 786f6cd..4d35e71 100644
--- a/src/ldblib.c
+++ b/src/ldblib.c
@@ -428,6 +428,60 @@ static int db_traceback (lua_State *L) {
}
+/* LUA_HALT { */
+static void haltf(lua_State *L, lua_Debug *ar) {
+ int oldTop = lua_gettop(L);
+ lua_getglobal(L, "__halt__");
+ if (lua_isfunction(L, -1))
+ {
+ lua_call(L, 0, 0);
+ lua_settop(L, oldTop);
+ }
+ else
+ {
+ lua_settop(L, oldTop);
+ luaL_error(L, "halt handler not found: _G.__halt__");
+ }
+}
+
+static int db_sethalt(lua_State *L) {
+ int lineNumber = luaL_checkinteger(L, 2);
+ int offset;
+ const char* chunkName;
+ luaL_checktype(L, 1, LUA_TSTRING);
+ chunkName = lua_tostring(L, 1);
+
+ offset = lua_sethalt(L, chunkName, lineNumber, haltf);
+ if (offset > 0) {
+ lua_pushinteger(L, offset);
+ }
+ else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int db_clearhalt(lua_State *L) {
+ const char* chunkName;
+ luaL_checktype(L, 1, LUA_TSTRING);
+ chunkName = lua_tostring(L, 1);
+
+ lua_clearhalt(L, chunkName);
+ return 0;
+}
+
+static int db_gethalts(lua_State *L) {
+ lua_gethalts(L);
+ return 1;
+}
+
+static int db_getchunknames(lua_State* L) {
+ lua_getchunknames(L);
+ return 1;
+}
+/* LUA_HALT } */
+
static const luaL_Reg dblib[] = {
{"debug", db_debug},
{"getuservalue", db_getuservalue},
@@ -445,6 +499,12 @@ static const luaL_Reg dblib[] = {
{"setmetatable", db_setmetatable},
{"setupvalue", db_setupvalue},
{"traceback", db_traceback},
+ /* LUA_HALT { */
+ {"sethalt", db_sethalt },
+ {"clearhalt", db_clearhalt },
+ {"gethalts", db_gethalts },
+ {"getchunknames", db_getchunknames },
+/* LUA_HALT } */
{NULL, NULL}
};
diff --git a/src/ldebug.c b/src/ldebug.c
index 239affb..b959569 100644
--- a/src/ldebug.c
+++ b/src/ldebug.c
@@ -665,6 +665,14 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
void luaG_traceexec (lua_State *L) {
CallInfo *ci = L->ci;
lu_byte mask = L->hookmask;
+
+ /* LUA_HALT { */
+ if (mask & LUA_MASKHALT) {
+ luaD_hook(L, LUA_HOOKHALT, -1);
+ return;
+ }
+ /* LUA_HALT } */
+
int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
if (counthook)
resethookcount(L); /* reset count */
@@ -696,3 +704,250 @@ void luaG_traceexec (lua_State *L) {
}
}
+
+/* LUA_HALT { */
+static int isvalidoffset(lua_State *L, Proto *p, int offset) {
+ return offset >= 0 && offset < p->sizecode;
+}
+
+static int findhalt(lua_State *L, Proto *p, int offset) {
+ Instruction i;
+ lua_assert(isvalidoffset(L, p, offset));
+
+ i = p->code[offset];
+ if (GET_OPCODE(i) == OP_HALT) {
+ lua_assert(offset == p->halts[GETARG_Bx(i)].offset);
+ return GETARG_Bx(i);
+ }
+ else {
+ return -1;
+ }
+}
+
+static int realinstr(lua_State *L, Proto *p, int offset) {
+ int h = findhalt(L, p, offset);
+
+ if (h < 0) {
+ return p->code[offset];
+ }
+ else {
+ return p->halts[h].orig;
+ }
+}
+
+static int clearhalt(lua_State *L, Proto *p, int offset) {
+ int existing = findhalt(L, p, offset);
+ if (existing >= 0) {
+ lua_assert(p->sizehalts > existing);
+ p->code[offset] = p->halts[existing].orig;
+ if (existing != p->sizehalts - 1) {
+ p->halts[existing] = p->halts[p->sizehalts - 1];
+ p->code[p->halts[existing].offset] = CREATE_ABx(OP_HALT, 0, existing);
+ }
+
+ luaM_reallocvector(L, p->halts, p->sizehalts, p->sizehalts - 1, Halt);
+ p->sizehalts = p->sizehalts - 1;
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static int closurecovers(lua_State *L, Proto *p, int ci, int offset) {
+ Proto *cp;
+ Instruction i;
+ i = realinstr(L, p, ci);
+ lua_assert(GET_OPCODE(i) == OP_CLOSURE);
+ lua_assert(GETARG_Bx(i) < p->sizep);
+ cp = p->p[GETARG_Bx(i)]; // the proto of the closure
+
+ return offset - ci <= cp->sizeupvalues; // true if offset is a pseudo of ci
+}
+
+static int avoidpseudo(lua_State *L, Proto *p, int offset) {
+ Instruction i = p->code[offset];
+ Instruction pr;
+ int ci;
+
+ if (offset > 0) {
+ pr = realinstr(L, p, offset - 1);
+
+ if (GET_OPCODE(i) == OP_JMP) {
+ // a JMP opcode following a conditional is a pseudo instruction that
+ // will never be hit and cannot be safely patched (in lvm.c, these
+ // opcode handlers look ahead and assume a JMP follows them)
+ switch (GET_OPCODE(pr)) {
+ case OP_EQ:
+ case OP_LT:
+ case OP_LE:
+ case OP_TEST:
+ case OP_TESTSET:
+ case OP_TFORLOOP:
+ return offset - 1;
+ default:
+ return offset; // bare JMP, which is fine.
+ }
+ }
+ else if (GET_OPCODE(pr) == OP_SETLIST && GETARG_C(pr) == 0) {
+ // a SETLIST with a C of 0 treats the next opcode as a raw int
+ // to do very large batch settable operations, which means that
+ // "opcode" should not be patched, obviously.
+ return offset - 1;
+ }
+ else if (GET_OPCODE(i) == OP_MOVE || GET_OPCODE(i) == OP_GETUPVAL) {
+ // Scan through OP_MOVE and OP_GETUPVAL instructions for
+ // an OP_CLOSURE instruction that implies they are pseudo.
+ for (ci = offset - 1; ci >= 0; ci--) {
+ pr = realinstr(L, p, ci);
+ switch (GET_OPCODE(pr)) {
+ case OP_CLOSURE:
+ // use the offset of the closure if the intended offset is
+ // one of the pseudo instructions used to bind upvalues.
+ return closurecovers(L, p, ci, offset) ? ci : offset;
+ case OP_MOVE:
+ case OP_GETUPVAL:
+ continue;
+ case OP_HALT:
+ lua_assert(0); // realinstr above should make this impossible
+ break;
+ default:
+ return offset;
+ }
+ }
+ }
+ }
+
+ return offset;
+}
+
+static int sethalt(lua_State *L, Proto *p, int offset, int lineNumber, lua_Hook hook) {
+ int existing;
+ lua_assert(hook != NULL);
+
+ offset = avoidpseudo(L, p, offset);
+
+ existing = findhalt(L, p, offset);
+
+ if (existing < 0) {
+ if (p->sizehalts > MAXARG_Bx) {
+ return -1;
+ }
+ luaM_reallocvector(L, p->halts, p->sizehalts, p->sizehalts + 1, Halt);
+ existing = p->sizehalts;
+ p->sizehalts = p->sizehalts + 1;
+ p->halts[existing].orig = p->code[offset];
+ p->halts[existing].offset = offset;
+ p->halts[existing].lineNumber = lineNumber;
+ p->code[offset] = CREATE_ABx(OP_HALT, 0, existing);
+ }
+ else {
+ lua_assert(p->sizehalts > existing);
+ }
+
+ p->halts[existing].hook = hook;
+
+ return offset;
+}
+
+static int getoffsetforchunkname(Proto* p, const char *chunkName, int lineNumber)
+{
+ int i;
+
+ if (p == NULL || p->source == NULL)
+ return 0;
+
+ if (p->lastlinedefined != 0 && (p->linedefined > lineNumber || p->lastlinedefined < lineNumber)) {
+ return 0;
+ }
+ if (strcmp(getstr(p->source), chunkName) != 0) {
+ return 0;
+ }
+ for (i = 0; i < p->sizelineinfo; i++) {
+ if (p->lineinfo[i] == lineNumber) {
+ return i + 1;
+ }
+ if (p->lineinfo[i] > lineNumber) {
+ break;
+ }
+ }
+ return 0;
+}
+
+LUA_API int lua_setprotohalt(lua_State *L, Proto* p, const char* chunkName, int lineNumber, lua_Hook hook) {
+ int offset = getoffsetforchunkname(p, chunkName, lineNumber);
+
+ if (!offset)
+ return 0;
+
+ offset = sethalt(L, p, offset - 1, lineNumber, hook);
+ return offset + 1;
+}
+
+LUA_API int lua_sethalt(lua_State *L, const char* chunkName, int lineNumber, lua_Hook hook) {
+ Proto* p = L->l_G->proto_list;
+ while (p)
+ {
+ int offset = lua_setprotohalt(L, p, chunkName, lineNumber, hook);
+ if (offset)
+ return offset;
+ p = p->list_next;
+ }
+ return 0;
+}
+
+LUA_API void lua_clearprotohalt(lua_State *L, Proto* p) {
+ while (p->sizehalts > 0)
+ {
+ int offset = p->halts[p->sizehalts - 1].offset;
+ clearhalt(L, p, offset);
+ }
+}
+
+LUA_API void lua_clearhalt(lua_State *L, const char* chunkName) {
+ Proto* p = L->l_G->proto_list;
+ while (p)
+ {
+ if (strcmp(getstr(p->source), chunkName) == 0)
+ {
+ lua_clearprotohalt(L, p);
+ }
+ p = p->list_next;
+ }
+}
+
+LUA_API void lua_gethalts(lua_State *L) {
+ Proto* p = L->l_G->proto_list;
+ int i;
+ int o = 1;
+
+ lua_newtable(L);
+ while (p)
+ {
+ for (i = 0; i < p->sizehalts; i++) {
+ lua_newtable(L);
+ lua_pushstring(L, getstr(p->source));
+ lua_setfield(L, -2, "s");
+ lua_pushinteger(L, p->halts[i].lineNumber);
+ lua_setfield(L, -2, "l");
+
+ lua_rawseti(L, -2, o++);
+ }
+
+ p = p->list_next;
+ }
+}
+
+LUA_API void lua_getchunknames(lua_State *L) {
+ Proto* p = L->l_G->proto_list;
+
+ lua_newtable(L);
+ while (p)
+ {
+ lua_pushboolean(L, 1);
+ lua_setfield(L, -2, getstr(p->source));
+
+ p = p->list_next;
+ }
+}
+/* LUA_HALT } */
diff --git a/src/ldo.c b/src/ldo.c
index 90b695f..1901a42 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -500,6 +500,10 @@ void luaD_call (lua_State *L, StkId func, int nResults) {
L->nCcalls--;
}
+/* LUA_HALT { */
+// note: duplicated in lvm.c due to dependency tangle (below requires lopcodes.h and lobject.h)
+#define GET_REAL_INSTR(i,p) (GET_OPCODE(i) == OP_HALT ? (p->halts[GETARG_Bx(i)].orig) : (i))
+/* LUA_HALT } */
/*
** Similar to 'luaD_call', but does not allow yields during the call
diff --git a/src/ldump.c b/src/ldump.c
index 016e300..3c2de58 100644
--- a/src/ldump.c
+++ b/src/ldump.c
@@ -45,7 +45,7 @@ static void DumpBlock (const void *b, size_t size, DumpState *D) {
}
}
-
+#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D)
#define DumpVar(x,D) DumpVector(&x,1,D)
@@ -93,6 +93,53 @@ static void DumpCode (const Proto *f, DumpState *D) {
}
+/* LUA_HALT { */
+static int nexthalt(Halt *halts, int sizehalts, int offset) {
+ int i, ho, nho, nhi; // index, tmp offset, next halt offset, next halt index
+ nho = -1;
+ nhi = -1;
+ for (i = 0; nho != offset && i < sizehalts; i++) {
+ ho = halts[i].offset;
+ if (ho >= offset && (nho == -1 || ho < nho)) {
+ nho = ho;
+ nhi = i;
+ }
+ }
+
+ lua_assert(nho == -1 || nho >= offset);
+ return nhi; // returns the index of the halt (not the offset)
+}
+
+static void DumpCodePatchingHalts(const Proto* f, DumpState* D) {
+ int ci, hi, ho; // codeindex, haltindex, haltoffset
+ DumpInt(f->sizecode, D);
+
+ ci = 0;
+ while (ci < f->sizecode) {
+ // note that the halts array is not sorted, so this routine is n^2 with
+ // the number of breakpoints in the function, betting that will be small
+ // compared to the number of instructions. if the number of breakpoints
+ // were large, it might be worth the complexity to sort it
+ hi = nexthalt(f->halts, f->sizehalts, ci);
+ ho = f->halts[hi].offset;
+ if (ho > ci) {
+ DumpMem(f->code + ci, ho - ci, sizeof(Instruction), D);
+ ci = ho;
+ }
+ if (ho == ci) {
+ DumpVar(f->halts[hi].orig, D);
+ ci++;
+ }
+ else {
+ lua_assert(hi == -1);
+ DumpMem(f->code + ci, f->sizecode - ci, sizeof(Instruction), D);
+ ci = f->sizecode;
+ }
+ }
+}
+/* LUA_HALT } */
+
+
static void DumpFunction(const Proto *f, TString *psource, DumpState *D);
static void DumpConstants (const Proto *f, DumpState *D) {
@@ -174,6 +221,15 @@ static void DumpFunction (const Proto *f, TString *psource, DumpState *D) {
DumpByte(f->is_vararg, D);
DumpByte(f->maxstacksize, D);
DumpCode(f, D);
+ /* LUA_HALT { */
+ // DumpCode(f, D);
+ if (f->sizehalts == 0) {
+ DumpCode(f, D);
+ }
+ else {
+ DumpCodePatchingHalts(f, D);
+ }
+ /* LUA_HALT } */
DumpConstants(f, D);
DumpUpvalues(f, D);
DumpProtos(f, D);
diff --git a/src/lfunc.c b/src/lfunc.c
index 67967da..0521cbe 100644
--- a/src/lfunc.c
+++ b/src/lfunc.c
@@ -95,6 +95,30 @@ void luaF_close (lua_State *L, StkId level) {
}
}
+/* LUA_HALT { */
+/*
+#include <assert.h>
+void check_protolist(global_State* g, Proto* p)
+{
+if (p == NULL) return;
+
+if (p->list_prev == NULL) {
+assert(g->proto_list == p);
+}
+else {
+assert(p->list_prev->list_next == p);
+}
+
+if (p->list_next == NULL) {
+// OK
+}
+else {
+assert(p->list_next->list_prev == p);
+check_protolist(g, p->list_next);
+}
+}
+*/
+/* LUA_HALT } */
Proto *luaF_newproto (lua_State *L) {
GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto));
@@ -118,11 +142,37 @@ Proto *luaF_newproto (lua_State *L) {
f->linedefined = 0;
f->lastlinedefined = 0;
f->source = NULL;
+ /* LUA_HALT { */
+ f->halts = NULL;
+ f->sizehalts = 0;
+ f->list_prev = NULL;
+ f->list_next = L->l_G->proto_list;
+ L->l_G->proto_list = f;
+ if (f->list_next != NULL)
+ {
+ f->list_next->list_prev = f;
+ }
+ //check_protolist(L->l_G, L->l_G->proto_list);
+ /* LUA_HALT } */
return f;
}
void luaF_freeproto (lua_State *L, Proto *f) {
+ /* LUA_HALT { */
+ //check_protolist(L->l_G, f);
+ if (f->list_prev) {
+ f->list_prev->list_next = f->list_next;
+ }
+ else {
+ L->l_G->proto_list = f->list_next;
+ }
+ if (f->list_next) {
+ f->list_next->list_prev = f->list_prev;
+ }
+ //check_protolist(L->l_G, L->l_G->proto_list);
+ luaM_freearray(L, f->halts, f->sizehalts);
+ /* LUA_HALT } */
luaM_freearray(L, f->code, f->sizecode);
luaM_freearray(L, f->p, f->sizep);
luaM_freearray(L, f->k, f->sizek);
diff --git a/src/lgc.c b/src/lgc.c
index ba2c19e..f41ac77 100644
--- a/src/lgc.c
+++ b/src/lgc.c
@@ -480,7 +480,7 @@ static int traverseproto (global_State *g, Proto *f) {
int i;
if (f->cache && iswhite(f->cache))
f->cache = NULL; /* allow cache to be collected */
- markobjectN(g, f->source);
+ markobjectN(g, f->source);
for (i = 0; i < f->sizek; i++) /* mark literals */
markvalue(g, &f->k[i]);
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
@@ -490,6 +490,7 @@ static int traverseproto (global_State *g, Proto *f) {
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
markobjectN(g, f->locvars[i].varname);
return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
+ sizeof(Halt) * f->sizehalts + /* LUA_HALT */
sizeof(Proto *) * f->sizep +
sizeof(TValue) * f->sizek +
sizeof(int) * f->sizelineinfo +
diff --git a/src/lobject.h b/src/lobject.h
index 3c04228..9498e5e 100644
--- a/src/lobject.h
+++ b/src/lobject.h
@@ -361,6 +361,16 @@ typedef union UUdata {
} UUdata;
+/* LUA_HALT { */
+typedef struct Halt {
+ Instruction orig;
+ int offset;
+ lua_Hook hook;
+ int lineNumber;
+} Halt;
+/* LUA_HALT } */
+
+
/*
** Get the address of memory block inside 'Udata'.
** (Access to 'ttuv_' ensures that value is really a 'Udata'.)
@@ -426,6 +436,12 @@ typedef struct Proto {
struct LClosure *cache; /* last-created closure with this prototype */
TString *source; /* used for debug information */
GCObject *gclist;
+ /* LUA_HALT { */
+ Halt *halts;
+ int sizehalts;
+ struct Proto* list_prev;
+ struct Proto* list_next;
+ /* LUA_HALT } */
} Proto;
diff --git a/src/lopcodes.c b/src/lopcodes.c
index a1cbef8..e705bee 100644
--- a/src/lopcodes.c
+++ b/src/lopcodes.c
@@ -65,6 +65,7 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
"CLOSURE",
"VARARG",
"EXTRAARG",
+ "HALT", /* LUA_HALT */
NULL
};
diff --git a/src/lopcodes.h b/src/lopcodes.h
index bbc4b61..6701299 100644
--- a/src/lopcodes.h
+++ b/src/lopcodes.h
@@ -230,13 +230,19 @@ OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */
OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */
-OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
-} OpCode;
+OP_EXTRAARG,/* Ax extra (larger) argument for previous opcode */
+ /* LUA_HALT { */
+OP_HALT/* A Bx halt and resume using breakpoint Bx */
+/* LUA_HALT } */
-#define NUM_OPCODES (cast(int, OP_EXTRAARG) + 1)
+} OpCode;
+/* LUA_HALT { */
+/*#define NUM_OPCODES (cast(int, OP_VARARG) + 1)*/
+#define NUM_OPCODES (cast(int, OP_HALT) + 1)
+/* LUA_HALT } */
/*===========================================================================
Notes:
diff --git a/src/lstate.c b/src/lstate.c
index 9194ac3..ce284e1 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -328,6 +328,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->gcfinnum = 0;
g->gcpause = LUAI_GCPAUSE;
g->gcstepmul = LUAI_GCMUL;
+ g->proto_list = NULL; /* LUA_HALT */
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
/* memory allocation error: free partial state */
diff --git a/src/lstate.h b/src/lstate.h
index a469466..c70a850 100644
--- a/src/lstate.h
+++ b/src/lstate.h
@@ -151,6 +151,7 @@ typedef struct global_State {
TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
+ Proto* proto_list; /* LUA_HALT */
} global_State;
diff --git a/src/lua.h b/src/lua.h
index 26c0e2d..38d5e7a 100644
--- a/src/lua.h
+++ b/src/lua.h
@@ -405,6 +405,8 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#define LUA_HOOKCOUNT 3
#define LUA_HOOKTAILCALL 4
+#define LUA_HOOKHALT 5 /* LUA_HALT */
+
/*
** Event masks
@@ -414,6 +416,8 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
+#define LUA_MASKHALT (1 << LUA_HOOKHALT) /* LUA_HALT */
+
typedef struct lua_Debug lua_Debug; /* activation record */
@@ -437,6 +441,13 @@ LUA_API lua_Hook (lua_gethook) (lua_State *L);
LUA_API int (lua_gethookmask) (lua_State *L);
LUA_API int (lua_gethookcount) (lua_State *L);
+/* LUA_HALT { */
+LUA_API int (lua_sethalt)(lua_State *L, const char* chunkName, int lineNumber, lua_Hook hook);
+LUA_API void (lua_clearhalt)(lua_State *L, const char* chunkName);
+LUA_API void (lua_gethalts)(lua_State *L);
+LUA_API void (lua_getchunknames)(lua_State *L);
+/* LUA_HALT } */
+
struct lua_Debug {
int event;
diff --git a/src/lvm.c b/src/lvm.c
index 84ade6b..5283903 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -751,12 +751,17 @@ void luaV_finishOp (lua_State *L) {
Protect(L->top = ci->top)); /* restore top */ \
luai_threadyield(L); }
+/* LUA_HALT { */
+// note: duplicated in ldo.c due to dependency tangle (below requires lopcodes.h and lobject.h)
+#define GET_REAL_INSTR(i,p) (GET_OPCODE(i) == OP_HALT ? (p->halts[GETARG_Bx(i)].orig) : (i))
+/* LUA_HALT } */
/* fetch an instruction and prepare its execution */
#define vmfetch() { \
i = *(ci->u.l.savedpc++); \
if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
Protect(luaG_traceexec(L)); \
+ resume: /* LUA_HALT */ \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
lua_assert(base == ci->u.l.base); \
lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
@@ -1314,6 +1319,26 @@ void luaV_execute (lua_State *L) {
lua_assert(0);
vmbreak;
}
+
+ /* LUA_HALT { */
+ vmcase(OP_HALT) {
+ lua_Hook old = L->hook;
+ Halt h = cl->p->halts[GETARG_Bx(i)];
+ L->hookmask |= LUA_MASKHALT;
+ L->hook = h.hook;
+ Protect(luaG_traceexec(L));
+ if (L->hookmask & LUA_MASKHALT)
+ L->hookmask ^= LUA_MASKHALT;
+ if (L->hook == h.hook)
+ L->hook = old;
+ if (L->status == LUA_YIELD) { /* did hook yield? */
+ L->ci->u.l.savedpc = ci->u.l.savedpc - 1;
+ return;
+ }
+ i = h.orig;
+ goto resume;
+ }
+ /* LUA_HALT } */
}
}
}