Skip to content

JavaScript backend: GHC.StgToJS.Rts.Rts module requires refactoring improvements

There are several places in the JavaScript backend's GHC.StgToJS.Rts.Rts module, responsible for generating JavaScript RTS functions, where code is repeated unnecessarily.

In some of these cases, there is a potential performance deficit in the form of FastStrings being formed several times from Strings, which are themselves repeated several times. Because these FastStrings are used in generating argument names for generated JavaScript ASTs, to be used in functions with increasing lengths, the argument names are repeated often. So we might have function f1(x1) {...}, function f2(x1, x2) {...}, ..., function f24(x1, x2, ..., x24) {...}.

An example of this is the variables generated by mkClosureCon. Variables up to x24 are used by h$cN, meaning x3 is generated 22 times, x4 21 times, and so on:

mkClosureCon :: Int -> JStat
mkClosureCon n = funName ||= toJExpr fun
  where
    funName = TxtI $ mkFastString ("h$c" ++ show n)
    -- args are: f x1 x2 .. xn [cc]
    args   = TxtI "f" : addCCArg' (map (TxtI . mkFastString . ('x':) . show) [(1::Int)..n])

In other cases, the code repetition is the result of unnecessary special cases for the "base cases" of recursively generated functions. These cases can simply be generalised.

An example of this is the 0, 1, and 2-length cases of mkClosureCon:

closureConstructors :: StgToJSConfig -> JStat
closureConstructors s = BlockStat
  [ declClsConstr "h$c" ["f"] $ Closure
      { clEntry  = var "f"
      , clField1 = null_
      , clField2 = null_
      , clMeta   = 0
      , clCC     = ccVal
      }
  , declClsConstr "h$c0" ["f"] $ Closure
      { clEntry  = var "f"
      , clField1 = null_
      , clField2 = null_
      , clMeta   = 0
      , clCC     = ccVal
      }
  , declClsConstr "h$c1" ["f", "x1"] $ Closure
      { clEntry  = var "f"
      , clField1 = var "x1"
      , clField2 = null_
      , clMeta   = 0
      , clCC     = ccVal
      }
  , declClsConstr "h$c2" ["f", "x1", "x2"] $ Closure
      { clEntry  = var "f"
      , clField1 = var "x1"
      , clField2 = var "x2"
      , clMeta   = 0
      , clCC     = ccVal
      }
  , mconcat (map mkClosureCon [3..24])
  , mconcat (map mkDataFill [1..24])
  ]
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information