Rodrigo Mesquita pushed to branch wip/romes/top-level-bcos-tag at Glasgow Haskell Compiler / GHC
Commits:
-
5cb4a42f
by Rodrigo Mesquita at 2025-05-22T14:35:38+01:00
16 changed files:
- compiler/GHC/Builtin/primops.txt.pp
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Linker.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/StgToByteCode.hs
- libraries/base/src/GHC/Exts.hs
- libraries/ghc-internal/src/GHC/Internal/Exts.hs
- libraries/ghci/GHCi/CreateBCO.hs
- libraries/ghci/GHCi/ResolvedBCO.hs
- rts/Interpreter.c
- rts/PrimOps.cmm
- rts/Printer.c
- rts/RtsSymbols.c
- rts/StgMiscClosures.cmm
- rts/include/stg/MiscClosures.h
Changes:
... | ... | @@ -3872,12 +3872,13 @@ primop MkApUpd0_Op "mkApUpd0#" GenPrimOp |
3872 | 3872 | with
|
3873 | 3873 | out_of_line = True
|
3874 | 3874 | |
3875 | -primop NewBCOOp "newBCO#" GenPrimOp
|
|
3876 | - ByteArray# -> ByteArray# -> Array# a -> Int# -> ByteArray# -> State# s -> (# State# s, BCO #)
|
|
3877 | - { @'newBCO#' instrs lits ptrs arity bitmap@ creates a new bytecode object. The
|
|
3875 | +primop NewBCOOp "newBCO2#" GenPrimOp
|
|
3876 | + Int8# -> ByteArray# -> ByteArray# -> Array# a -> Int# -> ByteArray# -> State# s -> (# State# s, BCO #)
|
|
3877 | + { @'newBCO2#' is_case_cont instrs lits ptrs arity bitmap@ creates a new bytecode object. The
|
|
3878 | 3878 | resulting object encodes a function of the given arity with the instructions
|
3879 | 3879 | encoded in @instrs@, and a static reference table usage bitmap given by
|
3880 | - @bitmap@. }
|
|
3880 | + @bitmap@. The @is_case_cont@ boolean indicates whether the BCO is a case
|
|
3881 | + continuation (see Note [Case continuation BCOs]) }
|
|
3881 | 3882 | with
|
3882 | 3883 | effect = ReadWriteEffect
|
3883 | 3884 | out_of_line = True
|
... | ... | @@ -85,7 +85,7 @@ bcoFreeNames :: UnlinkedBCO -> UniqDSet Name |
85 | 85 | bcoFreeNames bco
|
86 | 86 | = bco_refs bco `uniqDSetMinusUniqSet` mkNameSet [unlinkedBCOName bco]
|
87 | 87 | where
|
88 | - bco_refs (UnlinkedBCO _ _ _ _ nonptrs ptrs)
|
|
88 | + bco_refs (UnlinkedBCO _ _ _ _ nonptrs ptrs _)
|
|
89 | 89 | = unionManyUniqDSets (
|
90 | 90 | mkUniqDSet [ n | BCOPtrName n <- elemsFlatBag ptrs ] :
|
91 | 91 | mkUniqDSet [ n | BCONPtrItbl n <- elemsFlatBag nonptrs ] :
|
... | ... | @@ -236,7 +236,8 @@ assembleBCO platform |
236 | 236 | , protoBCOInstrs = instrs
|
237 | 237 | , protoBCOBitmap = bitmap
|
238 | 238 | , protoBCOBitmapSize = bsize
|
239 | - , protoBCOArity = arity }) = do
|
|
239 | + , protoBCOArity = arity
|
|
240 | + , protoBCOIsCaseCont = isCC }) = do
|
|
240 | 241 | -- pass 1: collect up the offsets of the local labels.
|
241 | 242 | let initial_offset = 0
|
242 | 243 | |
... | ... | @@ -266,7 +267,7 @@ assembleBCO platform |
266 | 267 | |
267 | 268 | let !insns_arr = mkBCOByteArray $ final_isn_array
|
268 | 269 | !bitmap_arr = mkBCOByteArray $ mkBitmapArray bsize bitmap
|
269 | - ul_bco = UnlinkedBCO nm arity insns_arr bitmap_arr (fromSmallArray final_lit_array) (fromSmallArray final_ptr_array)
|
|
270 | + ul_bco = UnlinkedBCO nm arity insns_arr bitmap_arr (fromSmallArray final_lit_array) (fromSmallArray final_ptr_array) isCC
|
|
270 | 271 | |
271 | 272 | -- 8 Aug 01: Finalisers aren't safe when attached to non-primitive
|
272 | 273 | -- objects, since they might get run too early. Disable this until
|
... | ... | @@ -53,7 +53,8 @@ data ProtoBCO a |
53 | 53 | -- what the BCO came from, for debugging only
|
54 | 54 | protoBCOExpr :: Either [CgStgAlt] CgStgRhs,
|
55 | 55 | -- malloc'd pointers
|
56 | - protoBCOFFIs :: [FFIInfo]
|
|
56 | + protoBCOFFIs :: [FFIInfo],
|
|
57 | + protoBCOIsCaseCont :: !Bool -- See Note [Case continuation BCOs]
|
|
57 | 58 | }
|
58 | 59 | |
59 | 60 | -- | A local block label (e.g. identifying a case alternative).
|
... | ... | @@ -59,7 +59,7 @@ linkBCO |
59 | 59 | -> UnlinkedBCO
|
60 | 60 | -> IO ResolvedBCO
|
61 | 61 | linkBCO interp pkgs_loaded le bco_ix
|
62 | - (UnlinkedBCO _ arity insns bitmap lits0 ptrs0) = do
|
|
62 | + (UnlinkedBCO _ arity insns bitmap lits0 ptrs0 isCC) = do
|
|
63 | 63 | -- fromIntegral Word -> Word64 should be a no op if Word is Word64
|
64 | 64 | -- otherwise it will result in a cast to longlong on 32bit systems.
|
65 | 65 | (lits :: [Word]) <- mapM (fmap fromIntegral . lookupLiteral interp pkgs_loaded le) (elemsFlatBag lits0)
|
... | ... | @@ -69,7 +69,7 @@ linkBCO interp pkgs_loaded le bco_ix |
69 | 69 | insns
|
70 | 70 | bitmap
|
71 | 71 | (mkBCOByteArray lits')
|
72 | - (addListToSS emptySS ptrs))
|
|
72 | + (addListToSS emptySS ptrs) isCC)
|
|
73 | 73 | |
74 | 74 | lookupLiteral :: Interp -> PkgsLoaded -> LinkerEnv -> BCONPtr -> IO Word
|
75 | 75 | lookupLiteral interp pkgs_loaded le ptr = case ptr of
|
... | ... | @@ -167,14 +167,109 @@ newtype ItblPtr = ItblPtr (RemotePtr Heap.StgInfoTable) |
167 | 167 | newtype AddrPtr = AddrPtr (RemotePtr ())
|
168 | 168 | deriving (NFData)
|
169 | 169 | |
170 | +{-
|
|
171 | +--------------------------------------------------------------------------------
|
|
172 | +-- * Byte Code Objects (BCOs)
|
|
173 | +--------------------------------------------------------------------------------
|
|
174 | + |
|
175 | +Note [Case continuation BCOs]
|
|
176 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
177 | + |
|
178 | +A stack with a BCO stack frame at the top looks like:
|
|
179 | + |
|
180 | + (an StgBCO)
|
|
181 | + | ... | +---> +---------[1]--+
|
|
182 | + +------------------+ | | info_tbl_ptr | ------+
|
|
183 | + | OTHER FRAME | | +--------------+ |
|
|
184 | + +------------------+ | | StgArrBytes* | <--- the byte code
|
|
185 | + | ... | | +--------------+ |
|
|
186 | + +------------------+ | | ... | |
|
|
187 | + | fvs1 | | |
|
|
188 | + +------------------+ | |
|
|
189 | + | ... | | (StgInfoTable) |
|
|
190 | + +------------------+ | +----------+ <---+
|
|
191 | + | args1 | | | ... |
|
|
192 | + +------------------+ | +----------+
|
|
193 | + | some StgBCO* | -----+ | type=BCO |
|
|
194 | + +------------------+ +----------+
|
|
195 | + Sp | stg_apply_interp | -----+ | ... |
|
|
196 | + +------------------+ |
|
|
197 | + |
|
|
198 | + | (StgInfoTable)
|
|
199 | + +----> +--------------+
|
|
200 | + | ... |
|
|
201 | + +--------------+
|
|
202 | + | type=RET_BCO |
|
|
203 | + +--------------+
|
|
204 | + | ... |
|
|
205 | + |
|
206 | + |
|
207 | +The byte code for a BCO heap object makes use of arguments and free variables
|
|
208 | +which can typically be found within the BCO stack frame. In the code, these
|
|
209 | +variables are referenced via a statically known stack offset (tracked using
|
|
210 | +`BCEnv` in `StgToByteCode`).
|
|
211 | + |
|
212 | +However, in /case continuation/ BCOs, the code may additionally refer to free
|
|
213 | +variables that are outside of that BCO's stack frame -- some free variables of a
|
|
214 | +case continuation BCO may only be found in the stack frame of a parent BCO.
|
|
215 | + |
|
216 | +Yet, references to these out-of-frame variables are also done in terms of stack
|
|
217 | +offsets. Thus, they rely on the position of /another frame/ to be fixed. (See
|
|
218 | +Note [PUSH_L underflow] for more information about references to previous
|
|
219 | +frames and nested BCOs)
|
|
220 | + |
|
221 | +This makes case continuation BCOs special: unlike normal BCOs, case cont BCO
|
|
222 | +frames cannot be moved on the stack independently from their parent BCOs.
|
|
223 | + |
|
224 | +In order to be able to distinguish them at runtime, the code generator will use
|
|
225 | +distinct info table pointers for their closures, even though they will have the
|
|
226 | +same structure on the heap (StgBCO). Specifically:
|
|
227 | + |
|
228 | + - Normal BCOs are always headed by the `stg_BCO_info` pointer.
|
|
229 | + - Case continuation BCOs are always headed by the `stg_CASE_CONT_BCO_info` pointer.
|
|
230 | + |
|
231 | +A primary reason why we need to distinguish these two cases is to know where we
|
|
232 | +can insert a debugger step-out frame (`stg_stop_after_ret_frame`). In
|
|
233 | +particular, because case cont BCOs may refer to the parent frame, we must not
|
|
234 | +insert step-out frames between a case cont BCO and its parent.
|
|
235 | +See Note [Debugger: Step-out] for further details.
|
|
236 | + |
|
237 | +As an example, consider the following, where `y` is free in the case alternatives:
|
|
238 | + |
|
239 | + f x y = case x of
|
|
240 | + True -> y - 1
|
|
241 | + False -> y + 1 :: Int
|
|
242 | + |
|
243 | +While interpreting f, the args x and y will be on the stack as part of f's frame.
|
|
244 | +In its body, a case continuation BCO is pushed (PUSH_ALTS) and then `x` is
|
|
245 | +entered to be evaluated. Upon entering `x`, the stack would look something like:
|
|
246 | + |
|
247 | + <f arg 2>
|
|
248 | + <f arg 1>
|
|
249 | + ...
|
|
250 | + <Case continuation BCO Frame>
|
|
251 | + |
|
252 | +We cannot insert a step out frame in between:
|
|
253 | + |
|
254 | + |
|
255 | + <f arg 2>
|
|
256 | + <f arg 1>
|
|
257 | + ...
|
|
258 | + <inserted step-out frame> <--- BAD! Breaks stack offsets in the case cont.
|
|
259 | + <Case continuation BCO Frame>
|
|
260 | + |
|
261 | +Instead, we must traverse until the parent BCO and insert the step-out frame before it instead.
|
|
262 | +-}
|
|
263 | + |
|
170 | 264 | data UnlinkedBCO
|
171 | 265 | = UnlinkedBCO {
|
172 | 266 | unlinkedBCOName :: !Name,
|
173 | 267 | unlinkedBCOArity :: {-# UNPACK #-} !Int,
|
174 | - unlinkedBCOInstrs :: !(BCOByteArray Word16), -- insns
|
|
175 | - unlinkedBCOBitmap :: !(BCOByteArray Word), -- bitmap
|
|
268 | + unlinkedBCOInstrs :: !(BCOByteArray Word16), -- insns
|
|
269 | + unlinkedBCOBitmap :: !(BCOByteArray Word), -- bitmap
|
|
176 | 270 | unlinkedBCOLits :: !(FlatBag BCONPtr), -- non-ptrs
|
177 | - unlinkedBCOPtrs :: !(FlatBag BCOPtr) -- ptrs
|
|
271 | + unlinkedBCOPtrs :: !(FlatBag BCOPtr), -- ptrs
|
|
272 | + unlinkedBCOIsCaseCont :: !Bool -- See Note [Case continuation BCOs]
|
|
178 | 273 | }
|
179 | 274 | |
180 | 275 | instance NFData UnlinkedBCO where
|
... | ... | @@ -227,10 +322,11 @@ seqCgBreakInfo CgBreakInfo{..} = |
227 | 322 | rnf cgb_resty
|
228 | 323 | |
229 | 324 | instance Outputable UnlinkedBCO where
|
230 | - ppr (UnlinkedBCO nm _arity _insns _bitmap lits ptrs)
|
|
325 | + ppr (UnlinkedBCO nm _arity _insns _bitmap lits ptrs pi)
|
|
231 | 326 | = sep [text "BCO", ppr nm, text "with",
|
232 | 327 | ppr (sizeFlatBag lits), text "lits",
|
233 | - ppr (sizeFlatBag ptrs), text "ptrs" ]
|
|
328 | + ppr (sizeFlatBag ptrs), text "ptrs",
|
|
329 | + ppr pi, text "is_pos_indep"]
|
|
234 | 330 | |
235 | 331 | instance Outputable CgBreakInfo where
|
236 | 332 | ppr info = text "CgBreakInfo" <+>
|
... | ... | @@ -253,7 +253,11 @@ mkProtoBCO |
253 | 253 | -> Int -- ^ arity
|
254 | 254 | -> WordOff -- ^ bitmap size
|
255 | 255 | -> [StgWord] -- ^ bitmap
|
256 | - -> Bool -- ^ True <=> is a return point, rather than a function
|
|
256 | + -> Bool -- ^ True <=> it's a case continuation, rather than a function
|
|
257 | + -- Used for
|
|
258 | + -- (A) Stack check collision and
|
|
259 | + -- (B) Mark the BCO wrt whether it contains non-local stack
|
|
260 | + -- references. See Note [Case continuation BCOs].
|
|
257 | 261 | -> [FFIInfo]
|
258 | 262 | -> ProtoBCO Name
|
259 | 263 | mkProtoBCO platform _add_bco_name nm instrs_ordlist origin arity bitmap_size bitmap is_ret ffis
|
... | ... | @@ -264,7 +268,8 @@ mkProtoBCO platform _add_bco_name nm instrs_ordlist origin arity bitmap_size bit |
264 | 268 | protoBCOBitmapSize = fromIntegral bitmap_size,
|
265 | 269 | protoBCOArity = arity,
|
266 | 270 | protoBCOExpr = origin,
|
267 | - protoBCOFFIs = ffis
|
|
271 | + protoBCOFFIs = ffis,
|
|
272 | + protoBCOIsCaseCont = is_ret
|
|
268 | 273 | }
|
269 | 274 | where
|
270 | 275 | #if MIN_VERSION_rts(1,0,3)
|
... | ... | @@ -353,6 +358,9 @@ schemeTopBind (id, rhs) |
353 | 358 | -- Park the resulting BCO in the monad. Also requires the
|
354 | 359 | -- name of the variable to which this value was bound,
|
355 | 360 | -- so as to give the resulting BCO a name.
|
361 | +--
|
|
362 | +-- The resulting ProtoBCO expects the free variables and the function arguments
|
|
363 | +-- to be in the stack directly before it.
|
|
356 | 364 | schemeR :: [Id] -- Free vars of the RHS, ordered as they
|
357 | 365 | -- will appear in the thunk. Empty for
|
358 | 366 | -- top-level things, which have no free vars.
|
... | ... | @@ -391,6 +399,8 @@ schemeR_wrk fvs nm original_body (args, body) |
391 | 399 | -- them unlike constructor fields.
|
392 | 400 | szsb_args = map (wordsToBytes platform . idSizeW platform) all_args
|
393 | 401 | sum_szsb_args = sum szsb_args
|
402 | + -- Make a stack offset for each argument or free var -- they should
|
|
403 | + -- appear contiguous in the stack, in order.
|
|
394 | 404 | p_init = Map.fromList (zip all_args (mkStackOffsets 0 szsb_args))
|
395 | 405 | |
396 | 406 | -- make the arg bitmap
|
... | ... | @@ -1401,7 +1411,7 @@ Note [unboxed tuple bytecodes and tuple_BCO] |
1401 | 1411 | tupleBCO :: Platform -> NativeCallInfo -> [(PrimRep, ByteOff)] -> [FFIInfo] -> ProtoBCO Name
|
1402 | 1412 | tupleBCO platform args_info args =
|
1403 | 1413 | mkProtoBCO platform Nothing invented_name body_code (Left [])
|
1404 | - 0{-no arity-} bitmap_size bitmap False{-is alts-}
|
|
1414 | + 0{-no arity-} bitmap_size bitmap False{-not alts-}
|
|
1405 | 1415 | where
|
1406 | 1416 | {-
|
1407 | 1417 | The tuple BCO is never referred to by name, so we can get away
|
... | ... | @@ -1422,7 +1432,7 @@ tupleBCO platform args_info args = |
1422 | 1432 | primCallBCO :: Platform -> NativeCallInfo -> [(PrimRep, ByteOff)] -> [FFIInfo] -> ProtoBCO Name
|
1423 | 1433 | primCallBCO platform args_info args =
|
1424 | 1434 | mkProtoBCO platform Nothing invented_name body_code (Left [])
|
1425 | - 0{-no arity-} bitmap_size bitmap False{-is alts-}
|
|
1435 | + 0{-no arity-} bitmap_size bitmap False{-not alts-}
|
|
1426 | 1436 | where
|
1427 | 1437 | {-
|
1428 | 1438 | The primcall BCO is never referred to by name, so we can get away
|
... | ... | @@ -26,12 +26,12 @@ module GHC.Exts |
26 | 26 | -- ** Legacy interface for arrays of arrays
|
27 | 27 | module GHC.Internal.ArrayArray,
|
28 | 28 | -- * Primitive operations
|
29 | - {-# DEPRECATED ["The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14", "These symbols should be imported from ghc-internal instead if needed."] #-}
|
|
29 | + {-# DEPRECATED ["The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 10.14", "These symbols should be imported from ghc-internal instead if needed."] #-}
|
|
30 | 30 | Prim.BCO,
|
31 | 31 | {-# DEPRECATED ["The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14", "These symbols should be imported from ghc-internal instead if needed."] #-}
|
32 | 32 | Prim.mkApUpd0#,
|
33 | 33 | {-# DEPRECATED ["The BCO, mkApUpd0#, and newBCO# re-exports from GHC.Exts have been deprecated and will be removed in 9.14", "These symbols should be imported from ghc-internal instead if needed."] #-}
|
34 | - Prim.newBCO#,
|
|
34 | + IExts.newBCO#,
|
|
35 | 35 | module GHC.Prim,
|
36 | 36 | module GHC.Prim.Ext,
|
37 | 37 | -- ** Running 'RealWorld' state thread
|
... | ... | @@ -119,7 +119,7 @@ module GHC.Exts |
119 | 119 | maxTupleSize
|
120 | 120 | ) where
|
121 | 121 | |
122 | -import GHC.Internal.Exts
|
|
122 | +import GHC.Internal.Exts hiding ( newBCO# )
|
|
123 | 123 | import GHC.Internal.ArrayArray
|
124 | 124 | import GHC.Prim hiding
|
125 | 125 | ( coerce
|
... | ... | @@ -132,7 +132,7 @@ import GHC.Prim hiding |
132 | 132 | , isByteArrayWeaklyPinned#, isMutableByteArrayWeaklyPinned#
|
133 | 133 | |
134 | 134 | -- deprecated
|
135 | - , BCO, mkApUpd0#, newBCO#
|
|
135 | + , BCO, mkApUpd0#
|
|
136 | 136 | |
137 | 137 | -- Don't re-export vector FMA instructions
|
138 | 138 | , fmaddFloatX4#
|
... | ... | @@ -256,8 +256,10 @@ import GHC.Prim hiding |
256 | 256 | , minWord8X32#
|
257 | 257 | , minWord8X64#
|
258 | 258 | )
|
259 | +import qualified GHC.Internal.Exts as IExts
|
|
260 | + ( newBCO# )
|
|
259 | 261 | import qualified GHC.Prim as Prim
|
260 | - ( BCO, mkApUpd0#, newBCO# )
|
|
262 | + ( BCO, mkApUpd0# )
|
|
261 | 263 | |
262 | 264 | import GHC.Prim.Ext
|
263 | 265 |
... | ... | @@ -163,6 +163,9 @@ module GHC.Internal.Exts |
163 | 163 | |
164 | 164 | -- * The maximum tuple size
|
165 | 165 | maxTupleSize,
|
166 | + |
|
167 | + -- * Interpreter
|
|
168 | + newBCO#
|
|
166 | 169 | ) where
|
167 | 170 | |
168 | 171 | import GHC.Internal.Prim hiding ( coerce, dataToTagSmall#, dataToTagLarge#, whereFrom# )
|
... | ... | @@ -469,3 +472,18 @@ resizeSmallMutableArray# arr0 szNew a s0 = |
469 | 472 | -- accessible\" by word.
|
470 | 473 | considerAccessible :: Bool
|
471 | 474 | considerAccessible = True
|
475 | + |
|
476 | +--------------------------------------------------------------------------------
|
|
477 | +-- Interpreter
|
|
478 | + |
|
479 | +{-|
|
|
480 | +@'newBCO#' instrs lits ptrs arity bitmap@ creates a new bytecode object. The
|
|
481 | +resulting object encodes a function of the given arity with the instructions
|
|
482 | +encoded in @instrs@, and a static reference table usage bitmap given by
|
|
483 | +@bitmap@.
|
|
484 | + |
|
485 | +Note: Case continuation BCOs, with non-local stack references, must be
|
|
486 | +constructed using @'newBCO2#' 1@ instead. See Note [Case continuation BCOs].
|
|
487 | +-}
|
|
488 | +newBCO# :: ByteArray# -> ByteArray# -> Array# a -> Int# -> ByteArray# -> State# s -> (# State# s, BCO #)
|
|
489 | +newBCO# b1 b2 a1 i1 b3 s = newBCO2# (intToInt8# 0#) b1 b2 a1 i1 b3 s |
... | ... | @@ -87,11 +87,11 @@ linkBCO' arr ResolvedBCO{..} = do |
87 | 87 | literals_barr = barr (getBCOByteArray resolvedBCOLits)
|
88 | 88 | |
89 | 89 | PtrsArr marr <- mkPtrsArray arr n_ptrs ptrs
|
90 | + let is_case_cont | resolvedBCOIsCaseCont = intToInt8# 1#
|
|
91 | + | otherwise = intToInt8# 0#
|
|
90 | 92 | IO $ \s ->
|
91 | 93 | case unsafeFreezeArray# marr s of { (# s, arr #) ->
|
92 | - case newBCO insns_barr literals_barr arr arity# bitmap_barr of { IO io ->
|
|
93 | - io s
|
|
94 | - }}
|
|
94 | + newBCO2# is_case_cont insns_barr literals_barr arr arity# bitmap_barr s }
|
|
95 | 95 | |
96 | 96 | |
97 | 97 | -- we recursively link any sub-BCOs while making the ptrs array
|
... | ... | @@ -45,7 +45,8 @@ data ResolvedBCO |
45 | 45 | resolvedBCOBitmap :: BCOByteArray Word, -- ^ bitmap
|
46 | 46 | resolvedBCOLits :: BCOByteArray Word,
|
47 | 47 | -- ^ non-ptrs - subword sized entries still take up a full (host) word
|
48 | - resolvedBCOPtrs :: (SizedSeq ResolvedBCOPtr) -- ^ ptrs
|
|
48 | + resolvedBCOPtrs :: (SizedSeq ResolvedBCOPtr), -- ^ ptrs
|
|
49 | + resolvedBCOIsCaseCont :: !Bool -- ^ See Note [Case continuation BCOs]
|
|
49 | 50 | }
|
50 | 51 | deriving (Generic, Show)
|
51 | 52 | |
... | ... | @@ -86,7 +87,8 @@ instance Binary ResolvedBCO where |
86 | 87 | put resolvedBCOBitmap
|
87 | 88 | put resolvedBCOLits
|
88 | 89 | put resolvedBCOPtrs
|
89 | - get = ResolvedBCO <$> get <*> get <*> get <*> get <*> get <*> get
|
|
90 | + put resolvedBCOIsCaseCont
|
|
91 | + get = ResolvedBCO <$> get <*> get <*> get <*> get <*> get <*> get <*> get
|
|
90 | 92 | |
91 | 93 | -- See Note [BCOByteArray serialization]
|
92 | 94 | instance (Binary a, Storable a, IArray UArray a) => Binary (BCOByteArray a) where
|
... | ... | @@ -203,14 +203,14 @@ PUSH_L instruction. |
203 | 203 | |
204 | 204 | |---------|
|
205 | 205 | | BCO_1 | -<-┐
|
206 | -|---------|
|
|
206 | +|---------| |
|
|
207 | 207 | ......... |
|
208 | 208 | |---------| | PUSH_L <n>
|
209 | 209 | | BCO_N | ->-┘
|
210 | 210 | |---------|
|
211 | 211 | |
212 | 212 | Here BCO_N is syntactically nested within the code for BCO_1 and will result
|
213 | -in code that references the prior stack frame of BCO_1 for some of it's local
|
|
213 | +in code that references the prior stack frame of BCO_1 for some of its local
|
|
214 | 214 | variables. If a stack overflow happens between the creation of the stack frame
|
215 | 215 | for BCO_1 and BCO_N the RTS might move BCO_N to a new stack chunk while leaving
|
216 | 216 | BCO_1 in place, invalidating a simple offset based reference to the outer stack
|
... | ... | @@ -524,14 +524,35 @@ interpretBCO (Capability* cap) |
524 | 524 | //
|
525 | 525 | // We have a BCO application to perform. Stack looks like:
|
526 | 526 | //
|
527 | - // | .... |
|
|
528 | - // +---------------+
|
|
529 | - // | arg1 |
|
|
530 | - // +---------------+
|
|
531 | - // | BCO |
|
|
532 | - // +---------------+
|
|
533 | - // Sp | RET_BCO |
|
|
534 | - // +---------------+
|
|
527 | + //
|
|
528 | + // (an StgBCO)
|
|
529 | + // +---> +---------[1]--+
|
|
530 | + // | | stg_BCO_info | ------+
|
|
531 | + // | +--------------+ |
|
|
532 | + // | | StgArrBytes* | <--- the byte code
|
|
533 | + // | ... | | +--------------+ |
|
|
534 | + // +------------------+ | | ... | |
|
|
535 | + // | fvs1 | | |
|
|
536 | + // +------------------+ | |
|
|
537 | + // | ... | | (StgInfoTable) |
|
|
538 | + // +------------------+ | +----------+ <---+
|
|
539 | + // | args1 | | | ... |
|
|
540 | + // +------------------+ | +----------+
|
|
541 | + // | some StgBCO* | -----+ | type=BCO |
|
|
542 | + // +------------------+ +----------+
|
|
543 | + // Sp | stg_apply_interp | -----+ | ... |
|
|
544 | + // +------------------+ |
|
|
545 | + // |
|
|
546 | + // | (StgInfoTable)
|
|
547 | + // +----> +--------------+
|
|
548 | + // | ... |
|
|
549 | + // +--------------+
|
|
550 | + // | type=RET_BCO |
|
|
551 | + // +--------------+
|
|
552 | + // | ... |
|
|
553 | + //
|
|
554 | + // [1] An StgBCO's info table pointer may also be stg_CASE_CONT_BCO_info.
|
|
555 | + // See Note [Case continuation BCOs].
|
|
535 | 556 | //
|
536 | 557 | else if (SpW(0) == (W_)&stg_apply_interp_info) {
|
537 | 558 | obj = UNTAG_CLOSURE((StgClosure *)ReadSpW(1));
|
... | ... | @@ -1500,7 +1521,7 @@ run_BCO: |
1500 | 1521 | // Here we make sure references we push are tagged.
|
1501 | 1522 | // See Note [CBV Functions and the interpreter] in Info.hs
|
1502 | 1523 | |
1503 | - //Safe some memory reads if we already have a tag.
|
|
1524 | + //Save some memory reads if we already have a tag.
|
|
1504 | 1525 | if(GET_CLOSURE_TAG(tagged_obj) == 0) {
|
1505 | 1526 | StgClosure *obj = UNTAG_CLOSURE(tagged_obj);
|
1506 | 1527 | switch ( get_itbl(obj)->type ) {
|
... | ... | @@ -55,6 +55,7 @@ import CLOSURE stg_AP_STACK_info; |
55 | 55 | import CLOSURE stg_AP_info;
|
56 | 56 | import CLOSURE stg_ARR_WORDS_info;
|
57 | 57 | import CLOSURE stg_BCO_info;
|
58 | +import CLOSURE stg_CASE_CONT_BCO_info;
|
|
58 | 59 | import CLOSURE stg_C_FINALIZER_LIST_info;
|
59 | 60 | import CLOSURE stg_DEAD_WEAK_info;
|
60 | 61 | import CLOSURE stg_END_STM_WATCH_QUEUE_closure;
|
... | ... | @@ -2434,7 +2435,8 @@ stg_deRefStablePtrzh ( P_ sp ) |
2434 | 2435 | Bytecode object primitives
|
2435 | 2436 | ------------------------------------------------------------------------- */
|
2436 | 2437 | |
2437 | -stg_newBCOzh ( P_ instrs,
|
|
2438 | +stg_newBCO2zh ( CBool is_case_cont,
|
|
2439 | + P_ instrs,
|
|
2438 | 2440 | P_ literals,
|
2439 | 2441 | P_ ptrs,
|
2440 | 2442 | W_ arity,
|
... | ... | @@ -2449,7 +2451,16 @@ stg_newBCOzh ( P_ instrs, |
2449 | 2451 | |
2450 | 2452 | bco = Hp - bytes + WDS(1);
|
2451 | 2453 | // No memory barrier necessary as this is a new allocation.
|
2452 | - SET_HDR(bco, stg_BCO_info, CCS_MAIN);
|
|
2454 | + if (is_case_cont > 0) {
|
|
2455 | + /* Uses stg_CASE_CONT_BCO_info to construct the BCO frame (rather than stg_BCO_info).
|
|
2456 | + * Case continuations may contain non-local references to parent frames. The distinct info table
|
|
2457 | + * tag allows the RTS to identify such non-local frames.
|
|
2458 | + * See Note [Case continuation BCOs]
|
|
2459 | + */
|
|
2460 | + SET_HDR(bco, stg_CASE_CONT_BCO_info, CCS_MAIN);
|
|
2461 | + } else {
|
|
2462 | + SET_HDR(bco, stg_BCO_info, CCS_MAIN);
|
|
2463 | + }
|
|
2453 | 2464 | |
2454 | 2465 | StgBCO_instrs(bco) = instrs;
|
2455 | 2466 | StgBCO_literals(bco) = literals;
|
... | ... | @@ -690,6 +690,8 @@ printStackChunk( StgPtr sp, StgPtr spBottom ) |
690 | 690 | debugBelch("stg_ctoi_V_info" );
|
691 | 691 | } else if (c == (StgWord)&stg_BCO_info) {
|
692 | 692 | debugBelch("stg_BCO_info" );
|
693 | + } else if (c == (StgWord)&stg_CASE_CONT_BCO_info) {
|
|
694 | + debugBelch("stg_CASE_CONT_BCO_info" );
|
|
693 | 695 | } else if (c == (StgWord)&stg_apply_interp_info) {
|
694 | 696 | debugBelch("stg_apply_interp_info" );
|
695 | 697 | } else if (c == (StgWord)&stg_ret_t_info) {
|
... | ... | @@ -639,7 +639,7 @@ extern char **environ; |
639 | 639 | SymI_HasDataProto(stg_copySmallMutableArrayzh) \
|
640 | 640 | SymI_HasDataProto(stg_casSmallArrayzh) \
|
641 | 641 | SymI_HasDataProto(stg_copyArray_barrier) \
|
642 | - SymI_HasDataProto(stg_newBCOzh) \
|
|
642 | + SymI_HasDataProto(stg_newBCO2zh) \
|
|
643 | 643 | SymI_HasDataProto(stg_newByteArrayzh) \
|
644 | 644 | SymI_HasDataProto(stg_casIntArrayzh) \
|
645 | 645 | SymI_HasDataProto(stg_casInt8Arrayzh) \
|
... | ... | @@ -464,6 +464,12 @@ INFO_TABLE_RET( stg_dead_thread, RET_SMALL, |
464 | 464 | |
465 | 465 | /* ----------------------------------------------------------------------------
|
466 | 466 | Entry code for a BCO
|
467 | + |
|
468 | + `stg_BCO` and `stg_CASE_CONT_BCO` distinguish between a BCO that refers to
|
|
469 | + non-local variables in its code (using a stack offset) and those that do not.
|
|
470 | + Only case-continuation BCOs should use non-local variables.
|
|
471 | + Otherwise, `stg_BCO` and `stg_CASE_CONT_BCO` behave the same.
|
|
472 | + See Note [Case continuation BCOs].
|
|
467 | 473 | ------------------------------------------------------------------------- */
|
468 | 474 | |
469 | 475 | INFO_TABLE_FUN( stg_BCO, 3, 0, BCO, "BCO", "BCO", 0, ARG_BCO )
|
... | ... | @@ -478,6 +484,15 @@ INFO_TABLE_FUN( stg_BCO, 3, 0, BCO, "BCO", "BCO", 0, ARG_BCO ) |
478 | 484 | jump stg_yield_to_interpreter [];
|
479 | 485 | }
|
480 | 486 | |
487 | +INFO_TABLE_FUN( stg_CASE_CONT_BCO, 3, 0, BCO, "BCO", "BCO", 0, ARG_BCO )
|
|
488 | +{
|
|
489 | + /* Exactly as for stg_BCO */
|
|
490 | + Sp_adj(-2);
|
|
491 | + Sp(1) = R1;
|
|
492 | + Sp(0) = stg_apply_interp_info;
|
|
493 | + jump stg_yield_to_interpreter [];
|
|
494 | +}
|
|
495 | + |
|
481 | 496 | /* ----------------------------------------------------------------------------
|
482 | 497 | Info tables for indirections.
|
483 | 498 |
... | ... | @@ -180,6 +180,7 @@ RTS_ENTRY(stg_BLOCKING_QUEUE_CLEAN); |
180 | 180 | RTS_ENTRY(stg_BLOCKING_QUEUE_DIRTY);
|
181 | 181 | |
182 | 182 | RTS_FUN(stg_BCO);
|
183 | +RTS_FUN(stg_CASE_CONT_BCO);
|
|
183 | 184 | RTS_ENTRY(stg_EVACUATED);
|
184 | 185 | RTS_ENTRY(stg_WEAK);
|
185 | 186 | RTS_ENTRY(stg_DEAD_WEAK);
|
... | ... | @@ -577,7 +578,7 @@ RTS_FUN_DECL(stg_deRefWeakzh); |
577 | 578 | |
578 | 579 | RTS_FUN_DECL(stg_runRWzh);
|
579 | 580 | |
580 | -RTS_FUN_DECL(stg_newBCOzh);
|
|
581 | +RTS_FUN_DECL(stg_newBCO2zh);
|
|
581 | 582 | RTS_FUN_DECL(stg_mkApUpd0zh);
|
582 | 583 | |
583 | 584 | RTS_FUN_DECL(stg_retryzh);
|