Browse Source

FFI: Change tonumber(cdata) semantics. Return nil for non-numbers.

Mike Pall 14 years ago
parent
commit
22946f268b
2 changed files with 24 additions and 17 deletions
  1. 12 13
      src/lib_base.c
  2. 12 4
      src/lj_crecord.c

+ 12 - 13
src/lib_base.c

@@ -197,21 +197,20 @@ LJLIB_ASM(tonumber)		LJLIB_REC(.)
 #if LJ_HASFFI
     if (tviscdata(o)) {
       CTState *cts = ctype_cts(L);
-      if (LJ_DUALNUM) {
-	CType *ct = ctype_raw(cts, cdataV(o)->typeid);
-	if (ctype_isinteger_or_bool(ct->info)) {
-	  int64_t i;
-	  lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT64), (uint8_t *)&i, o, 0);
-	  if ((ct->size == 8 && (ct->info & CTF_UNSIGNED)) ?
-	      (uint64_t)i <= 0x7fffffffu : checki32(i)) {
-	    setintV(L->base-1, (int32_t)i);
-	    return FFH_RES(1);
-	  }  /* else: retry and convert to double. */
+      CType *ct = lj_ctype_rawref(cts, cdataV(o)->typeid);
+      if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
+      if (ctype_isnum(ct->info) || ctype_iscomplex(ct->info)) {
+	if (LJ_DUALNUM && ctype_isinteger_or_bool(ct->info) &&
+	    ct->size <= 4 && !(ct->size == 4 && (ct->info & CTF_UNSIGNED))) {
+	  int32_t i;
+	  lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o, 0);
+	  setintV(L->base-1, i);
+	  return FFH_RES(1);
 	}
+	lj_cconv_ct_tv(cts, ctype_get(cts, CTID_DOUBLE),
+		       (uint8_t *)&(L->base-1)->n, o, 0);
+	return FFH_RES(1);
       }
-      lj_cconv_ct_tv(cts, ctype_get(cts, CTID_DOUBLE),
-		     (uint8_t *)&(L->base-1)->n, o, 0);
-      return FFH_RES(1);
     }
 #endif
   } else {

+ 12 - 4
src/lj_crecord.c

@@ -1138,10 +1138,18 @@ void LJ_FASTCALL recff_ffi_abi(jit_State *J, RecordFFData *rd)
 void LJ_FASTCALL lj_crecord_tonumber(jit_State *J, RecordFFData *rd)
 {
   CTState *cts = ctype_ctsG(J2G(J));
-  IRType st = crec_ct2irt(ctype_raw(cts, cdataV(&rd->argv[0])->typeid));
-  CTypeID did = (st >= IRT_I8 && st <= IRT_INT) ? CTID_INT32 : CTID_DOUBLE;
-  CType *d = ctype_get(cts, did);
-  J->base[0] = crec_ct_tv(J, d, 0, J->base[0], &rd->argv[0]);
+  CType *d, *ct = lj_ctype_rawref(cts, cdataV(&rd->argv[0])->typeid);
+  if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
+  if (ctype_isnum(ct->info) || ctype_iscomplex(ct->info)) {
+    if (ctype_isinteger_or_bool(ct->info) && ct->size <= 4 &&
+	!(ct->size == 4 && (ct->info & CTF_UNSIGNED)))
+      d = ctype_get(cts, CTID_INT32);
+    else
+      d = ctype_get(cts, CTID_DOUBLE);
+    J->base[0] = crec_ct_tv(J, d, 0, J->base[0], &rd->argv[0]);
+  } else {
+    J->base[0] = TREF_NIL;
+  }
 }
 
 #undef IR