You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2015/07/23 13:14:15 UTC

[18/43] trafficserver git commit: TS-3783 TS-3030 Add luajit v2.0.4 as a subtree

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_frame.h
----------------------------------------------------------------------
diff --git a/lib/luajit/src/lj_frame.h b/lib/luajit/src/lj_frame.h
new file mode 100644
index 0000000..cd57be2
--- /dev/null
+++ b/lib/luajit/src/lj_frame.h
@@ -0,0 +1,183 @@
+/*
+** Stack frames.
+** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#ifndef _LJ_FRAME_H
+#define _LJ_FRAME_H
+
+#include "lj_obj.h"
+#include "lj_bc.h"
+
+/* -- Lua stack frame ----------------------------------------------------- */
+
+/* Frame type markers in callee function slot (callee base-1). */
+enum {
+  FRAME_LUA, FRAME_C, FRAME_CONT, FRAME_VARG,
+  FRAME_LUAP, FRAME_CP, FRAME_PCALL, FRAME_PCALLH
+};
+#define FRAME_TYPE		3
+#define FRAME_P			4
+#define FRAME_TYPEP		(FRAME_TYPE|FRAME_P)
+
+/* Macros to access and modify Lua frames. */
+#define frame_gc(f)		(gcref((f)->fr.func))
+#define frame_func(f)		(&frame_gc(f)->fn)
+#define frame_ftsz(f)		((f)->fr.tp.ftsz)
+
+#define frame_type(f)		(frame_ftsz(f) & FRAME_TYPE)
+#define frame_typep(f)		(frame_ftsz(f) & FRAME_TYPEP)
+#define frame_islua(f)		(frame_type(f) == FRAME_LUA)
+#define frame_isc(f)		(frame_type(f) == FRAME_C)
+#define frame_iscont(f)		(frame_typep(f) == FRAME_CONT)
+#define frame_isvarg(f)		(frame_typep(f) == FRAME_VARG)
+#define frame_ispcall(f)	((frame_ftsz(f) & 6) == FRAME_PCALL)
+
+#define frame_pc(f)		(mref((f)->fr.tp.pcr, const BCIns))
+#define frame_contpc(f)		(frame_pc((f)-1))
+#if LJ_64
+#define frame_contf(f) \
+  ((ASMFunction)(void *)((intptr_t)lj_vm_asm_begin + \
+			 (intptr_t)(int32_t)((f)-1)->u32.lo))
+#else
+#define frame_contf(f)		((ASMFunction)gcrefp(((f)-1)->gcr, void))
+#endif
+#define frame_delta(f)		(frame_ftsz(f) >> 3)
+#define frame_sized(f)		(frame_ftsz(f) & ~FRAME_TYPEP)
+
+#define frame_prevl(f)		((f) - (1+bc_a(frame_pc(f)[-1])))
+#define frame_prevd(f)		((TValue *)((char *)(f) - frame_sized(f)))
+#define frame_prev(f)		(frame_islua(f)?frame_prevl(f):frame_prevd(f))
+/* Note: this macro does not skip over FRAME_VARG. */
+
+#define setframe_pc(f, pc)	(setmref((f)->fr.tp.pcr, (pc)))
+#define setframe_ftsz(f, sz)	((f)->fr.tp.ftsz = (sz))
+#define setframe_gc(f, p)	(setgcref((f)->fr.func, (p)))
+
+/* -- C stack frame ------------------------------------------------------- */
+
+/* Macros to access and modify the C stack frame chain. */
+
+/* These definitions must match with the arch-specific *.dasc files. */
+#if LJ_TARGET_X86
+#define CFRAME_OFS_ERRF		(15*4)
+#define CFRAME_OFS_NRES		(14*4)
+#define CFRAME_OFS_PREV		(13*4)
+#define CFRAME_OFS_L		(12*4)
+#define CFRAME_OFS_PC		(6*4)
+#define CFRAME_OFS_MULTRES	(5*4)
+#define CFRAME_SIZE		(12*4)
+#define CFRAME_SHIFT_MULTRES	0
+#elif LJ_TARGET_X64
+#if LJ_ABI_WIN
+#define CFRAME_OFS_PREV		(13*8)
+#define CFRAME_OFS_PC		(25*4)
+#define CFRAME_OFS_L		(24*4)
+#define CFRAME_OFS_ERRF		(23*4)
+#define CFRAME_OFS_NRES		(22*4)
+#define CFRAME_OFS_MULTRES	(21*4)
+#define CFRAME_SIZE		(10*8)
+#define CFRAME_SIZE_JIT		(CFRAME_SIZE + 9*16 + 4*8)
+#define CFRAME_SHIFT_MULTRES	0
+#else
+#define CFRAME_OFS_PREV		(4*8)
+#define CFRAME_OFS_PC		(7*4)
+#define CFRAME_OFS_L		(6*4)
+#define CFRAME_OFS_ERRF		(5*4)
+#define CFRAME_OFS_NRES		(4*4)
+#define CFRAME_OFS_MULTRES	(1*4)
+#define CFRAME_SIZE		(10*8)
+#define CFRAME_SIZE_JIT		(CFRAME_SIZE + 16)
+#define CFRAME_SHIFT_MULTRES	0
+#endif
+#elif LJ_TARGET_ARM
+#define CFRAME_OFS_ERRF		24
+#define CFRAME_OFS_NRES		20
+#define CFRAME_OFS_PREV		16
+#define CFRAME_OFS_L		12
+#define CFRAME_OFS_PC		8
+#define CFRAME_OFS_MULTRES	4
+#if LJ_ARCH_HASFPU
+#define CFRAME_SIZE		128
+#else
+#define CFRAME_SIZE		64
+#endif
+#define CFRAME_SHIFT_MULTRES	3
+#elif LJ_TARGET_PPC
+#if LJ_TARGET_XBOX360
+#define CFRAME_OFS_ERRF		424
+#define CFRAME_OFS_NRES		420
+#define CFRAME_OFS_PREV		400
+#define CFRAME_OFS_L		416
+#define CFRAME_OFS_PC		412
+#define CFRAME_OFS_MULTRES	408
+#define CFRAME_SIZE		384
+#define CFRAME_SHIFT_MULTRES	3
+#elif LJ_ARCH_PPC64
+#define CFRAME_OFS_ERRF		472
+#define CFRAME_OFS_NRES		468
+#define CFRAME_OFS_PREV		448
+#define CFRAME_OFS_L		464
+#define CFRAME_OFS_PC		460
+#define CFRAME_OFS_MULTRES	456
+#define CFRAME_SIZE		400
+#define CFRAME_SHIFT_MULTRES	3
+#else
+#define CFRAME_OFS_ERRF		48
+#define CFRAME_OFS_NRES		44
+#define CFRAME_OFS_PREV		40
+#define CFRAME_OFS_L		36
+#define CFRAME_OFS_PC		32
+#define CFRAME_OFS_MULTRES	28
+#define CFRAME_SIZE		272
+#define CFRAME_SHIFT_MULTRES	3
+#endif
+#elif LJ_TARGET_PPCSPE
+#define CFRAME_OFS_ERRF		28
+#define CFRAME_OFS_NRES		24
+#define CFRAME_OFS_PREV		20
+#define CFRAME_OFS_L		16
+#define CFRAME_OFS_PC		12
+#define CFRAME_OFS_MULTRES	8
+#define CFRAME_SIZE		184
+#define CFRAME_SHIFT_MULTRES	3
+#elif LJ_TARGET_MIPS
+#define CFRAME_OFS_ERRF		124
+#define CFRAME_OFS_NRES		120
+#define CFRAME_OFS_PREV		116
+#define CFRAME_OFS_L		112
+#define CFRAME_OFS_PC		20
+#define CFRAME_OFS_MULTRES	16
+#define CFRAME_SIZE		112
+#define CFRAME_SHIFT_MULTRES	3
+#else
+#error "Missing CFRAME_* definitions for this architecture"
+#endif
+
+#ifndef CFRAME_SIZE_JIT
+#define CFRAME_SIZE_JIT		CFRAME_SIZE
+#endif
+
+#define CFRAME_RESUME		1
+#define CFRAME_UNWIND_FF	2  /* Only used in unwinder. */
+#define CFRAME_RAWMASK		(~(intptr_t)(CFRAME_RESUME|CFRAME_UNWIND_FF))
+
+#define cframe_errfunc(cf)	(*(int32_t *)(((char *)(cf))+CFRAME_OFS_ERRF))
+#define cframe_nres(cf)		(*(int32_t *)(((char *)(cf))+CFRAME_OFS_NRES))
+#define cframe_prev(cf)		(*(void **)(((char *)(cf))+CFRAME_OFS_PREV))
+#define cframe_multres(cf)  (*(uint32_t *)(((char *)(cf))+CFRAME_OFS_MULTRES))
+#define cframe_multres_n(cf)	(cframe_multres((cf)) >> CFRAME_SHIFT_MULTRES)
+#define cframe_L(cf) \
+  (&gcref(*(GCRef *)(((char *)(cf))+CFRAME_OFS_L))->th)
+#define cframe_pc(cf) \
+  (mref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), const BCIns))
+#define setcframe_L(cf, L) \
+  (setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_L), (L)))
+#define setcframe_pc(cf, pc) \
+  (setmref(*(MRef *)(((char *)(cf))+CFRAME_OFS_PC), (pc)))
+#define cframe_canyield(cf)	((intptr_t)(cf) & CFRAME_RESUME)
+#define cframe_unwind_ff(cf)	((intptr_t)(cf) & CFRAME_UNWIND_FF)
+#define cframe_raw(cf)		((void *)((intptr_t)(cf) & CFRAME_RAWMASK))
+#define cframe_Lpc(L)		cframe_pc(cframe_raw(L->cframe))
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_func.c
----------------------------------------------------------------------
diff --git a/lib/luajit/src/lj_func.c b/lib/luajit/src/lj_func.c
new file mode 100644
index 0000000..eb8a9db
--- /dev/null
+++ b/lib/luajit/src/lj_func.c
@@ -0,0 +1,185 @@
+/*
+** Function handling (prototypes, functions and upvalues).
+** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
+**
+** Portions taken verbatim or adapted from the Lua interpreter.
+** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
+*/
+
+#define lj_func_c
+#define LUA_CORE
+
+#include "lj_obj.h"
+#include "lj_gc.h"
+#include "lj_func.h"
+#include "lj_trace.h"
+#include "lj_vm.h"
+
+/* -- Prototypes ---------------------------------------------------------- */
+
+void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt)
+{
+  lj_mem_free(g, pt, pt->sizept);
+}
+
+/* -- Upvalues ------------------------------------------------------------ */
+
+static void unlinkuv(GCupval *uv)
+{
+  lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv);
+  setgcrefr(uvnext(uv)->prev, uv->prev);
+  setgcrefr(uvprev(uv)->next, uv->next);
+}
+
+/* Find existing open upvalue for a stack slot or create a new one. */
+static GCupval *func_finduv(lua_State *L, TValue *slot)
+{
+  global_State *g = G(L);
+  GCRef *pp = &L->openupval;
+  GCupval *p;
+  GCupval *uv;
+  /* Search the sorted list of open upvalues. */
+  while (gcref(*pp) != NULL && uvval((p = gco2uv(gcref(*pp)))) >= slot) {
+    lua_assert(!p->closed && uvval(p) != &p->tv);
+    if (uvval(p) == slot) {  /* Found open upvalue pointing to same slot? */
+      if (isdead(g, obj2gco(p)))  /* Resurrect it, if it's dead. */
+	flipwhite(obj2gco(p));
+      return p;
+    }
+    pp = &p->nextgc;
+  }
+  /* No matching upvalue found. Create a new one. */
+  uv = lj_mem_newt(L, sizeof(GCupval), GCupval);
+  newwhite(g, uv);
+  uv->gct = ~LJ_TUPVAL;
+  uv->closed = 0;  /* Still open. */
+  setmref(uv->v, slot);  /* Pointing to the stack slot. */
+  /* NOBARRIER: The GCupval is new (marked white) and open. */
+  setgcrefr(uv->nextgc, *pp);  /* Insert into sorted list of open upvalues. */
+  setgcref(*pp, obj2gco(uv));
+  setgcref(uv->prev, obj2gco(&g->uvhead));  /* Insert into GC list, too. */
+  setgcrefr(uv->next, g->uvhead.next);
+  setgcref(uvnext(uv)->prev, obj2gco(uv));
+  setgcref(g->uvhead.next, obj2gco(uv));
+  lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv);
+  return uv;
+}
+
+/* Create an empty and closed upvalue. */
+static GCupval *func_emptyuv(lua_State *L)
+{
+  GCupval *uv = (GCupval *)lj_mem_newgco(L, sizeof(GCupval));
+  uv->gct = ~LJ_TUPVAL;
+  uv->closed = 1;
+  setnilV(&uv->tv);
+  setmref(uv->v, &uv->tv);
+  return uv;
+}
+
+/* Close all open upvalues pointing to some stack level or above. */
+void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level)
+{
+  GCupval *uv;
+  global_State *g = G(L);
+  while (gcref(L->openupval) != NULL &&
+	 uvval((uv = gco2uv(gcref(L->openupval)))) >= level) {
+    GCobj *o = obj2gco(uv);
+    lua_assert(!isblack(o) && !uv->closed && uvval(uv) != &uv->tv);
+    setgcrefr(L->openupval, uv->nextgc);  /* No longer in open list. */
+    if (isdead(g, o)) {
+      lj_func_freeuv(g, uv);
+    } else {
+      unlinkuv(uv);
+      lj_gc_closeuv(g, uv);
+    }
+  }
+}
+
+void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv)
+{
+  if (!uv->closed)
+    unlinkuv(uv);
+  lj_mem_freet(g, uv);
+}
+
+/* -- Functions (closures) ------------------------------------------------ */
+
+GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env)
+{
+  GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeCfunc(nelems));
+  fn->c.gct = ~LJ_TFUNC;
+  fn->c.ffid = FF_C;
+  fn->c.nupvalues = (uint8_t)nelems;
+  /* NOBARRIER: The GCfunc is new (marked white). */
+  setmref(fn->c.pc, &G(L)->bc_cfunc_ext);
+  setgcref(fn->c.env, obj2gco(env));
+  return fn;
+}
+
+static GCfunc *func_newL(lua_State *L, GCproto *pt, GCtab *env)
+{
+  uint32_t count;
+  GCfunc *fn = (GCfunc *)lj_mem_newgco(L, sizeLfunc((MSize)pt->sizeuv));
+  fn->l.gct = ~LJ_TFUNC;
+  fn->l.ffid = FF_LUA;
+  fn->l.nupvalues = 0;  /* Set to zero until upvalues are initialized. */
+  /* NOBARRIER: Really a setgcref. But the GCfunc is new (marked white). */
+  setmref(fn->l.pc, proto_bc(pt));
+  setgcref(fn->l.env, obj2gco(env));
+  /* Saturating 3 bit counter (0..7) for created closures. */
+  count = (uint32_t)pt->flags + PROTO_CLCOUNT;
+  pt->flags = (uint8_t)(count - ((count >> PROTO_CLC_BITS) & PROTO_CLCOUNT));
+  return fn;
+}
+
+/* Create a new Lua function with empty upvalues. */
+GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env)
+{
+  GCfunc *fn = func_newL(L, pt, env);
+  MSize i, nuv = pt->sizeuv;
+  /* NOBARRIER: The GCfunc is new (marked white). */
+  for (i = 0; i < nuv; i++) {
+    GCupval *uv = func_emptyuv(L);
+    uv->dhash = (uint32_t)(uintptr_t)pt ^ ((uint32_t)proto_uv(pt)[i] << 24);
+    setgcref(fn->l.uvptr[i], obj2gco(uv));
+  }
+  fn->l.nupvalues = (uint8_t)nuv;
+  return fn;
+}
+
+/* Do a GC check and create a new Lua function with inherited upvalues. */
+GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent)
+{
+  GCfunc *fn;
+  GCRef *puv;
+  MSize i, nuv;
+  TValue *base;
+  lj_gc_check_fixtop(L);
+  fn = func_newL(L, pt, tabref(parent->env));
+  /* NOBARRIER: The GCfunc is new (marked white). */
+  puv = parent->uvptr;
+  nuv = pt->sizeuv;
+  base = L->base;
+  for (i = 0; i < nuv; i++) {
+    uint32_t v = proto_uv(pt)[i];
+    GCupval *uv;
+    if ((v & PROTO_UV_LOCAL)) {
+      uv = func_finduv(L, base + (v & 0xff));
+      uv->immutable = ((v / PROTO_UV_IMMUTABLE) & 1);
+      uv->dhash = (uint32_t)(uintptr_t)mref(parent->pc, char) ^ (v << 24);
+    } else {
+      uv = &gcref(puv[v])->uv;
+    }
+    setgcref(fn->l.uvptr[i], obj2gco(uv));
+  }
+  fn->l.nupvalues = (uint8_t)nuv;
+  return fn;
+}
+
+void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *fn)
+{
+  MSize size = isluafunc(fn) ? sizeLfunc((MSize)fn->l.nupvalues) :
+			       sizeCfunc((MSize)fn->c.nupvalues);
+  lj_mem_free(g, fn, size);
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_func.h
----------------------------------------------------------------------
diff --git a/lib/luajit/src/lj_func.h b/lib/luajit/src/lj_func.h
new file mode 100644
index 0000000..a6e534e
--- /dev/null
+++ b/lib/luajit/src/lj_func.h
@@ -0,0 +1,24 @@
+/*
+** Function handling (prototypes, functions and upvalues).
+** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#ifndef _LJ_FUNC_H
+#define _LJ_FUNC_H
+
+#include "lj_obj.h"
+
+/* Prototypes. */
+LJ_FUNC void LJ_FASTCALL lj_func_freeproto(global_State *g, GCproto *pt);
+
+/* Upvalues. */
+LJ_FUNCA void LJ_FASTCALL lj_func_closeuv(lua_State *L, TValue *level);
+LJ_FUNC void LJ_FASTCALL lj_func_freeuv(global_State *g, GCupval *uv);
+
+/* Functions (closures). */
+LJ_FUNC GCfunc *lj_func_newC(lua_State *L, MSize nelems, GCtab *env);
+LJ_FUNC GCfunc *lj_func_newL_empty(lua_State *L, GCproto *pt, GCtab *env);
+LJ_FUNCA GCfunc *lj_func_newL_gc(lua_State *L, GCproto *pt, GCfuncL *parent);
+LJ_FUNC void LJ_FASTCALL lj_func_free(global_State *g, GCfunc *c);
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_gc.c
----------------------------------------------------------------------
diff --git a/lib/luajit/src/lj_gc.c b/lib/luajit/src/lj_gc.c
new file mode 100644
index 0000000..b498aba
--- /dev/null
+++ b/lib/luajit/src/lj_gc.c
@@ -0,0 +1,849 @@
+/*
+** Garbage collector.
+** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
+**
+** Major portions taken verbatim or adapted from the Lua interpreter.
+** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
+*/
+
+#define lj_gc_c
+#define LUA_CORE
+
+#include "lj_obj.h"
+#include "lj_gc.h"
+#include "lj_err.h"
+#include "lj_str.h"
+#include "lj_tab.h"
+#include "lj_func.h"
+#include "lj_udata.h"
+#include "lj_meta.h"
+#include "lj_state.h"
+#include "lj_frame.h"
+#if LJ_HASFFI
+#include "lj_ctype.h"
+#include "lj_cdata.h"
+#endif
+#include "lj_trace.h"
+#include "lj_vm.h"
+
+#define GCSTEPSIZE	1024u
+#define GCSWEEPMAX	40
+#define GCSWEEPCOST	10
+#define GCFINALIZECOST	100
+
+/* Macros to set GCobj colors and flags. */
+#define white2gray(x)		((x)->gch.marked &= (uint8_t)~LJ_GC_WHITES)
+#define gray2black(x)		((x)->gch.marked |= LJ_GC_BLACK)
+#define isfinalized(u)		((u)->marked & LJ_GC_FINALIZED)
+
+/* -- Mark phase ---------------------------------------------------------- */
+
+/* Mark a TValue (if needed). */
+#define gc_marktv(g, tv) \
+  { lua_assert(!tvisgcv(tv) || (~itype(tv) == gcval(tv)->gch.gct)); \
+    if (tviswhite(tv)) gc_mark(g, gcV(tv)); }
+
+/* Mark a GCobj (if needed). */
+#define gc_markobj(g, o) \
+  { if (iswhite(obj2gco(o))) gc_mark(g, obj2gco(o)); }
+
+/* Mark a string object. */
+#define gc_mark_str(s)		((s)->marked &= (uint8_t)~LJ_GC_WHITES)
+
+/* Mark a white GCobj. */
+static void gc_mark(global_State *g, GCobj *o)
+{
+  int gct = o->gch.gct;
+  lua_assert(iswhite(o) && !isdead(g, o));
+  white2gray(o);
+  if (LJ_UNLIKELY(gct == ~LJ_TUDATA)) {
+    GCtab *mt = tabref(gco2ud(o)->metatable);
+    gray2black(o);  /* Userdata are never gray. */
+    if (mt) gc_markobj(g, mt);
+    gc_markobj(g, tabref(gco2ud(o)->env));
+  } else if (LJ_UNLIKELY(gct == ~LJ_TUPVAL)) {
+    GCupval *uv = gco2uv(o);
+    gc_marktv(g, uvval(uv));
+    if (uv->closed)
+      gray2black(o);  /* Closed upvalues are never gray. */
+  } else if (gct != ~LJ_TSTR && gct != ~LJ_TCDATA) {
+    lua_assert(gct == ~LJ_TFUNC || gct == ~LJ_TTAB ||
+	       gct == ~LJ_TTHREAD || gct == ~LJ_TPROTO);
+    setgcrefr(o->gch.gclist, g->gc.gray);
+    setgcref(g->gc.gray, o);
+  }
+}
+
+/* Mark GC roots. */
+static void gc_mark_gcroot(global_State *g)
+{
+  ptrdiff_t i;
+  for (i = 0; i < GCROOT_MAX; i++)
+    if (gcref(g->gcroot[i]) != NULL)
+      gc_markobj(g, gcref(g->gcroot[i]));
+}
+
+/* Start a GC cycle and mark the root set. */
+static void gc_mark_start(global_State *g)
+{
+  setgcrefnull(g->gc.gray);
+  setgcrefnull(g->gc.grayagain);
+  setgcrefnull(g->gc.weak);
+  gc_markobj(g, mainthread(g));
+  gc_markobj(g, tabref(mainthread(g)->env));
+  gc_marktv(g, &g->registrytv);
+  gc_mark_gcroot(g);
+  g->gc.state = GCSpropagate;
+}
+
+/* Mark open upvalues. */
+static void gc_mark_uv(global_State *g)
+{
+  GCupval *uv;
+  for (uv = uvnext(&g->uvhead); uv != &g->uvhead; uv = uvnext(uv)) {
+    lua_assert(uvprev(uvnext(uv)) == uv && uvnext(uvprev(uv)) == uv);
+    if (isgray(obj2gco(uv)))
+      gc_marktv(g, uvval(uv));
+  }
+}
+
+/* Mark userdata in mmudata list. */
+static void gc_mark_mmudata(global_State *g)
+{
+  GCobj *root = gcref(g->gc.mmudata);
+  GCobj *u = root;
+  if (u) {
+    do {
+      u = gcnext(u);
+      makewhite(g, u);  /* Could be from previous GC. */
+      gc_mark(g, u);
+    } while (u != root);
+  }
+}
+
+/* Separate userdata objects to be finalized to mmudata list. */
+size_t lj_gc_separateudata(global_State *g, int all)
+{
+  size_t m = 0;
+  GCRef *p = &mainthread(g)->nextgc;
+  GCobj *o;
+  while ((o = gcref(*p)) != NULL) {
+    if (!(iswhite(o) || all) || isfinalized(gco2ud(o))) {
+      p = &o->gch.nextgc;  /* Nothing to do. */
+    } else if (!lj_meta_fastg(g, tabref(gco2ud(o)->metatable), MM_gc)) {
+      markfinalized(o);  /* Done, as there's no __gc metamethod. */
+      p = &o->gch.nextgc;
+    } else {  /* Otherwise move userdata to be finalized to mmudata list. */
+      m += sizeudata(gco2ud(o));
+      markfinalized(o);
+      *p = o->gch.nextgc;
+      if (gcref(g->gc.mmudata)) {  /* Link to end of mmudata list. */
+	GCobj *root = gcref(g->gc.mmudata);
+	setgcrefr(o->gch.nextgc, root->gch.nextgc);
+	setgcref(root->gch.nextgc, o);
+	setgcref(g->gc.mmudata, o);
+      } else {  /* Create circular list. */
+	setgcref(o->gch.nextgc, o);
+	setgcref(g->gc.mmudata, o);
+      }
+    }
+  }
+  return m;
+}
+
+/* -- Propagation phase --------------------------------------------------- */
+
+/* Traverse a table. */
+static int gc_traverse_tab(global_State *g, GCtab *t)
+{
+  int weak = 0;
+  cTValue *mode;
+  GCtab *mt = tabref(t->metatable);
+  if (mt)
+    gc_markobj(g, mt);
+  mode = lj_meta_fastg(g, mt, MM_mode);
+  if (mode && tvisstr(mode)) {  /* Valid __mode field? */
+    const char *modestr = strVdata(mode);
+    int c;
+    while ((c = *modestr++)) {
+      if (c == 'k') weak |= LJ_GC_WEAKKEY;
+      else if (c == 'v') weak |= LJ_GC_WEAKVAL;
+      else if (c == 'K') weak = (int)(~0u & ~LJ_GC_WEAKVAL);
+    }
+    if (weak > 0) {  /* Weak tables are cleared in the atomic phase. */
+      t->marked = (uint8_t)((t->marked & ~LJ_GC_WEAK) | weak);
+      setgcrefr(t->gclist, g->gc.weak);
+      setgcref(g->gc.weak, obj2gco(t));
+    }
+  }
+  if (weak == LJ_GC_WEAK)  /* Nothing to mark if both keys/values are weak. */
+    return 1;
+  if (!(weak & LJ_GC_WEAKVAL)) {  /* Mark array part. */
+    MSize i, asize = t->asize;
+    for (i = 0; i < asize; i++)
+      gc_marktv(g, arrayslot(t, i));
+  }
+  if (t->hmask > 0) {  /* Mark hash part. */
+    Node *node = noderef(t->node);
+    MSize i, hmask = t->hmask;
+    for (i = 0; i <= hmask; i++) {
+      Node *n = &node[i];
+      if (!tvisnil(&n->val)) {  /* Mark non-empty slot. */
+	lua_assert(!tvisnil(&n->key));
+	if (!(weak & LJ_GC_WEAKKEY)) gc_marktv(g, &n->key);
+	if (!(weak & LJ_GC_WEAKVAL)) gc_marktv(g, &n->val);
+      }
+    }
+  }
+  return weak;
+}
+
+/* Traverse a function. */
+static void gc_traverse_func(global_State *g, GCfunc *fn)
+{
+  gc_markobj(g, tabref(fn->c.env));
+  if (isluafunc(fn)) {
+    uint32_t i;
+    lua_assert(fn->l.nupvalues <= funcproto(fn)->sizeuv);
+    gc_markobj(g, funcproto(fn));
+    for (i = 0; i < fn->l.nupvalues; i++)  /* Mark Lua function upvalues. */
+      gc_markobj(g, &gcref(fn->l.uvptr[i])->uv);
+  } else {
+    uint32_t i;
+    for (i = 0; i < fn->c.nupvalues; i++)  /* Mark C function upvalues. */
+      gc_marktv(g, &fn->c.upvalue[i]);
+  }
+}
+
+#if LJ_HASJIT
+/* Mark a trace. */
+static void gc_marktrace(global_State *g, TraceNo traceno)
+{
+  GCobj *o = obj2gco(traceref(G2J(g), traceno));
+  lua_assert(traceno != G2J(g)->cur.traceno);
+  if (iswhite(o)) {
+    white2gray(o);
+    setgcrefr(o->gch.gclist, g->gc.gray);
+    setgcref(g->gc.gray, o);
+  }
+}
+
+/* Traverse a trace. */
+static void gc_traverse_trace(global_State *g, GCtrace *T)
+{
+  IRRef ref;
+  if (T->traceno == 0) return;
+  for (ref = T->nk; ref < REF_TRUE; ref++) {
+    IRIns *ir = &T->ir[ref];
+    if (ir->o == IR_KGC)
+      gc_markobj(g, ir_kgc(ir));
+  }
+  if (T->link) gc_marktrace(g, T->link);
+  if (T->nextroot) gc_marktrace(g, T->nextroot);
+  if (T->nextside) gc_marktrace(g, T->nextside);
+  gc_markobj(g, gcref(T->startpt));
+}
+
+/* The current trace is a GC root while not anchored in the prototype (yet). */
+#define gc_traverse_curtrace(g)	gc_traverse_trace(g, &G2J(g)->cur)
+#else
+#define gc_traverse_curtrace(g)	UNUSED(g)
+#endif
+
+/* Traverse a prototype. */
+static void gc_traverse_proto(global_State *g, GCproto *pt)
+{
+  ptrdiff_t i;
+  gc_mark_str(proto_chunkname(pt));
+  for (i = -(ptrdiff_t)pt->sizekgc; i < 0; i++)  /* Mark collectable consts. */
+    gc_markobj(g, proto_kgc(pt, i));
+#if LJ_HASJIT
+  if (pt->trace) gc_marktrace(g, pt->trace);
+#endif
+}
+
+/* Traverse the frame structure of a stack. */
+static MSize gc_traverse_frames(global_State *g, lua_State *th)
+{
+  TValue *frame, *top = th->top-1, *bot = tvref(th->stack);
+  /* Note: extra vararg frame not skipped, marks function twice (harmless). */
+  for (frame = th->base-1; frame > bot; frame = frame_prev(frame)) {
+    GCfunc *fn = frame_func(frame);
+    TValue *ftop = frame;
+    if (isluafunc(fn)) ftop += funcproto(fn)->framesize;
+    if (ftop > top) top = ftop;
+    gc_markobj(g, fn);  /* Need to mark hidden function (or L). */
+  }
+  top++;  /* Correct bias of -1 (frame == base-1). */
+  if (top > tvref(th->maxstack)) top = tvref(th->maxstack);
+  return (MSize)(top - bot);  /* Return minimum needed stack size. */
+}
+
+/* Traverse a thread object. */
+static void gc_traverse_thread(global_State *g, lua_State *th)
+{
+  TValue *o, *top = th->top;
+  for (o = tvref(th->stack)+1; o < top; o++)
+    gc_marktv(g, o);
+  if (g->gc.state == GCSatomic) {
+    top = tvref(th->stack) + th->stacksize;
+    for (; o < top; o++)  /* Clear unmarked slots. */
+      setnilV(o);
+  }
+  gc_markobj(g, tabref(th->env));
+  lj_state_shrinkstack(th, gc_traverse_frames(g, th));
+}
+
+/* Propagate one gray object. Traverse it and turn it black. */
+static size_t propagatemark(global_State *g)
+{
+  GCobj *o = gcref(g->gc.gray);
+  int gct = o->gch.gct;
+  lua_assert(isgray(o));
+  gray2black(o);
+  setgcrefr(g->gc.gray, o->gch.gclist);  /* Remove from gray list. */
+  if (LJ_LIKELY(gct == ~LJ_TTAB)) {
+    GCtab *t = gco2tab(o);
+    if (gc_traverse_tab(g, t) > 0)
+      black2gray(o);  /* Keep weak tables gray. */
+    return sizeof(GCtab) + sizeof(TValue) * t->asize +
+			   sizeof(Node) * (t->hmask + 1);
+  } else if (LJ_LIKELY(gct == ~LJ_TFUNC)) {
+    GCfunc *fn = gco2func(o);
+    gc_traverse_func(g, fn);
+    return isluafunc(fn) ? sizeLfunc((MSize)fn->l.nupvalues) :
+			   sizeCfunc((MSize)fn->c.nupvalues);
+  } else if (LJ_LIKELY(gct == ~LJ_TPROTO)) {
+    GCproto *pt = gco2pt(o);
+    gc_traverse_proto(g, pt);
+    return pt->sizept;
+  } else if (LJ_LIKELY(gct == ~LJ_TTHREAD)) {
+    lua_State *th = gco2th(o);
+    setgcrefr(th->gclist, g->gc.grayagain);
+    setgcref(g->gc.grayagain, o);
+    black2gray(o);  /* Threads are never black. */
+    gc_traverse_thread(g, th);
+    return sizeof(lua_State) + sizeof(TValue) * th->stacksize;
+  } else {
+#if LJ_HASJIT
+    GCtrace *T = gco2trace(o);
+    gc_traverse_trace(g, T);
+    return ((sizeof(GCtrace)+7)&~7) + (T->nins-T->nk)*sizeof(IRIns) +
+	   T->nsnap*sizeof(SnapShot) + T->nsnapmap*sizeof(SnapEntry);
+#else
+    lua_assert(0);
+    return 0;
+#endif
+  }
+}
+
+/* Propagate all gray objects. */
+static size_t gc_propagate_gray(global_State *g)
+{
+  size_t m = 0;
+  while (gcref(g->gc.gray) != NULL)
+    m += propagatemark(g);
+  return m;
+}
+
+/* -- Sweep phase --------------------------------------------------------- */
+
+/* Try to shrink some common data structures. */
+static void gc_shrink(global_State *g, lua_State *L)
+{
+  if (g->strnum <= (g->strmask >> 2) && g->strmask > LJ_MIN_STRTAB*2-1)
+    lj_str_resize(L, g->strmask >> 1);  /* Shrink string table. */
+  if (g->tmpbuf.sz > LJ_MIN_SBUF*2)
+    lj_str_resizebuf(L, &g->tmpbuf, g->tmpbuf.sz >> 1);  /* Shrink temp buf. */
+}
+
+/* Type of GC free functions. */
+typedef void (LJ_FASTCALL *GCFreeFunc)(global_State *g, GCobj *o);
+
+/* GC free functions for LJ_TSTR .. LJ_TUDATA. ORDER LJ_T */
+static const GCFreeFunc gc_freefunc[] = {
+  (GCFreeFunc)lj_str_free,
+  (GCFreeFunc)lj_func_freeuv,
+  (GCFreeFunc)lj_state_free,
+  (GCFreeFunc)lj_func_freeproto,
+  (GCFreeFunc)lj_func_free,
+#if LJ_HASJIT
+  (GCFreeFunc)lj_trace_free,
+#else
+  (GCFreeFunc)0,
+#endif
+#if LJ_HASFFI
+  (GCFreeFunc)lj_cdata_free,
+#else
+  (GCFreeFunc)0,
+#endif
+  (GCFreeFunc)lj_tab_free,
+  (GCFreeFunc)lj_udata_free
+};
+
+/* Full sweep of a GC list. */
+#define gc_fullsweep(g, p)	gc_sweep(g, (p), LJ_MAX_MEM)
+
+/* Partial sweep of a GC list. */
+static GCRef *gc_sweep(global_State *g, GCRef *p, uint32_t lim)
+{
+  /* Mask with other white and LJ_GC_FIXED. Or LJ_GC_SFIXED on shutdown. */
+  int ow = otherwhite(g);
+  GCobj *o;
+  while ((o = gcref(*p)) != NULL && lim-- > 0) {
+    if (o->gch.gct == ~LJ_TTHREAD)  /* Need to sweep open upvalues, too. */
+      gc_fullsweep(g, &gco2th(o)->openupval);
+    if (((o->gch.marked ^ LJ_GC_WHITES) & ow)) {  /* Black or current white? */
+      lua_assert(!isdead(g, o) || (o->gch.marked & LJ_GC_FIXED));
+      makewhite(g, o);  /* Value is alive, change to the current white. */
+      p = &o->gch.nextgc;
+    } else {  /* Otherwise value is dead, free it. */
+      lua_assert(isdead(g, o) || ow == LJ_GC_SFIXED);
+      setgcrefr(*p, o->gch.nextgc);
+      if (o == gcref(g->gc.root))
+	setgcrefr(g->gc.root, o->gch.nextgc);  /* Adjust list anchor. */
+      gc_freefunc[o->gch.gct - ~LJ_TSTR](g, o);
+    }
+  }
+  return p;
+}
+
+/* Check whether we can clear a key or a value slot from a table. */
+static int gc_mayclear(cTValue *o, int val)
+{
+  if (tvisgcv(o)) {  /* Only collectable objects can be weak references. */
+    if (tvisstr(o)) {  /* But strings cannot be used as weak references. */
+      gc_mark_str(strV(o));  /* And need to be marked. */
+      return 0;
+    }
+    if (iswhite(gcV(o)))
+      return 1;  /* Object is about to be collected. */
+    if (tvisudata(o) && val && isfinalized(udataV(o)))
+      return 1;  /* Finalized userdata is dropped only from values. */
+  }
+  return 0;  /* Cannot clear. */
+}
+
+/* Clear collected entries from weak tables. */
+static void gc_clearweak(GCobj *o)
+{
+  while (o) {
+    GCtab *t = gco2tab(o);
+    lua_assert((t->marked & LJ_GC_WEAK));
+    if ((t->marked & LJ_GC_WEAKVAL)) {
+      MSize i, asize = t->asize;
+      for (i = 0; i < asize; i++) {
+	/* Clear array slot when value is about to be collected. */
+	TValue *tv = arrayslot(t, i);
+	if (gc_mayclear(tv, 1))
+	  setnilV(tv);
+      }
+    }
+    if (t->hmask > 0) {
+      Node *node = noderef(t->node);
+      MSize i, hmask = t->hmask;
+      for (i = 0; i <= hmask; i++) {
+	Node *n = &node[i];
+	/* Clear hash slot when key or value is about to be collected. */
+	if (!tvisnil(&n->val) && (gc_mayclear(&n->key, 0) ||
+				  gc_mayclear(&n->val, 1)))
+	  setnilV(&n->val);
+      }
+    }
+    o = gcref(t->gclist);
+  }
+}
+
+/* Call a userdata or cdata finalizer. */
+static void gc_call_finalizer(global_State *g, lua_State *L,
+			      cTValue *mo, GCobj *o)
+{
+  /* Save and restore lots of state around the __gc callback. */
+  uint8_t oldh = hook_save(g);
+  MSize oldt = g->gc.threshold;
+  int errcode;
+  TValue *top;
+  lj_trace_abort(g);
+  top = L->top;
+  L->top = top+2;
+  hook_entergc(g);  /* Disable hooks and new traces during __gc. */
+  g->gc.threshold = LJ_MAX_MEM;  /* Prevent GC steps. */
+  copyTV(L, top, mo);
+  setgcV(L, top+1, o, ~o->gch.gct);
+  errcode = lj_vm_pcall(L, top+1, 1+0, -1);  /* Stack: |mo|o| -> | */
+  hook_restore(g, oldh);
+  g->gc.threshold = oldt;  /* Restore GC threshold. */
+  if (errcode)
+    lj_err_throw(L, errcode);  /* Propagate errors. */
+}
+
+/* Finalize one userdata or cdata object from the mmudata list. */
+static void gc_finalize(lua_State *L)
+{
+  global_State *g = G(L);
+  GCobj *o = gcnext(gcref(g->gc.mmudata));
+  cTValue *mo;
+  lua_assert(gcref(g->jit_L) == NULL);  /* Must not be called on trace. */
+  /* Unchain from list of userdata to be finalized. */
+  if (o == gcref(g->gc.mmudata))
+    setgcrefnull(g->gc.mmudata);
+  else
+    setgcrefr(gcref(g->gc.mmudata)->gch.nextgc, o->gch.nextgc);
+#if LJ_HASFFI
+  if (o->gch.gct == ~LJ_TCDATA) {
+    TValue tmp, *tv;
+    /* Add cdata back to the GC list and make it white. */
+    setgcrefr(o->gch.nextgc, g->gc.root);
+    setgcref(g->gc.root, o);
+    makewhite(g, o);
+    o->gch.marked &= (uint8_t)~LJ_GC_CDATA_FIN;
+    /* Resolve finalizer. */
+    setcdataV(L, &tmp, gco2cd(o));
+    tv = lj_tab_set(L, ctype_ctsG(g)->finalizer, &tmp);
+    if (!tvisnil(tv)) {
+      g->gc.nocdatafin = 0;
+      copyTV(L, &tmp, tv);
+      setnilV(tv);  /* Clear entry in finalizer table. */
+      gc_call_finalizer(g, L, &tmp, o);
+    }
+    return;
+  }
+#endif
+  /* Add userdata back to the main userdata list and make it white. */
+  setgcrefr(o->gch.nextgc, mainthread(g)->nextgc);
+  setgcref(mainthread(g)->nextgc, o);
+  makewhite(g, o);
+  /* Resolve the __gc metamethod. */
+  mo = lj_meta_fastg(g, tabref(gco2ud(o)->metatable), MM_gc);
+  if (mo)
+    gc_call_finalizer(g, L, mo, o);
+}
+
+/* Finalize all userdata objects from mmudata list. */
+void lj_gc_finalize_udata(lua_State *L)
+{
+  while (gcref(G(L)->gc.mmudata) != NULL)
+    gc_finalize(L);
+}
+
+#if LJ_HASFFI
+/* Finalize all cdata objects from finalizer table. */
+void lj_gc_finalize_cdata(lua_State *L)
+{
+  global_State *g = G(L);
+  CTState *cts = ctype_ctsG(g);
+  if (cts) {
+    GCtab *t = cts->finalizer;
+    Node *node = noderef(t->node);
+    ptrdiff_t i;
+    setgcrefnull(t->metatable);  /* Mark finalizer table as disabled. */
+    for (i = (ptrdiff_t)t->hmask; i >= 0; i--)
+      if (!tvisnil(&node[i].val) && tviscdata(&node[i].key)) {
+	GCobj *o = gcV(&node[i].key);
+	TValue tmp;
+	makewhite(g, o);
+	o->gch.marked &= (uint8_t)~LJ_GC_CDATA_FIN;
+	copyTV(L, &tmp, &node[i].val);
+	setnilV(&node[i].val);
+	gc_call_finalizer(g, L, &tmp, o);
+      }
+  }
+}
+#endif
+
+/* Free all remaining GC objects. */
+void lj_gc_freeall(global_State *g)
+{
+  MSize i, strmask;
+  /* Free everything, except super-fixed objects (the main thread). */
+  g->gc.currentwhite = LJ_GC_WHITES | LJ_GC_SFIXED;
+  gc_fullsweep(g, &g->gc.root);
+  strmask = g->strmask;
+  for (i = 0; i <= strmask; i++)  /* Free all string hash chains. */
+    gc_fullsweep(g, &g->strhash[i]);
+}
+
+/* -- Collector ----------------------------------------------------------- */
+
+/* Atomic part of the GC cycle, transitioning from mark to sweep phase. */
+static void atomic(global_State *g, lua_State *L)
+{
+  size_t udsize;
+
+  gc_mark_uv(g);  /* Need to remark open upvalues (the thread may be dead). */
+  gc_propagate_gray(g);  /* Propagate any left-overs. */
+
+  setgcrefr(g->gc.gray, g->gc.weak);  /* Empty the list of weak tables. */
+  setgcrefnull(g->gc.weak);
+  lua_assert(!iswhite(obj2gco(mainthread(g))));
+  gc_markobj(g, L);  /* Mark running thread. */
+  gc_traverse_curtrace(g);  /* Traverse current trace. */
+  gc_mark_gcroot(g);  /* Mark GC roots (again). */
+  gc_propagate_gray(g);  /* Propagate all of the above. */
+
+  setgcrefr(g->gc.gray, g->gc.grayagain);  /* Empty the 2nd chance list. */
+  setgcrefnull(g->gc.grayagain);
+  gc_propagate_gray(g);  /* Propagate it. */
+
+  udsize = lj_gc_separateudata(g, 0);  /* Separate userdata to be finalized. */
+  gc_mark_mmudata(g);  /* Mark them. */
+  udsize += gc_propagate_gray(g);  /* And propagate the marks. */
+
+  /* All marking done, clear weak tables. */
+  gc_clearweak(gcref(g->gc.weak));
+
+  /* Prepare for sweep phase. */
+  g->gc.currentwhite = (uint8_t)otherwhite(g);  /* Flip current white. */
+  g->strempty.marked = g->gc.currentwhite;
+  setmref(g->gc.sweep, &g->gc.root);
+  g->gc.estimate = g->gc.total - (MSize)udsize;  /* Initial estimate. */
+}
+
+/* GC state machine. Returns a cost estimate for each step performed. */
+static size_t gc_onestep(lua_State *L)
+{
+  global_State *g = G(L);
+  switch (g->gc.state) {
+  case GCSpause:
+    gc_mark_start(g);  /* Start a new GC cycle by marking all GC roots. */
+    return 0;
+  case GCSpropagate:
+    if (gcref(g->gc.gray) != NULL)
+      return propagatemark(g);  /* Propagate one gray object. */
+    g->gc.state = GCSatomic;  /* End of mark phase. */
+    return 0;
+  case GCSatomic:
+    if (gcref(g->jit_L))  /* Don't run atomic phase on trace. */
+      return LJ_MAX_MEM;
+    atomic(g, L);
+    g->gc.state = GCSsweepstring;  /* Start of sweep phase. */
+    g->gc.sweepstr = 0;
+    return 0;
+  case GCSsweepstring: {
+    MSize old = g->gc.total;
+    gc_fullsweep(g, &g->strhash[g->gc.sweepstr++]);  /* Sweep one chain. */
+    if (g->gc.sweepstr > g->strmask)
+      g->gc.state = GCSsweep;  /* All string hash chains sweeped. */
+    lua_assert(old >= g->gc.total);
+    g->gc.estimate -= old - g->gc.total;
+    return GCSWEEPCOST;
+    }
+  case GCSsweep: {
+    MSize old = g->gc.total;
+    setmref(g->gc.sweep, gc_sweep(g, mref(g->gc.sweep, GCRef), GCSWEEPMAX));
+    lua_assert(old >= g->gc.total);
+    g->gc.estimate -= old - g->gc.total;
+    if (gcref(*mref(g->gc.sweep, GCRef)) == NULL) {
+      gc_shrink(g, L);
+      if (gcref(g->gc.mmudata)) {  /* Need any finalizations? */
+	g->gc.state = GCSfinalize;
+#if LJ_HASFFI
+	g->gc.nocdatafin = 1;
+#endif
+      } else {  /* Otherwise skip this phase to help the JIT. */
+	g->gc.state = GCSpause;  /* End of GC cycle. */
+	g->gc.debt = 0;
+      }
+    }
+    return GCSWEEPMAX*GCSWEEPCOST;
+    }
+  case GCSfinalize:
+    if (gcref(g->gc.mmudata) != NULL) {
+      if (gcref(g->jit_L))  /* Don't call finalizers on trace. */
+	return LJ_MAX_MEM;
+      gc_finalize(L);  /* Finalize one userdata object. */
+      if (g->gc.estimate > GCFINALIZECOST)
+	g->gc.estimate -= GCFINALIZECOST;
+      return GCFINALIZECOST;
+    }
+#if LJ_HASFFI
+    if (!g->gc.nocdatafin) lj_tab_rehash(L, ctype_ctsG(g)->finalizer);
+#endif
+    g->gc.state = GCSpause;  /* End of GC cycle. */
+    g->gc.debt = 0;
+    return 0;
+  default:
+    lua_assert(0);
+    return 0;
+  }
+}
+
+/* Perform a limited amount of incremental GC steps. */
+int LJ_FASTCALL lj_gc_step(lua_State *L)
+{
+  global_State *g = G(L);
+  MSize lim;
+  int32_t ostate = g->vmstate;
+  setvmstate(g, GC);
+  lim = (GCSTEPSIZE/100) * g->gc.stepmul;
+  if (lim == 0)
+    lim = LJ_MAX_MEM;
+  if (g->gc.total > g->gc.threshold)
+    g->gc.debt += g->gc.total - g->gc.threshold;
+  do {
+    lim -= (MSize)gc_onestep(L);
+    if (g->gc.state == GCSpause) {
+      g->gc.threshold = (g->gc.estimate/100) * g->gc.pause;
+      g->vmstate = ostate;
+      return 1;  /* Finished a GC cycle. */
+    }
+  } while ((int32_t)lim > 0);
+  if (g->gc.debt < GCSTEPSIZE) {
+    g->gc.threshold = g->gc.total + GCSTEPSIZE;
+    g->vmstate = ostate;
+    return -1;
+  } else {
+    g->gc.debt -= GCSTEPSIZE;
+    g->gc.threshold = g->gc.total;
+    g->vmstate = ostate;
+    return 0;
+  }
+}
+
+/* Ditto, but fix the stack top first. */
+void LJ_FASTCALL lj_gc_step_fixtop(lua_State *L)
+{
+  if (curr_funcisL(L)) L->top = curr_topL(L);
+  lj_gc_step(L);
+}
+
+#if LJ_HASJIT
+/* Perform multiple GC steps. Called from JIT-compiled code. */
+int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps)
+{
+  lua_State *L = gco2th(gcref(g->jit_L));
+  L->base = mref(G(L)->jit_base, TValue);
+  L->top = curr_topL(L);
+  while (steps-- > 0 && lj_gc_step(L) == 0)
+    ;
+  /* Return 1 to force a trace exit. */
+  return (G(L)->gc.state == GCSatomic || G(L)->gc.state == GCSfinalize);
+}
+#endif
+
+/* Perform a full GC cycle. */
+void lj_gc_fullgc(lua_State *L)
+{
+  global_State *g = G(L);
+  int32_t ostate = g->vmstate;
+  setvmstate(g, GC);
+  if (g->gc.state <= GCSatomic) {  /* Caught somewhere in the middle. */
+    setmref(g->gc.sweep, &g->gc.root);  /* Sweep everything (preserving it). */
+    setgcrefnull(g->gc.gray);  /* Reset lists from partial propagation. */
+    setgcrefnull(g->gc.grayagain);
+    setgcrefnull(g->gc.weak);
+    g->gc.state = GCSsweepstring;  /* Fast forward to the sweep phase. */
+    g->gc.sweepstr = 0;
+  }
+  while (g->gc.state == GCSsweepstring || g->gc.state == GCSsweep)
+    gc_onestep(L);  /* Finish sweep. */
+  lua_assert(g->gc.state == GCSfinalize || g->gc.state == GCSpause);
+  /* Now perform a full GC. */
+  g->gc.state = GCSpause;
+  do { gc_onestep(L); } while (g->gc.state != GCSpause);
+  g->gc.threshold = (g->gc.estimate/100) * g->gc.pause;
+  g->vmstate = ostate;
+}
+
+/* -- Write barriers ------------------------------------------------------ */
+
+/* Move the GC propagation frontier forward. */
+void lj_gc_barrierf(global_State *g, GCobj *o, GCobj *v)
+{
+  lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
+  lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause);
+  lua_assert(o->gch.gct != ~LJ_TTAB);
+  /* Preserve invariant during propagation. Otherwise it doesn't matter. */
+  if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic)
+    gc_mark(g, v);  /* Move frontier forward. */
+  else
+    makewhite(g, o);  /* Make it white to avoid the following barrier. */
+}
+
+/* Specialized barrier for closed upvalue. Pass &uv->tv. */
+void LJ_FASTCALL lj_gc_barrieruv(global_State *g, TValue *tv)
+{
+#define TV2MARKED(x) \
+  (*((uint8_t *)(x) - offsetof(GCupval, tv) + offsetof(GCupval, marked)))
+  if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic)
+    gc_mark(g, gcV(tv));
+  else
+    TV2MARKED(tv) = (TV2MARKED(tv) & (uint8_t)~LJ_GC_COLORS) | curwhite(g);
+#undef TV2MARKED
+}
+
+/* Close upvalue. Also needs a write barrier. */
+void lj_gc_closeuv(global_State *g, GCupval *uv)
+{
+  GCobj *o = obj2gco(uv);
+  /* Copy stack slot to upvalue itself and point to the copy. */
+  copyTV(mainthread(g), &uv->tv, uvval(uv));
+  setmref(uv->v, &uv->tv);
+  uv->closed = 1;
+  setgcrefr(o->gch.nextgc, g->gc.root);
+  setgcref(g->gc.root, o);
+  if (isgray(o)) {  /* A closed upvalue is never gray, so fix this. */
+    if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic) {
+      gray2black(o);  /* Make it black and preserve invariant. */
+      if (tviswhite(&uv->tv))
+	lj_gc_barrierf(g, o, gcV(&uv->tv));
+    } else {
+      makewhite(g, o);  /* Make it white, i.e. sweep the upvalue. */
+      lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause);
+    }
+  }
+}
+
+#if LJ_HASJIT
+/* Mark a trace if it's saved during the propagation phase. */
+void lj_gc_barriertrace(global_State *g, uint32_t traceno)
+{
+  if (g->gc.state == GCSpropagate || g->gc.state == GCSatomic)
+    gc_marktrace(g, traceno);
+}
+#endif
+
+/* -- Allocator ----------------------------------------------------------- */
+
+/* Call pluggable memory allocator to allocate or resize a fragment. */
+void *lj_mem_realloc(lua_State *L, void *p, MSize osz, MSize nsz)
+{
+  global_State *g = G(L);
+  lua_assert((osz == 0) == (p == NULL));
+  p = g->allocf(g->allocd, p, osz, nsz);
+  if (p == NULL && nsz > 0)
+    lj_err_mem(L);
+  lua_assert((nsz == 0) == (p == NULL));
+  lua_assert(checkptr32(p));
+  g->gc.total = (g->gc.total - osz) + nsz;
+  return p;
+}
+
+/* Allocate new GC object and link it to the root set. */
+void * LJ_FASTCALL lj_mem_newgco(lua_State *L, MSize size)
+{
+  global_State *g = G(L);
+  GCobj *o = (GCobj *)g->allocf(g->allocd, NULL, 0, size);
+  if (o == NULL)
+    lj_err_mem(L);
+  lua_assert(checkptr32(o));
+  g->gc.total += size;
+  setgcrefr(o->gch.nextgc, g->gc.root);
+  setgcref(g->gc.root, o);
+  newwhite(g, o);
+  return o;
+}
+
+/* Resize growable vector. */
+void *lj_mem_grow(lua_State *L, void *p, MSize *szp, MSize lim, MSize esz)
+{
+  MSize sz = (*szp) << 1;
+  if (sz < LJ_MIN_VECSZ)
+    sz = LJ_MIN_VECSZ;
+  if (sz > lim)
+    sz = lim;
+  p = lj_mem_realloc(L, p, (*szp)*esz, sz*esz);
+  *szp = sz;
+  return p;
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_gc.h
----------------------------------------------------------------------
diff --git a/lib/luajit/src/lj_gc.h b/lib/luajit/src/lj_gc.h
new file mode 100644
index 0000000..ba061bc
--- /dev/null
+++ b/lib/luajit/src/lj_gc.h
@@ -0,0 +1,134 @@
+/*
+** Garbage collector.
+** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#ifndef _LJ_GC_H
+#define _LJ_GC_H
+
+#include "lj_obj.h"
+
+/* Garbage collector states. Order matters. */
+enum {
+  GCSpause, GCSpropagate, GCSatomic, GCSsweepstring, GCSsweep, GCSfinalize
+};
+
+/* Bitmasks for marked field of GCobj. */
+#define LJ_GC_WHITE0	0x01
+#define LJ_GC_WHITE1	0x02
+#define LJ_GC_BLACK	0x04
+#define LJ_GC_FINALIZED	0x08
+#define LJ_GC_WEAKKEY	0x08
+#define LJ_GC_WEAKVAL	0x10
+#define LJ_GC_CDATA_FIN	0x10
+#define LJ_GC_FIXED	0x20
+#define LJ_GC_SFIXED	0x40
+
+#define LJ_GC_WHITES	(LJ_GC_WHITE0 | LJ_GC_WHITE1)
+#define LJ_GC_COLORS	(LJ_GC_WHITES | LJ_GC_BLACK)
+#define LJ_GC_WEAK	(LJ_GC_WEAKKEY | LJ_GC_WEAKVAL)
+
+/* Macros to test and set GCobj colors. */
+#define iswhite(x)	((x)->gch.marked & LJ_GC_WHITES)
+#define isblack(x)	((x)->gch.marked & LJ_GC_BLACK)
+#define isgray(x)	(!((x)->gch.marked & (LJ_GC_BLACK|LJ_GC_WHITES)))
+#define tviswhite(x)	(tvisgcv(x) && iswhite(gcV(x)))
+#define otherwhite(g)	(g->gc.currentwhite ^ LJ_GC_WHITES)
+#define isdead(g, v)	((v)->gch.marked & otherwhite(g) & LJ_GC_WHITES)
+
+#define curwhite(g)	((g)->gc.currentwhite & LJ_GC_WHITES)
+#define newwhite(g, x)	(obj2gco(x)->gch.marked = (uint8_t)curwhite(g))
+#define makewhite(g, x) \
+  ((x)->gch.marked = ((x)->gch.marked & (uint8_t)~LJ_GC_COLORS) | curwhite(g))
+#define flipwhite(x)	((x)->gch.marked ^= LJ_GC_WHITES)
+#define black2gray(x)	((x)->gch.marked &= (uint8_t)~LJ_GC_BLACK)
+#define fixstring(s)	((s)->marked |= LJ_GC_FIXED)
+#define markfinalized(x)	((x)->gch.marked |= LJ_GC_FINALIZED)
+
+/* Collector. */
+LJ_FUNC size_t lj_gc_separateudata(global_State *g, int all);
+LJ_FUNC void lj_gc_finalize_udata(lua_State *L);
+#if LJ_HASFFI
+LJ_FUNC void lj_gc_finalize_cdata(lua_State *L);
+#else
+#define lj_gc_finalize_cdata(L)		UNUSED(L)
+#endif
+LJ_FUNC void lj_gc_freeall(global_State *g);
+LJ_FUNCA int LJ_FASTCALL lj_gc_step(lua_State *L);
+LJ_FUNCA void LJ_FASTCALL lj_gc_step_fixtop(lua_State *L);
+#if LJ_HASJIT
+LJ_FUNC int LJ_FASTCALL lj_gc_step_jit(global_State *g, MSize steps);
+#endif
+LJ_FUNC void lj_gc_fullgc(lua_State *L);
+
+/* GC check: drive collector forward if the GC threshold has been reached. */
+#define lj_gc_check(L) \
+  { if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) \
+      lj_gc_step(L); }
+#define lj_gc_check_fixtop(L) \
+  { if (LJ_UNLIKELY(G(L)->gc.total >= G(L)->gc.threshold)) \
+      lj_gc_step_fixtop(L); }
+
+/* Write barriers. */
+LJ_FUNC void lj_gc_barrierf(global_State *g, GCobj *o, GCobj *v);
+LJ_FUNCA void LJ_FASTCALL lj_gc_barrieruv(global_State *g, TValue *tv);
+LJ_FUNC void lj_gc_closeuv(global_State *g, GCupval *uv);
+#if LJ_HASJIT
+LJ_FUNC void lj_gc_barriertrace(global_State *g, uint32_t traceno);
+#endif
+
+/* Move the GC propagation frontier back for tables (make it gray again). */
+static LJ_AINLINE void lj_gc_barrierback(global_State *g, GCtab *t)
+{
+  GCobj *o = obj2gco(t);
+  lua_assert(isblack(o) && !isdead(g, o));
+  lua_assert(g->gc.state != GCSfinalize && g->gc.state != GCSpause);
+  black2gray(o);
+  setgcrefr(t->gclist, g->gc.grayagain);
+  setgcref(g->gc.grayagain, o);
+}
+
+/* Barrier for stores to table objects. TValue and GCobj variant. */
+#define lj_gc_anybarriert(L, t)  \
+  { if (LJ_UNLIKELY(isblack(obj2gco(t)))) lj_gc_barrierback(G(L), (t)); }
+#define lj_gc_barriert(L, t, tv) \
+  { if (tviswhite(tv) && isblack(obj2gco(t))) \
+      lj_gc_barrierback(G(L), (t)); }
+#define lj_gc_objbarriert(L, t, o)  \
+  { if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) \
+      lj_gc_barrierback(G(L), (t)); }
+
+/* Barrier for stores to any other object. TValue and GCobj variant. */
+#define lj_gc_barrier(L, p, tv) \
+  { if (tviswhite(tv) && isblack(obj2gco(p))) \
+      lj_gc_barrierf(G(L), obj2gco(p), gcV(tv)); }
+#define lj_gc_objbarrier(L, p, o) \
+  { if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \
+      lj_gc_barrierf(G(L), obj2gco(p), obj2gco(o)); }
+
+/* Allocator. */
+LJ_FUNC void *lj_mem_realloc(lua_State *L, void *p, MSize osz, MSize nsz);
+LJ_FUNC void * LJ_FASTCALL lj_mem_newgco(lua_State *L, MSize size);
+LJ_FUNC void *lj_mem_grow(lua_State *L, void *p,
+			  MSize *szp, MSize lim, MSize esz);
+
+#define lj_mem_new(L, s)	lj_mem_realloc(L, NULL, 0, (s))
+
+static LJ_AINLINE void lj_mem_free(global_State *g, void *p, size_t osize)
+{
+  g->gc.total -= (MSize)osize;
+  g->allocf(g->allocd, p, osize, 0);
+}
+
+#define lj_mem_newvec(L, n, t)	((t *)lj_mem_new(L, (MSize)((n)*sizeof(t))))
+#define lj_mem_reallocvec(L, p, on, n, t) \
+  ((p) = (t *)lj_mem_realloc(L, p, (on)*sizeof(t), (MSize)((n)*sizeof(t))))
+#define lj_mem_growvec(L, p, n, m, t) \
+  ((p) = (t *)lj_mem_grow(L, (p), &(n), (m), (MSize)sizeof(t)))
+#define lj_mem_freevec(g, p, n, t)	lj_mem_free(g, (p), (n)*sizeof(t))
+
+#define lj_mem_newobj(L, t)	((t *)lj_mem_newgco(L, sizeof(t)))
+#define lj_mem_newt(L, s, t)	((t *)lj_mem_new(L, (s)))
+#define lj_mem_freet(g, p)	lj_mem_free(g, (p), sizeof(*(p)))
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_gdbjit.c
----------------------------------------------------------------------
diff --git a/lib/luajit/src/lj_gdbjit.c b/lib/luajit/src/lj_gdbjit.c
new file mode 100644
index 0000000..d3f3e61
--- /dev/null
+++ b/lib/luajit/src/lj_gdbjit.c
@@ -0,0 +1,795 @@
+/*
+** Client for the GDB JIT API.
+** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#define lj_gdbjit_c
+#define LUA_CORE
+
+#include "lj_obj.h"
+
+#if LJ_HASJIT
+
+#include "lj_gc.h"
+#include "lj_err.h"
+#include "lj_debug.h"
+#include "lj_frame.h"
+#include "lj_jit.h"
+#include "lj_dispatch.h"
+
+/* This is not compiled in by default.
+** Enable with -DLUAJIT_USE_GDBJIT in the Makefile and recompile everything.
+*/
+#ifdef LUAJIT_USE_GDBJIT
+
+/* The GDB JIT API allows JIT compilers to pass debug information about
+** JIT-compiled code back to GDB. You need at least GDB 7.0 or higher
+** to see it in action.
+**
+** This is a passive API, so it works even when not running under GDB
+** or when attaching to an already running process. Alas, this implies
+** enabling it always has a non-negligible overhead -- do not use in
+** release mode!
+**
+** The LuaJIT GDB JIT client is rather minimal at the moment. It gives
+** each trace a symbol name and adds a source location and frame unwind
+** information. Obviously LuaJIT itself and any embedding C application
+** should be compiled with debug symbols, too (see the Makefile).
+**
+** Traces are named TRACE_1, TRACE_2, ... these correspond to the trace
+** numbers from -jv or -jdump. Use "break TRACE_1" or "tbreak TRACE_1" etc.
+** to set breakpoints on specific traces (even ahead of their creation).
+**
+** The source location for each trace allows listing the corresponding
+** source lines with the GDB command "list" (but only if the Lua source
+** has been loaded from a file). Currently this is always set to the
+** location where the trace has been started.
+**
+** Frame unwind information can be inspected with the GDB command
+** "info frame". This also allows proper backtraces across JIT-compiled
+** code with the GDB command "bt".
+**
+** You probably want to add the following settings to a .gdbinit file
+** (or add them to ~/.gdbinit):
+**   set disassembly-flavor intel
+**   set breakpoint pending on
+**
+** Here's a sample GDB session:
+** ------------------------------------------------------------------------
+
+$ cat >x.lua
+for outer=1,100 do
+  for inner=1,100 do end
+end
+^D
+
+$ luajit -jv x.lua
+[TRACE   1 x.lua:2]
+[TRACE   2 (1/3) x.lua:1 -> 1]
+
+$ gdb --quiet --args luajit x.lua
+(gdb) tbreak TRACE_1
+Function "TRACE_1" not defined.
+Temporary breakpoint 1 (TRACE_1) pending.
+(gdb) run
+Starting program: luajit x.lua
+
+Temporary breakpoint 1, TRACE_1 () at x.lua:2
+2	  for inner=1,100 do end
+(gdb) list
+1	for outer=1,100 do
+2	  for inner=1,100 do end
+3	end
+(gdb) bt
+#0  TRACE_1 () at x.lua:2
+#1  0x08053690 in lua_pcall [...]
+[...]
+#7  0x0806ff90 in main [...]
+(gdb) disass TRACE_1
+Dump of assembler code for function TRACE_1:
+0xf7fd9fba <TRACE_1+0>:	mov    DWORD PTR ds:0xf7e0e2a0,0x1
+0xf7fd9fc4 <TRACE_1+10>:	movsd  xmm7,QWORD PTR [edx+0x20]
+[...]
+0xf7fd9ff8 <TRACE_1+62>:	jmp    0xf7fd2014
+End of assembler dump.
+(gdb) tbreak TRACE_2
+Function "TRACE_2" not defined.
+Temporary breakpoint 2 (TRACE_2) pending.
+(gdb) cont
+Continuing.
+
+Temporary breakpoint 2, TRACE_2 () at x.lua:1
+1	for outer=1,100 do
+(gdb) info frame
+Stack level 0, frame at 0xffffd7c0:
+ eip = 0xf7fd9f60 in TRACE_2 (x.lua:1); saved eip 0x8053690
+ called by frame at 0xffffd7e0
+ source language unknown.
+ Arglist at 0xffffd78c, args:
+ Locals at 0xffffd78c, Previous frame's sp is 0xffffd7c0
+ Saved registers:
+  ebx at 0xffffd7ac, ebp at 0xffffd7b8, esi at 0xffffd7b0, edi at 0xffffd7b4,
+  eip at 0xffffd7bc
+(gdb)
+
+** ------------------------------------------------------------------------
+*/
+
+/* -- GDB JIT API --------------------------------------------------------- */
+
+/* GDB JIT actions. */
+enum {
+  GDBJIT_NOACTION = 0,
+  GDBJIT_REGISTER,
+  GDBJIT_UNREGISTER
+};
+
+/* GDB JIT entry. */
+typedef struct GDBJITentry {
+  struct GDBJITentry *next_entry;
+  struct GDBJITentry *prev_entry;
+  const char *symfile_addr;
+  uint64_t symfile_size;
+} GDBJITentry;
+
+/* GDB JIT descriptor. */
+typedef struct GDBJITdesc {
+  uint32_t version;
+  uint32_t action_flag;
+  GDBJITentry *relevant_entry;
+  GDBJITentry *first_entry;
+} GDBJITdesc;
+
+GDBJITdesc __jit_debug_descriptor = {
+  1, GDBJIT_NOACTION, NULL, NULL
+};
+
+/* GDB sets a breakpoint at this function. */
+void LJ_NOINLINE __jit_debug_register_code()
+{
+  __asm__ __volatile__("");
+};
+
+/* -- In-memory ELF object definitions ------------------------------------ */
+
+/* ELF definitions. */
+typedef struct ELFheader {
+  uint8_t emagic[4];
+  uint8_t eclass;
+  uint8_t eendian;
+  uint8_t eversion;
+  uint8_t eosabi;
+  uint8_t eabiversion;
+  uint8_t epad[7];
+  uint16_t type;
+  uint16_t machine;
+  uint32_t version;
+  uintptr_t entry;
+  uintptr_t phofs;
+  uintptr_t shofs;
+  uint32_t flags;
+  uint16_t ehsize;
+  uint16_t phentsize;
+  uint16_t phnum;
+  uint16_t shentsize;
+  uint16_t shnum;
+  uint16_t shstridx;
+} ELFheader;
+
+typedef struct ELFsectheader {
+  uint32_t name;
+  uint32_t type;
+  uintptr_t flags;
+  uintptr_t addr;
+  uintptr_t ofs;
+  uintptr_t size;
+  uint32_t link;
+  uint32_t info;
+  uintptr_t align;
+  uintptr_t entsize;
+} ELFsectheader;
+
+#define ELFSECT_IDX_ABS		0xfff1
+
+enum {
+  ELFSECT_TYPE_PROGBITS = 1,
+  ELFSECT_TYPE_SYMTAB = 2,
+  ELFSECT_TYPE_STRTAB = 3,
+  ELFSECT_TYPE_NOBITS = 8
+};
+
+#define ELFSECT_FLAGS_WRITE	1
+#define ELFSECT_FLAGS_ALLOC	2
+#define ELFSECT_FLAGS_EXEC	4
+
+typedef struct ELFsymbol {
+#if LJ_64
+  uint32_t name;
+  uint8_t info;
+  uint8_t other;
+  uint16_t sectidx;
+  uintptr_t value;
+  uint64_t size;
+#else
+  uint32_t name;
+  uintptr_t value;
+  uint32_t size;
+  uint8_t info;
+  uint8_t other;
+  uint16_t sectidx;
+#endif
+} ELFsymbol;
+
+enum {
+  ELFSYM_TYPE_FUNC = 2,
+  ELFSYM_TYPE_FILE = 4,
+  ELFSYM_BIND_LOCAL = 0 << 4,
+  ELFSYM_BIND_GLOBAL = 1 << 4,
+};
+
+/* DWARF definitions. */
+#define DW_CIE_VERSION	1
+
+enum {
+  DW_CFA_nop = 0x0,
+  DW_CFA_offset_extended = 0x5,
+  DW_CFA_def_cfa = 0xc,
+  DW_CFA_def_cfa_offset = 0xe,
+  DW_CFA_offset_extended_sf = 0x11,
+  DW_CFA_advance_loc = 0x40,
+  DW_CFA_offset = 0x80
+};
+
+enum {
+  DW_EH_PE_udata4 = 3,
+  DW_EH_PE_textrel = 0x20
+};
+
+enum {
+  DW_TAG_compile_unit = 0x11
+};
+
+enum {
+  DW_children_no = 0,
+  DW_children_yes = 1
+};
+
+enum {
+  DW_AT_name = 0x03,
+  DW_AT_stmt_list = 0x10,
+  DW_AT_low_pc = 0x11,
+  DW_AT_high_pc = 0x12
+};
+
+enum {
+  DW_FORM_addr = 0x01,
+  DW_FORM_data4 = 0x06,
+  DW_FORM_string = 0x08
+};
+
+enum {
+  DW_LNS_extended_op = 0,
+  DW_LNS_copy = 1,
+  DW_LNS_advance_pc = 2,
+  DW_LNS_advance_line = 3
+};
+
+enum {
+  DW_LNE_end_sequence = 1,
+  DW_LNE_set_address = 2
+};
+
+enum {
+#if LJ_TARGET_X86
+  DW_REG_AX, DW_REG_CX, DW_REG_DX, DW_REG_BX,
+  DW_REG_SP, DW_REG_BP, DW_REG_SI, DW_REG_DI,
+  DW_REG_RA,
+#elif LJ_TARGET_X64
+  /* Yes, the order is strange, but correct. */
+  DW_REG_AX, DW_REG_DX, DW_REG_CX, DW_REG_BX,
+  DW_REG_SI, DW_REG_DI, DW_REG_BP, DW_REG_SP,
+  DW_REG_8, DW_REG_9, DW_REG_10, DW_REG_11,
+  DW_REG_12, DW_REG_13, DW_REG_14, DW_REG_15,
+  DW_REG_RA,
+#elif LJ_TARGET_ARM
+  DW_REG_SP = 13,
+  DW_REG_RA = 14,
+#elif LJ_TARGET_PPC
+  DW_REG_SP = 1,
+  DW_REG_RA = 65,
+  DW_REG_CR = 70,
+#elif LJ_TARGET_MIPS
+  DW_REG_SP = 29,
+  DW_REG_RA = 31,
+#else
+#error "Unsupported target architecture"
+#endif
+};
+
+/* Minimal list of sections for the in-memory ELF object. */
+enum {
+  GDBJIT_SECT_NULL,
+  GDBJIT_SECT_text,
+  GDBJIT_SECT_eh_frame,
+  GDBJIT_SECT_shstrtab,
+  GDBJIT_SECT_strtab,
+  GDBJIT_SECT_symtab,
+  GDBJIT_SECT_debug_info,
+  GDBJIT_SECT_debug_abbrev,
+  GDBJIT_SECT_debug_line,
+  GDBJIT_SECT__MAX
+};
+
+enum {
+  GDBJIT_SYM_UNDEF,
+  GDBJIT_SYM_FILE,
+  GDBJIT_SYM_FUNC,
+  GDBJIT_SYM__MAX
+};
+
+/* In-memory ELF object. */
+typedef struct GDBJITobj {
+  ELFheader hdr;			/* ELF header. */
+  ELFsectheader sect[GDBJIT_SECT__MAX];	/* ELF sections. */
+  ELFsymbol sym[GDBJIT_SYM__MAX];	/* ELF symbol table. */
+  uint8_t space[4096];			/* Space for various section data. */
+} GDBJITobj;
+
+/* Combined structure for GDB JIT entry and ELF object. */
+typedef struct GDBJITentryobj {
+  GDBJITentry entry;
+  size_t sz;
+  GDBJITobj obj;
+} GDBJITentryobj;
+
+/* Template for in-memory ELF header. */
+static const ELFheader elfhdr_template = {
+  .emagic = { 0x7f, 'E', 'L', 'F' },
+  .eclass = LJ_64 ? 2 : 1,
+  .eendian = LJ_ENDIAN_SELECT(1, 2),
+  .eversion = 1,
+#if LJ_TARGET_LINUX
+  .eosabi = 0,  /* Nope, it's not 3. */
+#elif defined(__FreeBSD__)
+  .eosabi = 9,
+#elif defined(__NetBSD__)
+  .eosabi = 2,
+#elif defined(__OpenBSD__)
+  .eosabi = 12,
+#elif defined(__DragonFly__)
+  .eosabi = 0,
+#elif (defined(__sun__) && defined(__svr4__))
+  .eosabi = 6,
+#else
+  .eosabi = 0,
+#endif
+  .eabiversion = 0,
+  .epad = { 0, 0, 0, 0, 0, 0, 0 },
+  .type = 1,
+#if LJ_TARGET_X86
+  .machine = 3,
+#elif LJ_TARGET_X64
+  .machine = 62,
+#elif LJ_TARGET_ARM
+  .machine = 40,
+#elif LJ_TARGET_PPC
+  .machine = 20,
+#elif LJ_TARGET_MIPS
+  .machine = 8,
+#else
+#error "Unsupported target architecture"
+#endif
+  .version = 1,
+  .entry = 0,
+  .phofs = 0,
+  .shofs = offsetof(GDBJITobj, sect),
+  .flags = 0,
+  .ehsize = sizeof(ELFheader),
+  .phentsize = 0,
+  .phnum = 0,
+  .shentsize = sizeof(ELFsectheader),
+  .shnum = GDBJIT_SECT__MAX,
+  .shstridx = GDBJIT_SECT_shstrtab
+};
+
+/* -- In-memory ELF object generation ------------------------------------- */
+
+/* Context for generating the ELF object for the GDB JIT API. */
+typedef struct GDBJITctx {
+  uint8_t *p;		/* Pointer to next address in obj.space. */
+  uint8_t *startp;	/* Pointer to start address in obj.space. */
+  GCtrace *T;		/* Generate symbols for this trace. */
+  uintptr_t mcaddr;	/* Machine code address. */
+  MSize szmcode;	/* Size of machine code. */
+  MSize spadjp;		/* Stack adjustment for parent trace or interpreter. */
+  MSize spadj;		/* Stack adjustment for trace itself. */
+  BCLine lineno;	/* Starting line number. */
+  const char *filename;	/* Starting file name. */
+  size_t objsize;	/* Final size of ELF object. */
+  GDBJITobj obj;	/* In-memory ELF object. */
+} GDBJITctx;
+
+/* Add a zero-terminated string. */
+static uint32_t gdbjit_strz(GDBJITctx *ctx, const char *str)
+{
+  uint8_t *p = ctx->p;
+  uint32_t ofs = (uint32_t)(p - ctx->startp);
+  do {
+    *p++ = (uint8_t)*str;
+  } while (*str++);
+  ctx->p = p;
+  return ofs;
+}
+
+/* Append a decimal number. */
+static void gdbjit_catnum(GDBJITctx *ctx, uint32_t n)
+{
+  if (n >= 10) { uint32_t m = n / 10; n = n % 10; gdbjit_catnum(ctx, m); }
+  *ctx->p++ = '0' + n;
+}
+
+/* Add a ULEB128 value. */
+static void gdbjit_uleb128(GDBJITctx *ctx, uint32_t v)
+{
+  uint8_t *p = ctx->p;
+  for (; v >= 0x80; v >>= 7)
+    *p++ = (uint8_t)((v & 0x7f) | 0x80);
+  *p++ = (uint8_t)v;
+  ctx->p = p;
+}
+
+/* Add a SLEB128 value. */
+static void gdbjit_sleb128(GDBJITctx *ctx, int32_t v)
+{
+  uint8_t *p = ctx->p;
+  for (; (uint32_t)(v+0x40) >= 0x80; v >>= 7)
+    *p++ = (uint8_t)((v & 0x7f) | 0x80);
+  *p++ = (uint8_t)(v & 0x7f);
+  ctx->p = p;
+}
+
+/* Shortcuts to generate DWARF structures. */
+#define DB(x)		(*p++ = (x))
+#define DI8(x)		(*(int8_t *)p = (x), p++)
+#define DU16(x)		(*(uint16_t *)p = (x), p += 2)
+#define DU32(x)		(*(uint32_t *)p = (x), p += 4)
+#define DADDR(x)	(*(uintptr_t *)p = (x), p += sizeof(uintptr_t))
+#define DUV(x)		(ctx->p = p, gdbjit_uleb128(ctx, (x)), p = ctx->p)
+#define DSV(x)		(ctx->p = p, gdbjit_sleb128(ctx, (x)), p = ctx->p)
+#define DSTR(str)	(ctx->p = p, gdbjit_strz(ctx, (str)), p = ctx->p)
+#define DALIGNNOP(s)	while ((uintptr_t)p & ((s)-1)) *p++ = DW_CFA_nop
+#define DSECT(name, stmt) \
+  { uint32_t *szp_##name = (uint32_t *)p; p += 4; stmt \
+    *szp_##name = (uint32_t)((p-(uint8_t *)szp_##name)-4); } \
+
+/* Initialize ELF section headers. */
+static void LJ_FASTCALL gdbjit_secthdr(GDBJITctx *ctx)
+{
+  ELFsectheader *sect;
+
+  *ctx->p++ = '\0';  /* Empty string at start of string table. */
+
+#define SECTDEF(id, tp, al) \
+  sect = &ctx->obj.sect[GDBJIT_SECT_##id]; \
+  sect->name = gdbjit_strz(ctx, "." #id); \
+  sect->type = ELFSECT_TYPE_##tp; \
+  sect->align = (al)
+
+  SECTDEF(text, NOBITS, 16);
+  sect->flags = ELFSECT_FLAGS_ALLOC|ELFSECT_FLAGS_EXEC;
+  sect->addr = ctx->mcaddr;
+  sect->ofs = 0;
+  sect->size = ctx->szmcode;
+
+  SECTDEF(eh_frame, PROGBITS, sizeof(uintptr_t));
+  sect->flags = ELFSECT_FLAGS_ALLOC;
+
+  SECTDEF(shstrtab, STRTAB, 1);
+  SECTDEF(strtab, STRTAB, 1);
+
+  SECTDEF(symtab, SYMTAB, sizeof(uintptr_t));
+  sect->ofs = offsetof(GDBJITobj, sym);
+  sect->size = sizeof(ctx->obj.sym);
+  sect->link = GDBJIT_SECT_strtab;
+  sect->entsize = sizeof(ELFsymbol);
+  sect->info = GDBJIT_SYM_FUNC;
+
+  SECTDEF(debug_info, PROGBITS, 1);
+  SECTDEF(debug_abbrev, PROGBITS, 1);
+  SECTDEF(debug_line, PROGBITS, 1);
+
+#undef SECTDEF
+}
+
+/* Initialize symbol table. */
+static void LJ_FASTCALL gdbjit_symtab(GDBJITctx *ctx)
+{
+  ELFsymbol *sym;
+
+  *ctx->p++ = '\0';  /* Empty string at start of string table. */
+
+  sym = &ctx->obj.sym[GDBJIT_SYM_FILE];
+  sym->name = gdbjit_strz(ctx, "JIT mcode");
+  sym->sectidx = ELFSECT_IDX_ABS;
+  sym->info = ELFSYM_TYPE_FILE|ELFSYM_BIND_LOCAL;
+
+  sym = &ctx->obj.sym[GDBJIT_SYM_FUNC];
+  sym->name = gdbjit_strz(ctx, "TRACE_"); ctx->p--;
+  gdbjit_catnum(ctx, ctx->T->traceno); *ctx->p++ = '\0';
+  sym->sectidx = GDBJIT_SECT_text;
+  sym->value = 0;
+  sym->size = ctx->szmcode;
+  sym->info = ELFSYM_TYPE_FUNC|ELFSYM_BIND_GLOBAL;
+}
+
+/* Initialize .eh_frame section. */
+static void LJ_FASTCALL gdbjit_ehframe(GDBJITctx *ctx)
+{
+  uint8_t *p = ctx->p;
+  uint8_t *framep = p;
+
+  /* Emit DWARF EH CIE. */
+  DSECT(CIE,
+    DU32(0);			/* Offset to CIE itself. */
+    DB(DW_CIE_VERSION);
+    DSTR("zR");			/* Augmentation. */
+    DUV(1);			/* Code alignment factor. */
+    DSV(-(int32_t)sizeof(uintptr_t));  /* Data alignment factor. */
+    DB(DW_REG_RA);		/* Return address register. */
+    DB(1); DB(DW_EH_PE_textrel|DW_EH_PE_udata4);  /* Augmentation data. */
+    DB(DW_CFA_def_cfa); DUV(DW_REG_SP); DUV(sizeof(uintptr_t));
+#if LJ_TARGET_PPC
+    DB(DW_CFA_offset_extended_sf); DB(DW_REG_RA); DSV(-1);
+#else
+    DB(DW_CFA_offset|DW_REG_RA); DUV(1);
+#endif
+    DALIGNNOP(sizeof(uintptr_t));
+  )
+
+  /* Emit DWARF EH FDE. */
+  DSECT(FDE,
+    DU32((uint32_t)(p-framep));	/* Offset to CIE. */
+    DU32(0);			/* Machine code offset relative to .text. */
+    DU32(ctx->szmcode);		/* Machine code length. */
+    DB(0);			/* Augmentation data. */
+    /* Registers saved in CFRAME. */
+#if LJ_TARGET_X86
+    DB(DW_CFA_offset|DW_REG_BP); DUV(2);
+    DB(DW_CFA_offset|DW_REG_DI); DUV(3);
+    DB(DW_CFA_offset|DW_REG_SI); DUV(4);
+    DB(DW_CFA_offset|DW_REG_BX); DUV(5);
+#elif LJ_TARGET_X64
+    DB(DW_CFA_offset|DW_REG_BP); DUV(2);
+    DB(DW_CFA_offset|DW_REG_BX); DUV(3);
+    DB(DW_CFA_offset|DW_REG_15); DUV(4);
+    DB(DW_CFA_offset|DW_REG_14); DUV(5);
+    /* Extra registers saved for JIT-compiled code. */
+    DB(DW_CFA_offset|DW_REG_13); DUV(9);
+    DB(DW_CFA_offset|DW_REG_12); DUV(10);
+#elif LJ_TARGET_ARM
+    {
+      int i;
+      for (i = 11; i >= 4; i--) { DB(DW_CFA_offset|i); DUV(2+(11-i)); }
+    }
+#elif LJ_TARGET_PPC
+    {
+      int i;
+      DB(DW_CFA_offset_extended); DB(DW_REG_CR); DUV(55);
+      for (i = 14; i <= 31; i++) {
+	DB(DW_CFA_offset|i); DUV(37+(31-i));
+	DB(DW_CFA_offset|32|i); DUV(2+2*(31-i));
+      }
+    }
+#elif LJ_TARGET_MIPS
+    {
+      int i;
+      DB(DW_CFA_offset|30); DUV(2);
+      for (i = 23; i >= 16; i--) { DB(DW_CFA_offset|i); DUV(26-i); }
+      for (i = 30; i >= 20; i -= 2) { DB(DW_CFA_offset|32|i); DUV(42-i); }
+    }
+#else
+#error "Unsupported target architecture"
+#endif
+    if (ctx->spadjp != ctx->spadj) {  /* Parent/interpreter stack frame size. */
+      DB(DW_CFA_def_cfa_offset); DUV(ctx->spadjp);
+      DB(DW_CFA_advance_loc|1);  /* Only an approximation. */
+    }
+    DB(DW_CFA_def_cfa_offset); DUV(ctx->spadj);  /* Trace stack frame size. */
+    DALIGNNOP(sizeof(uintptr_t));
+  )
+
+  ctx->p = p;
+}
+
+/* Initialize .debug_info section. */
+static void LJ_FASTCALL gdbjit_debuginfo(GDBJITctx *ctx)
+{
+  uint8_t *p = ctx->p;
+
+  DSECT(info,
+    DU16(2);			/* DWARF version. */
+    DU32(0);			/* Abbrev offset. */
+    DB(sizeof(uintptr_t));	/* Pointer size. */
+
+    DUV(1);			/* Abbrev #1: DW_TAG_compile_unit. */
+    DSTR(ctx->filename);	/* DW_AT_name. */
+    DADDR(ctx->mcaddr);		/* DW_AT_low_pc. */
+    DADDR(ctx->mcaddr + ctx->szmcode);  /* DW_AT_high_pc. */
+    DU32(0);			/* DW_AT_stmt_list. */
+  )
+
+  ctx->p = p;
+}
+
+/* Initialize .debug_abbrev section. */
+static void LJ_FASTCALL gdbjit_debugabbrev(GDBJITctx *ctx)
+{
+  uint8_t *p = ctx->p;
+
+  /* Abbrev #1: DW_TAG_compile_unit. */
+  DUV(1); DUV(DW_TAG_compile_unit);
+  DB(DW_children_no);
+  DUV(DW_AT_name);	DUV(DW_FORM_string);
+  DUV(DW_AT_low_pc);	DUV(DW_FORM_addr);
+  DUV(DW_AT_high_pc);	DUV(DW_FORM_addr);
+  DUV(DW_AT_stmt_list);	DUV(DW_FORM_data4);
+  DB(0); DB(0);
+
+  ctx->p = p;
+}
+
+#define DLNE(op, s)	(DB(DW_LNS_extended_op), DUV(1+(s)), DB((op)))
+
+/* Initialize .debug_line section. */
+static void LJ_FASTCALL gdbjit_debugline(GDBJITctx *ctx)
+{
+  uint8_t *p = ctx->p;
+
+  DSECT(line,
+    DU16(2);			/* DWARF version. */
+    DSECT(header,
+      DB(1);			/* Minimum instruction length. */
+      DB(1);			/* is_stmt. */
+      DI8(0);			/* Line base for special opcodes. */
+      DB(2);			/* Line range for special opcodes. */
+      DB(3+1);			/* Opcode base at DW_LNS_advance_line+1. */
+      DB(0); DB(1); DB(1);	/* Standard opcode lengths. */
+      /* Directory table. */
+      DB(0);
+      /* File name table. */
+      DSTR(ctx->filename); DUV(0); DUV(0); DUV(0);
+      DB(0);
+    )
+
+    DLNE(DW_LNE_set_address, sizeof(uintptr_t)); DADDR(ctx->mcaddr);
+    if (ctx->lineno) {
+      DB(DW_LNS_advance_line); DSV(ctx->lineno-1);
+    }
+    DB(DW_LNS_copy);
+    DB(DW_LNS_advance_pc); DUV(ctx->szmcode);
+    DLNE(DW_LNE_end_sequence, 0);
+  )
+
+  ctx->p = p;
+}
+
+#undef DLNE
+
+/* Undef shortcuts. */
+#undef DB
+#undef DI8
+#undef DU16
+#undef DU32
+#undef DADDR
+#undef DUV
+#undef DSV
+#undef DSTR
+#undef DALIGNNOP
+#undef DSECT
+
+/* Type of a section initializer callback. */
+typedef void (LJ_FASTCALL *GDBJITinitf)(GDBJITctx *ctx);
+
+/* Call section initializer and set the section offset and size. */
+static void gdbjit_initsect(GDBJITctx *ctx, int sect, GDBJITinitf initf)
+{
+  ctx->startp = ctx->p;
+  ctx->obj.sect[sect].ofs = (uintptr_t)((char *)ctx->p - (char *)&ctx->obj);
+  initf(ctx);
+  ctx->obj.sect[sect].size = (uintptr_t)(ctx->p - ctx->startp);
+}
+
+#define SECTALIGN(p, a) \
+  ((p) = (uint8_t *)(((uintptr_t)(p) + ((a)-1)) & ~(uintptr_t)((a)-1)))
+
+/* Build in-memory ELF object. */
+static void gdbjit_buildobj(GDBJITctx *ctx)
+{
+  GDBJITobj *obj = &ctx->obj;
+  /* Fill in ELF header and clear structures. */
+  memcpy(&obj->hdr, &elfhdr_template, sizeof(ELFheader));
+  memset(&obj->sect, 0, sizeof(ELFsectheader)*GDBJIT_SECT__MAX);
+  memset(&obj->sym, 0, sizeof(ELFsymbol)*GDBJIT_SYM__MAX);
+  /* Initialize sections. */
+  ctx->p = obj->space;
+  gdbjit_initsect(ctx, GDBJIT_SECT_shstrtab, gdbjit_secthdr);
+  gdbjit_initsect(ctx, GDBJIT_SECT_strtab, gdbjit_symtab);
+  gdbjit_initsect(ctx, GDBJIT_SECT_debug_info, gdbjit_debuginfo);
+  gdbjit_initsect(ctx, GDBJIT_SECT_debug_abbrev, gdbjit_debugabbrev);
+  gdbjit_initsect(ctx, GDBJIT_SECT_debug_line, gdbjit_debugline);
+  SECTALIGN(ctx->p, sizeof(uintptr_t));
+  gdbjit_initsect(ctx, GDBJIT_SECT_eh_frame, gdbjit_ehframe);
+  ctx->objsize = (size_t)((char *)ctx->p - (char *)obj);
+  lua_assert(ctx->objsize < sizeof(GDBJITobj));
+}
+
+#undef SECTALIGN
+
+/* -- Interface to GDB JIT API -------------------------------------------- */
+
+/* Add new entry to GDB JIT symbol chain. */
+static void gdbjit_newentry(lua_State *L, GDBJITctx *ctx)
+{
+  /* Allocate memory for GDB JIT entry and ELF object. */
+  MSize sz = (MSize)(sizeof(GDBJITentryobj) - sizeof(GDBJITobj) + ctx->objsize);
+  GDBJITentryobj *eo = lj_mem_newt(L, sz, GDBJITentryobj);
+  memcpy(&eo->obj, &ctx->obj, ctx->objsize);  /* Copy ELF object. */
+  eo->sz = sz;
+  ctx->T->gdbjit_entry = (void *)eo;
+  /* Link new entry to chain and register it. */
+  eo->entry.prev_entry = NULL;
+  eo->entry.next_entry = __jit_debug_descriptor.first_entry;
+  if (eo->entry.next_entry)
+    eo->entry.next_entry->prev_entry = &eo->entry;
+  eo->entry.symfile_addr = (const char *)&eo->obj;
+  eo->entry.symfile_size = ctx->objsize;
+  __jit_debug_descriptor.first_entry = &eo->entry;
+  __jit_debug_descriptor.relevant_entry = &eo->entry;
+  __jit_debug_descriptor.action_flag = GDBJIT_REGISTER;
+  __jit_debug_register_code();
+}
+
+/* Add debug info for newly compiled trace and notify GDB. */
+void lj_gdbjit_addtrace(jit_State *J, GCtrace *T)
+{
+  GDBJITctx ctx;
+  GCproto *pt = &gcref(T->startpt)->pt;
+  TraceNo parent = T->ir[REF_BASE].op1;
+  const BCIns *startpc = mref(T->startpc, const BCIns);
+  ctx.T = T;
+  ctx.mcaddr = (uintptr_t)T->mcode;
+  ctx.szmcode = T->szmcode;
+  ctx.spadjp = CFRAME_SIZE_JIT +
+	       (MSize)(parent ? traceref(J, parent)->spadjust : 0);
+  ctx.spadj = CFRAME_SIZE_JIT + T->spadjust;
+  lua_assert(startpc >= proto_bc(pt) && startpc < proto_bc(pt) + pt->sizebc);
+  ctx.lineno = lj_debug_line(pt, proto_bcpos(pt, startpc));
+  ctx.filename = proto_chunknamestr(pt);
+  if (*ctx.filename == '@' || *ctx.filename == '=')
+    ctx.filename++;
+  else
+    ctx.filename = "(string)";
+  gdbjit_buildobj(&ctx);
+  gdbjit_newentry(J->L, &ctx);
+}
+
+/* Delete debug info for trace and notify GDB. */
+void lj_gdbjit_deltrace(jit_State *J, GCtrace *T)
+{
+  GDBJITentryobj *eo = (GDBJITentryobj *)T->gdbjit_entry;
+  if (eo) {
+    if (eo->entry.prev_entry)
+      eo->entry.prev_entry->next_entry = eo->entry.next_entry;
+    else
+      __jit_debug_descriptor.first_entry = eo->entry.next_entry;
+    if (eo->entry.next_entry)
+      eo->entry.next_entry->prev_entry = eo->entry.prev_entry;
+    __jit_debug_descriptor.relevant_entry = &eo->entry;
+    __jit_debug_descriptor.action_flag = GDBJIT_UNREGISTER;
+    __jit_debug_register_code();
+    lj_mem_free(J2G(J), eo, eo->sz);
+  }
+}
+
+#endif
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_gdbjit.h
----------------------------------------------------------------------
diff --git a/lib/luajit/src/lj_gdbjit.h b/lib/luajit/src/lj_gdbjit.h
new file mode 100644
index 0000000..49c5863
--- /dev/null
+++ b/lib/luajit/src/lj_gdbjit.h
@@ -0,0 +1,22 @@
+/*
+** Client for the GDB JIT API.
+** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#ifndef _LJ_GDBJIT_H
+#define _LJ_GDBJIT_H
+
+#include "lj_obj.h"
+#include "lj_jit.h"
+
+#if LJ_HASJIT && defined(LUAJIT_USE_GDBJIT)
+
+LJ_FUNC void lj_gdbjit_addtrace(jit_State *J, GCtrace *T);
+LJ_FUNC void lj_gdbjit_deltrace(jit_State *J, GCtrace *T);
+
+#else
+#define lj_gdbjit_addtrace(J, T)	UNUSED(T)
+#define lj_gdbjit_deltrace(J, T)	UNUSED(T)
+#endif
+
+#endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/1f27b840/lib/luajit/src/lj_ir.c
----------------------------------------------------------------------
diff --git a/lib/luajit/src/lj_ir.c b/lib/luajit/src/lj_ir.c
new file mode 100644
index 0000000..439f3fc
--- /dev/null
+++ b/lib/luajit/src/lj_ir.c
@@ -0,0 +1,501 @@
+/*
+** SSA IR (Intermediate Representation) emitter.
+** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#define lj_ir_c
+#define LUA_CORE
+
+/* For pointers to libc/libm functions. */
+#include <stdio.h>
+#include <math.h>
+
+#include "lj_obj.h"
+
+#if LJ_HASJIT
+
+#include "lj_gc.h"
+#include "lj_str.h"
+#include "lj_tab.h"
+#include "lj_ir.h"
+#include "lj_jit.h"
+#include "lj_ircall.h"
+#include "lj_iropt.h"
+#include "lj_trace.h"
+#if LJ_HASFFI
+#include "lj_ctype.h"
+#include "lj_cdata.h"
+#include "lj_carith.h"
+#endif
+#include "lj_vm.h"
+#include "lj_strscan.h"
+#include "lj_lib.h"
+
+/* Some local macros to save typing. Undef'd at the end. */
+#define IR(ref)			(&J->cur.ir[(ref)])
+#define fins			(&J->fold.ins)
+
+/* Pass IR on to next optimization in chain (FOLD). */
+#define emitir(ot, a, b)        (lj_ir_set(J, (ot), (a), (b)), lj_opt_fold(J))
+
+/* -- IR tables ----------------------------------------------------------- */
+
+/* IR instruction modes. */
+LJ_DATADEF const uint8_t lj_ir_mode[IR__MAX+1] = {
+IRDEF(IRMODE)
+  0
+};
+
+/* IR type sizes. */
+LJ_DATADEF const uint8_t lj_ir_type_size[IRT__MAX+1] = {
+#define IRTSIZE(name, size)	size,
+IRTDEF(IRTSIZE)
+#undef IRTSIZE
+  0
+};
+
+/* C call info for CALL* instructions. */
+LJ_DATADEF const CCallInfo lj_ir_callinfo[] = {
+#define IRCALLCI(cond, name, nargs, kind, type, flags) \
+  { (ASMFunction)IRCALLCOND_##cond(name), \
+    (nargs)|(CCI_CALL_##kind)|(IRT_##type<<CCI_OTSHIFT)|(flags) },
+IRCALLDEF(IRCALLCI)
+#undef IRCALLCI
+  { NULL, 0 }
+};
+
+/* -- IR emitter ---------------------------------------------------------- */
+
+/* Grow IR buffer at the top. */
+void LJ_FASTCALL lj_ir_growtop(jit_State *J)
+{
+  IRIns *baseir = J->irbuf + J->irbotlim;
+  MSize szins = J->irtoplim - J->irbotlim;
+  if (szins) {
+    baseir = (IRIns *)lj_mem_realloc(J->L, baseir, szins*sizeof(IRIns),
+				     2*szins*sizeof(IRIns));
+    J->irtoplim = J->irbotlim + 2*szins;
+  } else {
+    baseir = (IRIns *)lj_mem_realloc(J->L, NULL, 0, LJ_MIN_IRSZ*sizeof(IRIns));
+    J->irbotlim = REF_BASE - LJ_MIN_IRSZ/4;
+    J->irtoplim = J->irbotlim + LJ_MIN_IRSZ;
+  }
+  J->cur.ir = J->irbuf = baseir - J->irbotlim;
+}
+
+/* Grow IR buffer at the bottom or shift it up. */
+static void lj_ir_growbot(jit_State *J)
+{
+  IRIns *baseir = J->irbuf + J->irbotlim;
+  MSize szins = J->irtoplim - J->irbotlim;
+  lua_assert(szins != 0);
+  lua_assert(J->cur.nk == J->irbotlim);
+  if (J->cur.nins + (szins >> 1) < J->irtoplim) {
+    /* More than half of the buffer is free on top: shift up by a quarter. */
+    MSize ofs = szins >> 2;
+    memmove(baseir + ofs, baseir, (J->cur.nins - J->irbotlim)*sizeof(IRIns));
+    J->irbotlim -= ofs;
+    J->irtoplim -= ofs;
+    J->cur.ir = J->irbuf = baseir - J->irbotlim;
+  } else {
+    /* Double the buffer size, but split the growth amongst top/bottom. */
+    IRIns *newbase = lj_mem_newt(J->L, 2*szins*sizeof(IRIns), IRIns);
+    MSize ofs = szins >= 256 ? 128 : (szins >> 1);  /* Limit bottom growth. */
+    memcpy(newbase + ofs, baseir, (J->cur.nins - J->irbotlim)*sizeof(IRIns));
+    lj_mem_free(G(J->L), baseir, szins*sizeof(IRIns));
+    J->irbotlim -= ofs;
+    J->irtoplim = J->irbotlim + 2*szins;
+    J->cur.ir = J->irbuf = newbase - J->irbotlim;
+  }
+}
+
+/* Emit IR without any optimizations. */
+TRef LJ_FASTCALL lj_ir_emit(jit_State *J)
+{
+  IRRef ref = lj_ir_nextins(J);
+  IRIns *ir = IR(ref);
+  IROp op = fins->o;
+  ir->prev = J->chain[op];
+  J->chain[op] = (IRRef1)ref;
+  ir->o = op;
+  ir->op1 = fins->op1;
+  ir->op2 = fins->op2;
+  J->guardemit.irt |= fins->t.irt;
+  return TREF(ref, irt_t((ir->t = fins->t)));
+}
+
+/* Emit call to a C function. */
+TRef lj_ir_call(jit_State *J, IRCallID id, ...)
+{
+  const CCallInfo *ci = &lj_ir_callinfo[id];
+  uint32_t n = CCI_NARGS(ci);
+  TRef tr = TREF_NIL;
+  va_list argp;
+  va_start(argp, id);
+  if ((ci->flags & CCI_L)) n--;
+  if (n > 0)
+    tr = va_arg(argp, IRRef);
+  while (n-- > 1)
+    tr = emitir(IRT(IR_CARG, IRT_NIL), tr, va_arg(argp, IRRef));
+  va_end(argp);
+  if (CCI_OP(ci) == IR_CALLS)
+    J->needsnap = 1;  /* Need snapshot after call with side effect. */
+  return emitir(CCI_OPTYPE(ci), tr, id);
+}
+
+/* -- Interning of constants ---------------------------------------------- */
+
+/*
+** IR instructions for constants are kept between J->cur.nk >= ref < REF_BIAS.
+** They are chained like all other instructions, but grow downwards.
+** The are interned (like strings in the VM) to facilitate reference
+** comparisons. The same constant must get the same reference.
+*/
+
+/* Get ref of next IR constant and optionally grow IR.
+** Note: this may invalidate all IRIns *!
+*/
+static LJ_AINLINE IRRef ir_nextk(jit_State *J)
+{
+  IRRef ref = J->cur.nk;
+  if (LJ_UNLIKELY(ref <= J->irbotlim)) lj_ir_growbot(J);
+  J->cur.nk = --ref;
+  return ref;
+}
+
+/* Intern int32_t constant. */
+TRef LJ_FASTCALL lj_ir_kint(jit_State *J, int32_t k)
+{
+  IRIns *ir, *cir = J->cur.ir;
+  IRRef ref;
+  for (ref = J->chain[IR_KINT]; ref; ref = cir[ref].prev)
+    if (cir[ref].i == k)
+      goto found;
+  ref = ir_nextk(J);
+  ir = IR(ref);
+  ir->i = k;
+  ir->t.irt = IRT_INT;
+  ir->o = IR_KINT;
+  ir->prev = J->chain[IR_KINT];
+  J->chain[IR_KINT] = (IRRef1)ref;
+found:
+  return TREF(ref, IRT_INT);
+}
+
+/* The MRef inside the KNUM/KINT64 IR instructions holds the address of the
+** 64 bit constant. The constants themselves are stored in a chained array
+** and shared across traces.
+**
+** Rationale for choosing this data structure:
+** - The address of the constants is embedded in the generated machine code
+**   and must never move. A resizable array or hash table wouldn't work.
+** - Most apps need very few non-32 bit integer constants (less than a dozen).
+** - Linear search is hard to beat in terms of speed and low complexity.
+*/
+typedef struct K64Array {
+  MRef next;			/* Pointer to next list. */
+  MSize numk;			/* Number of used elements in this array. */
+  TValue k[LJ_MIN_K64SZ];	/* Array of constants. */
+} K64Array;
+
+/* Free all chained arrays. */
+void lj_ir_k64_freeall(jit_State *J)
+{
+  K64Array *k;
+  for (k = mref(J->k64, K64Array); k; ) {
+    K64Array *next = mref(k->next, K64Array);
+    lj_mem_free(J2G(J), k, sizeof(K64Array));
+    k = next;
+  }
+}
+
+/* Find 64 bit constant in chained array or add it. */
+cTValue *lj_ir_k64_find(jit_State *J, uint64_t u64)
+{
+  K64Array *k, *kp = NULL;
+  TValue *ntv;
+  MSize idx;
+  /* Search for the constant in the whole chain of arrays. */
+  for (k = mref(J->k64, K64Array); k; k = mref(k->next, K64Array)) {
+    kp = k;  /* Remember previous element in list. */
+    for (idx = 0; idx < k->numk; idx++) {  /* Search one array. */
+      TValue *tv = &k->k[idx];
+      if (tv->u64 == u64)  /* Needed for +-0/NaN/absmask. */
+	return tv;
+    }
+  }
+  /* Constant was not found, need to add it. */
+  if (!(kp && kp->numk < LJ_MIN_K64SZ)) {  /* Allocate a new array. */
+    K64Array *kn = lj_mem_newt(J->L, sizeof(K64Array), K64Array);
+    setmref(kn->next, NULL);
+    kn->numk = 0;
+    if (kp)
+      setmref(kp->next, kn);  /* Chain to the end of the list. */
+    else
+      setmref(J->k64, kn);  /* Link first array. */
+    kp = kn;
+  }
+  ntv = &kp->k[kp->numk++];  /* Add to current array. */
+  ntv->u64 = u64;
+  return ntv;
+}
+
+/* Intern 64 bit constant, given by its address. */
+TRef lj_ir_k64(jit_State *J, IROp op, cTValue *tv)
+{
+  IRIns *ir, *cir = J->cur.ir;
+  IRRef ref;
+  IRType t = op == IR_KNUM ? IRT_NUM : IRT_I64;
+  for (ref = J->chain[op]; ref; ref = cir[ref].prev)
+    if (ir_k64(&cir[ref]) == tv)
+      goto found;
+  ref = ir_nextk(J);
+  ir = IR(ref);
+  lua_assert(checkptr32(tv));
+  setmref(ir->ptr, tv);
+  ir->t.irt = t;
+  ir->o = op;
+  ir->prev = J->chain[op];
+  J->chain[op] = (IRRef1)ref;
+found:
+  return TREF(ref, t);
+}
+
+/* Intern FP constant, given by its 64 bit pattern. */
+TRef lj_ir_knum_u64(jit_State *J, uint64_t u64)
+{
+  return lj_ir_k64(J, IR_KNUM, lj_ir_k64_find(J, u64));
+}
+
+/* Intern 64 bit integer constant. */
+TRef lj_ir_kint64(jit_State *J, uint64_t u64)
+{
+  return lj_ir_k64(J, IR_KINT64, lj_ir_k64_find(J, u64));
+}
+
+/* Check whether a number is int and return it. -0 is NOT considered an int. */
+static int numistrueint(lua_Number n, int32_t *kp)
+{
+  int32_t k = lj_num2int(n);
+  if (n == (lua_Number)k) {
+    if (kp) *kp = k;
+    if (k == 0) {  /* Special check for -0. */
+      TValue tv;
+      setnumV(&tv, n);
+      if (tv.u32.hi != 0)
+	return 0;
+    }
+    return 1;
+  }
+  return 0;
+}
+
+/* Intern number as int32_t constant if possible, otherwise as FP constant. */
+TRef lj_ir_knumint(jit_State *J, lua_Number n)
+{
+  int32_t k;
+  if (numistrueint(n, &k))
+    return lj_ir_kint(J, k);
+  else
+    return lj_ir_knum(J, n);
+}
+
+/* Intern GC object "constant". */
+TRef lj_ir_kgc(jit_State *J, GCobj *o, IRType t)
+{
+  IRIns *ir, *cir = J->cur.ir;
+  IRRef ref;
+  lua_assert(!isdead(J2G(J), o));
+  for (ref = J->chain[IR_KGC]; ref; ref = cir[ref].prev)
+    if (ir_kgc(&cir[ref]) == o)
+      goto found;
+  ref = ir_nextk(J);
+  ir = IR(ref);
+  /* NOBARRIER: Current trace is a GC root. */
+  setgcref(ir->gcr, o);
+  ir->t.irt = (uint8_t)t;
+  ir->o = IR_KGC;
+  ir->prev = J->chain[IR_KGC];
+  J->chain[IR_KGC] = (IRRef1)ref;
+found:
+  return TREF(ref, t);
+}
+
+/* Intern 32 bit pointer constant. */
+TRef lj_ir_kptr_(jit_State *J, IROp op, void *ptr)
+{
+  IRIns *ir, *cir = J->cur.ir;
+  IRRef ref;
+  lua_assert((void *)(intptr_t)i32ptr(ptr) == ptr);
+  for (ref = J->chain[op]; ref; ref = cir[ref].prev)
+    if (mref(cir[ref].ptr, void) == ptr)
+      goto found;
+  ref = ir_nextk(J);
+  ir = IR(ref);
+  setmref(ir->ptr, ptr);
+  ir->t.irt = IRT_P32;
+  ir->o = op;
+  ir->prev = J->chain[op];
+  J->chain[op] = (IRRef1)ref;
+found:
+  return TREF(ref, IRT_P32);
+}
+
+/* Intern typed NULL constant. */
+TRef lj_ir_knull(jit_State *J, IRType t)
+{
+  IRIns *ir, *cir = J->cur.ir;
+  IRRef ref;
+  for (ref = J->chain[IR_KNULL]; ref; ref = cir[ref].prev)
+    if (irt_t(cir[ref].t) == t)
+      goto found;
+  ref = ir_nextk(J);
+  ir = IR(ref);
+  ir->i = 0;
+  ir->t.irt = (uint8_t)t;
+  ir->o = IR_KNULL;
+  ir->prev = J->chain[IR_KNULL];
+  J->chain[IR_KNULL] = (IRRef1)ref;
+found:
+  return TREF(ref, t);
+}
+
+/* Intern key slot. */
+TRef lj_ir_kslot(jit_State *J, TRef key, IRRef slot)
+{
+  IRIns *ir, *cir = J->cur.ir;
+  IRRef2 op12 = IRREF2((IRRef1)key, (IRRef1)slot);
+  IRRef ref;
+  /* Const part is not touched by CSE/DCE, so 0-65535 is ok for IRMlit here. */
+  lua_assert(tref_isk(key) && slot == (IRRef)(IRRef1)slot);
+  for (ref = J->chain[IR_KSLOT]; ref; ref = cir[ref].prev)
+    if (cir[ref].op12 == op12)
+      goto found;
+  ref = ir_nextk(J);
+  ir = IR(ref);
+  ir->op12 = op12;
+  ir->t.irt = IRT_P32;
+  ir->o = IR_KSLOT;
+  ir->prev = J->chain[IR_KSLOT];
+  J->chain[IR_KSLOT] = (IRRef1)ref;
+found:
+  return TREF(ref, IRT_P32);
+}
+
+/* -- Access to IR constants ---------------------------------------------- */
+
+/* Copy value of IR constant. */
+void lj_ir_kvalue(lua_State *L, TValue *tv, const IRIns *ir)
+{
+  UNUSED(L);
+  lua_assert(ir->o != IR_KSLOT);  /* Common mistake. */
+  switch (ir->o) {
+  case IR_KPRI: setitype(tv, irt_toitype(ir->t)); break;
+  case IR_KINT: setintV(tv, ir->i); break;
+  case IR_KGC: setgcV(L, tv, ir_kgc(ir), irt_toitype(ir->t)); break;
+  case IR_KPTR: case IR_KKPTR: case IR_KNULL:
+    setlightudV(tv, mref(ir->ptr, void));
+    break;
+  case IR_KNUM: setnumV(tv, ir_knum(ir)->n); break;
+#if LJ_HASFFI
+  case IR_KINT64: {
+    GCcdata *cd = lj_cdata_new_(L, CTID_INT64, 8);
+    *(uint64_t *)cdataptr(cd) = ir_kint64(ir)->u64;
+    setcdataV(L, tv, cd);
+    break;
+    }
+#endif
+  default: lua_assert(0); break;
+  }
+}
+
+/* -- Convert IR operand types -------------------------------------------- */
+
+/* Convert from string to number. */
+TRef LJ_FASTCALL lj_ir_tonumber(jit_State *J, TRef tr)
+{
+  if (!tref_isnumber(tr)) {
+    if (tref_isstr(tr))
+      tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0);
+    else
+      lj_trace_err(J, LJ_TRERR_BADTYPE);
+  }
+  return tr;
+}
+
+/* Convert from integer or string to number. */
+TRef LJ_FASTCALL lj_ir_tonum(jit_State *J, TRef tr)
+{
+  if (!tref_isnum(tr)) {
+    if (tref_isinteger(tr))
+      tr = emitir(IRTN(IR_CONV), tr, IRCONV_NUM_INT);
+    else if (tref_isstr(tr))
+      tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0);
+    else
+      lj_trace_err(J, LJ_TRERR_BADTYPE);
+  }
+  return tr;
+}
+
+/* Convert from integer or number to string. */
+TRef LJ_FASTCALL lj_ir_tostr(jit_State *J, TRef tr)
+{
+  if (!tref_isstr(tr)) {
+    if (!tref_isnumber(tr))
+      lj_trace_err(J, LJ_TRERR_BADTYPE);
+    tr = emitir(IRT(IR_TOSTR, IRT_STR), tr, 0);
+  }
+  return tr;
+}
+
+/* -- Miscellaneous IR ops ------------------------------------------------ */
+
+/* Evaluate numeric comparison. */
+int lj_ir_numcmp(lua_Number a, lua_Number b, IROp op)
+{
+  switch (op) {
+  case IR_EQ: return (a == b);
+  case IR_NE: return (a != b);
+  case IR_LT: return (a < b);
+  case IR_GE: return (a >= b);
+  case IR_LE: return (a <= b);
+  case IR_GT: return (a > b);
+  case IR_ULT: return !(a >= b);
+  case IR_UGE: return !(a < b);
+  case IR_ULE: return !(a > b);
+  case IR_UGT: return !(a <= b);
+  default: lua_assert(0); return 0;
+  }
+}
+
+/* Evaluate string comparison. */
+int lj_ir_strcmp(GCstr *a, GCstr *b, IROp op)
+{
+  int res = lj_str_cmp(a, b);
+  switch (op) {
+  case IR_LT: return (res < 0);
+  case IR_GE: return (res >= 0);
+  case IR_LE: return (res <= 0);
+  case IR_GT: return (res > 0);
+  default: lua_assert(0); return 0;
+  }
+}
+
+/* Rollback IR to previous state. */
+void lj_ir_rollback(jit_State *J, IRRef ref)
+{
+  IRRef nins = J->cur.nins;
+  while (nins > ref) {
+    IRIns *ir;
+    nins--;
+    ir = IR(nins);
+    J->chain[ir->o] = ir->prev;
+  }
+  J->cur.nins = nins;
+}
+
+#undef IR
+#undef fins
+#undef emitir
+
+#endif