Biweekly update from the GHC DevX team at IOG.
Previous updates can be found here.
JavaScript backendโ
Template Haskellโ
Luite: fixed the support for one-shot mode (GHC's -c
command-line flag)
in the TH JS linker.
Luite: Investigated a warning about the temporary directory not being removed
after running Template Haskell with the JavaScript backend. It turned out
that GHC's GHC.Utils.TmpFs.newTempDir
, which is used by the Template Haskell
linker, does not allow the newly created directory to be removed
(see #22952).
Sylvain: cleaned up the merge request, removing unnecessary changes and adding documentation.
JavaScript backend CIโ
Jeff: JavaScript backend CI was finally merged! Now that we have CI we are unblocked on several fronts, such as, implementing faster arithmetic and fixing some async exceptions. In general, we can now have confidence that our work is progressing the JavaScript backend to a better state.
Sylvain: fixed a spurious failure on JS CI due to some test passing on fast runners while it was expected to fail (see !9934).
Josh: fixed some inaccurate test predicates !9939
FileStatโ
Josh: rebased and merged !9755.
This patch changes the representation of the JavaScript equivalent of the C struct stat
to make its field offsets match the C ones: some Haskell codes directly access fields of
this structure using hsc2hs
to get the field offsets from the C headers.
This patch also adds fields to the JavaScript file stat that were previously not included, such as modification and access times.
JavaScript RTS refactorโ
Josh: rebased !9794 which consists in the refactor of the module generating some part of the RTS. The new JS CI job found a bug in the patch that caused ~50 tests to time out, so waiting for CI to be set up before merging this MR was judicious.
This MR also became an opportunity to revisit some arbitrary cache sizes in the RTS code generator. This is still ongoing work.
Warningsโ
Luite: We accidently removed the check for the "javascript" calling convention on foreign imports, allowing this convention to be wrongly used on native platform. Fixed in !9880.
Fix for asynchronous exceptionsโ
Luite: Fixed an issue in the garbage collector for the JavaScript backend:
A thread that posts an asynchronous exception (throwTo
) to another thread
is temporarily suspended until the exception has been delivered. The
garbage collector did not correctly follow the list of threads suspended in
this way, potentially considering them unreachable and cleaning up data
referenced by them. See #22836 and
!9879.
Integer performanceโ
Evaluating the following expression is very slow in general but especially with the JS backend:
1 `shiftL` (1 `shiftL` 20) :: Integer
We've had to mark a test computing this as broken on CI because it triggers a
timeout error. Luckily the identification of slow operations is easy with
JavaScript profiling tools (see graphs in
https://gitlab.haskell.org/ghc/ghc/-/issues/22835) and we know that Word32
primops are the culprit in this case.
Sylvain started replacing the uses of JavaScript's BigInt
in the
implementation of these primops with usual JavaScript numbers
.
See !9825.
JavaScript EDSLโ
Jeff: JavaScript eDSL based on
sunroof close to MR, see
#22736 for background.
Compiler is complete. Major items left are: the interpreter to translate to
JStat
, filling in documentation, and testing now that CI has been merged.
Documentationโ
Jeff: Wrote the JavaScript backend release notes. Notes pending approval. We cite the JavaScript backend wiki page in the release notes. So Jeff and Sylvain heavily edited the wiki pages to make them suitable for external customers.
Change from js
to javascript
architectureโ
In #22740 it was noticed that
hackage-server
would prevent the upload of the upcoming base
package bundled with GHC 9.6.
The reason is that hackage-server
relies on the cabal --check
feature which filters
out perfectly valid packages (it happened before, for example with ghc-api-compat).
In our case, the package was rejected because the js
architecture wasn't recognized
as a built-in one, but luckily we could fall back to the existing javascript
built-in
architecture defined for GHCJS (if it wasn't a JS backend, we would have had to fix Cabal,
update hackage-server
dependencies, and redeploy hackage-server
...).
Sylvain completed Ben's MR in !9814.
For early users of the JS backend the change means that from now on:
configure
command is:emconfigure ./configure --target=javascript-unknown-ghcjs
- Cabal condition is:
arch(javascript)
- CPP condition is:
#if defined(javascript_HOST_ARCH)
Compiler performanceโ
More-strict break
โ
Josh: opened merge request !9868 to add a stricter break'
version to base
- however, this would require a CLC proposal.
Further analysis was done using ticky profiles on a simple test program that benchmarks GHC's startup code. This has found an example where a more-strict break is an improvement in GHC, which will provide motivation for the CLC proposal.
Unboxed CodeBuffersโ
Josh: implemented changes to GHC's text encoding buffers to use unboxed tuples on handle encoders/decoders.
The buffers pass around and repeatedly pack/unpack a tuple in an IO
inner loop, which causes a significant
number of unnecessary allocations. By replacing this with an unboxed tuple, and replacing the IO
with
manually passing around a State# RealWorld
in the same tuple, we're able to reduce allocations by nearly 50%
in a pathological example (non-allocating loop printing characters). See #22946 and !9948.
Optimization Handbookโ
Jeff: opened IT ticket to move the Optimization Handbook to Haskell Foundation's repository. IT stated they need to check with legal, of course.
Jeff: almost finished the lambda lifting chapter; major remaining items are adding some glossary terms and describing the interaction between lambda lifting and calling conventions.
Constant folding for division operationsโ
While looking into his old merge requests still opened, Sylvain nerd-snipped himself into fixing constant folding rules for division operations (see #22152).
MR !8956 adds the following rewrite rules:
case quotRemInt# x y of
(# q, _ #) -> body
====>
case quotInt# x y of
q -> body
case quotRemInt# x y of
(# _, r #) -> body
====>
case remInt# x y of
r -> body
For all primitive numerical types:
(x `quot` l1) `quot` l2
| l1 /= 0
| l2 /= 0
| l1*l2 doesn't overflow/underflow
====>
x `quot` (l1 * l2)
It also makes some division primops (Word64/Int64 Quot/Rem, WordQuotRem2Op) ok-for-speculation when the divisor is known to be non-zero, similarly to other division primops. Otherwise the last rule wasn't firing in the added test because we got the following Core (simplified for the presentation):
case quotWord64# x# 10#Word64 of
ds1 -> case quotWord64# ds1 20#Word64 of
ds2 -> ...
and not:
case quotWord64# (quotWord64# x# 10#Word64) 20#Word64 of
ds2 -> ...
GHCiโ
Luite: A test run of GHC 9.6 with the -fbyte-code-and-object-code
flag
on head.hackage revealed
issue #22888 with bytecode
size limits. Many bytecode instructions have Word16
operands, which
is not always enough to run programs generated from optimized core. The solution
is to enable large operands for all the bytecode instructions that deal with
stack offsets. See #22888
and !9957.