浏览代码

FFI: Move code for cdata arithmetic to lj_carith.c.

Mike Pall 14 年之前
父节点
当前提交
3184f17169
共有 11 个文件被更改,包括 308 次插入260 次删除
  1. 2 1
      src/Makefile
  2. 15 12
      src/Makefile.dep
  3. 8 209
      src/lib_ffi.c
  4. 260 0
      src/lj_carith.c
  5. 19 0
      src/lj_carith.h
  6. 0 34
      src/lj_cdata.c
  7. 0 2
      src/lj_cdata.h
  8. 1 1
      src/lj_crecord.c
  9. 1 0
      src/lj_ir.c
  10. 1 1
      src/lj_ir.h
  11. 1 0
      src/ljamalg.c

+ 2 - 1
src/Makefile

@@ -334,7 +334,8 @@ LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o \
 	  lj_opt_dce.o lj_opt_loop.o \
 	  lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \
 	  lj_asm.o lj_trace.o lj_gdbjit.o \
-	  lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_clib.o lj_cparse.o \
+	  lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_carith.o lj_clib.o \
+	  lj_cparse.o \
 	  lj_lib.o lj_alloc.o lib_aux.o \
 	  $(LJLIB_O) lib_init.o
 

+ 15 - 12
src/Makefile.dep

@@ -22,8 +22,8 @@ lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
  lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h
 lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
  lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cparse.h \
- lj_cdata.h lj_cconv.h lj_ccall.h lj_clib.h lj_ff.h lj_ffdef.h lj_lib.h \
- lj_libdef.h
+ lj_cdata.h lj_cconv.h lj_carith.h lj_ccall.h lj_clib.h lj_ff.h \
+ lj_ffdef.h lj_lib.h lj_libdef.h
 lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h
 lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
  lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \
@@ -56,6 +56,9 @@ lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
  lj_asm.h lj_vm.h lj_target.h lj_target_*.h
 lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
  lj_bcdef.h
+lj_carith.o: lj_carith.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
+ lj_gc.h lj_err.h lj_errmsg.h lj_ctype.h lj_cconv.h lj_cdata.h \
+ lj_carith.h
 lj_ccall.o: lj_ccall.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
  lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cconv.h lj_cdata.h \
  lj_ccall.h lj_trace.h lj_jit.h lj_ir.h lj_dispatch.h lj_bc.h \
@@ -99,7 +102,7 @@ lj_gdbjit.o: lj_gdbjit.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
  lj_dispatch.h
 lj_ir.o: lj_ir.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
  lj_str.h lj_tab.h lj_ir.h lj_jit.h lj_iropt.h lj_trace.h lj_dispatch.h \
- lj_bc.h lj_traceerr.h lj_ctype.h lj_cdata.h lj_lib.h
+ lj_bc.h lj_traceerr.h lj_ctype.h lj_cdata.h lj_carith.h lj_lib.h
 lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
  lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_ctype.h lj_cdata.h lualib.h \
  lj_state.h lj_lex.h lj_parse.h lj_char.h
@@ -161,13 +164,13 @@ ljamalg.o: ljamalg.c lua.h luaconf.h lauxlib.h lj_gc.c lj_obj.h lj_def.h \
  lj_func.c lj_udata.c lj_meta.c lj_state.c lj_lex.h lj_alloc.h \
  lj_dispatch.c lj_ff.h lj_ffdef.h luajit.h lj_vmevent.c lj_vmevent.h \
  lj_api.c lj_parse.h lj_lex.c lualib.h lj_parse.c lj_ctype.c lj_cdata.c \
- lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h lj_clib.c lj_clib.h \
- lj_cparse.c lj_cparse.h lj_lib.c lj_lib.h lj_ir.c lj_iropt.h \
- lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c lj_opt_dce.c \
- lj_opt_loop.c lj_snap.h lj_mcode.c lj_mcode.h lj_snap.c lj_target.h \
- lj_target_*.h lj_record.c lj_record.h lj_ffrecord.h lj_crecord.c \
- lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h lj_trace.c \
- lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c lib_base.c lj_libdef.h \
- lib_math.c lib_string.c lib_table.c lib_io.c lib_os.c lib_package.c \
- lib_debug.c lib_bit.c lib_jit.c lib_ffi.c lib_init.c
+ lj_cconv.h lj_cconv.c lj_ccall.c lj_ccall.h lj_carith.c lj_carith.h \
+ lj_clib.c lj_clib.h lj_cparse.c lj_cparse.h lj_lib.c lj_lib.h lj_ir.c \
+ lj_iropt.h lj_opt_mem.c lj_opt_fold.c lj_folddef.h lj_opt_narrow.c \
+ lj_opt_dce.c lj_opt_loop.c lj_snap.h lj_mcode.c lj_mcode.h lj_snap.c \
+ lj_target.h lj_target_*.h lj_record.c lj_record.h lj_ffrecord.h \
+ lj_crecord.c lj_crecord.h lj_ffrecord.c lj_recdef.h lj_asm.c lj_asm.h \
+ lj_trace.c lj_gdbjit.h lj_gdbjit.c lj_alloc.c lib_aux.c lib_base.c \
+ lj_libdef.h lib_math.c lib_string.c lib_table.c lib_io.c lib_os.c \
+ lib_package.c lib_debug.c lib_bit.c lib_jit.c lib_ffi.c lib_init.c
 luajit.o: luajit.c lua.h luaconf.h lauxlib.h lualib.h luajit.h lj_arch.h

+ 8 - 209
src/lib_ffi.c

@@ -21,6 +21,7 @@
 #include "lj_cparse.h"
 #include "lj_cdata.h"
 #include "lj_cconv.h"
+#include "lj_carith.h"
 #include "lj_ccall.h"
 #include "lj_clib.h"
 #include "lj_ff.h"
@@ -77,215 +78,6 @@ static void *ffi_checkptr(lua_State *L, int narg, CTypeID id)
   return p;
 }
 
-/* -- C data arithmetic --------------------------------------------------- */
-
-typedef struct FFIArith {
-  uint8_t *p[2];
-  CType *ct[2];
-} FFIArith;
-
-/* Check arguments for arithmetic metamethods. */
-static int ffi_checkarith(lua_State *L, CTState *cts, FFIArith *fa)
-{
-  TValue *o = L->base;
-  int ok = 1;
-  MSize i;
-  if (o+1 >= L->top)
-    lj_err_argt(L, 1, LUA_TCDATA);
-  for (i = 0; i < 2; i++, o++) {
-    if (tviscdata(o)) {
-      GCcdata *cd = cdataV(o);
-      CType *ct = ctype_raw(cts, (CTypeID)cd->typeid);
-      uint8_t *p = (uint8_t *)cdataptr(cd);
-      if (ctype_isptr(ct->info)) {
-	p = (uint8_t *)cdata_getptr(p, ct->size);
-	if (ctype_isref(ct->info)) ct = ctype_rawchild(cts, ct);
-      }
-      fa->ct[i] = ct;
-      fa->p[i] = p;
-    } else if (tvisnum(o)) {
-      fa->ct[i] = ctype_get(cts, CTID_DOUBLE);
-      fa->p[i] = (uint8_t *)&o->n;
-    } else if (tvisnil(o)) {
-      fa->ct[i] = ctype_get(cts, CTID_P_VOID);
-      fa->p[i] = (uint8_t *)0;
-    } else {
-      fa->ct[i] = NULL;
-      fa->p[i] = NULL;
-      ok = 0;
-    }
-  }
-  return ok;
-}
-
-/* Pointer arithmetic. */
-static int ffi_arith_ptr(lua_State *L, CTState *cts, FFIArith *fa, MMS mm)
-{
-  CType *ctp = fa->ct[0];
-  uint8_t *pp = fa->p[0];
-  ptrdiff_t idx;
-  CTSize sz;
-  CTypeID id;
-  GCcdata *cd;
-  if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) {
-    if ((mm == MM_sub || mm == MM_eq || mm == MM_lt || mm == MM_le) &&
-	(ctype_isptr(fa->ct[1]->info) || ctype_isrefarray(fa->ct[1]->info))) {
-      uint8_t *pp2 = fa->p[1];
-      if (mm == MM_eq) {  /* Pointer equality. Incompatible pointers are ok. */
-	setboolV(L->top-1, (pp == pp2));
-	return 1;
-      }
-      if (!lj_cconv_compatptr(cts, ctp, fa->ct[1], CCF_IGNQUAL))
-	return 0;
-      if (mm == MM_sub) {  /* Pointer difference. */
-	intptr_t diff;
-	sz = lj_ctype_size(cts, ctype_cid(ctp->info));  /* Element size. */
-	if (sz == 0 || sz == CTSIZE_INVALID)
-	  return 0;
-	diff = ((intptr_t)pp - (intptr_t)pp2) / (int32_t)sz;
-	/* All valid pointer differences on x64 are in (-2^47, +2^47),
-	** which fits into a double without loss of precision.
-	*/
-	setnumV(L->top-1, (lua_Number)diff);
-	return 1;
-      } else if (mm == MM_lt) {  /* Pointer comparison (unsigned). */
-	setboolV(L->top-1, ((uintptr_t)pp < (uintptr_t)pp2));
-	return 1;
-      } else {
-	lua_assert(mm == MM_le);
-	setboolV(L->top-1, ((uintptr_t)pp <= (uintptr_t)pp2));
-	return 1;
-      }
-    }
-    if (!((mm == MM_add || mm == MM_sub) && ctype_isnum(fa->ct[1]->info)))
-      return 0;
-    lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), fa->ct[1],
-		   (uint8_t *)&idx, fa->p[1], 0);
-    if (mm == MM_sub) idx = -idx;
-  } else if (mm == MM_add && ctype_isnum(ctp->info) &&
-      (ctype_isptr(fa->ct[1]->info) || ctype_isrefarray(fa->ct[1]->info))) {
-    /* Swap pointer and index. */
-    ctp = fa->ct[1]; pp = fa->p[1];
-    lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), fa->ct[0],
-		   (uint8_t *)&idx, fa->p[0], 0);
-  } else {
-    return 0;
-  }
-  sz = lj_ctype_size(cts, ctype_cid(ctp->info));  /* Element size. */
-  if (sz == CTSIZE_INVALID)
-    return 0;
-  pp += idx*(int32_t)sz;  /* Compute pointer + index. */
-  id = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ctp->info)),
-		       CTSIZE_PTR);
-  cd = lj_cdata_new(cts, id, CTSIZE_PTR);
-  *(uint8_t **)cdataptr(cd) = pp;
-  setcdataV(L, L->top-1, cd);
-  lj_gc_check(L);
-  return 1;
-}
-
-/* 64 bit integer arithmetic. */
-static int ffi_arith_int64(lua_State *L, CTState *cts, FFIArith *fa, MMS mm)
-{
-  if (ctype_isnum(fa->ct[0]->info) && fa->ct[0]->size <= 8 &&
-      ctype_isnum(fa->ct[1]->info) && fa->ct[1]->size <= 8) {
-    CTypeID id = (((fa->ct[0]->info & CTF_UNSIGNED) && fa->ct[0]->size == 8) ||
-		  ((fa->ct[1]->info & CTF_UNSIGNED) && fa->ct[1]->size == 8)) ?
-		 CTID_UINT64 : CTID_INT64;
-    CType *ct = ctype_get(cts, id);
-    GCcdata *cd;
-    uint64_t u0, u1, *up;
-    lj_cconv_ct_ct(cts, ct, fa->ct[0], (uint8_t *)&u0, fa->p[0], 0);
-    if (mm != MM_unm)
-      lj_cconv_ct_ct(cts, ct, fa->ct[1], (uint8_t *)&u1, fa->p[1], 0);
-    switch (mm) {
-    case MM_eq:
-      setboolV(L->top-1, (u0 == u1));
-      return 1;
-    case MM_lt:
-      setboolV(L->top-1,
-	       id == CTID_INT64 ? ((int64_t)u0 < (int64_t)u1) : (u0 < u1));
-      return 1;
-    case MM_le:
-      setboolV(L->top-1,
-	       id == CTID_INT64 ? ((int64_t)u0 <= (int64_t)u1) : (u0 <= u1));
-      return 1;
-    case MM_div: case MM_mod:
-      if (u1 == 0) {  /* Division by zero. */
-	if (u0 == 0)
-	  setnanV(L->top-1);
-	else if (id == CTID_INT64 && (int64_t)u0 < 0)
-	  setminfV(L->top-1);
-	else
-	  setpinfV(L->top-1);
-	return 1;
-      } else if (id == CTID_INT64 && (int64_t)u1 == -1 &&
-		 u0 == U64x(80000000,00000000)) {  /* MIN64 / -1. */
-	if (mm == MM_div) id = CTID_UINT64; else u0 = 0;
-	mm = MM_unm;  /* Result is 0x8000000000000000ULL or 0LL. */
-      }
-      break;
-    default: break;
-    }
-    cd = lj_cdata_new(cts, id, 8);
-    up = (uint64_t *)cdataptr(cd);
-    setcdataV(L, L->top-1, cd);
-    switch (mm) {
-    case MM_add: *up = u0 + u1; break;
-    case MM_sub: *up = u0 - u1; break;
-    case MM_mul: *up = u0 * u1; break;
-    case MM_div:
-      if (id == CTID_INT64)
-	*up = (uint64_t)((int64_t)u0 / (int64_t)u1);
-      else
-	*up = u0 / u1;
-      break;
-    case MM_mod:
-      if (id == CTID_INT64)
-	*up = (uint64_t)((int64_t)u0 % (int64_t)u1);
-      else
-	*up = u0 % u1;
-      break;
-    case MM_pow: *up = lj_cdata_powi64(u0, u1, (id == CTID_UINT64)); break;
-    case MM_unm: *up = (uint64_t)-(int64_t)u0; break;
-    default: lua_assert(0); break;
-    }
-    lj_gc_check(L);
-    return 1;
-  }
-  return 0;
-}
-
-/* cdata arithmetic. */
-static int ffi_arith(lua_State *L)
-{
-  CTState *cts = ctype_cts(L);
-  FFIArith fa;
-  MMS mm = (MMS)(curr_func(L)->c.ffid - (int)FF_ffi_meta___eq + (int)MM_eq);
-  if (ffi_checkarith(L, cts, &fa)) {
-    if (ffi_arith_int64(L, cts, &fa, mm) || ffi_arith_ptr(L, cts, &fa, mm)) {
-      copyTV(L, &G(L)->tmptv2, L->top-1);  /* Remember for trace recorder. */
-      return 1;
-    }
-  }
-  /* NYI: per-cdata metamethods. */
-  {
-    const char *repr[2];
-    int i;
-    for (i = 0; i < 2; i++) {
-      if (fa.ct[i])
-	repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, fa.ct[i]), NULL));
-      else
-	repr[i] = typename(&L->base[i]);
-    }
-    lj_err_callerv(L, mm == MM_len ? LJ_ERR_FFI_BADLEN :
-		      mm == MM_concat ? LJ_ERR_FFI_BADCONCAT :
-		      mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH,
-		   repr[0], repr[1]);
-  }
-  return 0;  /* unreachable */
-}
-
 /* -- C type metamethods -------------------------------------------------- */
 
 #define LJLIB_MODULE_ffi_meta
@@ -319,6 +111,13 @@ LJLIB_CF(ffi_meta___newindex)	LJLIB_REC(cdata_index 1)
   return 0;
 }
 
+/* Common handler for cdata arithmetic. */
+static int ffi_arith(lua_State *L)
+{
+  MMS mm = (MMS)(curr_func(L)->c.ffid - (int)FF_ffi_meta___eq + (int)MM_eq);
+  return lj_carith_op(L, mm);
+}
+
 /* The following functions must be in contiguous ORDER MM. */
 LJLIB_CF(ffi_meta___eq)		LJLIB_REC(cdata_arith MM_eq)
 {

+ 260 - 0
src/lj_carith.c

@@ -0,0 +1,260 @@
+/*
+** C data arithmetic.
+** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#include "lj_obj.h"
+
+#if LJ_HASFFI
+
+#include "lj_gc.h"
+#include "lj_err.h"
+#include "lj_ctype.h"
+#include "lj_cconv.h"
+#include "lj_cdata.h"
+#include "lj_carith.h"
+
+/* -- C data arithmetic --------------------------------------------------- */
+
+/* Binary operands of an operator converted to ctypes. */
+typedef struct CDArith {
+  uint8_t *p[2];
+  CType *ct[2];
+} CDArith;
+
+/* Check arguments for arithmetic metamethods. */
+static int carith_checkarg(lua_State *L, CTState *cts, CDArith *ca)
+{
+  TValue *o = L->base;
+  int ok = 1;
+  MSize i;
+  if (o+1 >= L->top)
+    lj_err_argt(L, 1, LUA_TCDATA);
+  for (i = 0; i < 2; i++, o++) {
+    if (tviscdata(o)) {
+      GCcdata *cd = cdataV(o);
+      CType *ct = ctype_raw(cts, (CTypeID)cd->typeid);
+      uint8_t *p = (uint8_t *)cdataptr(cd);
+      if (ctype_isptr(ct->info)) {
+	p = (uint8_t *)cdata_getptr(p, ct->size);
+	if (ctype_isref(ct->info)) ct = ctype_rawchild(cts, ct);
+      }
+      ca->ct[i] = ct;
+      ca->p[i] = p;
+    } else if (tvisnum(o)) {
+      ca->ct[i] = ctype_get(cts, CTID_DOUBLE);
+      ca->p[i] = (uint8_t *)&o->n;
+    } else if (tvisnil(o)) {
+      ca->ct[i] = ctype_get(cts, CTID_P_VOID);
+      ca->p[i] = (uint8_t *)0;
+    } else {
+      ca->ct[i] = NULL;
+      ca->p[i] = NULL;
+      ok = 0;
+    }
+  }
+  return ok;
+}
+
+/* Pointer arithmetic. */
+static int carith_ptr(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
+{
+  CType *ctp = ca->ct[0];
+  uint8_t *pp = ca->p[0];
+  ptrdiff_t idx;
+  CTSize sz;
+  CTypeID id;
+  GCcdata *cd;
+  if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) {
+    if ((mm == MM_sub || mm == MM_eq || mm == MM_lt || mm == MM_le) &&
+	(ctype_isptr(ca->ct[1]->info) || ctype_isrefarray(ca->ct[1]->info))) {
+      uint8_t *pp2 = ca->p[1];
+      if (mm == MM_eq) {  /* Pointer equality. Incompatible pointers are ok. */
+	setboolV(L->top-1, (pp == pp2));
+	return 1;
+      }
+      if (!lj_cconv_compatptr(cts, ctp, ca->ct[1], CCF_IGNQUAL))
+	return 0;
+      if (mm == MM_sub) {  /* Pointer difference. */
+	intptr_t diff;
+	sz = lj_ctype_size(cts, ctype_cid(ctp->info));  /* Element size. */
+	if (sz == 0 || sz == CTSIZE_INVALID)
+	  return 0;
+	diff = ((intptr_t)pp - (intptr_t)pp2) / (int32_t)sz;
+	/* All valid pointer differences on x64 are in (-2^47, +2^47),
+	** which fits into a double without loss of precision.
+	*/
+	setnumV(L->top-1, (lua_Number)diff);
+	return 1;
+      } else if (mm == MM_lt) {  /* Pointer comparison (unsigned). */
+	setboolV(L->top-1, ((uintptr_t)pp < (uintptr_t)pp2));
+	return 1;
+      } else {
+	lua_assert(mm == MM_le);
+	setboolV(L->top-1, ((uintptr_t)pp <= (uintptr_t)pp2));
+	return 1;
+      }
+    }
+    if (!((mm == MM_add || mm == MM_sub) && ctype_isnum(ca->ct[1]->info)))
+      return 0;
+    lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ca->ct[1],
+		   (uint8_t *)&idx, ca->p[1], 0);
+    if (mm == MM_sub) idx = -idx;
+  } else if (mm == MM_add && ctype_isnum(ctp->info) &&
+      (ctype_isptr(ca->ct[1]->info) || ctype_isrefarray(ca->ct[1]->info))) {
+    /* Swap pointer and index. */
+    ctp = ca->ct[1]; pp = ca->p[1];
+    lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ca->ct[0],
+		   (uint8_t *)&idx, ca->p[0], 0);
+  } else {
+    return 0;
+  }
+  sz = lj_ctype_size(cts, ctype_cid(ctp->info));  /* Element size. */
+  if (sz == CTSIZE_INVALID)
+    return 0;
+  pp += idx*(int32_t)sz;  /* Compute pointer + index. */
+  id = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ctp->info)),
+		       CTSIZE_PTR);
+  cd = lj_cdata_new(cts, id, CTSIZE_PTR);
+  *(uint8_t **)cdataptr(cd) = pp;
+  setcdataV(L, L->top-1, cd);
+  lj_gc_check(L);
+  return 1;
+}
+
+/* 64 bit integer arithmetic. */
+static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
+{
+  if (ctype_isnum(ca->ct[0]->info) && ca->ct[0]->size <= 8 &&
+      ctype_isnum(ca->ct[1]->info) && ca->ct[1]->size <= 8) {
+    CTypeID id = (((ca->ct[0]->info & CTF_UNSIGNED) && ca->ct[0]->size == 8) ||
+		  ((ca->ct[1]->info & CTF_UNSIGNED) && ca->ct[1]->size == 8)) ?
+		 CTID_UINT64 : CTID_INT64;
+    CType *ct = ctype_get(cts, id);
+    GCcdata *cd;
+    uint64_t u0, u1, *up;
+    lj_cconv_ct_ct(cts, ct, ca->ct[0], (uint8_t *)&u0, ca->p[0], 0);
+    if (mm != MM_unm)
+      lj_cconv_ct_ct(cts, ct, ca->ct[1], (uint8_t *)&u1, ca->p[1], 0);
+    switch (mm) {
+    case MM_eq:
+      setboolV(L->top-1, (u0 == u1));
+      return 1;
+    case MM_lt:
+      setboolV(L->top-1,
+	       id == CTID_INT64 ? ((int64_t)u0 < (int64_t)u1) : (u0 < u1));
+      return 1;
+    case MM_le:
+      setboolV(L->top-1,
+	       id == CTID_INT64 ? ((int64_t)u0 <= (int64_t)u1) : (u0 <= u1));
+      return 1;
+    case MM_div: case MM_mod:
+      if (u1 == 0) {  /* Division by zero. */
+	if (u0 == 0)
+	  setnanV(L->top-1);
+	else if (id == CTID_INT64 && (int64_t)u0 < 0)
+	  setminfV(L->top-1);
+	else
+	  setpinfV(L->top-1);
+	return 1;
+      } else if (id == CTID_INT64 && (int64_t)u1 == -1 &&
+		 u0 == U64x(80000000,00000000)) {  /* MIN64 / -1. */
+	if (mm == MM_div) id = CTID_UINT64; else u0 = 0;
+	mm = MM_unm;  /* Result is 0x8000000000000000ULL or 0LL. */
+      }
+      break;
+    default: break;
+    }
+    cd = lj_cdata_new(cts, id, 8);
+    up = (uint64_t *)cdataptr(cd);
+    setcdataV(L, L->top-1, cd);
+    switch (mm) {
+    case MM_add: *up = u0 + u1; break;
+    case MM_sub: *up = u0 - u1; break;
+    case MM_mul: *up = u0 * u1; break;
+    case MM_div:
+      if (id == CTID_INT64)
+	*up = (uint64_t)((int64_t)u0 / (int64_t)u1);
+      else
+	*up = u0 / u1;
+      break;
+    case MM_mod:
+      if (id == CTID_INT64)
+	*up = (uint64_t)((int64_t)u0 % (int64_t)u1);
+      else
+	*up = u0 % u1;
+      break;
+    case MM_pow: *up = lj_carith_powi64(u0, u1, (id == CTID_UINT64)); break;
+    case MM_unm: *up = (uint64_t)-(int64_t)u0; break;
+    default: lua_assert(0); break;
+    }
+    lj_gc_check(L);
+    return 1;
+  }
+  return 0;
+}
+
+/* Arithmetic operators for cdata. */
+int lj_carith_op(lua_State *L, MMS mm)
+{
+  CTState *cts = ctype_cts(L);
+  CDArith ca;
+  if (carith_checkarg(L, cts, &ca)) {
+    if (carith_int64(L, cts, &ca, mm) || carith_ptr(L, cts, &ca, mm)) {
+      copyTV(L, &G(L)->tmptv2, L->top-1);  /* Remember for trace recorder. */
+      return 1;
+    }
+  }
+  /* NYI: per-cdata metamethods. */
+  {
+    const char *repr[2];
+    int i;
+    for (i = 0; i < 2; i++) {
+      if (ca.ct[i])
+	repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca.ct[i]), NULL));
+      else
+	repr[i] = typename(&L->base[i]);
+    }
+    lj_err_callerv(L, mm == MM_len ? LJ_ERR_FFI_BADLEN :
+		      mm == MM_concat ? LJ_ERR_FFI_BADCONCAT :
+		      mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH,
+		   repr[0], repr[1]);
+  }
+  return 0;  /* unreachable */
+}
+
+/* -- 64 bit integer arithmetic helpers ----------------------------------- */
+
+/* 64 bit integer x^k. */
+uint64_t lj_carith_powi64(uint64_t x, uint64_t k, int isunsigned)
+{
+  uint64_t y = 0;
+  if (k == 0)
+    return 1;
+  if (!isunsigned) {
+    if ((int64_t)k < 0) {
+      if (x == 0)
+	return U64x(7fffffff,ffffffff);
+      else if (x == 1)
+	return 1;
+      else if ((int64_t)x == -1)
+	return (k & 1) ? -1 : 1;
+      else
+	return 0;
+    }
+  }
+  for (; (k & 1) == 0; k >>= 1) x *= x;
+  y = x;
+  if ((k >>= 1) != 0) {
+    for (;;) {
+      x *= x;
+      if (k == 1) break;
+      if (k & 1) y *= x;
+      k >>= 1;
+    }
+    y *= x;
+  }
+  return y;
+}
+
+#endif

+ 19 - 0
src/lj_carith.h

@@ -0,0 +1,19 @@
+/*
+** C data arithmetic.
+** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h
+*/
+
+#ifndef _LJ_CARITH_H
+#define _LJ_CARITH_H
+
+#include "lj_obj.h"
+
+#if LJ_HASFFI
+
+LJ_FUNC int lj_carith_op(lua_State *L, MMS mm);
+
+LJ_FUNC uint64_t lj_carith_powi64(uint64_t x, uint64_t k, int isunsigned);
+
+#endif
+
+#endif

+ 0 - 34
src/lj_cdata.c

@@ -251,38 +251,4 @@ void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o, CTInfo qual)
   lj_cconv_ct_tv(cts, d, dp, o, 0);
 }
 
-/* -- 64 bit integer arithmetic helpers ----------------------------------- */
-
-/* 64 bit integer x^k. */
-uint64_t lj_cdata_powi64(uint64_t x, uint64_t k, int isunsigned)
-{
-  uint64_t y = 0;
-  if (k == 0)
-    return 1;
-  if (!isunsigned) {
-    if ((int64_t)k < 0) {
-      if (x == 0)
-	return U64x(7fffffff,ffffffff);
-      else if (x == 1)
-	return 1;
-      else if ((int64_t)x == -1)
-	return (k & 1) ? -1 : 1;
-      else
-	return 0;
-    }
-  }
-  for (; (k & 1) == 0; k >>= 1) x *= x;
-  y = x;
-  if ((k >>= 1) != 0) {
-    for (;;) {
-      x *= x;
-      if (k == 1) break;
-      if (k & 1) y *= x;
-      k >>= 1;
-    }
-    y *= x;
-  }
-  return y;
-}
-
 #endif

+ 0 - 2
src/lj_cdata.h

@@ -69,8 +69,6 @@ LJ_FUNC int lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp);
 LJ_FUNC void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o,
 			  CTInfo qual);
 
-LJ_FUNC uint64_t lj_cdata_powi64(uint64_t x, uint64_t k, int isunsigned);
-
 #endif
 
 #endif

+ 1 - 1
src/lj_crecord.c

@@ -689,7 +689,7 @@ static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm)
       J->postproc = LJ_POST_FIXGUARD;
       return TREF_TRUE;
     } else if (mm == MM_pow) {
-      tr = lj_ir_call(J, IRCALL_lj_cdata_powi64, sp[0], sp[1],
+      tr = lj_ir_call(J, IRCALL_lj_carith_powi64, sp[0], sp[1],
 		      lj_ir_kint(J, (int)dt-(int)IRT_I64));
     } else {
       if (mm == MM_div || mm == MM_mod)

+ 1 - 0
src/lj_ir.c

@@ -24,6 +24,7 @@
 #if LJ_HASFFI
 #include "lj_ctype.h"
 #include "lj_cdata.h"
+#include "lj_carith.h"
 #endif
 #include "lj_lib.h"
 

+ 1 - 1
src/lj_ir.h

@@ -255,7 +255,7 @@ typedef struct CCallInfo {
 /* Function definitions for CALL* instructions. */
 #if LJ_HASFFI
 #define IRCALLDEF_FFI(_) \
-  _(lj_cdata_powi64,	3,   N, U64, CCI_NOFPRCLOBBER)
+  _(lj_carith_powi64,	3,   N, U64, CCI_NOFPRCLOBBER)
 #else
 #define IRCALLDEF_FFI(_)
 #endif

+ 1 - 0
src/ljamalg.c

@@ -48,6 +48,7 @@
 #include "lj_cdata.c"
 #include "lj_cconv.c"
 #include "lj_ccall.c"
+#include "lj_carith.c"
 #include "lj_clib.c"
 #include "lj_cparse.c"
 #include "lj_lib.c"