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