From 19b69f21d409375ad8362c04186b246c1749fc8e Mon Sep 17 00:00:00 2001
From: Mike Pall <mike>
Date: Tue, 1 Apr 2014 00:30:22 +0200
Subject: FFI: Allow non-scalar cdata to be compared for equality by address.

---
 src/lj_carith.c  |  6 ++++--
 src/lj_crecord.c | 61 +++++++++++++++++++++++++++++++-------------------------
 2 files changed, 38 insertions(+), 29 deletions(-)

diff --git a/src/lj_carith.c b/src/lj_carith.c
index 9f94091d..92fe5597 100644
--- a/src/lj_carith.c
+++ b/src/lj_carith.c
@@ -73,7 +73,7 @@ static int carith_checkarg(lua_State *L, CTState *cts, CDArith *ca)
 	  ok = 1;
 	} else {
 	  ca->ct[1-i] = ct;  /* Use enum to improve error message. */
-	  ca->p[1-i] = NULL;
+	  ca->p[1-i] = (void *)(intptr_t)1;  /* To make it unequal. */
 	  break;
 	}
       }
@@ -234,7 +234,9 @@ static int lj_carith_meta(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
     const char *repr[2];
     int i, isenum = -1, isstr = -1;
     if (mm == MM_eq) {  /* Equality checks never raise an error. */
-      setboolV(L->top-1, 0);
+      int eq = ca->p[0] == ca->p[1];
+      setboolV(L->top-1, eq);
+      setboolV(&G(L)->tmptv2, eq);  /* Remember for trace recorder. */
       return 1;
     }
     for (i = 0; i < 2; i++) {
diff --git a/src/lj_crecord.c b/src/lj_crecord.c
index da9013f0..71f3d069 100644
--- a/src/lj_crecord.c
+++ b/src/lj_crecord.c
@@ -1317,7 +1317,8 @@ static TRef crec_arith_ptr(jit_State *J, TRef *sp, CType **s, MMS mm)
 }
 
 /* Record ctype arithmetic metamethods. */
-static void crec_arith_meta(jit_State *J, CTState *cts, RecordFFData *rd)
+static TRef crec_arith_meta(jit_State *J, TRef *sp, CTState *cts,
+			    RecordFFData *rd)
 {
   cTValue *tv = NULL;
   if (J->base[0]) {
@@ -1338,13 +1339,20 @@ static void crec_arith_meta(jit_State *J, CTState *cts, RecordFFData *rd)
     if (tvisfunc(tv)) {
       J->base[-1] = lj_ir_kfunc(J, funcV(tv)) | TREF_FRAME;
       rd->nres = -1;  /* Pending tailcall. */
-      return;
+      return 0;
     }  /* NYI: non-function metamethods. */
-  } else if ((MMS)rd->data == MM_eq) {
-    J->base[0] = TREF_FALSE;
-    return;
+  } else if ((MMS)rd->data == MM_eq) {  /* Fallback cdata pointer comparison. */
+    if (sp[0] && sp[1]) {
+      /* Assume true comparison. Fixup and emit pending guard later. */
+      lj_ir_set(J, IRTG(IR_EQ, IRT_PTR), sp[0], sp[1]);
+      J->postproc = LJ_POST_FIXGUARD;
+      return TREF_TRUE;
+    } else {
+      return TREF_FALSE;
+    }
   }
   lj_trace_err(J, LJ_TRERR_BADTYPE);
+  return 0;
 }
 
 void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
@@ -1357,7 +1365,7 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
     TRef tr = J->base[i];
     CType *ct = ctype_get(cts, CTID_DOUBLE);
     if (!tr) {
-      goto trymeta;
+      lj_trace_err(J, LJ_TRERR_BADTYPE);
     } else if (tref_iscdata(tr)) {
       CTypeID id = argv2cdata(J, tr, &rd->argv[i])->ctypeid;
       IRType t;
@@ -1387,11 +1395,12 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
       }
       if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
       if (ctype_isnum(ct->info)) {
-	if (t == IRT_CDATA) goto trymeta;
-	if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J);
-	tr = emitir(IRT(IR_XLOAD, t), tr, 0);
-      } else if (!(ctype_isptr(ct->info) || ctype_isrefarray(ct->info))) {
-	goto trymeta;
+	if (t == IRT_CDATA) {
+	  tr = 0;
+	} else {
+	  if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J);
+	  tr = emitir(IRT(IR_XLOAD, t), tr, 0);
+	}
       }
     } else if (tref_isnil(tr)) {
       tr = lj_ir_kptr(J, NULL);
@@ -1414,7 +1423,7 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
 	}  /* else: interpreter will throw. */
       }  /* else: interpreter will throw. */
     } else if (!tref_isnum(tr)) {
-      goto trymeta;
+      tr = 0;
     }
   ok:
     s[i] = ct;
@@ -1422,22 +1431,20 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
   }
   {
     TRef tr;
-    if ((tr = crec_arith_int64(J, sp, s, (MMS)rd->data)) ||
-	(tr = crec_arith_ptr(J, sp, s, (MMS)rd->data))) {
-      J->base[0] = tr;
-      /* Fixup cdata comparisons, too. Avoids some cdata escapes. */
-      if (J->postproc == LJ_POST_FIXGUARD && frame_iscont(J->L->base-1) &&
-	  !irt_isguard(J->guardemit)) {
-	const BCIns *pc = frame_contpc(J->L->base-1) - 1;
-	if (bc_op(*pc) <= BC_ISNEP) {
-	  setframe_pc(&J2G(J)->tmptv, pc);
-	  J2G(J)->tmptv.u32.lo = ((tref_istrue(tr) ^ bc_op(*pc)) & 1);
-	  J->postproc = LJ_POST_FIXCOMP;
-	}
+    if (!(tr = crec_arith_int64(J, sp, s, (MMS)rd->data)) &&
+	!(tr = crec_arith_ptr(J, sp, s, (MMS)rd->data)) &&
+	!(tr = crec_arith_meta(J, sp, cts, rd)))
+      return;
+    J->base[0] = tr;
+    /* Fixup cdata comparisons, too. Avoids some cdata escapes. */
+    if (J->postproc == LJ_POST_FIXGUARD && frame_iscont(J->L->base-1) &&
+	!irt_isguard(J->guardemit)) {
+      const BCIns *pc = frame_contpc(J->L->base-1) - 1;
+      if (bc_op(*pc) <= BC_ISNEP) {
+	setframe_pc(&J2G(J)->tmptv, pc);
+	J2G(J)->tmptv.u32.lo = ((tref_istrue(tr) ^ bc_op(*pc)) & 1);
+	J->postproc = LJ_POST_FIXCOMP;
       }
-    } else {
-    trymeta:
-      crec_arith_meta(J, cts, rd);
     }
   }
 }
-- 
cgit v1.2.3-55-g6feb