Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • ghc/ghc
  • bgamari/ghc
  • syd/ghc
  • ggreif/ghc
  • watashi/ghc
  • RolandSenn/ghc
  • mpickering/ghc
  • DavidEichmann/ghc
  • carter/ghc
  • harpocrates/ghc
  • ethercrow/ghc
  • mijicd/ghc
  • adamse/ghc
  • alexbiehl/ghc
  • gridaphobe/ghc
  • trofi/ghc
  • supersven/ghc
  • ppk/ghc
  • ulysses4ever/ghc
  • AndreasK/ghc
  • ghuntley/ghc
  • shayne-fletcher-da/ghc
  • fgaz/ghc
  • yav/ghc
  • osa1/ghc
  • mbbx6spp/ghc
  • JulianLeviston/ghc
  • reactormonk/ghc
  • rae/ghc
  • takenobu-hs/ghc
  • michalt/ghc
  • andrewthad/ghc
  • hsyl20/ghc
  • scottgw/ghc
  • sjakobi/ghc
  • angerman/ghc
  • RyanGlScott/ghc
  • hvr/ghc
  • howtonotwin/ghc
  • chessai/ghc
  • m-renaud/ghc
  • brprice/ghc
  • stevehartdata/ghc
  • sighingnow/ghc
  • kgardas/ghc
  • ckoparkar/ghc
  • alp/ghc
  • smaeul/ghc
  • kakkun61/ghc
  • sykloid/ghc
  • newhoggy/ghc
  • toonn/ghc
  • nineonine/ghc
  • Phyx/ghc
  • ezyang/ghc
  • tweag/ghc
  • langston/ghc
  • ndmitchell/ghc
  • rockbmb/ghc
  • artempyanykh/ghc
  • mniip/ghc
  • mynguyenbmc/ghc
  • alexfmpe/ghc
  • crockeea/ghc
  • nh2/ghc
  • vaibhavsagar/ghc
  • phadej/ghc
  • Haskell-mouse/ghc
  • lolotp/ghc
  • spacekitteh/ghc
  • michaelpj/ghc
  • mgsloan/ghc
  • HPCohen/ghc
  • tmobile/ghc
  • radrow/ghc
  • simonmar/ghc
  • _deepfire/ghc
  • Ericson2314/ghc
  • leitao/ghc
  • fumieval/ghc
  • trac-isovector/ghc
  • cblp/ghc
  • xich/ghc
  • ciil/ghc
  • erthalion/ghc
  • xldenis/ghc
  • autotaker/ghc
  • haskell-wasm/ghc
  • kcsongor/ghc
  • agander/ghc
  • Baranowski/ghc
  • trac-dredozubov/ghc
  • 23Skidoo/ghc
  • iustin/ghc
  • ningning/ghc
  • josefs/ghc
  • kabuhr/ghc
  • gallais/ghc
  • dten/ghc
  • expipiplus1/ghc
  • Pluralia/ghc
  • rohanjr/ghc
  • intricate/ghc
  • kirelagin/ghc
  • Javran/ghc
  • DanielG/ghc
  • trac-mizunashi_mana/ghc
  • pparkkin/ghc
  • bollu/ghc
  • ntc2/ghc
  • jaspervdj/ghc
  • JoshMeredith/ghc
  • wz1000/ghc
  • zkourouma/ghc
  • code5hot/ghc
  • jdprice/ghc
  • tdammers/ghc
  • J-mie6/ghc
  • trac-lantti/ghc
  • ch1bo/ghc
  • cgohla/ghc
  • lucamolteni/ghc
  • acairncross/ghc
  • amerocu/ghc
  • chreekat/ghc
  • txsmith/ghc
  • trupill/ghc
  • typetetris/ghc
  • sergv/ghc
  • fryguybob/ghc
  • erikd/ghc
  • trac-roland/ghc
  • setupminimal/ghc
  • Friede80/ghc
  • SkyWriter/ghc
  • xplorld/ghc
  • abrar/ghc
  • obsidiansystems/ghc
  • Icelandjack/ghc
  • adinapoli/ghc
  • trac-matthewbauer/ghc
  • heatsink/ghc
  • dwijnand/ghc
  • Cmdv/ghc
  • alinab/ghc
  • pepeiborra/ghc
  • fommil/ghc
  • luochen1990/ghc
  • rlupton20/ghc
  • applePrincess/ghc
  • lehins/ghc
  • ronmrdechai/ghc
  • leeadam/ghc
  • harendra/ghc
  • mightymosquito1991/ghc
  • trac-gershomb/ghc
  • lucajulian/ghc
  • Rizary/ghc
  • VictorCMiraldo/ghc
  • jamesbrock/ghc
  • andrewdmeier/ghc
  • luke/ghc
  • pranaysashank/ghc
  • cocreature/ghc
  • hithroc/ghc
  • obreitwi/ghc
  • slrtbtfs/ghc
  • kaol/ghc
  • yairchu/ghc
  • Mathemagician98/ghc
  • trac-taylorfausak/ghc
  • leungbk/ghc
  • MichaWiedenmann/ghc
  • chris-martin/ghc
  • TDecki/ghc
  • adithyaov/ghc
  • trac-gelisam/ghc
  • Lysxia/ghc
  • complyue/ghc
  • bwignall/ghc
  • sternmull/ghc
  • sonika/ghc
  • leif/ghc
  • broadwaylamb/ghc
  • myszon/ghc
  • danbroooks/ghc
  • Mechachleopteryx/ghc
  • zardyh/ghc
  • trac-vdukhovni/ghc
  • OmarKhaledAbdo/ghc
  • arrowd/ghc
  • Bodigrim/ghc
  • matheus23/ghc
  • cardenaso11/ghc
  • trac-Athas/ghc
  • mb720/ghc
  • DylanZA/ghc
  • liff/ghc
  • typedrat/ghc
  • trac-claude/ghc
  • jbm/ghc
  • Gertjan423/ghc
  • PHO/ghc
  • JKTKops/ghc
  • kockahonza/ghc
  • msakai/ghc
  • Sir4ur0n/ghc
  • barambani/ghc
  • vishnu.c/ghc
  • dcoutts/ghc
  • trac-runeks/ghc
  • trac-MaxGabriel/ghc
  • lexi.lambda/ghc
  • strake/ghc
  • spavikevik/ghc
  • JakobBruenker/ghc
  • rmanne/ghc
  • gdziadkiewicz/ghc
  • ani/ghc
  • iliastsi/ghc
  • smunix/ghc
  • judah/ghc
  • blackgnezdo/ghc
  • emilypi/ghc
  • trac-bpfoley/ghc
  • muesli4/ghc
  • trac-gkaracha/ghc
  • Kleidukos/ghc
  • nek0/ghc
  • TristanCacqueray/ghc
  • dwulive/ghc
  • mbakke/ghc
  • arybczak/ghc
  • Yang123321/ghc
  • maksbotan/ghc
  • QuietMisdreavus/ghc
  • trac-olshanskydr/ghc
  • emekoi/ghc
  • samuela/ghc
  • josephcsible/ghc
  • dramforever/ghc
  • lpsmith/ghc
  • DenisFrezzato/ghc
  • michivi/ghc
  • jneira/ghc
  • jeffhappily/ghc
  • Ivan-Yudin/ghc
  • nakaji-dayo/ghc
  • gdevanla/ghc
  • galen/ghc
  • fendor/ghc
  • yaitskov/ghc
  • rcythr/ghc
  • awpr/ghc
  • jeremyschlatter/ghc
  • Aver1y/ghc
  • mitchellvitez/ghc
  • merijn/ghc
  • tomjaguarpaw1/ghc
  • trac-NoidedSuper/ghc
  • erewok/ghc
  • trac-junji.hashimoto/ghc
  • adamwespiser/ghc
  • bjaress/ghc
  • jhrcek/ghc
  • leonschoorl/ghc
  • lukasz-golebiewski/ghc
  • sheaf/ghc
  • last-g/ghc
  • carassius1014/ghc
  • eschwartz/ghc
  • dwincort/ghc
  • felixwiemuth/ghc
  • TimWSpence/ghc
  • marcusmonteirodesouza/ghc
  • WJWH/ghc
  • vtols/ghc
  • theobat/ghc
  • BinderDavid/ghc
  • ckoparkar0/ghc
  • alexander-kjeldaas/ghc
  • dme2/ghc
  • philderbeast/ghc
  • aaronallen8455/ghc
  • rayshih/ghc
  • benkard/ghc
  • mpardalos/ghc
  • saidelman/ghc
  • leiftw/ghc
  • ca333/ghc
  • bwroga/ghc
  • nmichael44/ghc
  • trac-crobbins/ghc
  • felixonmars/ghc
  • adityagupta1089/ghc
  • hgsipiere/ghc
  • treeowl/ghc
  • alexpeits/ghc
  • CraigFe/ghc
  • dnlkrgr/ghc
  • kerckhove_ts/ghc
  • cptwunderlich/ghc
  • eiais/ghc
  • hahohihu/ghc
  • sanchayan/ghc
  • lemmih/ghc
  • sehqlr/ghc
  • trac-dbeacham/ghc
  • luite/ghc
  • trac-f-a/ghc
  • vados/ghc
  • luntain/ghc
  • fatho/ghc
  • alexbiehl-gc/ghc
  • dcbdan/ghc
  • tvh/ghc
  • liam-ly/ghc
  • timbobbarnes/ghc
  • GovanifY/ghc
  • shanth2600/ghc
  • gliboc/ghc
  • duog/ghc
  • moxonsghost/ghc
  • zander/ghc
  • masaeedu/ghc
  • georgefst/ghc
  • guibou/ghc
  • nicuveo/ghc
  • mdebruijne/ghc
  • stjordanis/ghc
  • emiflake/ghc
  • wygulmage/ghc
  • frasertweedale/ghc
  • coot/ghc
  • aratamizuki/ghc
  • tsandstr/ghc
  • mrBliss/ghc
  • Anton-Latukha/ghc
  • tadfisher/ghc
  • vapourismo/ghc
  • Sorokin-Anton/ghc
  • basile-henry/ghc
  • trac-mightybyte/ghc
  • AbsoluteNikola/ghc
  • cobrien99/ghc
  • songzh/ghc
  • blamario/ghc
  • aj4ayushjain/ghc
  • trac-utdemir/ghc
  • tangcl/ghc
  • hdgarrood/ghc
  • maerwald/ghc
  • arjun/ghc
  • ratherforky/ghc
  • haskieLambda/ghc
  • EmilGedda/ghc
  • Bogicevic/ghc
  • eddiejessup/ghc
  • kozross/ghc
  • AlistairB/ghc
  • 3Rafal/ghc
  • christiaanb/ghc
  • trac-bit/ghc
  • matsumonkie/ghc
  • trac-parsonsmatt/ghc
  • chisui/ghc
  • jaro/ghc
  • trac-kmiyazato/ghc
  • davidsd/ghc
  • Tritlo/ghc
  • I-B-3/ghc
  • lykahb/ghc
  • AriFordsham/ghc
  • turion1/ghc
  • berberman/ghc
  • christiantakle/ghc
  • zyklotomic/ghc
  • trac-ocramz/ghc
  • CSEdd/ghc
  • doyougnu/ghc
  • mmhat/ghc
  • why-not-try-calmer/ghc
  • plutotulp/ghc
  • kjekac/ghc
  • Manvi07/ghc
  • teo/ghc
  • cactus/ghc
  • CarrieMY/ghc
  • abel/ghc
  • yihming/ghc
  • tsakki/ghc
  • jessicah/ghc
  • oliverbunting/ghc
  • meld/ghc
  • friedbrice/ghc
  • Joald/ghc
  • abarbu/ghc
  • DigitalBrains1/ghc
  • sterni/ghc
  • alexDarcy/ghc
  • hexchain/ghc
  • minimario/ghc
  • zliu41/ghc
  • tommd/ghc
  • jazcarate/ghc
  • peterbecich/ghc
  • alirezaghey/ghc
  • solomon/ghc
  • mikael.urankar/ghc
  • davjam/ghc
  • int-index/ghc
  • MorrowM/ghc
  • nrnrnr/ghc
  • Sonfamm/ghc-test-only
  • afzt1/ghc
  • nguyenhaibinh-tpc/ghc
  • trac-lierdakil/ghc
  • MichaWiedenmann1/ghc
  • jmorag/ghc
  • Ziharrk/ghc
  • trac-MitchellSalad/ghc
  • juampe/ghc
  • jwaldmann/ghc
  • snowleopard/ghc
  • juhp/ghc
  • normalcoder/ghc
  • ksqsf/ghc
  • trac-jberryman/ghc
  • roberth/ghc
  • 1ntEgr8/ghc
  • epworth/ghc
  • MrAdityaAlok/ghc
  • JunmingZhao42/ghc
  • jappeace/ghc
  • trac-Gabriel439/ghc
  • alt-romes/ghc
  • HugoPeters1024/ghc
  • 10ne1/ghc-fork
  • agentultra/ghc
  • Garfield1002/ghc
  • ChickenProp/ghc
  • clyring/ghc
  • MaxHearnden/ghc
  • jumper149/ghc
  • vem/ghc
  • ketzacoatl/ghc
  • Rosuavio/ghc
  • jackohughes/ghc
  • p4l1ly/ghc
  • konsumlamm/ghc
  • shlevy/ghc
  • torsten.schmits/ghc
  • andremarianiello/ghc
  • amesgen/ghc
  • googleson78/ghc
  • InfiniteVerma/ghc
  • uhbif19/ghc
  • yiyunliu/ghc
  • raehik/ghc
  • mrkun/ghc
  • telser/ghc
  • 1Jajen1/ghc
  • slotThe/ghc
  • WinstonHartnett/ghc
  • mpilgrem/ghc
  • dreamsmasher/ghc
  • schuelermine/ghc
  • trac-Viwor/ghc
  • undergroundquizscene/ghc
  • evertedsphere/ghc
  • coltenwebb/ghc
  • oberblastmeister/ghc
  • agrue/ghc
  • lf-/ghc
  • zacwood9/ghc
  • steshaw/ghc
  • high-cloud/ghc
  • SkamDart/ghc
  • PiDelport/ghc
  • maoif/ghc
  • RossPaterson/ghc
  • CharlesTaylor7/ghc
  • ribosomerocker/ghc
  • trac-ramirez7/ghc
  • daig/ghc
  • NicolasT/ghc
  • FinleyMcIlwaine/ghc
  • lawtonnichols/ghc
  • jmtd/ghc
  • ozkutuk/ghc
  • wildsebastian/ghc
  • nikshalark/ghc
  • lrzlin/ghc
  • tobias/ghc
  • fw/ghc
  • hawkinsw/ghc
  • type-dance/ghc
  • rui314/ghc
  • ocharles/ghc
  • wavewave/ghc
  • TheKK/ghc
  • nomeata/ghc
  • trac-csabahruska/ghc
  • jonathanjameswatson/ghc
  • L-as/ghc
  • Axman6/ghc
  • barracuda156/ghc
  • trac-jship/ghc
  • jake-87/ghc
  • meooow/ghc
  • rebeccat/ghc
  • hamana55/ghc
  • Enigmage/ghc
  • kokobd/ghc
  • agevelt/ghc
  • gshen42/ghc
  • chrismwendt/ghc
  • MangoIV/ghc
  • teto/ghc
  • Sookr1/ghc
  • trac-thomasjm/ghc
  • barci2/ghc-dev
  • trac-m4dc4p/ghc
  • dixonary/ghc
  • breakerzirconia/ghc
  • alexsio27444/ghc
  • glocq/ghc
  • sourabhxyz/ghc
  • ryantrinkle/ghc
  • Jade/ghc
  • scedfaliako/ghc
  • martijnbastiaan/ghc
  • trac-george.colpitts/ghc
  • ammarbinfaisal/ghc
  • mimi.vx/ghc
  • lortabac/ghc
  • trac-zyla/ghc
  • benbellick/ghc
  • aadaa-fgtaa/ghc
  • jvanbruegge/ghc
  • archbung/ghc
  • gilmi/ghc
  • mfonism/ghc
  • alex-mckenna/ghc
  • Ei30metry/ghc
  • DiegoDiverio/ghc
  • jorgecunhamendes/ghc
  • liesnikov/ghc
  • akrmn/ghc
  • trac-simplifierticks/ghc
  • jacco/ghc
  • rhendric/ghc
  • damhiya/ghc
  • ryndubei/ghc
  • DaveBarton/ghc
  • trac-Profpatsch/ghc
  • GZGavinZhao/ghc
  • ncfavier/ghc
  • jameshaydon/ghc
  • ajccosta/ghc
  • dschrempf/ghc
  • cydparser/ghc
  • LinuxUserGD/ghc
  • elodielander/ghc
  • facundominguez/ghc
  • psilospore/ghc
  • lachrimae/ghc
  • dylan-thinnes/ghc-type-errors-plugin
  • hamishmack/ghc
  • Leary/ghc
  • lzszt/ghc
  • lyokha/ghc
  • trac-glaubitz/ghc
  • Rewbert/ghc
  • andreabedini/ghc
  • Jasagredo/ghc
  • sol/ghc
  • OlegAlexander/ghc
  • trac-sthibaul/ghc
  • avdv/ghc
  • Wendaolee/ghc
  • ur4t/ghc
  • daylily/ghc
  • boltzmannrain/ghc
  • mmzk1526/ghc
  • trac-fizzixnerd/ghc
  • soulomoon/ghc
  • rwmjones/ghc
  • j14i/ghc
  • tracsis/ghc
  • gesh/ghc
  • flip101/ghc
  • eldritch-cookie/ghc
  • LemonjamesD/ghc
  • pgujjula/ghc
  • skeuchel/ghc
  • noteed/ghc
  • gulin.serge/ghc
  • Torrekie/ghc
  • jlwoodwa/ghc
  • ayanamists/ghc
  • husong998/ghc
  • trac-edmundnoble/ghc
  • josephf/ghc
  • contrun/ghc
  • baulig/ghc
  • edsko/ghc
  • mzschr/ghc-issue-24732
  • ulidtko/ghc
  • Arsen/ghc
  • trac-sjoerd_visscher/ghc
  • crumbtoo/ghc
  • L0neGamer/ghc
  • DrewFenwick/ghc
  • benz0li/ghc
  • MaciejWas/ghc
  • jordanrule/ghc
  • trac-qqwy/ghc
  • LiamGoodacre/ghc
  • isomorpheme/ghc
  • trac-danidiaz/ghc
  • Kariim/ghc
  • MTaimoorZaeem/ghc
  • hololeap/ghc
  • ticat-fp/ghc
  • meritamen/ghc
  • criskell/ghc
  • trac-kraai/ghc
  • aergus/ghc
  • jdral/ghc
  • SamB/ghc
  • Tristian/ghc
  • ywgrit/ghc
  • KatsuPatrick/ghc
  • OsePedro/ghc
  • mpscholten/ghc
  • fp/ghc
  • zaquest/ghc
  • fangyi-zhou/ghc
  • augyg/ghc
640 results
Show changes
Commits on Source (13)
  • Ben Gamari's avatar
    ghc-internal: Update CHANGELOG to reflect current version · 580fef7b
    Ben Gamari authored and Marge Bot's avatar Marge Bot committed
    580fef7b
  • Ben Gamari's avatar
    ghc-internal: Update prologue.txt to reflect package description · 391ecff5
    Ben Gamari authored and Marge Bot's avatar Marge Bot committed
    391ecff5
  • Ben Gamari's avatar
    compiler: Clarify comment regarding need for MOVABS · 3dca3b7d
    Ben Gamari authored and Marge Bot's avatar Marge Bot committed
    The comment wasn't clear in stating that it was only applicable to
    immediate source and memory target operands.
    3dca3b7d
  • Duncan Coutts's avatar
    Permit ARR_WORDS closures outside HEAP_ALLOCED space · a64609e5
    Duncan Coutts authored
    In the GC, evacuate() is prepared to deal with some heap objects that
    are not in the HEAP_ALLOCED() memory space. These are mainly the heap
    objects that GHC puts into the data sections of object files.
    
    It is also useful however to allow ByteArray# and MutableByteArray#
    heap objects to appear outside of the HEAP_ALLOCED() memory space. These
    have the ARR_WORDS closure type and contain no pointer should be easy to
    deal with. Indeed evacuate() already deals with closure types for
    constructors containing no pointers by doing nothing.
    
    So we just tack the ARR_WORDS case into this group of closure types that
    are permitted outside the HEAP_ALLOCED area but otherwise ignored.
    a64609e5
  • Duncan Coutts's avatar
    Add new primop placeByteArray# · 62c81cff
    Duncan Coutts authored
    It places a byte array heap object header at the given address, which
    must be outside the heap. It also sets the byte array size.
    62c81cff
  • Duncan Coutts's avatar
    Define HEAP_ALLOCED for CMM code · 6e4abd45
    Duncan Coutts authored
    Allow rts/sm/HeapAlloc.h to be #included by CMM code and have it provide
    a suitable implementation of HEAP_ALLOCED.
    
    The HEAP_ALLOCED system has three implementations, the large address
    space case, two fallbakc impls, one for 32bit and one for 64bit. The
    first two are simple enough that we can provide a HEAP_ALLOCED macro
    that can be used in a CMM expression context.
    
    The 64bit fallback case is rather more tricky. We provide a different
    interface to HEAP_ALLOCED for this case, which has to be called in a
    statement/"callish" style.
    6e4abd45
  • Duncan Coutts's avatar
    Fix isByteArrayPinned# for the !HEAP_ALLOCATED case · b63b99f4
    Duncan Coutts authored
    The isByteArrayPinned# primop works by looking up the block descriptor
    for the byte array to see if it lives in a pinned area or not. This of
    course cannot work for byte arrays that are not HEAP_ALLOCATED since
    they don't have block descriptors.
    
    The solution is to check if it is HEAP_ALLOCATED first. Since this is
    done in CMM code we make use of the new HEAP_ALLOCATED support for CMM.
    It is a bit awkward since it does not have a uniform interface.
    b63b99f4
  • Duncan Coutts's avatar
    Add test T17747 · 2f41a273
    Duncan Coutts authored
    Closes issue #17747
    
    Test that we can allocate ByteArray#s outside of the HEAP_ALLOCED()
    address space without upsetting the GC. To be extra sure we attach weak
    pointers with C finalizers to the ByteArray#s. We keep them alive and
    run a major GC so that the GC has to trace the live ByteArray#s.
    
    Prior to the first patch in this series, doing this would upset the GC
    because the GC does not expect heap objects with closure type ARR_WORDS
    to exist outside the GC heap.
    
    > internal error: evacuate(static): strange closure type 42
    
    Finally we allow everything to be GC'd again, and check that the C
    finalizers did run.
    
    This feature also required a change to the isByteArrayPinned# which
    itself required a CMM implementation of the HEAP_ALLOCED system. So we
    also add a check that the CMM and C implementations of HEAP_ALLOCED
    agree with each other.
    2f41a273
  • Duncan Coutts's avatar
    Update user guide for byte arrays outside of the heap · be931552
    Duncan Coutts authored
    Add a sub-subsection in the chapter on GHC extensions to the FFI, under
    the existing Memory Allocation subsection.
    
    Explain that it's permitted to have {Mutable}ByteArray# outside the heap
    and the tricky associated constraints. Mention the new primop
    placeByteArray#.
    be931552
  • Duncan Coutts's avatar
    5c4cd525
  • Duncan Coutts's avatar
    Add Note [Byte arrays outside of the HEAP_ALLOCED space] · fc03a9be
    Duncan Coutts authored
    And refer to it from the various places involved in the scheme.
    fc03a9be
  • Duncan Coutts's avatar
    c2c664aa
  • davide's avatar
    f5936ecb
Showing
with 474 additions and 20 deletions
...@@ -1852,6 +1852,70 @@ section "Byte Arrays" ...@@ -1852,6 +1852,70 @@ section "Byte Arrays"
------------------------------------------------------------------------ ------------------------------------------------------------------------
-- Note [Byte arrays outside of the HEAP_ALLOCED space]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
-- It is useful to be able to allocate byte arrays outside of the heap,
-- i.e. outside of the memory space covered by the HEAP_ALLOCED() test.
--
-- There are two major use cases (see issue #17747):
--
-- 1. Having foreign memory appear as a normal GHC byte array. This
-- are use cases similar to the use of a ForeignPtr, but where it
-- is useful to have the representation be a byte array type, for
-- easier interoperability with existing libraries.
--
-- 2. Static byte arrays in object files for constant values.
--
-- The second is not yet available as it requires additional support
-- from the code gen.
--
-- An example of the first category can be seen in GHC test T17747.
-- A concrete use-case is to memory map a file
-- but have it appear as a ByteArray# rather than a ForeignPtr. Doing
-- so of course requires that space is reserved immediately before the
-- file data for the byte array heap object header. See the
-- placeByteArray# primop documentation below and the FFI section of
-- the user guide for more details.
--
-- To have the first use-case work requires a few things:
--
-- * For the GC to not fail when it encounters byte arrays outside of
-- the HEAP_ALLOCED space. This is straightforward because the GC
-- has support for a number of different closure types to appear
-- outside the heap (primarily for statically allocated values), and
-- byte arrays are easy because they contain no heap pointers. See
-- the reference back to this note in `evacuate(StgClosure **p)` in
-- `rts/sm/Evac.c`
--
-- * For all other byte array primops (e.g. shrinkMutableByteArray#,
-- sameMutableByteArray#, isByteArrayPinned#, etc.) to not fail when
-- encountering byte arrays outside of the heap. Specifically
-- isByteArrayPinned# requires special support. This is currently the
-- only primop that needs special support.
-- See Note [isByteArrayPinned# support for off heap byte arrays].
--
-- * A mechanism to set up the heap object header for a byte array at
-- an address outside of the HEAP_ALLOCED space. This is needed to
-- make the foreign allocated memory look like a byte array. This is
-- provided by the placeByteArray# primop.
--
-- Note [isByteArrayPinned# support for off heap byte arrays]
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- The isByteArrayPinned# primop is implemented by reading block descriptor
-- flags. Since off heap byte arrays don't have block descriptors,
-- isByteArrayPinned# must explicitly check if the byte array is HEAP_ALLOCED
-- or not. If not HEAP_ALLOCED then it is certainly pinned. This requires CMM
-- support for the HEAP_ALLOCED test, which is otherwise only called from C
-- code in the RTS. The current design is to provide full CMM
-- implementations of HEAP_ALLOCED enabled in `rts/storage/HeapAlloc.h` with the
-- CMINUSMINUS cpp flag. This includes HEAP_ALLOCED_CALLISH which essentially
-- duplicates what is already a complex C implementation. This is fast
-- but an alternative would be to use a CMM C call to a C function that use
-- the existing C implementation of HEAP_ALLOCED.
primtype ByteArray# primtype ByteArray#
{ {
A boxed, unlifted datatype representing a region of raw memory in the garbage-collected heap, A boxed, unlifted datatype representing a region of raw memory in the garbage-collected heap,
...@@ -1902,6 +1966,20 @@ primop NewByteArrayOp_Char "newByteArray#" GenPrimOp ...@@ -1902,6 +1966,20 @@ primop NewByteArrayOp_Char "newByteArray#" GenPrimOp
with out_of_line = True with out_of_line = True
effect = ReadWriteEffect effect = ReadWriteEffect
-- See [Byte arrays outside of the HEAP_ALLOCED space]
primop PlaceByteArrayOp_Char "placeByteArray#" GenPrimOp
Addr# -> Int# -> State# s -> (# State# s, MutableByteArray# s #)
{Place a new byte array header at the specified address outside of the heap,
for the specified payload size (in bytes), in the specified state thread. In
C code with `#include "Rts.h"`, use `sizeOf(StgArrBytes)` or
`sizeOfW(StgArrBytes)` to get the size of a byte array header in bytes or
words respectively. The caller must ensure `sizeof(StgArrBytes) + n` bytes of
space is allocated at the give address for the heap object header followed by
n bytes of payload. See the FFI section of the user guide for more details
on how to use this primop.}
with out_of_line = True
effect = ReadWriteEffect
primop NewPinnedByteArrayOp_Char "newPinnedByteArray#" GenPrimOp primop NewPinnedByteArrayOp_Char "newPinnedByteArray#" GenPrimOp
Int# -> State# s -> (# State# s, MutableByteArray# s #) Int# -> State# s -> (# State# s, MutableByteArray# s #)
{Like 'newByteArray#' but GC guarantees not to move it.} {Like 'newByteArray#' but GC guarantees not to move it.}
......
...@@ -198,10 +198,13 @@ data Instr ...@@ -198,10 +198,13 @@ data Instr
-- Moves. -- Moves.
| MOV Format Operand Operand | MOV Format Operand Operand
-- ^ N.B. when used with the 'II64' 'Format', the source -- ^ N.B. Due to AT&T assembler quirks, when used with 'II64'
-- 'Format' immediate source and memory target operand, the source
-- operand is interpreted to be a 32-bit sign-extended value. -- operand is interpreted to be a 32-bit sign-extended value.
-- True 64-bit operands need to be moved with @MOVABS@, which we -- True 64-bit operands need to be either first moved to a register or moved
-- currently don't use. -- with @MOVABS@; we currently do not use this instruction in GHC.
-- See https://stackoverflow.com/questions/52434073/whats-the-difference-between-the-x86-64-att-instructions-movq-and-movabsq.
| MOVD Format Operand Operand -- ^ MOVD/MOVQ SSE2 instructions | MOVD Format Operand Operand -- ^ MOVD/MOVQ SSE2 instructions
-- (bitcast between a general purpose -- (bitcast between a general purpose
-- register and a float register). -- register and a float register).
......
...@@ -1665,6 +1665,7 @@ emitPrimOp cfg primop = ...@@ -1665,6 +1665,7 @@ emitPrimOp cfg primop =
CasArrayOp -> alwaysExternal CasArrayOp -> alwaysExternal
UnsafeThawSmallArrayOp -> alwaysExternal UnsafeThawSmallArrayOp -> alwaysExternal
CasSmallArrayOp -> alwaysExternal CasSmallArrayOp -> alwaysExternal
PlaceByteArrayOp_Char -> alwaysExternal
NewPinnedByteArrayOp_Char -> alwaysExternal NewPinnedByteArrayOp_Char -> alwaysExternal
NewAlignedPinnedByteArrayOp_Char -> alwaysExternal NewAlignedPinnedByteArrayOp_Char -> alwaysExternal
MutableByteArrayIsPinnedOp -> alwaysExternal MutableByteArrayIsPinnedOp -> alwaysExternal
......
...@@ -1198,6 +1198,10 @@ genPrim prof bound ty op = case op of ...@@ -1198,6 +1198,10 @@ genPrim prof bound ty op = case op of
VecReadScalarOffAddrOp _ _ _ -> unhandledPrimop op VecReadScalarOffAddrOp _ _ _ -> unhandledPrimop op
VecWriteScalarOffAddrOp _ _ _ -> unhandledPrimop op VecWriteScalarOffAddrOp _ _ _ -> unhandledPrimop op
-- This primop can be used to create a ByteArray# header outside the managed heap.
-- This operation is not supported in the Javascript backend.
PlaceByteArrayOp_Char -> unhandledPrimop op
PrefetchByteArrayOp3 -> noOp PrefetchByteArrayOp3 -> noOp
PrefetchMutableByteArrayOp3 -> noOp PrefetchMutableByteArrayOp3 -> noOp
PrefetchAddrOp3 -> noOp PrefetchAddrOp3 -> noOp
......
...@@ -811,6 +811,37 @@ the different kinds of allocation perform with GHC. ...@@ -811,6 +811,37 @@ the different kinds of allocation perform with GHC.
allocation than using one of the other forms of allocation. They are allocation than using one of the other forms of allocation. They are
backed by the RTS internal arena instead of ``malloc/free``. backed by the RTS internal arena instead of ``malloc/free``.
Foreign allocation of native byte arrays
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
GHC allows ``ByteArray#`` and ``MutableByteArray#`` to be allocated
outside of the GHC heap. This enables manually allocated data to be
represented as these native types. It is also possible to attach weak
pointers with finalisers to these byte array types. For example, in
principle it is possible to arrange for a memory mapped file to be
presented as a byte array, including a weak pointer finaliser to unmap
the file after it is no longer referenced. This can be useful because
these native types are used directly or indirectly by many libraries.
It does however require some care and attention.
The in-memory representation of ``ByteArray#`` and ``MutableByteArray#``
are exactly the same whether inside or outside the heap. In particular
they use a few prefix words for the object header and array size field.
Note that the object header size is different for normal and profiling
builds. When allocating in foreign memory, space must be made available
for this in the memory layout immediately before the data payload.
In C code, ``#include "Rts.h"`` and use ``sizeOf(StgArrBytes)`` or
``sizeOfW(StgArrBytes)`` to get the size of a byte array heap object
header in bytes or words respectively. This is the space that must be
reserved at the memory location immediately before the intended payload.
Then use the primop ``placeByteArray#`` to place the heap object header
at the intended location with the appropriate payload size in bytes.
To add a finaliser, use GHC's weak pointer support. If appropriate make
use of the ability to use C functions for finalisers.
.. _ffi-threads: .. _ffi-threads:
Multi-threading and the FFI Multi-threading and the FFI
......
# Revision history for `ghc-internal` # Revision history for `ghc-internal`
## 0.1.0.0 -- YYYY-mm-dd ## 9.1001.0 -- 2024-05-01
* First version. Released on an unsuspecting world. * Package created containing implementation moved from `base`.
This package contains the @Prelude@ and its support libraries, and a large This package contains the implementation of GHC's standard libraries and is
collection of useful libraries ranging from data structures to parsing not intended for use by end-users.
combinators and debugging utilities.
...@@ -9,3 +9,4 @@ ...@@ -9,3 +9,4 @@
#include "Capability.h" #include "Capability.h"
#include "WSDeque.h" #include "WSDeque.h"
#include "SMPClosureOps.h" #include "SMPClosureOps.h"
#include "rts/storage/HeapAlloc.h"
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "Cmm.h" #include "Cmm.h"
#include "MachDeps.h" #include "MachDeps.h"
#include "SMPClosureOps.h" #include "SMPClosureOps.h"
#include "rts/storage/HeapAlloc.h" /* for HEAP_ALLOCED() */
#if defined(__PIC__) #if defined(__PIC__)
import pthread_mutex_lock; import pthread_mutex_lock;
...@@ -133,9 +134,22 @@ stg_newByteArrayzh ( W_ n ) ...@@ -133,9 +134,22 @@ stg_newByteArrayzh ( W_ n )
return (p); return (p);
} }
stg_placeByteArrayzh ( W_ addr, W_ n )
// Addr# -> Int# -> MutableByteArray# {
{
/* Place an ARR_WORDS object header at the given address outside the heap.
The caller must arrange for space for the heap object header. */
gcptr p;
p = addr;
SET_HDR(p, stg_ARR_WORDS_info, CCCS);
StgArrBytes_bytes(p) = n;
return (p);
}
#define BA_ALIGN 16 #define BA_ALIGN 16
#define BA_MASK (BA_ALIGN-1) #define BA_MASK (BA_ALIGN-1)
// See Note [Byte arrays outside of the HEAP_ALLOCED space]
stg_newPinnedByteArrayzh ( W_ n ) stg_newPinnedByteArrayzh ( W_ n )
{ {
W_ words, bytes, payload_words; W_ words, bytes, payload_words;
...@@ -203,16 +217,29 @@ stg_isByteArrayPinnedzh ( gcptr ba ) ...@@ -203,16 +217,29 @@ stg_isByteArrayPinnedzh ( gcptr ba )
// ByteArray# s -> Int# // ByteArray# s -> Int#
{ {
W_ bd, flags; W_ bd, flags;
bd = Bdescr(ba);
// Pinned byte arrays live in blocks with the BF_PINNED flag set.
// We also consider BF_LARGE objects to be immovable. See #13894.
// See the comment in Storage.c:allocatePinned.
// We also consider BF_COMPACT objects to be immovable. See #14900.
flags = TO_W_(bdescr_flags(bd));
// We used to also consider BF_LARGE pinned, but stopped doing so // See Note [Byte arrays outside of the HEAP_ALLOCED space]
// because it interacted badly with compact regions. See #22255 #if defined(HEAP_ALLOCED)
return (flags & BF_PINNED != 0); if (HEAP_ALLOCED(ba)) {
#else
W_ result;
HEAP_ALLOCED_CALLISH(result, ba)
if (result == 1) {
#endif
// Safe to look up the block descriptor when the object is in the heap.
bd = Bdescr(ba);
// Pinned byte arrays live in blocks with the BF_PINNED flag set.
// See the comment in Storage.c:allocatePinned.
// We used to also considered BF_LARGE & BF_COMPACT pinned. See #13894 & 14900.
// We stopped doing so because it interacted badly with compact regions. See #22255.
flags = TO_W_(bdescr_flags(bd));
return (flags & BF_PINNED != 0);
} else {
// If it's not in the heap at all then we GC will not move it, so we
// can report to application code that it is pinned.
return (1);
}
} }
stg_isMutableByteArrayPinnedzh ( gcptr mba ) stg_isMutableByteArrayPinnedzh ( gcptr mba )
...@@ -2975,4 +3002,3 @@ stg_castFloatToWord32zh(F_ f) ...@@ -2975,4 +3002,3 @@ stg_castFloatToWord32zh(F_ f)
return (w); return (w);
} }
...@@ -637,6 +637,7 @@ extern char **environ; ...@@ -637,6 +637,7 @@ extern char **environ;
SymI_HasDataProto(stg_copyArray_barrier) \ SymI_HasDataProto(stg_copyArray_barrier) \
SymI_HasDataProto(stg_newBCOzh) \ SymI_HasDataProto(stg_newBCOzh) \
SymI_HasDataProto(stg_newByteArrayzh) \ SymI_HasDataProto(stg_newByteArrayzh) \
SymI_HasDataProto(stg_placeByteArrayzh) \
SymI_HasDataProto(stg_casIntArrayzh) \ SymI_HasDataProto(stg_casIntArrayzh) \
SymI_HasDataProto(stg_casInt8Arrayzh) \ SymI_HasDataProto(stg_casInt8Arrayzh) \
SymI_HasDataProto(stg_casInt16Arrayzh) \ SymI_HasDataProto(stg_casInt16Arrayzh) \
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#pragma once #pragma once
#if !defined(CMINUSMINUS)
#if defined(THREADED_RTS) #if defined(THREADED_RTS)
// needed for HEAP_ALLOCED below // needed for HEAP_ALLOCED below
extern SpinLock gc_alloc_block_sync; extern SpinLock gc_alloc_block_sync;
...@@ -16,6 +18,8 @@ extern SpinLock gc_alloc_block_sync; ...@@ -16,6 +18,8 @@ extern SpinLock gc_alloc_block_sync;
#define ACQUIRE_ALLOC_BLOCK_SPIN_LOCK() ACQUIRE_SPIN_LOCK(&gc_alloc_block_sync) #define ACQUIRE_ALLOC_BLOCK_SPIN_LOCK() ACQUIRE_SPIN_LOCK(&gc_alloc_block_sync)
#define RELEASE_ALLOC_BLOCK_SPIN_LOCK() RELEASE_SPIN_LOCK(&gc_alloc_block_sync) #define RELEASE_ALLOC_BLOCK_SPIN_LOCK() RELEASE_SPIN_LOCK(&gc_alloc_block_sync)
#endif // !defined(CMINUSMINUS)
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
The HEAP_ALLOCED() test. The HEAP_ALLOCED() test.
...@@ -56,17 +60,39 @@ extern SpinLock gc_alloc_block_sync; ...@@ -56,17 +60,39 @@ extern SpinLock gc_alloc_block_sync;
#if defined(USE_LARGE_ADDRESS_SPACE) #if defined(USE_LARGE_ADDRESS_SPACE)
#if !defined(CMINUSMINUS)
// If this struct is changed, the CMM macro below must be adjusted to match.
struct mblock_address_range { struct mblock_address_range {
W_ begin, end; W_ begin, end;
W_ padding[6]; // ensure nothing else inhabits this cache line W_ padding[6]; // ensure nothing else inhabits this cache line
} ATTRIBUTE_ALIGNED(64); } ATTRIBUTE_ALIGNED(64);
extern struct mblock_address_range mblock_address_space; extern struct mblock_address_range mblock_address_space;
// This implementation is duplicated to `Cmm` because performing an `ccall` is relatively high
// compared to the bounds check performed here. If this implementation changes the decisions should
// be reevaluated.
# define HEAP_ALLOCED(p) ((W_)(p) >= mblock_address_space.begin && \ # define HEAP_ALLOCED(p) ((W_)(p) >= mblock_address_space.begin && \
(W_)(p) < (mblock_address_space.end)) (W_)(p) < (mblock_address_space.end))
# define HEAP_ALLOCED_GC(p) HEAP_ALLOCED(p) # define HEAP_ALLOCED_GC(p) HEAP_ALLOCED(p)
#else /* defined(CMINUSMINUS) */
/* See Note [Byte arrays outside of the HEAP_ALLOCED space] */
import mblock_address_space;
// We explicitly duplicate the bound checking implementation of `HEAP_ALLOCED` for performance
// reasons. It doesn't make sense to perform a `ccall` for such a simple implementation.
# define HEAP_ALLOCED(p) ((p) >= W_[mblock_address_space + WDS(0)] && \
(p) < W_[mblock_address_space + WDS(1)])
#endif
#elif SIZEOF_VOID_P == 4 #elif SIZEOF_VOID_P == 4
#if !defined(CMINUSMINUS)
extern StgWord8 mblock_map[]; extern StgWord8 mblock_map[];
# define MBLOCK_MAP_SIZE (1 << (32 - MBLOCK_SHIFT)) # define MBLOCK_MAP_SIZE (1 << (32 - MBLOCK_SHIFT))
...@@ -74,6 +100,17 @@ extern StgWord8 mblock_map[]; ...@@ -74,6 +100,17 @@ extern StgWord8 mblock_map[];
# define HEAP_ALLOCED(p) mblock_map[MBLOCK_MAP_ENTRY(p)] # define HEAP_ALLOCED(p) mblock_map[MBLOCK_MAP_ENTRY(p)]
# define HEAP_ALLOCED_GC(p) HEAP_ALLOCED(p) # define HEAP_ALLOCED_GC(p) HEAP_ALLOCED(p)
#else /* defined(CMINUSMINUS) */
/* See Note [Byte arrays outside of the HEAP_ALLOCED space] */
import mblock_map;
# define MBLOCK_MAP_ENTRY(p) ((p) >> MBLOCK_SHIFT)
# define HEAP_ALLOCED(p) (TO_W_(I8[mblock_map + MBLOCK_MAP_ENTRY(p)]) != 0)
#endif
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
HEAP_ALLOCED for 64-bit machines (without LARGE_ADDRESS_SPACE). HEAP_ALLOCED for 64-bit machines (without LARGE_ADDRESS_SPACE).
...@@ -130,11 +167,13 @@ extern StgWord8 mblock_map[]; ...@@ -130,11 +167,13 @@ extern StgWord8 mblock_map[];
---------------------------------------------------------------------------- */ ---------------------------------------------------------------------------- */
#elif SIZEOF_VOID_P == 8 #elif SIZEOF_VOID_P == 8 /* && !defined(USE_LARGE_ADDRESS_SPACE) */
#define MBC_LINE_BITS 0 #define MBC_LINE_BITS 0
#define MBC_TAG_BITS 15 #define MBC_TAG_BITS 15
#if !defined(CMINUSMINUS)
#if defined(x86_64_HOST_ARCH) #if defined(x86_64_HOST_ARCH)
// 32bits are enough for 'entry' as modern amd64 boxes have // 32bits are enough for 'entry' as modern amd64 boxes have
// only 48bit sized virtual address. // only 48bit sized virtual address.
...@@ -168,7 +207,7 @@ extern W_ mpc_misses; ...@@ -168,7 +207,7 @@ extern W_ mpc_misses;
StgBool HEAP_ALLOCED_miss(StgWord mblock, const void *p); StgBool HEAP_ALLOCED_miss(StgWord mblock, const void *p);
INLINE_HEADER EXTERN_INLINE
StgBool HEAP_ALLOCED(const void *p) StgBool HEAP_ALLOCED(const void *p)
{ {
StgWord mblock; StgWord mblock;
...@@ -222,6 +261,21 @@ StgBool HEAP_ALLOCED_GC(const void *p) ...@@ -222,6 +261,21 @@ StgBool HEAP_ALLOCED_GC(const void *p)
} }
} }
#else /* defined(CMINUSMINUS) */
/* See Note [Byte arrays outside of the HEAP_ALLOCED space] */
// This is a call to HEAP_ALLOCED C function defined above. That function is reified via the
// Inlines.c file. Since the implementation that can't use USE_LARGE_ADDRESS_SPACE is big and
// complicated we prevent duplicating it's logic. We define the interface to be used in a statement
// "callish op" style.
#define HEAP_ALLOCED_CALLISH(result, p) \
CInt r; \
(r) = ccall HEAP_ALLOCED(p "ptr"); \
result = TO_W_(r); \
#endif
#else #else
# error HEAP_ALLOCED not defined # error HEAP_ALLOCED not defined
#endif #endif
...@@ -450,6 +450,7 @@ RTS_FUN_DECL(stg_decodeDoublezuInt64zh); ...@@ -450,6 +450,7 @@ RTS_FUN_DECL(stg_decodeDoublezuInt64zh);
RTS_FUN_DECL(stg_unsafeThawArrayzh); RTS_FUN_DECL(stg_unsafeThawArrayzh);
RTS_FUN_DECL(stg_casArrayzh); RTS_FUN_DECL(stg_casArrayzh);
RTS_FUN_DECL(stg_newByteArrayzh); RTS_FUN_DECL(stg_newByteArrayzh);
RTS_FUN_DECL(stg_placeByteArrayzh);
RTS_FUN_DECL(stg_newPinnedByteArrayzh); RTS_FUN_DECL(stg_newPinnedByteArrayzh);
RTS_FUN_DECL(stg_newAlignedPinnedByteArrayzh); RTS_FUN_DECL(stg_newAlignedPinnedByteArrayzh);
RTS_FUN_DECL(stg_isByteArrayPinnedzh); RTS_FUN_DECL(stg_isByteArrayPinnedzh);
......
...@@ -741,6 +741,8 @@ loop: ...@@ -741,6 +741,8 @@ loop:
case CONSTR_0_1: case CONSTR_0_1:
case CONSTR_0_2: case CONSTR_0_2:
case CONSTR_NOCAF: case CONSTR_NOCAF:
/* See Note [Byte arrays outside of the HEAP_ALLOCED space] */
case ARR_WORDS:
/* no need to put these on the static linked list, they don't need /* no need to put these on the static linked list, they don't need
* to be scavenged. * to be scavenged.
*/ */
......
...@@ -126,6 +126,12 @@ EventlogOutput2: ...@@ -126,6 +126,12 @@ EventlogOutput2:
./EventlogOutput +RTS -l ./EventlogOutput +RTS -l
ls EventlogOutput.eventlog >/dev/null ls EventlogOutput.eventlog >/dev/null
.PHONY: T17747
T17747:
$(RM) T17747_c.o T17747.o T17747.hi
'$(TEST_HC)' $(TEST_HC_OPTS) -v0 --make T17747 T17747_c.c T17747_cmm.cmm -I$(TOP)/../rts
./T17747
.PHONY: EventlogOutputNull .PHONY: EventlogOutputNull
EventlogOutputNull: EventlogOutputNull:
"$(TEST_HC)" -rtsopts -v0 EventlogOutput.hs "$(TEST_HC)" -rtsopts -v0 EventlogOutput.hs
......
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UnliftedFFITypes #-}
{-# LANGUAGE GHCForeignImportPrim #-}
module Main (main) where
import Foreign.C
import Foreign.Ptr
import Foreign.Storable
import System.Mem (performMajorGC)
import GHC.Exts
import GHC.Base (IO(IO))
-- | Test that we can allocate 'ByteArray#'s outside of the @HEAP_ALLOCED()@ address space without
-- upsetting the GC. To be extra sure we attach weak pointers with C finalizers to the
-- 'ByteArray#'s. We keep them alive and run a major GC so that the GC has to trace the live
-- 'ByteArray#'s.
--
-- On older GHC versions this upsets the GC because it does not expect heap objects with closure
-- type @ARR_WORDS@ to exist outside the heap.
--
-- > internal error: evacuate(static): strange closure type 42
--
-- Finally we free the backing memory with `unsafeFreeByteArray`. Then we rerun the GC'd again.
-- Note: When connecting finalizers they seem to fire on shutdown of the RTS not on a major GC
-- invocation.
--
main :: IO ()
main = do
heapallocedTest
bytearrayTest
-- | This checks that the CMM impl of HEAP_ALLOCED matches the behaviour of
-- the C version. This test lives here since the CMM HEAP_ALLOCED is used by
-- the isByteArrayPinned# primop now that it supports byte arrays that are
-- not themselves HEAP_ALLOCED.
--
heapallocedTest :: IO ()
heapallocedTest = do
let same = and [ c_HEAP_ALLOCED ptr == cmm_HEAP_ALLOCED ptr
| addr <- addrs
, let ptr = plusPtr nullPtr addr ]
putStrLn ("HEAP_ALLOCED = " ++ show same
++ "\t(c_HEAP_ALLOCED ptr == cmm_HEAP_ALLOCED ptr)")
where
-- For values selected here see OSMem.c
heapLowerbound = 8 * (2^30) -- 8GB lower bound starting index of the heap
heapDefaultStart = 0x4200000000 -- > 32GB default starting address of the heap
heapSizes = [0 -- Check the heap lower starting bound
, 2^40, 2^38] -- Check the heap upper bounds at both 1TB and 1/4TB of virtual memory
addrs
-- Addresses around the start of the heap
= [heapStart + heapSize + offset
| heapStart <- [heapLowerbound, heapDefaultStart]
, heapSize <- heapSizes
, offset <- [-1000..1000]] -- Area of the bounds check
-- 2k address probes, appropriate to the address space
++ case sizeOf (nullPtr :: Ptr ()) of
4 -> [0, 2^21 .. 2^32-1] -- 0 to 4Gb-1 in 2Mb jumps
8 -> [0, 2^30 .. 2^41-1] -- 0 to 2Tb-1 in 1Gb jumps
_ -> error "sizeOf ptr not 4 or 8"
bytearrayTest :: IO ()
bytearrayTest = do
printMallocCount "initial"
let byteLengths = [0..99]
-- malloc() a bunch of ByteArray#s on the C heap
(foreignPtrs, foreignBAs) <- unzip <$> mapM newForeignHeapByteArray byteLengths
printMallocCount "alloced"
-- allocate a bunch of ByteArray#s on the GHC heap
nativeBAs <- mapM newNativeHeapByteArray byteLengths
-- as a sanity check compare them to each other
let same = and (zipWith equalByteArrays foreignBAs nativeBAs)
putStrLn ("arrays equal = " ++ show same
++ "\t(and (zipWith equalByteArrays foreignBAs nativeBAs))")
-- and test the isByteArrayPinned# primop on them foreign byte arrays
let pinnedForeign = all isByteArrayPinned foreignBAs
putStrLn ("arrays pinned = " ++ show pinnedForeign
++ "\t(all isByteArrayPinned foreignBAs)")
-- and test the isByteArrayPinned# primop on them native byte arrays
let pinnedNative = all isByteArrayPinned nativeBAs
putStrLn ("arrays pinned = " ++ show pinnedNative
++ "\t(all isByteArrayPinned nativeBAs)")
-- while they're still live, have the GC inspect them all
performMajorGC
printMallocCount "alive"
mapM_ touchByteArray foreignBAs
-- after they have been freed, have another GC run
mapM_ unsafeFreeByteArray foreignPtrs
-- WARNING: DO NOT USE `foreignPtrs` OR `foreignBAs` AFTER THIS POINT
-- We have released the memory backing the byte arrays
performMajorGC
printMallocCount "final"
printMallocCount :: String -> IO ()
printMallocCount phase = do
n <- getMallocByteArrayCount
putStrLn ("malloc_count = " ++ show n ++ "\t" ++ phase)
data ByteArray = ByteArray ByteArray#
data MutableByteArray = MutableByteArray (MutableByteArray# RealWorld)
newNativeHeapByteArray :: Int -> IO ByteArray
newNativeHeapByteArray n = do
mba <- newByteArray n
fillAndFreezeByteArray mba n
newForeignHeapByteArray :: Int -> IO (Ptr a, ByteArray)
newForeignHeapByteArray n = do
-- mallocByteArray also allocates memory for the header of a ByteArray#
ptr <- mallocByteArray (fromIntegral n)
-- placeByteArray# writes the ByteArray# header in this additionally allocated memory
mba <- placeByteArray ptr n
ba <- fillAndFreezeByteArray mba n
pure (ptr, ba)
newByteArray :: Int -> IO MutableByteArray
newByteArray (I# n#) =
IO $ \s0 ->
case newByteArray# n# s0 of
(# s1, mba# #) -> (# s1, MutableByteArray mba# #)
placeByteArray :: Ptr a -> Int -> IO MutableByteArray
placeByteArray (Ptr addr#) (I# n#) =
IO $ \s0 ->
case placeByteArray# addr# n# s0 of
(# s1, mba# #) -> (# s1, MutableByteArray mba# #)
fillAndFreezeByteArray :: MutableByteArray -> Int -> IO ByteArray
fillAndFreezeByteArray (MutableByteArray mba#) (I# n#) =
IO $ \s0 ->
case setByteArray# mba# 0# n# n# s0 of
s1 ->
case unsafeFreezeByteArray# mba# s1 of
(# s2, ba# #) -> (# s2, ByteArray ba# #)
touchByteArray :: ByteArray -> IO ()
touchByteArray (ByteArray ba#) =
IO $ \s0 ->
case touch# ba# s0 of
s1 -> (# s1, () #)
equalByteArrays :: ByteArray -> ByteArray -> Bool
equalByteArrays (ByteArray ba1#) (ByteArray ba2#)
| let ba1len = I# (sizeofByteArray# ba1#)
ba2len = I# (sizeofByteArray# ba2#)
I# balen# = ba1len
, ba1len == ba2len
= isTrue# (0# ==# compareByteArrays# ba1# 0# ba2# 0# balen#)
isByteArrayPinned :: ByteArray -> Bool
isByteArrayPinned (ByteArray ba#) = isTrue# (isByteArrayPinned# ba#)
cmm_HEAP_ALLOCED :: Ptr a -> Int
cmm_HEAP_ALLOCED (Ptr addr#) = I# (cmm_HEAP_ALLOCED# addr#)
foreign import ccall unsafe "mallocByteArray"
mallocByteArray :: CInt -> IO (Ptr a)
foreign import ccall unsafe "unsafeFreeByteArray"
unsafeFreeByteArray :: Ptr a -> IO ()
foreign import ccall unsafe "getMallocByteArrayCount"
getMallocByteArrayCount :: IO CInt
foreign import ccall unsafe "c_HEAP_ALLOCED"
c_HEAP_ALLOCED :: Ptr a -> Int
foreign import prim "cmm_HEAP_ALLOCED"
cmm_HEAP_ALLOCED# :: Addr# -> Int#
HEAP_ALLOCED = True (c_HEAP_ALLOCED ptr == cmm_HEAP_ALLOCED ptr)
malloc_count = 0 initial
malloc_count = 100 alloced
arrays equal = True (and (zipWith equalByteArrays foreignBAs nativeBAs))
arrays pinned = True (all isByteArrayPinned foreignBAs)
arrays pinned = False (all isByteArrayPinned nativeBAs)
malloc_count = 100 alive
malloc_count = 0 final
#include "Rts.h"
#include "rts/storage/HeapAlloc.h"
int malloc_count = 0;
void *mallocByteArray (StgWord len)
{
malloc_count++;
/* allocate enough space for the object header + length */
return malloc(sizeof(StgArrBytes) + len);
}
void unsafeFreeByteArray (void *arr)
{
free(arr);
malloc_count--;
}
int getMallocByteArrayCount(void)
{
return malloc_count;
}
int c_HEAP_ALLOCED(void * p)
{
return HEAP_ALLOCED(p);
}
#include "Cmm.h"
#include "rts/storage/HeapAlloc.h" /* for HEAP_ALLOCED() */
cmm_HEAP_ALLOCED ( W_ p )
// Addr# -> Int#
{
#if defined(HEAP_ALLOCED)
if (HEAP_ALLOCED(p)) {
#else
W_ result;
HEAP_ALLOCED_CALLISH(result, p)
if (result == 1) {
#endif
return (1);
} else {
return (0);
}
}
...@@ -523,6 +523,15 @@ test('T17088', ...@@ -523,6 +523,15 @@ test('T17088',
compile_and_run, ['-rtsopts -O2']) compile_and_run, ['-rtsopts -O2'])
test('T15427', js_broken(22374), compile_and_run, ['']) test('T15427', js_broken(22374), compile_and_run, [''])
test('T17747',
[# This test tries to allocate virtual memory outside of the managed heap.
# The required primops are not available on the following platforms:
when(arch('javascript'), expect_fail),
when(arch('wasm32'), expect_fail),
# This test uses Posix specific memory mapping, which isn't available on windows.
when(opsys('mingw32'), expect_fail)],
makefile_test,
['T17747'])
test('T19481', test('T19481',
[extra_run_opts('+RTS -T -RTS'), [extra_run_opts('+RTS -T -RTS'),
......