[Git][ghc/ghc][wip/js-staging] Doc
Sylvain Henry (@hsyl20)
gitlab at gitlab.haskell.org
Mon Aug 8 11:24:22 UTC 2022
Sylvain Henry pushed to branch wip/js-staging at Glasgow Haskell Compiler / GHC
Commits:
63051477 by Sylvain Henry at 2022-08-08T13:27:10+02:00
Doc
- - - - -
1 changed file:
- compiler/GHC/StgToJS.hs
Changes:
=====================================
compiler/GHC/StgToJS.hs
=====================================
@@ -25,56 +25,115 @@ import GHC.StgToJS.CodeGen
--
-- Primitives
-- ~~~~~~~~~~
--- See GHC.StgToJS.Types:VarType
--- - Addr#: represented with two fields: array (used as a namespace) and index
--- - StablePtr#: similar to Addr# with array fixed to h$stablePtrBuf
--- - Int64#/Word64#: represented with two fields: high, low
--- - Float#/Double#: both represented as Javascript Double (no Float!)
--- - JSVal#: any Javascript object (used to pass JS objects via FFI)
--- - TVar#, MVar#, etc. are represented with a JS object
+-- Haskell primitives have to be represented as JavaScript values. This is done
+-- as follows:
+--
+-- - Int#/Int32# -> number in Int32 range
+-- - Int16# -> number in Int16 range
+-- - Int8# -> number in Int8 range
+-- - Word#/Word32# -> number in Word32 range
+-- - Word16# -> number in Word16 range
+-- - Word8# -> number in Word8 range
+--
+-- - Float#/Double# -> both represented as Javascript Double (no Float!)
+--
+-- - Int64# -> represented with two fields:
+-- high -> number in Int32 range
+-- low -> number in Word32 range
+-- - Word64# -> represented with two fields: high, low
+-- high -> number in Word32 range
+-- low -> number in Word32 range
+--
+-- - Addr# -> represented with two fields: array (used as a namespace) and index
+-- - StablePtr# -> similar to Addr# with array fixed to h$stablePtrBuf
+--
+-- - JSVal# -> any Javascript object (used to pass JS objects via FFI)
+--
+-- - TVar#, MVar#, etc. are represented with JS objects
--
-- Foreign JavaScript imports
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~
-- StgToJS supports inline JavaScript code. Example:
--
-- > foreign import javascript unsafe
--- > "$1 + $2"
+-- > "((x,y) => x + y)"
-- > plus :: Int -> Int -> Int
--
--- The parser is inherited from JMacro and supports local variable declarations,
--- loops, etc. Local variables are converted to hygienic names to avoid capture.
---
--- TODO: argument order for multi-values primreps (Int64#, Word64#, Addr#)
--- TODO: "$c" safe call continuation?
+-- Currently the JS backend only supports functions as JS imports.
+--
+-- In comparison, GHCJS supports JavaScript snippets with $1, $2... variables
+-- as placeholders for the arguments. It requires a JavaScript parser that the
+-- JS backend lacks. In GHCJS, the parser is inherited from JMacro and supports
+-- local variable declarations, loops, etc. Local variables are converted to
+-- hygienic names to avoid capture.
+--
+-- Primitives that are represented as multiple values (Int64#, Word64#, Addr#)
+-- are passed to FFI functions with multiple arguments.
+--
+-- FIXME: specify argument order:
+-- high then low (Int64#/Word64#)?
+-- array then offset(Addr#)?
+-- StablePtr#: do we pass the array?
+-- FIXME: how do we return them from FFI? With h$retN variables as for
+-- unboex tuples?
+--
+-- Interruptible convention: FFI imports with the "interruptible" calling
+-- convention are passed an extra argument (usually named "$c") that is a
+-- continuation function. The FFI function must call this function to return to
+-- Haskell code.
+--
+-- Unboxed tuples: returning an unboxed tuple can be done with the predefined
+-- macros RETURN_UBX_TUPn where n is the size of the tuples. Internally it uses
+-- predefined "h$retN" global variables to pass additional values; the first
+-- element of the tuple is returned normally.
--
-- Memory management
-- ~~~~~~~~~~~~~~~~~
--- Stack: the Haskell stack is implemented with a dynamically growing JavaScript
--- array ("h$stack").
--- TODO: does it shrink sometimes?
--- TODO: what are the elements of the stack? one JS object per stack frame?
---
--- Heap: objects on the heap ("closures") are represented as JavaScript objects
--- with the following fields:
---
--- { f: function -- entry function
--- , m: meta -- meta data
--- , d1: x -- closure specific fields
--- , d2: y
+-- Heap objects are represented as JavaScript values.
+--
+-- Most heap objects are represented generically as JavaScript "objects" (hash
+-- maps). However, some Haskell heap objects can use use a more memory efficient
+-- JavaScript representation: number, string... An example of a consequence of
+-- this is that both Int# and Int are represented the same as a JavaScript
+-- number. JavaScript introspection (e.g. typeof) is used to differentiate
+-- heap object representations when necessary.
+--
+-- Generic representation: objects on the heap ("closures") are represented as
+-- JavaScript objects with the following fields:
+--
+-- { f -- (function) entry function + info table
+-- , d1 -- two fields of payload
+-- , d2
+-- , m -- GC mark
+-- , cc -- optional cost-center
-- }
--
--- Every heap object has an entry function "f".
---
--- Similarly to info tables in native code generation, the JS function object
--- "f" also contains some metadata about the Haskell object:
---
--- { t: closure type
--- , a: constructor tag / fun arity
+-- Payload: payload only consists of two fields (d1, d2). When more than two
+-- fields of payload are required, the second field is itself an object.
+-- payload [] ==> { d1 = null, d2 = null }
+-- payload [a] ==> { d1 = a , d2 = null }
+-- payload [a,b] ==> { d1 = a , d2 = b }
+-- payload [a,b,c] ==> { d1 = a , d2 = { d1 = b, d2 = c} }
+-- payload [a,b,c...] ==> { d1 = a , d2 = { d1 = b, d2 = c, ...} }
+--
+-- Entry function/ info tables: JavaScript functions are JavaScript objects. If
+-- "f" is a function, we can:
+-- - call it, e.g. "f(arg0,arg1...)"
+-- - get/set its fields, e.g. "f.xyz = abc"
+-- This is used to implement the equivalent of tables-next-to-code in
+-- JavaScript: every heap object has an entry function "f" that also contains
+-- some metadata (info table) about the Haskell object:
+-- { t -- object type
+-- , size -- number of fields in the payload (-1 if variable layout)
+-- , i -- (array) fields layout (empty if variable layout)
+-- , n -- (string) object name for easier dubugging
+-- , a -- constructor tag / fun arity
+-- , r -- FIXME
+-- , s -- static references? FIXME
+-- , m -- GC mark?
-- }
--
--- Note that functions in JS are objects so if "f" is a function we can:
--- - call it, e.g. "f(arg0,arg1...)"
--- - get/set its metadata, e.g. "var closureType = f.t"
+-- Payloads for each kind of heap object:
--
-- THUNK =
-- { f = returns the object reduced to WHNF
@@ -127,6 +186,12 @@ import GHC.StgToJS.CodeGen
-- When a shared thunk is entered, it is overriden with a black hole ("eager
-- blackholing") and an update frame is pushed on the stack.
--
+-- Stack: the Haskell stack is implemented with a dynamically growing JavaScript
+-- array ("h$stack").
+-- TODO: does it shrink sometimes?
+-- TODO: what are the elements of the stack? one JS object per stack frame?
+--
+--
-- Interaction with JavaScript's garbage collector
-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- Using JS objects to represent Haskell heap objects means that JS's GC does
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/630514779b31e0573250bd67bef645af5c02ab43
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/630514779b31e0573250bd67bef645af5c02ab43
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20220808/d91f6c51/attachment-0001.html>
More information about the ghc-commits
mailing list