Skip to content

Commit adbf88e

Browse files
treeowlsjakobi
authored andcommitted
Avoid boxing arrays
Previously, we used a lot of things that looked like runST (act >>= unsafeFreeze) The trouble is that GHC can't unbox past the `runRW#` primitive that `runST` is based on. So this actually allocates an `Array` constructor which we will then throw away immediately. The way to avoid this is to call `runRW#` manually to produce a raw `SmallArray#`, then apply the `Array` constructor on the outside.
1 parent f1ea9a4 commit adbf88e

File tree

2 files changed

+37
-19
lines changed

2 files changed

+37
-19
lines changed

Data/HashMap/Internal.hs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ module Data.HashMap.Internal
120120
, two
121121
, unionArrayBy
122122
, update32
123-
, update32M
123+
, update32Mut
124124
, update32With'
125125
, updateOrConcatWith
126126
, updateOrConcatWithKey
@@ -2224,16 +2224,16 @@ subsetArray cmpV ary1 ary2 = A.length ary1 <= A.length ary2 && A.all inAry2 ary1
22242224

22252225
-- | /O(n)/ Update the element at the given position in this array.
22262226
update32 :: A.Array e -> Int -> e -> A.Array e
2227-
update32 ary idx b = runST (update32M ary idx b)
2227+
update32 ary idx b = A.run (update32Mut ary idx b)
22282228
{-# INLINE update32 #-}
22292229

22302230
-- | /O(n)/ Update the element at the given position in this array.
2231-
update32M :: A.Array e -> Int -> e -> ST s (A.Array e)
2232-
update32M ary idx b = do
2231+
update32Mut :: A.Array e -> Int -> e -> ST s (A.MArray s e)
2232+
update32Mut ary idx b = do
22332233
mary <- clone ary
22342234
A.write mary idx b
2235-
A.unsafeFreeze mary
2236-
{-# INLINE update32M #-}
2235+
return mary
2236+
{-# INLINE update32Mut #-}
22372237

22382238
-- | /O(n)/ Update the element at the given position in this array, by applying a function to it.
22392239
update32With' :: A.Array e -> Int -> (e -> e) -> A.Array e

Data/HashMap/Internal/Array.hs

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ import GHC.Exts (Int (..), SmallArray#, SmallMutableArray#,
8686
cloneSmallMutableArray#, copySmallArray#,
8787
copySmallMutableArray#, indexSmallArray#,
8888
newSmallArray#, readSmallArray#,
89-
reallyUnsafePtrEquality#, sizeofSmallArray#,
89+
reallyUnsafePtrEquality#, runRW#, sizeofSmallArray#,
9090
sizeofSmallMutableArray#, tagToEnum#,
9191
thawSmallArray#, unsafeCoerce#,
9292
unsafeFreezeSmallArray#, unsafeThawSmallArray#,
@@ -205,13 +205,17 @@ new_ :: Int -> ST s (MArray s a)
205205
new_ n = new n undefinedElem
206206

207207
singleton :: a -> Array a
208-
singleton x = runST (singletonM x)
208+
singleton x = run (singletonMut x)
209209
{-# INLINE singleton #-}
210210

211211
singletonM :: a -> ST s (Array a)
212212
singletonM x = new 1 x >>= unsafeFreeze
213213
{-# INLINE singletonM #-}
214214

215+
singletonMut :: a -> ST s (MArray s a)
216+
singletonMut x = new 1 x
217+
{-# INLINE singletonMut #-}
218+
215219
pair :: a -> a -> Array a
216220
pair x y = run $ do
217221
ary <- new 2 x
@@ -263,7 +267,17 @@ unsafeThaw ary
263267
{-# INLINE unsafeThaw #-}
264268

265269
run :: (forall s . ST s (MArray s e)) -> Array e
266-
run act = runST $ act >>= unsafeFreeze
270+
#if MIN_VERSION_base(4,9,0)
271+
-- GHC can't unbox across the runRW# boundary, so we apply the Array constructor
272+
-- on the outside.
273+
run (ST act) =
274+
case runRW# $ \s ->
275+
case act s of { (# s', MArray mary #) ->
276+
unsafeFreezeSmallArray# mary s' } of
277+
(# _, ary #) -> Array ary
278+
#else
279+
run act = runST (act >>= unsafeFreeze)
280+
#endif
267281
{-# INLINE run #-}
268282

269283
-- | Unsafely copy the elements of an array. Array bounds are not checked.
@@ -300,33 +314,37 @@ trim mary n = cloneM mary 0 n >>= unsafeFreeze
300314
-- | /O(n)/ Insert an element at the given position in this array,
301315
-- increasing its size by one.
302316
insert :: Array e -> Int -> e -> Array e
303-
insert ary idx b = runST (insertM ary idx b)
317+
insert ary idx b = run (insertMut ary idx b)
304318
{-# INLINE insert #-}
305319

306320
-- | /O(n)/ Insert an element at the given position in this array,
307321
-- increasing its size by one.
308322
insertM :: Array e -> Int -> e -> ST s (Array e)
309-
insertM ary idx b =
323+
insertM ary idx b = insertMut ary idx b >>= unsafeFreeze
324+
{-# INLINE insertM #-}
325+
326+
insertMut :: Array e -> Int -> e -> ST s (MArray s e)
327+
insertMut ary idx b =
310328
CHECK_BOUNDS("insertM", count + 1, idx)
311329
do mary <- new (count+1) b
312330
copy ary 0 mary 0 idx
313331
copy ary idx mary (idx+1) (count-idx)
314-
unsafeFreeze mary
332+
return mary
315333
where !count = length ary
316-
{-# INLINE insertM #-}
334+
{-# INLINE insertMut #-}
317335

318336
-- | /O(n)/ Update the element at the given position in this array.
319337
update :: Array e -> Int -> e -> Array e
320-
update ary idx b = runST (updateM ary idx b)
338+
update ary idx b = run (updateM ary idx b)
321339
{-# INLINE update #-}
322340

323341
-- | /O(n)/ Update the element at the given position in this array.
324-
updateM :: Array e -> Int -> e -> ST s (Array e)
342+
updateM :: Array e -> Int -> e -> ST s (MArray s e)
325343
updateM ary idx b =
326344
CHECK_BOUNDS("updateM", count, idx)
327345
do mary <- thaw ary 0 count
328346
write mary idx b
329-
unsafeFreeze mary
347+
return mary
330348
where !count = length ary
331349
{-# INLINE updateM #-}
332350

@@ -421,18 +439,18 @@ thaw !ary !_o@(I# o#) _n@(I# n#) =
421439
-- | /O(n)/ Delete an element at the given position in this array,
422440
-- decreasing its size by one.
423441
delete :: Array e -> Int -> Array e
424-
delete ary idx = runST (deleteM ary idx)
442+
delete ary idx = run (deleteM ary idx)
425443
{-# INLINE delete #-}
426444

427445
-- | /O(n)/ Delete an element at the given position in this array,
428446
-- decreasing its size by one.
429-
deleteM :: Array e -> Int -> ST s (Array e)
447+
deleteM :: Array e -> Int -> ST s (MArray s e)
430448
deleteM ary idx = do
431449
CHECK_BOUNDS("deleteM", count, idx)
432450
do mary <- new_ (count-1)
433451
copy ary 0 mary 0 idx
434452
copy ary (idx+1) mary idx (count-(idx+1))
435-
unsafeFreeze mary
453+
return mary
436454
where !count = length ary
437455
{-# INLINE deleteM #-}
438456

0 commit comments

Comments
 (0)