
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