Skip to content

JS: specialize unpackCString# CAFs

Summary

We should generate better JS code for unpackCString# "xyz"#.

Steps to reproduce

Consider the following example:

module Main where

xyz :: String
xyz = "xyz"

main = putStrLn xyz   

We generate:

// "xyz"#: offset 0 + array of bytes
var h$mainZCMainzixyzz1_2 = 0;
var h$mainZCMainzixyzz1_1 = h$rawStringData([120, 121, 122]);

// CAF object
var h$mainZCMainzixyzz = h$d();
h$stc(h$mainZCMainzixyzz, h$mainZCMainzixyzz_e, [h$ghczmprimZCGHCziCStringziunpackCStringzh]);

// Fun infotable + entry code
h$o(h$mainZCMainzixyzz_e, 0, 0, 1, 256, null);

function h$mainZCMainzixyzz_e() {
  var a = h$r1.d1;
  h$bh();
  h$r3 = h$mainZCMainzixyzz1_2;
  h$r2 = h$mainZCMainzixyzz1_1;
  h$r1 = a;
  return h$ap_1_2_fast();
};

Ideally we would have much more code sharing as the entry code is always almost the same.

For example, the CAF could capture the Addr# like this:

h$stc(h$mainZCMainzixyzz, h$mainZCMainzixyzz_e, [h$ghczmprimZCGHCziCStringziunpackCStringzh, h$mainZCMainzixyzz1_1, h$mainZCMainzixyzz1_2]);

// Fun infotable + entry code
h$o(h$mainZCMainzixyzz_e, ...);

function h$mainZCMainzixyzz_e() {
  var a = h$r1.d1;
  var b = h$r1.d2.d1;
  var c = h$r1.d2.d2;
  h$bh();
  h$r3 = c;
  h$r2 = b;
  h$r1 = a;
  return h$ap_1_2_fast();
};

Then #24743 would take care of sharing the entry code which would always be the same.

We might also be more clever and detect that we're dealing with unpackCString#, similarly to what native backends do: see Note [unpack_cstring closures] in rts/StgStdThunks.cmm


Also the offset is always 0 for these constant strings, so we should try to inline the offset and to not generate the variables as it is a bit ridiculous to have:

var h$ghczminternalZCGHCziInternalziTextziReadziLexzim67_2=0;
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim67_1=h$rawStringData([68,69,76]);
var h$ghczminternalZCGHCziInternalziTextziReadziLexzilvl122_2=0;
var h$ghczminternalZCGHCziInternalziTextziReadziLexzilvl122_1=h$rawStringData([92,38]);
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim65_2=0;
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim65_1=h$rawStringData([83,80]);
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim63_2=0;
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim63_1=h$rawStringData([85,83]);
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim61_2=0;
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim61_1=h$rawStringData([82,83]);
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim59_2=0;
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim59_1=h$rawStringData([71,83]);
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim57_2=0;
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim57_1=h$rawStringData([70,83]);
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim55_2=0;
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim55_1=h$rawStringData([69,83,67]);
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim53_2=0;
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim53_1=h$rawStringData([83,85,66]);
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim51_2=0;
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim51_1=h$rawStringData([69,77]);
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim49_2=0;
var h$ghczminternalZCGHCziInternalziTextziReadziLexzim49_1=h$rawStringData([67,65,78]);
...
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information