Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

js_toJSArrayPure could be used with unforced JSVal (unless FFI is lazy?) #98

Open
louispan opened this issue Jul 7, 2017 · 0 comments

Comments

@louispan
Copy link
Contributor

louispan commented Jul 7, 2017

There are parts of ghc-base that forces to whnf using seq for some javascript functions that expect forced JSVals. Eg.

Data/JSString/Text.hs
46:lazyTextToJSString t = rnf t seq js_lazyTextToString (unsafeCoerce t)

Data/JSString.hs
228:pack x = rnf x seq js_pack (unsafeCoerce x)
518:intercalate i xs = rnf xs seq js_intercalate i (unsafeCoerce xs)
788:concat xs = rnf xs seq js_concat (unsafeCoerce xs)
1558:unlines xs = rnf xs seq js_unlines (unsafeCoerce xs)
1563:unwords xs = rnf xs seq js_unwords (unsafeCoerce xs)

JavaScript/Array/Internal.hs
52:fromList xs = rnf xs seq js_toJSArrayPure (unsafeCoerce xs)
56:fromListIO xs = IO (\s -> rnf xs seq js_toJSArray (unsafeCoerce xs) s)

JavaScript/Array/ST.hs
59:fromList xs = ST (\s -> rnf xs seq I.js_toJSArray (unsafeCoerce xs) s)

Eg. The comment on shim/strings.js h$fromHsListJSVal(xs) says

list of JSVal to array, list must have been completely forced first

However, the documentation for seq says

A note on evaluation order: the expression seq a b does not guarantee that a will be evaluated before b. The only guarantee given by seq is that the both a and b will be evaluated before seq returns a value. In particular, this means that b may be evaluated before a. If you need to guarantee a specific order of evaluation, you must use the function pseq from the "parallel" package.

This means that is is possible to break the precondition for h$fromHsListJSVal and pass it an unforced JSVal.

Note, pseq is defined as

-- The reason for the strange "lazy" call is that
-- it fools the compiler into thinking that pseq and par are non-strict in
-- their second argument (even if it inlines pseq at the call site).
-- If it thinks pseq is strict in "y", then it often evaluates
-- "y" before "x", which is totally wrong.
pseq :: a -> b -> b
pseq x y = x seq lazy y

And GHC.Exts.lazy is documented:

The lazy function restrains strictness analysis a little. The call lazy e means the same as e, but lazy has a magical property so far as strictness analysis is concerned: it is lazy in its first argument, even though its semantics is strict. After strictness analysis has run, calls to lazy are inlined to be the identity function.

Are javascript FFI's implicitly lazy? If javascript FFI have the same effect as lazy, then this is a non issue. Otherwise, there may be cases where the javascript functions does not get a forced JSVal as expected.

Even so, it might still be best to replace seq with pseq in case in the future the FFI behaviour changes.

@louispan louispan changed the title js_toJSArrayPure could get be used with unforced JSVal (unless FFI is lazy?) js_toJSArrayPure could be used with unforced JSVal (unless FFI is lazy?) Jul 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant