How unsafe are unsafeThawArray# and unsafeFreezeArray#

Simon Marlow marlowsd at gmail.com
Fri Mar 9 11:58:26 CET 2012


On 09/03/2012 01:13, Johan Tibell wrote:
> Hi,
>
> I just ran across some code that calls unsafeThawArray#, writeArray#,
> and unsafeFreezeArray#, in that order. How unsafe is that?
>
>   * Is it unsafe in the sense that if someone has a reference to the
> original Array# they will see the value of that pure array change?

Yes.

>   * Is it unsafe in the sense things will crash and burn?

No. (at least, we would consider it a bug if a crash was the result)

> I looked at the implementation of unsafeFreezeArray#, which is
>
>      emitPrimOp [res] UnsafeFreezeArrayOp [arg] _
>         = stmtsC [ setInfo arg (CmmLit (CmmLabel mkMAP_FROZEN_infoLabel)),
>             CmmAssign (CmmLocal res) arg ]
>
> but I couldn't find any implementation of unsafeThawArray#. Is it a
> no-op? It seems to me that if unsafeFreezeArray# changes the head of
> the array heap object so should unsafeThawArray#.

You'll find the implementation of unsafeThawArray# in rts/PrimOps.cmm, 
reproduced here for your enjoyment:

stg_unsafeThawArrayzh
{
   // SUBTLETY TO DO WITH THE OLD GEN MUTABLE LIST
   //
   // A MUT_ARR_PTRS lives on the mutable list, but a MUT_ARR_PTRS_FROZEN
   // normally doesn't.  However, when we freeze a MUT_ARR_PTRS, we leave
   // it on the mutable list for the GC to remove (removing something from
   // the mutable list is not easy).
   //
   // So that we can tell whether a MUT_ARR_PTRS_FROZEN is on the 
mutable list,
   // when we freeze it we set the info ptr to be MUT_ARR_PTRS_FROZEN0
   // to indicate that it is still on the mutable list.
   //
   // So, when we thaw a MUT_ARR_PTRS_FROZEN, we must cope with two cases:
   // either it is on a mut_list, or it isn't.  We adopt the convention that
   // the closure type is MUT_ARR_PTRS_FROZEN0 if it is on the mutable list,
   // and MUT_ARR_PTRS_FROZEN otherwise.  In fact it wouldn't matter if
   // we put it on the mutable list more than once, but it would get 
scavenged
   // multiple times during GC, which would be unnecessarily slow.
   //
   if (StgHeader_info(R1) != stg_MUT_ARR_PTRS_FROZEN0_info) {
	SET_INFO(R1,stg_MUT_ARR_PTRS_DIRTY_info);
	recordMutable(R1, R1);
	// must be done after SET_INFO, because it ASSERTs closure_MUTABLE()
	RET_P(R1);
   } else {
	SET_INFO(R1,stg_MUT_ARR_PTRS_DIRTY_info);
	RET_P(R1);
   }
}


Cheers,
	Simon



More information about the Glasgow-haskell-users mailing list