[GHC] #12972: Missed specialisation opportunity with phantom type class parameter?
GHC
ghc-devs at haskell.org
Wed Dec 14 21:35:19 UTC 2016
#12972: Missed specialisation opportunity with phantom type class parameter?
-------------------------------------+-------------------------------------
Reporter: mpickering | Owner:
Type: bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 8.0.1
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: None/Unknown | Test Case:
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by danharaj):
We discovered this while analyzing a moderately large production system
based on `reflex` and `reflex-dom` compiled with ghcjs. Web applications
that use this framework rely heavily on specialization in order to be
performant when run in a browser. One feature of `reflex-dom` is a
javascript FFI facility built to allow uniform interaction with either
ghcjs's low-level JS FFI or a native JS engine (such as WebKit) when built
with ghc. This type class is the user interface for this feature:
{{{#!hs
class (Monad m, MonadIO (JSM m), MonadFix (JSM m), MonadJS x (JSM m)) =>
HasJS x m | m -> x where
type JSM m :: * -> *
liftJS :: JSM m a -> m a
}}}
The `x` parameter is important. There are situations where a program will
manage multiple Javascript execution contexts. In general, references
cannot be shared between execution contexts. So this is a slightly more
elaborate version of the phantom type parameter used by the `ST` monad.
The `x` parameter is used by the implementation of the FFI to tag various
JS datastructures so that they cannot be intermixed: It guarantees this
aspect of semantic correctness.
Unfortunately, using this FFI via `HasJS` prevents automatic
specialization because even though the dictionary for `HasJS` need not
depend on `x` in an essential way, GHC seems unable to automatically
create a specialized version of a polymorphic declaration that is
constrained by `HasJS` and marked `INLINABLE`. I believe this is because,
according to the documentation in the `Specialise` module, the invariant
of the specialiser for generated specialisations is that "no specialised
version is overloaded" and GHC cannot deduce that the overloading caused
by `x` is benign.
The workaround was to create an escape hatch that allowed the user to
specify a concrete dummy type for `x` at the top-level, namely `()`. This
allowed GHC to specialize all of their code which led to significant
performance gains. This isn't the best situation: a user had to abandon
type discipline ensuring semantic correctness in order to avoid
unacceptable performance overhead.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/12972#comment:1>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list