[project @ 2001-03-23 16:36:20 by simonmar]
[ghc-hetmet.git] / ghc / rts / PrimOps.hc
index 5b13303..8c5c55e 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: PrimOps.hc,v 1.59 2000/11/16 12:49:05 simonmar Exp $
+ * $Id: PrimOps.hc,v 1.75 2001/03/23 16:36:21 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2000
  *
@@ -7,6 +7,7 @@
  *
  * ---------------------------------------------------------------------------*/
 
+#include "Stg.h"
 #include "Rts.h"
 
 #include "RtsFlags.h"
    classes CCallable and CReturnable don't really exist, but the
    compiler insists on generating dictionaries containing references
    to GHC_ZcCCallable_static_info etc., so we provide dummy symbols
-   for these.
+   for these.  Some C compilers can't cope with zero-length static arrays,
+   so we have to make these one element long.
 */
 
-W_ GHC_ZCCCallable_static_info[0];
-W_ GHC_ZCCReturnable_static_info[0];
-
-
+StgWord GHC_ZCCCallable_static_info[1];
+StgWord GHC_ZCCReturnable_static_info[1];
+  
 /* -----------------------------------------------------------------------------
    Macros for Hand-written primitives.
    -------------------------------------------------------------------------- */
@@ -244,15 +245,14 @@ W_ GHC_ZCCReturnable_static_info[0];
 
 #define BYTES_TO_STGWORDS(n) ((n) + sizeof(W_) - 1)/sizeof(W_)
 
-#define newByteArray(ty,scale)                         \
- FN_(new##ty##Arrayzh_fast)                            \
+FN_(newByteArrayzh_fast)                               \
  {                                                     \
-   W_ stuff_size, size, n;                             \
+   W_ size, stuff_size, n;                             \
    StgArrWords* p;                                     \
    FB_                                                 \
-     MAYBE_GC(NO_PTRS,new##ty##Arrayzh_fast);          \
+     MAYBE_GC(NO_PTRS,newByteArrayzh_fast);            \
      n = R1.w;                                         \
-     stuff_size = BYTES_TO_STGWORDS(n*scale);          \
+     stuff_size = BYTES_TO_STGWORDS(n);                        \
      size = sizeofW(StgArrWords)+ stuff_size;          \
      p = (StgArrWords *)RET_STGCALL1(P_,allocate,size);        \
      TICK_ALLOC_PRIM(sizeofW(StgArrWords),stuff_size,0); \
@@ -263,15 +263,6 @@ W_ GHC_ZCCReturnable_static_info[0];
    FE_                                                 \
  }
 
-newByteArray(Char,   1)
-/* Char arrays really contain only 8-bit bytes for compatibility. */
-newByteArray(Int,    sizeof(I_))
-newByteArray(Word,   sizeof(W_))
-newByteArray(Addr,   sizeof(P_))
-newByteArray(Float,  sizeof(StgFloat))
-newByteArray(Double, sizeof(StgDouble))
-newByteArray(StablePtr, sizeof(StgStablePtr))
-
 FN_(newArrayzh_fast)
 {
   W_ size, n, init;
@@ -324,7 +315,6 @@ FN_(newMutVarzh_fast)
 
    -------------------------------------------------------------------------- */
 
-#ifndef PAR
 FN_(mkForeignObjzh_fast)
 {
   /* R1.p = ptr to foreign object,
@@ -346,7 +336,6 @@ FN_(mkForeignObjzh_fast)
   RET_P(result);
   FE_
 }
-#endif
 
 /* These two are out-of-line for the benefit of the NCG */
 FN_(unsafeThawArrayzh_fast)
@@ -364,8 +353,6 @@ FN_(unsafeThawArrayzh_fast)
    Weak Pointer Primitives
    -------------------------------------------------------------------------- */
 
-#ifndef PAR
-
 FN_(mkWeakzh_fast)
 {
   /* R1.p = key
@@ -429,8 +416,6 @@ FN_(finalizzeWeakzh_fast)
   FE_
 }
 
-#endif /* !PAR */
-
 /* -----------------------------------------------------------------------------
    Arbitrary-precision Integer operations.
    -------------------------------------------------------------------------- */
@@ -540,12 +525,12 @@ FN_(int64ToIntegerzh_fast)
    if ( val < 0LL ) {
      neg = 1;
      val = -val;
-   } 
+   }
 
    hi = (W_)((LW_)val / 0x100000000ULL);
 
    if ( words_needed == 2 )  { 
-      s = 2; 
+      s = 2;
       Hp[-1] = (W_)val;
       Hp[0] = hi;
    } else if ( val != 0 ) {
@@ -886,6 +871,21 @@ FN_(takeMVarzh_fast)
   val = mvar->value;
   mvar->value = (StgClosure *)&stg_END_TSO_QUEUE_closure;
 
+  /* wake up the first thread on the queue
+   */
+  if (mvar->head != (StgTSO *)&stg_END_TSO_QUEUE_closure) {
+      ASSERT(mvar->head->why_blocked == BlockedOnMVar);
+#if defined(GRAN) || defined(PAR)
+      /* ToDo: check 2nd arg (mvar) is right */
+      mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
+#else
+      mvar->head = RET_STGCALL1(StgTSO *,unblockOne,mvar->head);
+#endif
+      if (mvar->head == (StgTSO *)&stg_END_TSO_QUEUE_closure) {
+         mvar->tail = (StgTSO *)&stg_END_TSO_QUEUE_closure;
+      }
+  }
+
   /* do this last... we might have locked the MVar in the SMP case,
    * and writing the info pointer will unlock it.
    */
@@ -927,6 +927,21 @@ FN_(tryTakeMVarzh_fast)
   val = mvar->value;
   mvar->value = (StgClosure *)&stg_END_TSO_QUEUE_closure;
 
+  /* wake up the first thread on the queue
+   */
+  if (mvar->head != (StgTSO *)&stg_END_TSO_QUEUE_closure) {
+      ASSERT(mvar->head->why_blocked == BlockedOnMVar);
+#if defined(GRAN) || defined(PAR)
+      /* ToDo: check 2nd arg (mvar) is right */
+      mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
+#else
+      mvar->head = RET_STGCALL1(StgTSO *,unblockOne,mvar->head);
+#endif
+      if (mvar->head == (StgTSO *)&stg_END_TSO_QUEUE_closure) {
+         mvar->tail = (StgTSO *)&stg_END_TSO_QUEUE_closure;
+      }
+  }
+
   /* do this last... we might have locked the MVar in the SMP case,
    * and writing the info pointer will unlock it.
    */
@@ -954,13 +969,21 @@ FN_(putMVarzh_fast)
 #endif
 
   if (info == &stg_FULL_MVAR_info) {
-#ifdef INTERPRETER
-    fprintf(stderr, "fatal: put on a full MVar in Hugs; aborting\n" );
-    exit(1);
-#else
-    R1.cl = (StgClosure *)PutFullMVar_closure;
-    JMP_(raisezh_fast);
+    if (mvar->head == (StgTSO *)&stg_END_TSO_QUEUE_closure) {
+      mvar->head = CurrentTSO;
+    } else {
+      mvar->tail->link = CurrentTSO;
+    }
+    CurrentTSO->link = (StgTSO *)&stg_END_TSO_QUEUE_closure;
+    CurrentTSO->why_blocked = BlockedOnMVar;
+    CurrentTSO->block_info.closure = (StgClosure *)mvar;
+    mvar->tail = CurrentTSO;
+
+#ifdef SMP
+    /* unlock the MVar */
+    mvar->header.info = &stg_FULL_MVAR_info;
 #endif
+    BLOCK( R1_PTR | R2_PTR, putMVarzh_fast );
   }
   
   mvar->value = R2.cl;
@@ -970,10 +993,8 @@ FN_(putMVarzh_fast)
    */
   if (mvar->head != (StgTSO *)&stg_END_TSO_QUEUE_closure) {
     ASSERT(mvar->head->why_blocked == BlockedOnMVar);
-#if defined(GRAN)
-    mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
-#elif defined(PAR)
-    // ToDo: check 2nd arg (mvar) is right
+#if defined(GRAN) || defined(PAR)
+    /* ToDo: check 2nd arg (mvar) is right */
     mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
 #else
     mvar->head = RET_STGCALL1(StgTSO *,unblockOne,mvar->head);
@@ -991,6 +1012,59 @@ FN_(putMVarzh_fast)
   FE_
 }
 
+FN_(tryPutMVarzh_fast)
+{
+  StgMVar *mvar;
+  const StgInfoTable *info;
+
+  FB_
+  /* args: R1 = MVar, R2 = value */
+
+  mvar = (StgMVar *)R1.p;
+
+#ifdef SMP
+  info = LOCK_CLOSURE(mvar);
+#else
+  info = GET_INFO(mvar);
+#endif
+
+  if (info == &stg_FULL_MVAR_info) {
+
+#ifdef SMP
+    /* unlock the MVar */
+    mvar->header.info = &stg_FULL_MVAR_info;
+#endif
+
+    /* HACK: we need a pointer to pass back, so we abuse NO_FINALIZER_closure */
+    RET_N(0);
+  }
+  
+  mvar->value = R2.cl;
+
+  /* wake up the first thread on the queue, it will continue with the
+   * takeMVar operation and mark the MVar empty again.
+   */
+  if (mvar->head != (StgTSO *)&stg_END_TSO_QUEUE_closure) {
+    ASSERT(mvar->head->why_blocked == BlockedOnMVar);
+#if defined(GRAN) || defined(PAR)
+    /* ToDo: check 2nd arg (mvar) is right */
+    mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
+#else
+    mvar->head = RET_STGCALL1(StgTSO *,unblockOne,mvar->head);
+#endif
+    if (mvar->head == (StgTSO *)&stg_END_TSO_QUEUE_closure) {
+      mvar->tail = (StgTSO *)&stg_END_TSO_QUEUE_closure;
+    }
+  }
+
+  /* unlocks the MVar in the SMP case */
+  SET_INFO(mvar,&stg_FULL_MVAR_info);
+
+  /* ToDo: yield here for better communication performance? */
+  RET_N(1);
+  FE_
+}
+
 /* -----------------------------------------------------------------------------
    Stable pointer primitives
    -------------------------------------------------------------------------  */
@@ -1023,6 +1097,56 @@ FN_(makeStableNamezh_fast)
 }
 
 /* -----------------------------------------------------------------------------
+   Bytecode object primitives
+   -------------------------------------------------------------------------  */
+
+FN_(newBCOzh_fast)
+{
+  /* R1.p = instrs
+     R2.p = literals
+     R3.p = ptrs
+     R4.p = itbls
+  */
+  StgBCO *bco;
+  FB_
+
+  HP_CHK_GEN_TICKY(sizeofW(StgBCO),R1_PTR|R2_PTR|R3_PTR|R4_PTR, newBCOzh_fast,);
+  TICK_ALLOC_PRIM(sizeofW(StgHeader), sizeofW(StgBCO)-sizeofW(StgHeader), 0);
+  CCS_ALLOC(CCCS,sizeofW(StgBCO)); /* ccs prof */
+  bco = (StgBCO *) (Hp + 1 - sizeofW(StgBCO));
+  SET_HDR(bco, &stg_BCO_info, CCCS);
+
+  bco->instrs     = (StgArrWords*)R1.cl;
+  bco->literals   = (StgArrWords*)R2.cl;
+  bco->ptrs       = (StgMutArrPtrs*)R3.cl;
+  bco->itbls      = (StgArrWords*)R4.cl;
+
+  TICK_RET_UNBOXED_TUP(1);
+  RET_P(bco);
+  FE_
+}
+
+FN_(mkApUpd0zh_fast)
+{
+  /* R1.p = the fn for the AP_UPD
+  */
+  StgAP_UPD* ap;
+  FB_
+  HP_CHK_GEN_TICKY(AP_sizeW(0), R1_PTR, mkApUpd0zh_fast,);
+  TICK_ALLOC_PRIM(sizeofW(StgHeader), AP_sizeW(0)-sizeofW(StgHeader), 0);
+  CCS_ALLOC(CCCS,AP_sizeW(0)); /* ccs prof */
+  ap = (StgAP_UPD *) (Hp + 1 - AP_sizeW(0));
+  SET_HDR(ap, &stg_AP_UPD_info, CCCS);
+
+  ap->n_args = 0;
+  ap->fun = R1.cl;
+
+  TICK_RET_UNBOXED_TUP(1);
+  RET_P(ap);
+  FE_
+}
+
+/* -----------------------------------------------------------------------------
    Thread I/O blocking primitives
    -------------------------------------------------------------------------- */
 
@@ -1065,7 +1189,7 @@ FN_(delayzh_fast)
 
     ACQUIRE_LOCK(&sched_mutex);
 
-    target = (R1.i / (TICK_MILLISECS*1000)) + timestamp + ticks_since_timestamp;
+    target = (R1.i / (TICK_MILLISECS*1000)) + getourtimeofday();
     CurrentTSO->block_info.target = target;
 
     /* Insert the new thread in the sleeping queue. */