Miscellaneous 'sendfile' fixes and improved tests.
[bpt/guile.git] / libguile / vm-i-scheme.c
index 3e80a0e..b85d980 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2009, 2010 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -124,11 +124,7 @@ VM_DEFINE_FUNCTION (140, cons, "cons", 2)
 }
 
 #define VM_VALIDATE_CONS(x, proc)              \
-  if (SCM_UNLIKELY (!scm_is_pair (x)))          \
-    { func_name = proc;                         \
-      finish_args = x;                          \
-      goto vm_error_not_a_pair;                 \
-    }
+  VM_ASSERT (scm_is_pair (x), vm_error_not_a_pair (proc, x))
   
 VM_DEFINE_FUNCTION (141, car, "car", 1)
 {
@@ -147,8 +143,7 @@ VM_DEFINE_FUNCTION (142, cdr, "cdr", 1)
 VM_DEFINE_INSTRUCTION (143, set_car, "set-car!", 0, 2, 0)
 {
   SCM x, y;
-  POP (y);
-  POP (x);
+  POP2 (y, x);
   VM_VALIDATE_CONS (x, "set-car!");
   SCM_SETCAR (x, y);
   NEXT;
@@ -157,8 +152,7 @@ VM_DEFINE_INSTRUCTION (143, set_car, "set-car!", 0, 2, 0)
 VM_DEFINE_INSTRUCTION (144, set_cdr, "set-cdr!", 0, 2, 0)
 {
   SCM x, y;
-  POP (y);
-  POP (x);
+  POP2 (y, x);
   VM_VALIDATE_CONS (x, "set-cdr!");
   SCM_SETCDR (x, y);
   NEXT;
@@ -170,14 +164,15 @@ VM_DEFINE_INSTRUCTION (144, set_cdr, "set-cdr!", 0, 2, 0)
  */
 
 #undef REL
-#define REL(crel,srel)                                         \
-{                                                              \
-  ARGS2 (x, y);                                                        \
-  if (SCM_I_INUMP (x) && SCM_I_INUMP (y))                      \
-    RETURN (scm_from_bool (SCM_I_INUM (x) crel SCM_I_INUM (y)));  \
-  SYNC_REGISTER ();                                             \
-  RETURN (srel (x, y));                                         \
-}
+#define REL(crel,srel)                                                  \
+  {                                                                     \
+    ARGS2 (x, y);                                                       \
+    if (SCM_I_INUMP (x) && SCM_I_INUMP (y))                             \
+      RETURN (scm_from_bool (((scm_t_signed_bits) SCM_UNPACK (x))       \
+                             crel ((scm_t_signed_bits) SCM_UNPACK (y)))); \
+    SYNC_REGISTER ();                                                   \
+    RETURN (srel (x, y));                                              \
+  }
 
 VM_DEFINE_FUNCTION (145, ee, "ee?", 2)
 {
@@ -210,6 +205,8 @@ VM_DEFINE_FUNCTION (149, ge, "ge?", 2)
  */
 
 /* The maximum/minimum tagged integers.  */
+#undef INUM_MAX
+#undef INUM_MIN
 #define INUM_MAX (INTPTR_MAX - 1)
 #define INUM_MIN (INTPTR_MIN + scm_tc2_int)
 
@@ -227,9 +224,68 @@ VM_DEFINE_FUNCTION (149, ge, "ge?", 2)
   RETURN (SFUNC (x, y));                               \
 }
 
+/* Assembly tagged integer arithmetic routines.  This code uses the
+   `asm goto' feature introduced in GCC 4.5.  */
+
+#if defined __x86_64__ && SCM_GNUC_PREREQ (4, 5)
+
+/* The macros below check the CPU's overflow flag to improve fixnum
+   arithmetic.  The %rcx register is explicitly clobbered because `asm
+   goto' can't have outputs, in which case the `r' constraint could be
+   used to let the register allocator choose a register.
+
+   TODO: Use `cold' label attribute in GCC 4.6.
+   http://gcc.gnu.org/ml/gcc-patches/2010-10/msg01777.html  */
+
+# define ASM_ADD(x, y)                                                 \
+    {                                                                  \
+      asm volatile goto ("mov %1, %%rcx; "                             \
+                        "test %[tag], %%cl; je %l[slow_add]; "         \
+                        "test %[tag], %0;   je %l[slow_add]; "         \
+                        "add %0, %%rcx;     jo %l[slow_add]; "         \
+                        "sub %[tag], %%rcx; "                          \
+                        "mov %%rcx, (%[vsp])\n"                        \
+                        : /* no outputs */                             \
+                        : "r" (x), "r" (y),                            \
+                          [vsp] "r" (sp), [tag] "i" (scm_tc2_int)      \
+                        : "rcx", "memory"                              \
+                        : slow_add);                                   \
+      NEXT;                                                            \
+    }                                                                  \
+  slow_add:                                                            \
+    do { } while (0)
+
+# define ASM_SUB(x, y)                                                 \
+    {                                                                  \
+      asm volatile goto ("mov %0, %%rcx; "                             \
+                        "test %[tag], %%cl; je %l[slow_sub]; "         \
+                        "test %[tag], %1;   je %l[slow_sub]; "         \
+                        "sub %1, %%rcx;     jo %l[slow_sub]; "         \
+                        "add %[tag], %%rcx; "                          \
+                        "mov %%rcx, (%[vsp])\n"                        \
+                        : /* no outputs */                             \
+                        : "r" (x), "r" (y),                            \
+                          [vsp] "r" (sp), [tag] "i" (scm_tc2_int)      \
+                        : "rcx", "memory"                              \
+                        : slow_sub);                                   \
+      NEXT;                                                            \
+    }                                                                  \
+  slow_sub:                                                            \
+    do { } while (0)
+
+#endif
+
+
 VM_DEFINE_FUNCTION (150, add, "add", 2)
 {
+#ifndef ASM_ADD
   FUNC2 (+, scm_sum);
+#else
+  ARGS2 (x, y);
+  ASM_ADD (x, y);
+  SYNC_REGISTER ();
+  RETURN (scm_sum (x, y));
+#endif
 }
 
 VM_DEFINE_FUNCTION (151, add1, "add1", 1)
@@ -237,13 +293,13 @@ VM_DEFINE_FUNCTION (151, add1, "add1", 1)
   ARGS1 (x);
 
   /* Check for overflow.  */
-  if (SCM_LIKELY ((scm_t_intptr) x < INUM_MAX))
+  if (SCM_LIKELY ((scm_t_intptr) SCM_UNPACK (x) < INUM_MAX))
     {
       SCM result;
 
       /* Add the integers without untagging.  */
-      result = SCM_PACK ((scm_t_intptr) x
-                        + (scm_t_intptr) SCM_I_MAKINUM (1)
+      result = SCM_PACK ((scm_t_intptr) SCM_UNPACK (x)
+                        + (scm_t_intptr) SCM_UNPACK (SCM_I_MAKINUM (1))
                         - scm_tc2_int);
 
       if (SCM_LIKELY (SCM_I_INUMP (result)))
@@ -256,7 +312,14 @@ VM_DEFINE_FUNCTION (151, add1, "add1", 1)
 
 VM_DEFINE_FUNCTION (152, sub, "sub", 2)
 {
+#ifndef ASM_SUB
   FUNC2 (-, scm_difference);
+#else
+  ARGS2 (x, y);
+  ASM_SUB (x, y);
+  SYNC_REGISTER ();
+  RETURN (scm_difference (x, y));
+#endif
 }
 
 VM_DEFINE_FUNCTION (153, sub1, "sub1", 1)
@@ -264,13 +327,13 @@ VM_DEFINE_FUNCTION (153, sub1, "sub1", 1)
   ARGS1 (x);
 
   /* Check for underflow.  */
-  if (SCM_LIKELY ((scm_t_intptr) x > INUM_MIN))
+  if (SCM_LIKELY ((scm_t_intptr) SCM_UNPACK (x) > INUM_MIN))
     {
       SCM result;
 
       /* Substract the integers without untagging.  */
-      result = SCM_PACK ((scm_t_intptr) x
-                        - (scm_t_intptr) SCM_I_MAKINUM (1)
+      result = SCM_PACK ((scm_t_intptr) SCM_UNPACK (x)
+                        - (scm_t_intptr) SCM_UNPACK (SCM_I_MAKINUM (1))
                         + scm_tc2_int);
 
       if (SCM_LIKELY (SCM_I_INUMP (result)))
@@ -281,6 +344,9 @@ VM_DEFINE_FUNCTION (153, sub1, "sub1", 1)
   RETURN (scm_difference (x, SCM_I_MAKINUM (1)));
 }
 
+# undef ASM_ADD
+# undef ASM_SUB
+
 VM_DEFINE_FUNCTION (154, mul, "mul", 2)
 {
   ARGS2 (x, y);
@@ -327,13 +393,13 @@ VM_DEFINE_FUNCTION (159, ash, "ash", 2)
       else
         /* Left shift. See comments in scm_ash. */
         {
-          long nn, bits_to_shift;
+          scm_t_signed_bits nn, bits_to_shift;
 
           nn = SCM_I_INUM (x);
           bits_to_shift = SCM_I_INUM (y);
 
           if (bits_to_shift < SCM_I_FIXNUM_BIT-1
-              && ((unsigned long)
+              && ((scm_t_bits)
                   (SCM_SRS (nn, (SCM_I_FIXNUM_BIT-1 - bits_to_shift)) + 1)
                   <= 1))
             RETURN (SCM_I_MAKINUM (nn << bits_to_shift));
@@ -379,7 +445,7 @@ VM_DEFINE_FUNCTION (162, logxor, "logxor", 2)
 
 VM_DEFINE_FUNCTION (163, vector_ref, "vector-ref", 2)
 {
-  long i = 0;
+  scm_t_signed_bits i = 0;
   ARGS2 (vect, idx);
   if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
                   && SCM_I_INUMP (idx)
@@ -395,9 +461,9 @@ VM_DEFINE_FUNCTION (163, vector_ref, "vector-ref", 2)
 
 VM_DEFINE_INSTRUCTION (164, vector_set, "vector-set", 0, 3, 0)
 {
-  long i = 0;
+  scm_t_signed_bits i = 0;
   SCM vect, idx, val;
-  POP (val); POP (idx); POP (vect);
+  POP3 (val, idx, vect);
   if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
                   && SCM_I_INUMP (idx)
                   && ((i = SCM_I_INUM (idx)) >= 0)
@@ -433,12 +499,7 @@ VM_DEFINE_INSTRUCTION (165, make_array, "make-array", 3, -1, 1)
  * Structs
  */
 #define VM_VALIDATE_STRUCT(obj, proc)           \
-  if (SCM_UNLIKELY (!SCM_STRUCTP (obj)))       \
-    {                                          \
-      func_name = proc;                         \
-      finish_args = (obj);                     \
-      goto vm_error_not_a_struct;              \
-    }
+  VM_ASSERT (SCM_STRUCTP (obj), vm_error_not_a_struct (proc, obj))
 
 VM_DEFINE_FUNCTION (166, struct_p, "struct?", 1)
 {
@@ -498,6 +559,9 @@ VM_DEFINE_FUNCTION (169, struct_ref, "struct-ref", 2)
       SCM vtable;
       scm_t_bits index, len;
 
+      /* True, an inum is a signed value, but cast to unsigned it will
+         certainly be more than the length, so we will fall through if
+         index is negative. */
       index = SCM_I_INUM (pos);
       vtable = SCM_STRUCT_VTABLE (obj);
       len = SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size);
@@ -527,6 +591,7 @@ VM_DEFINE_FUNCTION (170, struct_set, "struct-set", 3)
       SCM vtable;
       scm_t_bits index, len;
 
+      /* See above regarding index being >= 0. */
       index = SCM_I_INUM (pos);
       vtable = SCM_STRUCT_VTABLE (obj);
       len = SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size);
@@ -555,6 +620,7 @@ VM_DEFINE_FUNCTION (171, class_of, "class-of", 1)
   RETURN (scm_class_of (obj));
 }
 
+/* FIXME: No checking whatsoever. */
 VM_DEFINE_FUNCTION (172, slot_ref, "slot-ref", 2)
 {
   size_t slot;
@@ -563,13 +629,12 @@ VM_DEFINE_FUNCTION (172, slot_ref, "slot-ref", 2)
   RETURN (SCM_PACK (SCM_STRUCT_DATA (instance) [slot]));
 }
 
+/* FIXME: No checking whatsoever. */
 VM_DEFINE_INSTRUCTION (173, slot_set, "slot-set", 0, 3, 0)
 {
   SCM instance, idx, val;
   size_t slot;
-  POP (val);
-  POP (idx);
-  POP (instance);
+  POP3 (val, idx, instance);
   slot = SCM_I_INUM (idx);
   SCM_STRUCT_DATA (instance) [slot] = SCM_UNPACK (val);
   NEXT;
@@ -580,16 +645,7 @@ VM_DEFINE_INSTRUCTION (173, slot_set, "slot-set", 0, 3, 0)
  * Bytevectors
  */
 #define VM_VALIDATE_BYTEVECTOR(x, proc)                \
-  do                                           \
-    {                                          \
-      if (SCM_UNLIKELY (!SCM_BYTEVECTOR_P (x)))        \
-       {                                       \
-          func_name = proc;                     \
-         finish_args = x;                      \
-         goto vm_error_not_a_bytevector;       \
-       }                                       \
-    }                                          \
-  while (0)
+  VM_ASSERT (SCM_BYTEVECTOR_P (x), vm_error_not_a_bytevector (proc, x))
 
 #define BV_REF_WITH_ENDIANNESS(stem, fn_stem)                           \
 {                                                                       \
@@ -606,7 +662,7 @@ VM_DEFINE_INSTRUCTION (173, slot_set, "slot-set", 0, 3, 0)
 
 /* Return true (non-zero) if PTR has suitable alignment for TYPE.  */
 #define ALIGNED_P(ptr, type)                   \
-  ((scm_t_uintptr) (ptr) % alignof (type) == 0)
+  ((scm_t_uintptr) (ptr) % alignof_type (type) == 0)
 
 VM_DEFINE_FUNCTION (174, bv_u16_ref, "bv-u16-ref", 3)
 BV_REF_WITH_ENDIANNESS (u16, u16)
@@ -629,7 +685,7 @@ BV_REF_WITH_ENDIANNESS (f64, ieee_double)
 
 #define BV_FIXABLE_INT_REF(stem, fn_stem, type, size)                  \
 {                                                                      \
-  long i;                                                              \
+  scm_t_signed_bits i;                                                 \
   const scm_t_ ## type *int_ptr;                                       \
   ARGS2 (bv, idx);                                                     \
                                                                        \
@@ -651,7 +707,7 @@ BV_REF_WITH_ENDIANNESS (f64, ieee_double)
 
 #define BV_INT_REF(stem, type, size)                                   \
 {                                                                      \
-  long i;                                                              \
+  scm_t_signed_bits i;                                                 \
   const scm_t_ ## type *int_ptr;                                       \
   ARGS2 (bv, idx);                                                     \
                                                                        \
@@ -682,7 +738,7 @@ BV_REF_WITH_ENDIANNESS (f64, ieee_double)
 
 #define BV_FLOAT_REF(stem, fn_stem, type, size)                                \
 {                                                                      \
-  long i;                                                              \
+  scm_t_signed_bits i;                                                 \
   const type *float_ptr;                                               \
   ARGS2 (bv, idx);                                                     \
                                                                        \
@@ -742,7 +798,8 @@ BV_FLOAT_REF (f64, ieee_double, double, 8)
   if (scm_is_eq (endianness, scm_i_native_endianness))                  \
     goto VM_LABEL (bv_##stem##_native_set);                             \
   {                                                                     \
-    SCM bv, idx, val; POP (val); POP (idx); POP (bv);                   \
+    SCM bv, idx, val; POP3 (val, idx, bv);                              \
+    SYNC_REGISTER ();                                                   \
     scm_bytevector_##fn_stem##_set_x (bv, idx, val, endianness);        \
     NEXT;                                                               \
   }                                                                     \
@@ -769,11 +826,11 @@ BV_SET_WITH_ENDIANNESS (f64, ieee_double)
 
 #define BV_FIXABLE_INT_SET(stem, fn_stem, type, min, max, size)                \
 {                                                                      \
-  long i, j = 0;                                                       \
+  scm_t_signed_bits i, j = 0;                                          \
   SCM bv, idx, val;                                                    \
   scm_t_ ## type *int_ptr;                                             \
                                                                        \
-  POP (val); POP (idx); POP (bv);                                      \
+  POP3 (val, idx, bv);                                                  \
   VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set");                      \
   i = SCM_I_INUM (idx);                                                        \
   int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i);     \
@@ -787,17 +844,20 @@ BV_SET_WITH_ENDIANNESS (f64, ieee_double)
                   && (j <= max)))                                      \
     *int_ptr = (scm_t_ ## type) j;                                     \
   else                                                                 \
-    scm_bytevector_ ## fn_stem ## _set_x (bv, idx, val);               \
+    {                                                                   \
+      SYNC_REGISTER ();                                                 \
+      scm_bytevector_ ## fn_stem ## _set_x (bv, idx, val);             \
+    }                                                                   \
   NEXT;                                                                        \
 }
 
 #define BV_INT_SET(stem, type, size)                                   \
 {                                                                      \
-  long i = 0;                                                          \
+  scm_t_signed_bits i = 0;                                             \
   SCM bv, idx, val;                                                    \
   scm_t_ ## type *int_ptr;                                             \
                                                                        \
-  POP (val); POP (idx); POP (bv);                                      \
+  POP3 (val, idx, bv);                                                  \
   VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set");                      \
   i = SCM_I_INUM (idx);                                                        \
   int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i);     \
@@ -808,29 +868,35 @@ BV_SET_WITH_ENDIANNESS (f64, ieee_double)
                   && (ALIGNED_P (int_ptr, scm_t_ ## type))))           \
     *int_ptr = scm_to_ ## type (val);                                  \
   else                                                                 \
-    scm_bytevector_ ## stem ## _native_set_x (bv, idx, val);           \
-  NEXT;                                                                        \
+    {                                                                   \
+      SYNC_REGISTER ();                                                 \
+      scm_bytevector_ ## stem ## _native_set_x (bv, idx, val);         \
+    }                                                                   \
+  NEXT;                                                                 \
 }
 
-#define BV_FLOAT_SET(stem, fn_stem, type, size)                        \
-{                                                              \
-  long i = 0;                                                  \
-  SCM bv, idx, val;                                            \
-  type *float_ptr;                                             \
-                                                               \
-  POP (val); POP (idx); POP (bv);                              \
-  VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set");              \
-  i = SCM_I_INUM (idx);                                                \
-  float_ptr = (type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i);     \
-                                                               \
-  if (SCM_LIKELY (SCM_I_INUMP (idx)                            \
-                  && (i >= 0)                                  \
-                  && (i + size <= SCM_BYTEVECTOR_LENGTH (bv))  \
-                  && (ALIGNED_P (float_ptr, type))))           \
-    *float_ptr = scm_to_double (val);                          \
-  else                                                         \
-    scm_bytevector_ ## fn_stem ## _native_set_x (bv, idx, val);        \
-  NEXT;                                                                \
+#define BV_FLOAT_SET(stem, fn_stem, type, size)                         \
+{                                                                       \
+  scm_t_signed_bits i = 0;                                              \
+  SCM bv, idx, val;                                                     \
+  type *float_ptr;                                                      \
+                                                                        \
+  POP3 (val, idx, bv);                                                  \
+  VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set");                      \
+  i = SCM_I_INUM (idx);                                                 \
+  float_ptr = (type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i);              \
+                                                                        \
+  if (SCM_LIKELY (SCM_I_INUMP (idx)                                     \
+                  && (i >= 0)                                           \
+                  && (i + size <= SCM_BYTEVECTOR_LENGTH (bv))           \
+                  && (ALIGNED_P (float_ptr, type))))                    \
+    *float_ptr = scm_to_double (val);                                   \
+  else                                                                  \
+    {                                                                   \
+      SYNC_REGISTER ();                                                 \
+      scm_bytevector_ ## fn_stem ## _native_set_x (bv, idx, val);       \
+    }                                                                   \
+  NEXT;                                                                 \
 }
 
 VM_DEFINE_INSTRUCTION (200, bv_u8_set, "bv-u8-set", 0, 3, 0)