1 /* -----------------------------------------------------------------------------
2 * $Id: PrimOps.hc,v 1.43 2000/02/28 13:59:43 simonmar Exp $
4 * (c) The GHC Team, 1998-1999
6 * Primitive functions / data
8 * ---------------------------------------------------------------------------*/
13 #include "StgStartup.h"
18 #include "BlockAlloc.h" /* tmp */
19 #include "StablePriv.h"
20 #include "HeapStackCheck.h"
25 classes CCallable and CReturnable don't really exist, but the
26 compiler insists on generating dictionaries containing references
27 to GHC_ZcCCallable_static_info etc., so we provide dummy symbols
31 W_ GHC_ZCCCallable_static_info[0];
32 W_ GHC_ZCCReturnable_static_info[0];
35 /* -----------------------------------------------------------------------------
36 Macros for Hand-written primitives.
37 -------------------------------------------------------------------------- */
40 * Horrible macros for returning unboxed tuples.
42 * How an unboxed tuple is returned depends on two factors:
43 * - the number of real registers we have available
44 * - the boxedness of the returned fields.
46 * To return an unboxed tuple from a primitive operation, we have macros
47 * RET_<layout> where <layout> describes the boxedness of each field of the
48 * unboxed tuple: N indicates a non-pointer field, and P indicates a pointer.
50 * We only define the cases actually used, to avoid having too much
51 * garbage in this section. Warning: any bugs in here will be hard to
55 /*------ All Regs available */
57 # define RET_P(a) R1.w = (W_)(a); JMP_(ENTRY_CODE(Sp[0]));
58 # define RET_N(a) RET_P(a)
60 # define RET_PP(a,b) R1.w = (W_)(a); R2.w = (W_)(b); JMP_(ENTRY_CODE(Sp[0]));
61 # define RET_NN(a,b) RET_PP(a,b)
62 # define RET_NP(a,b) RET_PP(a,b)
64 # define RET_PPP(a,b,c) \
65 R1.w = (W_)(a); R2.w = (W_)(b); R3.w = (W_)(c); JMP_(ENTRY_CODE(Sp[0]));
66 # define RET_NNP(a,b,c) RET_PPP(a,b,c)
68 # define RET_NNNP(a,b,c,d) \
69 R1.w = (W_)(a); R2.w = (W_)(b); R3.w = (W_)(c); R4.w = (W_)d; \
70 JMP_(ENTRY_CODE(Sp[0]));
72 # define RET_NPNP(a,b,c,d) \
73 R1.w = (W_)(a); R2.w = (W_)(b); R3.w = (W_)(c); R4.w = (W_)(d); \
74 JMP_(ENTRY_CODE(Sp[0]));
76 # define RET_NNPNNP(a,b,c,d,e,f) \
77 R1.w = (W_)(a); R2.w = (W_)(b); R3.w = (W_)(c); \
78 R4.w = (W_)(d); R5.w = (W_)(e); R6.w = (W_)(f); \
79 JMP_(ENTRY_CODE(Sp[0]));
81 #elif defined(REG_R7) || defined(REG_R6) || defined(REG_R5) || \
82 defined(REG_R4) || defined(REG_R3)
83 # error RET_n macros not defined for this setup.
85 /*------ 2 Registers available */
88 # define RET_P(a) R1.w = (W_)(a); JMP_(ENTRY_CODE(Sp[0]));
89 # define RET_N(a) RET_P(a)
91 # define RET_PP(a,b) R1.w = (W_)(a); R2.w = (W_)(b); \
92 JMP_(ENTRY_CODE(Sp[0]));
93 # define RET_NN(a,b) RET_PP(a,b)
94 # define RET_NP(a,b) RET_PP(a,b)
96 # define RET_PPP(a,b,c) \
97 R1.w = (W_)(a); R2.w = (W_)(b); Sp[-1] = (W_)(c); Sp -= 1; \
98 JMP_(ENTRY_CODE(Sp[1]));
99 # define RET_NNP(a,b,c) \
100 R1.w = (W_)(a); R2.w = (W_)(b); Sp[-1] = (W_)(c); Sp -= 1; \
101 JMP_(ENTRY_CODE(Sp[1]));
103 # define RET_NNNP(a,b,c,d) \
106 /* Sp[-3] = ARGTAG(1); */ \
110 JMP_(ENTRY_CODE(Sp[3]));
112 # define RET_NPNP(a,b,c,d) \
115 /* Sp[-3] = ARGTAG(1); */ \
119 JMP_(ENTRY_CODE(Sp[3]));
121 # define RET_NNPNNP(a,b,c,d,e,f) \
125 /* Sp[-5] = ARGTAG(1); */ \
127 /* Sp[-3] = ARGTAG(1); */ \
131 JMP_(ENTRY_CODE(Sp[6]));
133 /*------ 1 Register available */
134 #elif defined(REG_R1)
135 # define RET_P(a) R1.w = (W_)(a); JMP_(ENTRY_CODE(Sp[0]));
136 # define RET_N(a) RET_P(a)
138 # define RET_PP(a,b) R1.w = (W_)(a); Sp[-1] = (W_)(b); Sp -= 1; \
139 JMP_(ENTRY_CODE(Sp[1]));
140 # define RET_NN(a,b) R1.w = (W_)(a); Sp[-1] = (W_)(b); Sp -= 2; \
141 JMP_(ENTRY_CODE(Sp[2]));
142 # define RET_NP(a,b) RET_PP(a,b)
144 # define RET_PPP(a,b,c) \
145 R1.w = (W_)(a); Sp[-2] = (W_)(b); Sp[-1] = (W_)(c); Sp -= 2; \
146 JMP_(ENTRY_CODE(Sp[2]));
147 # define RET_NNP(a,b,c) \
148 R1.w = (W_)(a); Sp[-2] = (W_)(b); Sp[-1] = (W_)(c); Sp -= 3; \
149 JMP_(ENTRY_CODE(Sp[3]));
151 # define RET_NNNP(a,b,c,d) \
153 /* Sp[-5] = ARGTAG(1); */ \
155 /* Sp[-3] = ARGTAG(1); */ \
159 JMP_(ENTRY_CODE(Sp[5]));
161 # define RET_NPNP(a,b,c,d) \
164 /* Sp[-3] = ARGTAG(1); */ \
168 JMP_(ENTRY_CODE(Sp[4]));
170 # define RET_NNPNNP(a,b,c,d,e,f) \
174 /* Sp[-3] = ARGTAG(1); */ \
176 /* Sp[-5] = ARGTAG(1); */ \
179 /* Sp[-8] = ARGTAG(1); */ \
181 JMP_(ENTRY_CODE(Sp[8]));
183 #else /* 0 Regs available */
185 #define PUSH_P(o,x) Sp[-o] = (W_)(x)
188 #define PUSH_N(o,x) Sp[1-o] = (W_)(x); Sp[-o] = ARG_TAG(1);
190 #define PUSH_N(o,x) Sp[1-o] = (W_)(x);
193 #define PUSHED(m) Sp -= (m); JMP_(ENTRY_CODE(Sp[m]));
195 /* Here's how to construct these macros:
197 * N = number of N's in the name;
198 * P = number of P's in the name;
200 * while (nonNull(name)) {
201 * if (nextChar == 'P') {
212 # define RET_P(a) PUSH_P(1,a); PUSHED(1)
213 # define RET_N(a) PUSH_N(2,a); PUSHED(2)
215 # define RET_PP(a,b) PUSH_P(2,a); PUSH_P(1,b); PUSHED(2)
216 # define RET_NN(a,b) PUSH_N(4,a); PUSH_N(2,b); PUSHED(4)
217 # define RET_NP(a,b) PUSH_N(3,a); PUSH_P(1,b); PUSHED(3)
219 # define RET_PPP(a,b,c) PUSH_P(3,a); PUSH_P(2,b); PUSH_P(1,c); PUSHED(3)
220 # define RET_NNP(a,b,c) PUSH_N(5,a); PUSH_N(3,b); PUSH_P(1,c); PUSHED(5)
222 # define RET_NNNP(a,b,c,d) PUSH_N(7,a); PUSH_N(5,b); PUSH_N(3,c); PUSH_P(1,d); PUSHED(7)
223 # define RET_NPNP(a,b,c,d) PUSH_N(6,a); PUSH_P(4,b); PUSH_N(3,c); PUSH_P(1,d); PUSHED(6)
224 # define RET_NNPNNP(a,b,c,d,e,f) PUSH_N(10,a); PUSH_N(8,b); PUSH_P(6,c); PUSH_N(5,d); PUSH_N(3,e); PUSH_P(1,f); PUSHED(10)
228 /*-----------------------------------------------------------------------------
231 Basically just new*Array - the others are all inline macros.
233 The size arg is always passed in R1, and the result returned in R1.
235 The slow entry point is for returning from a heap check, the saved
236 size argument must be re-loaded from the stack.
237 -------------------------------------------------------------------------- */
239 /* for objects that are *less* than the size of a word, make sure we
240 * round up to the nearest word for the size of the array.
243 #define BYTES_TO_STGWORDS(n) ((n) + sizeof(W_) - 1)/sizeof(W_)
245 #define newByteArray(ty,scale) \
246 FN_(new##ty##Arrayzh_fast) \
248 W_ stuff_size, size, n; \
251 MAYBE_GC(NO_PTRS,new##ty##Arrayzh_fast); \
253 stuff_size = BYTES_TO_STGWORDS(n*scale); \
254 size = sizeofW(StgArrWords)+ stuff_size; \
255 p = (StgArrWords *)RET_STGCALL1(P_,allocate,size); \
256 TICK_ALLOC_PRIM(sizeofW(StgArrWords),stuff_size,0); \
257 SET_HDR(p, &ARR_WORDS_info, CCCS); \
258 p->words = stuff_size; \
259 TICK_RET_UNBOXED_TUP(1) \
264 newByteArray(Char, sizeof(C_))
265 newByteArray(Int, sizeof(I_));
266 newByteArray(Word, sizeof(W_));
267 newByteArray(Addr, sizeof(P_));
268 newByteArray(Float, sizeof(StgFloat));
269 newByteArray(Double, sizeof(StgDouble));
270 newByteArray(StablePtr, sizeof(StgStablePtr));
280 MAYBE_GC(R2_PTR,newArrayzh_fast);
282 size = sizeofW(StgMutArrPtrs) + n;
283 arr = (StgMutArrPtrs *)RET_STGCALL1(P_, allocate, size);
284 TICK_ALLOC_PRIM(sizeofW(StgMutArrPtrs), n, 0);
286 SET_HDR(arr,&MUT_ARR_PTRS_info,CCCS);
290 for (p = (P_)arr + sizeofW(StgMutArrPtrs);
291 p < (P_)arr + size; p++) {
295 TICK_RET_UNBOXED_TUP(1);
300 FN_(newMutVarzh_fast)
303 /* Args: R1.p = initialisation value */
306 HP_CHK_GEN_TICKY(sizeofW(StgMutVar), R1_PTR, newMutVarzh_fast,);
307 TICK_ALLOC_PRIM(sizeofW(StgHeader)+1,1, 0); /* hack, dependent on rep. */
308 CCS_ALLOC(CCCS,sizeofW(StgMutVar));
310 mv = (StgMutVar *)(Hp-sizeofW(StgMutVar)+1);
311 SET_HDR(mv,&MUT_VAR_info,CCCS);
314 TICK_RET_UNBOXED_TUP(1);
319 /* -----------------------------------------------------------------------------
320 Foreign Object Primitives
322 -------------------------------------------------------------------------- */
325 FN_(makeForeignObjzh_fast)
327 /* R1.p = ptr to foreign object,
329 StgForeignObj *result;
332 HP_CHK_GEN_TICKY(sizeofW(StgForeignObj), NO_PTRS, makeForeignObjzh_fast,);
333 TICK_ALLOC_PRIM(sizeofW(StgHeader),
334 sizeofW(StgForeignObj)-sizeofW(StgHeader), 0);
335 CCS_ALLOC(CCCS,sizeofW(StgForeignObj)); /* ccs prof */
337 result = (StgForeignObj *) (Hp + 1 - sizeofW(StgForeignObj));
338 SET_HDR(result,&FOREIGN_info,CCCS);
341 /* returns (# s#, ForeignObj# #) */
342 TICK_RET_UNBOXED_TUP(1);
348 /* These two are out-of-line for the benefit of the NCG */
349 FN_(unsafeThawArrayzh_fast)
352 SET_INFO((StgClosure *)R1.cl,&MUT_ARR_PTRS_info);
353 recordMutable((StgMutClosure*)R1.cl);
355 TICK_RET_UNBOXED_TUP(1);
360 /* -----------------------------------------------------------------------------
361 Weak Pointer Primitives
362 -------------------------------------------------------------------------- */
370 R3.p = finalizer (or NULL)
376 R3.cl = &NO_FINALIZER_closure;
379 HP_CHK_GEN_TICKY(sizeofW(StgWeak),R1_PTR|R2_PTR|R3_PTR, mkWeakzh_fast,);
380 TICK_ALLOC_PRIM(sizeofW(StgHeader)+1, // +1 is for the link field
381 sizeofW(StgWeak)-sizeofW(StgHeader)-1, 0);
382 CCS_ALLOC(CCCS,sizeofW(StgWeak)); /* ccs prof */
384 w = (StgWeak *) (Hp + 1 - sizeofW(StgWeak));
385 SET_HDR(w, &WEAK_info, CCCS);
389 w->finalizer = R3.cl;
391 w->link = weak_ptr_list;
393 IF_DEBUG(weak, fprintf(stderr,"New weak pointer at %p\n",w));
395 TICK_RET_UNBOXED_TUP(1);
400 FN_(finalizzeWeakzh_fast)
407 TICK_RET_UNBOXED_TUP(0);
408 w = (StgDeadWeak *)R1.p;
411 if (w->header.info == &DEAD_WEAK_info) {
412 RET_NP(0,&NO_FINALIZER_closure);
416 w->header.info = &DEAD_WEAK_info;
417 f = ((StgWeak *)w)->finalizer;
418 w->link = ((StgWeak *)w)->link;
420 /* return the finalizer */
421 if (f == &NO_FINALIZER_closure) {
422 RET_NP(0,&NO_FINALIZER_closure);
431 /* -----------------------------------------------------------------------------
432 Arbitrary-precision Integer operations.
433 -------------------------------------------------------------------------- */
435 FN_(int2Integerzh_fast)
437 /* arguments: R1 = Int# */
439 I_ val, s; /* to avoid aliasing */
440 StgArrWords* p; /* address of array result */
444 HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+1, NO_PTRS, int2Integerzh_fast,);
445 TICK_ALLOC_PRIM(sizeofW(StgArrWords),1,0);
446 CCS_ALLOC(CCCS,sizeofW(StgArrWords)+1); /* ccs prof */
448 p = (StgArrWords *)Hp - 1;
449 SET_ARR_HDR(p, &ARR_WORDS_info, CCCS, 1);
451 /* mpz_set_si is inlined here, makes things simpler */
455 } else if (val > 0) {
462 /* returns (# size :: Int#,
466 TICK_RET_UNBOXED_TUP(2);
471 FN_(word2Integerzh_fast)
473 /* arguments: R1 = Word# */
475 W_ val; /* to avoid aliasing */
477 StgArrWords* p; /* address of array result */
481 HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+1, NO_PTRS, word2Integerzh_fast,)
482 TICK_ALLOC_PRIM(sizeofW(StgArrWords),1,0);
483 CCS_ALLOC(CCCS,sizeofW(StgArrWords)+1); /* ccs prof */
485 p = (StgArrWords *)Hp - 1;
486 SET_ARR_HDR(p, &ARR_WORDS_info, CCCS, 1);
495 /* returns (# size :: Int#,
499 TICK_RET_UNBOXED_TUP(2);
504 FN_(addr2Integerzh_fast)
510 MAYBE_GC(NO_PTRS,addr2Integerzh_fast);
512 /* args: R1 :: Addr# */
515 /* Perform the operation */
516 if (RET_STGCALL3(int, mpz_init_set_str,&result,(str),/*base*/10))
519 /* returns (# size :: Int#,
523 TICK_RET_UNBOXED_TUP(2);
524 RET_NP(result._mp_size,
525 result._mp_d - sizeofW(StgArrWords));
530 * 'long long' primops for converting to/from Integers.
533 #ifdef SUPPORT_LONG_LONGS
535 FN_(int64ToIntegerzh_fast)
537 /* arguments: L1 = Int64# */
539 StgInt64 val; /* to avoid aliasing */
541 I_ s, neg, words_needed;
542 StgArrWords* p; /* address of array result */
548 if ( val >= 0x100000000LL || val <= -0x100000000LL ) {
551 /* minimum is one word */
554 HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+words_needed, NO_PTRS, int64ToIntegerzh_fast,)
555 TICK_ALLOC_PRIM(sizeofW(StgArrWords),words_needed,0);
556 CCS_ALLOC(CCCS,sizeofW(StgArrWords)+words_needed); /* ccs prof */
558 p = (StgArrWords *)(Hp-words_needed+1) - 1;
559 SET_ARR_HDR(p, &ARR_WORDS_info, CCCS, words_needed);
566 hi = (W_)((LW_)val / 0x100000000ULL);
568 if ( words_needed == 2 ) {
572 } else if ( val != 0 ) {
575 } else /* val==0 */ {
578 s = ( neg ? -s : s );
580 /* returns (# size :: Int#,
584 TICK_RET_UNBOXED_TUP(2);
589 FN_(word64ToIntegerzh_fast)
591 /* arguments: L1 = Word64# */
593 StgWord64 val; /* to avoid aliasing */
596 StgArrWords* p; /* address of array result */
600 if ( val >= 0x100000000ULL ) {
605 HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+words_needed, NO_PTRS, word64ToIntegerzh_fast,)
606 TICK_ALLOC_PRIM(sizeofW(StgArrWords),words_needed,0);
607 CCS_ALLOC(CCCS,sizeofW(StgArrWords)+words_needed); /* ccs prof */
609 p = (StgArrWords *)(Hp-words_needed+1) - 1;
610 SET_ARR_HDR(p, &ARR_WORDS_info, CCCS, words_needed);
612 hi = (W_)((LW_)val / 0x100000000ULL);
613 if ( val >= 0x100000000ULL ) {
617 } else if ( val != 0 ) {
620 } else /* val==0 */ {
624 /* returns (# size :: Int#,
628 TICK_RET_UNBOXED_TUP(2);
634 #endif /* HAVE_LONG_LONG */
636 /* ToDo: this is shockingly inefficient */
638 #define GMP_TAKE2_RET1(name,mp_fun) \
641 MP_INT arg1, arg2, result; \
647 /* call doYouWantToGC() */ \
648 MAYBE_GC(R2_PTR | R4_PTR, name); \
650 d1 = (StgArrWords *)R2.p; \
652 d2 = (StgArrWords *)R4.p; \
655 arg1._mp_alloc = d1->words; \
656 arg1._mp_size = (s1); \
657 arg1._mp_d = (unsigned long int *) (BYTE_ARR_CTS(d1)); \
658 arg2._mp_alloc = d2->words; \
659 arg2._mp_size = (s2); \
660 arg2._mp_d = (unsigned long int *) (BYTE_ARR_CTS(d2)); \
662 STGCALL1(mpz_init,&result); \
664 /* Perform the operation */ \
665 STGCALL3(mp_fun,&result,&arg1,&arg2); \
667 TICK_RET_UNBOXED_TUP(2); \
668 RET_NP(result._mp_size, \
669 result._mp_d-sizeofW(StgArrWords)); \
673 #define GMP_TAKE2_RET2(name,mp_fun) \
676 MP_INT arg1, arg2, result1, result2; \
682 /* call doYouWantToGC() */ \
683 MAYBE_GC(R2_PTR | R4_PTR, name); \
685 d1 = (StgArrWords *)R2.p; \
687 d2 = (StgArrWords *)R4.p; \
690 arg1._mp_alloc = d1->words; \
691 arg1._mp_size = (s1); \
692 arg1._mp_d = (unsigned long int *) (BYTE_ARR_CTS(d1)); \
693 arg2._mp_alloc = d2->words; \
694 arg2._mp_size = (s2); \
695 arg2._mp_d = (unsigned long int *) (BYTE_ARR_CTS(d2)); \
697 STGCALL1(mpz_init,&result1); \
698 STGCALL1(mpz_init,&result2); \
700 /* Perform the operation */ \
701 STGCALL4(mp_fun,&result1,&result2,&arg1,&arg2); \
703 TICK_RET_UNBOXED_TUP(4); \
704 RET_NPNP(result1._mp_size, \
705 result1._mp_d-sizeofW(StgArrWords), \
707 result2._mp_d-sizeofW(StgArrWords)); \
711 GMP_TAKE2_RET1(plusIntegerzh_fast, mpz_add);
712 GMP_TAKE2_RET1(minusIntegerzh_fast, mpz_sub);
713 GMP_TAKE2_RET1(timesIntegerzh_fast, mpz_mul);
714 GMP_TAKE2_RET1(gcdIntegerzh_fast, mpz_gcd);
715 GMP_TAKE2_RET1(quotIntegerzh_fast, mpz_tdiv_q);
716 GMP_TAKE2_RET1(remIntegerzh_fast, mpz_tdiv_r);
717 GMP_TAKE2_RET1(divExactIntegerzh_fast, mpz_divexact);
719 GMP_TAKE2_RET2(quotRemIntegerzh_fast, mpz_tdiv_qr);
720 GMP_TAKE2_RET2(divModIntegerzh_fast, mpz_fdiv_qr);
722 #ifndef FLOATS_AS_DOUBLES
723 FN_(decodeFloatzh_fast)
731 /* arguments: F1 = Float# */
734 HP_CHK_GEN_TICKY(sizeofW(StgArrWords)+1, NO_PTRS, decodeFloatzh_fast,);
735 TICK_ALLOC_PRIM(sizeofW(StgArrWords),1,0);
736 CCS_ALLOC(CCCS,sizeofW(StgArrWords)+1); /* ccs prof */
738 /* Be prepared to tell Lennart-coded __decodeFloat */
739 /* where mantissa._mp_d can be put (it does not care about the rest) */
740 p = (StgArrWords *)Hp - 1;
741 SET_ARR_HDR(p,&ARR_WORDS_info,CCCS,1)
742 mantissa._mp_d = (void *)BYTE_ARR_CTS(p);
744 /* Perform the operation */
745 STGCALL3(__decodeFloat,&mantissa,&exponent,arg);
747 /* returns: (Int# (expn), Int#, ByteArray#) */
748 TICK_RET_UNBOXED_TUP(3);
749 RET_NNP(exponent,mantissa._mp_size,p);
752 #endif /* !FLOATS_AS_DOUBLES */
754 #define DOUBLE_MANTISSA_SIZE (sizeofW(StgDouble))
755 #define ARR_SIZE (sizeofW(StgArrWords) + DOUBLE_MANTISSA_SIZE)
757 FN_(decodeDoublezh_fast)
764 /* arguments: D1 = Double# */
767 HP_CHK_GEN_TICKY(ARR_SIZE, NO_PTRS, decodeDoublezh_fast,);
768 TICK_ALLOC_PRIM(sizeofW(StgArrWords),DOUBLE_MANTISSA_SIZE,0);
769 CCS_ALLOC(CCCS,ARR_SIZE); /* ccs prof */
771 /* Be prepared to tell Lennart-coded __decodeDouble */
772 /* where mantissa.d can be put (it does not care about the rest) */
773 p = (StgArrWords *)(Hp-ARR_SIZE+1);
774 SET_ARR_HDR(p, &ARR_WORDS_info, CCCS, DOUBLE_MANTISSA_SIZE);
775 mantissa._mp_d = (void *)BYTE_ARR_CTS(p);
777 /* Perform the operation */
778 STGCALL3(__decodeDouble,&mantissa,&exponent,arg);
780 /* returns: (Int# (expn), Int#, ByteArray#) */
781 TICK_RET_UNBOXED_TUP(3);
782 RET_NNP(exponent,mantissa._mp_size,p);
786 /* -----------------------------------------------------------------------------
787 * Concurrency primitives
788 * -------------------------------------------------------------------------- */
793 /* args: R1 = closure to spark */
795 MAYBE_GC(R1_PTR, forkzh_fast);
797 /* create it right now, return ThreadID in R1 */
798 R1.t = RET_STGCALL2(StgTSO *, createIOThread,
799 RtsFlags.GcFlags.initialStkSize, R1.cl);
800 STGCALL1(scheduleThread, R1.t);
802 /* switch at the earliest opportunity */
805 JMP_(ENTRY_CODE(Sp[0]));
812 JMP_(stg_yield_noregs);
823 HP_CHK_GEN_TICKY(sizeofW(StgMVar), NO_PTRS, newMVarzh_fast,);
824 TICK_ALLOC_PRIM(sizeofW(StgMutVar)-1, // consider head,tail,link as admin wds
826 CCS_ALLOC(CCCS,sizeofW(StgMVar)); /* ccs prof */
828 mvar = (StgMVar *) (Hp - sizeofW(StgMVar) + 1);
829 SET_HDR(mvar,&EMPTY_MVAR_info,CCCS);
830 mvar->head = mvar->tail = (StgTSO *)&END_TSO_QUEUE_closure;
831 mvar->value = (StgClosure *)&END_TSO_QUEUE_closure;
833 TICK_RET_UNBOXED_TUP(1);
842 const StgInfoTable *info;
845 /* args: R1 = MVar closure */
847 mvar = (StgMVar *)R1.p;
850 info = LOCK_CLOSURE(mvar);
852 info = GET_INFO(mvar);
855 /* If the MVar is empty, put ourselves on its blocking queue,
856 * and wait until we're woken up.
858 if (info == &EMPTY_MVAR_info) {
859 if (mvar->head == (StgTSO *)&END_TSO_QUEUE_closure) {
860 mvar->head = CurrentTSO;
862 mvar->tail->link = CurrentTSO;
864 CurrentTSO->link = (StgTSO *)&END_TSO_QUEUE_closure;
865 CurrentTSO->why_blocked = BlockedOnMVar;
866 CurrentTSO->block_info.closure = (StgClosure *)mvar;
867 mvar->tail = CurrentTSO;
870 /* unlock the MVar */
871 mvar->header.info = &EMPTY_MVAR_info;
873 BLOCK(R1_PTR, takeMVarzh_fast);
877 mvar->value = (StgClosure *)&END_TSO_QUEUE_closure;
879 /* do this last... we might have locked the MVar in the SMP case,
880 * and writing the info pointer will unlock it.
882 SET_INFO(mvar,&EMPTY_MVAR_info);
884 TICK_RET_UNBOXED_TUP(1);
892 const StgInfoTable *info;
895 /* args: R1 = MVar, R2 = value */
897 mvar = (StgMVar *)R1.p;
900 info = LOCK_CLOSURE(mvar);
902 info = GET_INFO(mvar);
905 if (info == &FULL_MVAR_info) {
906 barf("putMVar#: MVar already full");
911 /* wake up the first thread on the queue, it will continue with the
912 * takeMVar operation and mark the MVar empty again.
914 if (mvar->head != (StgTSO *)&END_TSO_QUEUE_closure) {
915 ASSERT(mvar->head->why_blocked == BlockedOnMVar);
917 mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
919 // ToDo: check 2nd arg (mvar) is right
920 mvar->head = RET_STGCALL2(StgTSO *,unblockOne,mvar->head,mvar);
922 mvar->head = RET_STGCALL1(StgTSO *,unblockOne,mvar->head);
924 if (mvar->head == (StgTSO *)&END_TSO_QUEUE_closure) {
925 mvar->tail = (StgTSO *)&END_TSO_QUEUE_closure;
929 /* unlocks the MVar in the SMP case */
930 SET_INFO(mvar,&FULL_MVAR_info);
932 /* ToDo: yield here for better communication performance? */
933 JMP_(ENTRY_CODE(Sp[0]));
937 /* -----------------------------------------------------------------------------
938 Stable pointer primitives
939 ------------------------------------------------------------------------- */
941 FN_(makeStableNamezh_fast)
944 StgStableName *sn_obj;
947 HP_CHK_GEN_TICKY(sizeofW(StgStableName), R1_PTR, makeStableNamezh_fast,);
948 TICK_ALLOC_PRIM(sizeofW(StgHeader),
949 sizeofW(StgStableName)-sizeofW(StgHeader), 0);
950 CCS_ALLOC(CCCS,sizeofW(StgStableName)); /* ccs prof */
952 index = RET_STGCALL1(StgWord,lookupStableName,R1.p);
954 /* Is there already a StableName for this heap object? */
955 if (stable_ptr_table[index].sn_obj == NULL) {
956 sn_obj = (StgStableName *) (Hp - sizeofW(StgStableName) + 1);
957 sn_obj->header.info = &STABLE_NAME_info;
959 stable_ptr_table[index].sn_obj = (StgClosure *)sn_obj;
961 (StgClosure *)sn_obj = stable_ptr_table[index].sn_obj;
964 TICK_RET_UNBOXED_TUP(1);
968 /* -----------------------------------------------------------------------------
969 Thread I/O blocking primitives
970 -------------------------------------------------------------------------- */
976 ASSERT(CurrentTSO->why_blocked == NotBlocked);
977 CurrentTSO->why_blocked = BlockedOnRead;
978 CurrentTSO->block_info.fd = R1.i;
979 ACQUIRE_LOCK(&sched_mutex);
980 APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
981 RELEASE_LOCK(&sched_mutex);
982 JMP_(stg_block_noregs);
986 FN_(waitWritezh_fast)
990 ASSERT(CurrentTSO->why_blocked == NotBlocked);
991 CurrentTSO->why_blocked = BlockedOnWrite;
992 CurrentTSO->block_info.fd = R1.i;
993 ACQUIRE_LOCK(&sched_mutex);
994 APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
995 RELEASE_LOCK(&sched_mutex);
996 JMP_(stg_block_noregs);
1004 ASSERT(CurrentTSO->why_blocked == NotBlocked);
1005 CurrentTSO->why_blocked = BlockedOnDelay;
1007 ACQUIRE_LOCK(&sched_mutex);
1009 /* Add on ticks_since_select, since these will be subtracted at
1010 * the next awaitEvent call.
1012 CurrentTSO->block_info.delay = R1.i + ticks_since_select;
1014 APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
1016 RELEASE_LOCK(&sched_mutex);
1017 JMP_(stg_block_noregs);