1
1
mirror of https://github.com/tweag/asterius.git synced 2024-09-21 05:48:04 +03:00

Asyncify the rts api (#190)

This commit is contained in:
Shao Cheng 2019-06-18 12:10:30 +03:00 committed by Siddharth Bhat
parent 9356fb4d97
commit 6b9b03e366
14 changed files with 202 additions and 239 deletions

View File

@ -0,0 +1,38 @@
export class Exports {
constructor(reentrancy_guard, symbol_table, tso_manager, exports) {
this.context = Object.freeze({
reentrancyGuard: reentrancy_guard,
symbolTable: symbol_table,
tsoManager: tso_manager
});
Object.assign(this, exports);
}
async rts_eval(p) {
this.context.reentrancyGuard.enter(0);
const tso = this.createGenThread(p);
this.scheduleWaitThread(tso, false);
this.context.reentrancyGuard.exit(0);
return this.context.tsoManager.getTSOid(tso);
}
async rts_evalIO(p) {
this.context.reentrancyGuard.enter(0);
const tso = this.createStrictIOThread(p);
this.scheduleWaitThread(tso, false);
this.context.reentrancyGuard.exit(0);
return this.context.tsoManager.getTSOid(tso);
}
async rts_evalLazyIO(p) {
this.context.reentrancyGuard.enter(0);
const tso = this.createIOThread(p);
this.scheduleWaitThread(tso, false);
this.context.reentrancyGuard.exit(0);
return this.context.tsoManager.getTSOid(tso);
}
main() {
return this.rts_evalLazyIO(this.context.symbolTable.Main_main_closure);
}
}

View File

@ -23,6 +23,7 @@ import { ThreadPaused } from "./rts.threadpaused.mjs";
import { MD5 } from "./rts.md5.mjs"
import { FloatCBits } from "./rts.float.mjs";
import { Unicode } from "./rts.unicode.mjs";
import { Exports } from "./rts.exports.mjs";
import * as rtsConstants from "./rts.constants.mjs";
export function newAsteriusInstance(req) {
@ -37,7 +38,7 @@ export function newAsteriusInstance(req) {
__asterius_mblockalloc = new MBlockAlloc(),
__asterius_heapalloc = new HeapAlloc(__asterius_memory, __asterius_mblockalloc),
__asterius_stableptr_manager = new StablePtrManager(),
__asterius_tso_manager = new TSOManager(),
__asterius_tso_manager = new TSOManager(__asterius_memory, req.symbolTable),
__asterius_heap_builder = new HeapBuilder(req.symbolTable, __asterius_heapalloc, __asterius_memory, __asterius_stableptr_manager),
__asterius_integer_manager = new IntegerManager(__asterius_stableptr_manager, __asterius_heap_builder),
__asterius_fs = new MemoryFileSystem(__asterius_logger),
@ -46,9 +47,10 @@ export function newAsteriusInstance(req) {
__asterius_exception_helper = new ExceptionHelper(__asterius_memory, __asterius_heapalloc, req.infoTables, req.symbolTable),
__asterius_threadpaused = new ThreadPaused(__asterius_memory, req.infoTables, req.symbolTable),
__asterius_float_cbits = new FloatCBits(__asterius_memory),
__asterius_messages = new Messages(__asterius_memory, __asterius_fs),
__asterius_unicode = new Unicode(),
__asterius_md5 = new MD5(__asterius_memory),
__asterius_messages = new Messages(__asterius_memory, __asterius_fs);
__asterius_exports = new Exports(__asterius_reentrancy_guard, req.symbolTable, __asterius_tso_manager, req.exports),
__asterius_md5 = new MD5(__asterius_memory);
function __asterius_show_I64(x) {
return "0x" + x.toString(16).padStart(8, "0");
@ -67,30 +69,30 @@ export function newAsteriusInstance(req) {
newTmpJSVal: v => __asterius_stableptr_manager.newTmpJSVal(v),
mutTmpJSVal: (i, f) => __asterius_stableptr_manager.mutTmpJSVal(i, f),
freezeTmpJSVal: i => __asterius_stableptr_manager.freezeTmpJSVal(i),
makeHaskellCallback: sp => () => {
const tid = __asterius_wasm_instance.exports.rts_evalLazyIO(__asterius_stableptr_manager.deRefStablePtr(sp));
__asterius_wasm_instance.exports.rts_checkSchedStatus(tid);
makeHaskellCallback: sp => async () => {
const tid = await __asterius_exports.rts_evalLazyIO(__asterius_stableptr_manager.deRefStablePtr(sp));
__asterius_exports.rts_checkSchedStatus(tid);
},
makeHaskellCallback1: sp => ev => {
const tid = __asterius_wasm_instance.exports.rts_evalLazyIO(
__asterius_wasm_instance.exports.rts_apply(
makeHaskellCallback1: sp => async ev => {
const tid = await __asterius_exports.rts_evalLazyIO(
__asterius_exports.rts_apply(
__asterius_stableptr_manager.deRefStablePtr(sp),
__asterius_wasm_instance.exports.rts_mkInt(
__asterius_exports.rts_mkInt(
__asterius_stableptr_manager.newJSVal(ev)
)
)
);
__asterius_wasm_instance.exports.rts_checkSchedStatus(tid);
__asterius_exports.rts_checkSchedStatus(tid);
},
makeHaskellCallback2: sp => (x, y) => {
const tid = __asterius_wasm_instance.exports.rts_evalLazyIO(
__asterius_wasm_instance.exports.rts_apply(
__asterius_wasm_instance.exports.rts_apply(
__asterius_stableptr_manager.deRefStablePtr(sp), __asterius_wasm_instance.exports.rts_mkInt(
makeHaskellCallback2: sp => async (x, y) => {
const tid = await __asterius_exports.rts_evalLazyIO(
__asterius_exports.rts_apply(
__asterius_exports.rts_apply(
__asterius_stableptr_manager.deRefStablePtr(sp), __asterius_exports.rts_mkInt(
__asterius_stableptr_manager.newJSVal(x))),
__asterius_wasm_instance.exports.rts_mkInt(
__asterius_exports.rts_mkInt(
__asterius_stableptr_manager.newJSVal(y))));
__asterius_wasm_instance.exports.rts_checkSchedStatus(tid);
__asterius_exports.rts_checkSchedStatus(tid);
},
Integer: __asterius_integer_manager,
FloatCBits: __asterius_float_cbits,
@ -162,6 +164,7 @@ export function newAsteriusInstance(req) {
return Object.assign(__asterius_jsffi_instance, {
wasmModule: req.module,
wasmInstance: __asterius_wasm_instance,
exports: Object.freeze(Object.assign(__asterius_exports, __asterius_wasm_instance.exports)),
symbolTable: req.symbolTable,
logger: __asterius_logger
});

View File

@ -1,16 +1,21 @@
import { Memory } from "./rts.memory.mjs";
import * as rtsConstants from "./rts.constants.mjs";
class TSO {
constructor() {
this.addr = undefined;
this.ret = undefined;
this.rstat = undefined;
Object.seal(this);
}
}
export class TSOManager {
constructor() {
constructor(memory, symbol_table) {
this.memory = memory;
this.symbolTable = symbol_table;
this.last = 0;
this.tsos = [];
Object.freeze(this);
Object.seal(this);
}
newTSO() { return this.tsos.push(new TSO()) - 1; }
@ -26,4 +31,8 @@ export class TSOManager {
setTSOret(i, ret) { this.tsos[i].ret = ret; }
setTSOrstat(i, rstat) { this.tsos[i].rstat = rstat; }
getTSOid(tso) {
return this.memory.i32Load(tso + rtsConstants.offset_StgTSO_id);
}
}

View File

@ -119,13 +119,8 @@ rtsAsteriusModule opts =
Map.fromList $
map (\(func_sym, (_, func)) -> (func_sym, func))
(byteStringCBits <> floatCBits <> unicodeCBits <> md5CBits)
} <> mainFunction opts
<> hsInitFunction opts
<> scheduleWaitThreadFunction opts
} <> hsInitFunction opts
<> createThreadFunction opts
<> createGenThreadFunction opts
<> createIOThreadFunction opts
<> createStrictIOThreadFunction opts
<> genAllocateFunction opts "allocate"
<> genAllocateFunction opts "allocateMightFail"
<> allocatePinnedFunction opts
@ -168,9 +163,10 @@ rtsAsteriusModule opts =
generateRtsExternalInterfaceModule :: BuiltinsOptions -> AsteriusModule
generateRtsExternalInterfaceModule opts = mempty
<> rtsApplyFunction opts
<> rtsEvalFunction opts
<> rtsEvalIOFunction opts
<> rtsEvalLazyIOFunction opts
<> createGenThreadFunction opts
<> createIOThreadFunction opts
<> createStrictIOThreadFunction opts
<> scheduleWaitThreadFunction opts
<> rtsGetSchedStatusFunction opts
<> rtsCheckSchedStatusFunction opts
<> getStablePtrWrapperFunction opts
@ -505,8 +501,8 @@ rtsFunctionImports debug =
else []) <>
map (fst . snd) (byteStringCBits <> floatCBits <> unicodeCBits <> md5CBits)
rtsFunctionExports :: Bool -> Bool -> [FunctionExport]
rtsFunctionExports debug has_main =
rtsFunctionExports :: Bool -> [FunctionExport]
rtsFunctionExports debug =
[ FunctionExport {internalName = f <> "_wrapper", externalName = f}
| f <-
[ "loadI64"
@ -525,9 +521,10 @@ rtsFunctionExports debug has_main =
, "rts_getPtr"
, "rts_getStablePtr"
, "rts_apply"
, "rts_eval"
, "rts_evalIO"
, "rts_evalLazyIO"
, "createGenThread"
, "createStrictIOThread"
, "createIOThread"
, "scheduleWaitThread"
, "rts_getSchedStatus"
, "rts_checkSchedStatus"
, "getStablePtr"
@ -547,8 +544,7 @@ rtsFunctionExports debug has_main =
, "__asterius_Load_HpLim"
]
else []) <>
["hs_init"] <>
["main" | has_main]
["hs_init"]
]
emitErrorMessage :: [ValueType] -> SBS.ShortByteString -> Expression
@ -697,12 +693,8 @@ generateWrapperModule mod = mod {
mainFunction, hsInitFunction, rtsApplyFunction, rtsEvalFunction, rtsEvalIOFunction, rtsEvalLazyIOFunction, rtsGetSchedStatusFunction, rtsCheckSchedStatusFunction, scheduleWaitThreadFunction, createThreadFunction, createGenThreadFunction, createIOThreadFunction, createStrictIOThreadFunction, allocatePinnedFunction, newCAFFunction, stgReturnFunction, getStablePtrWrapperFunction, deRefStablePtrWrapperFunction, freeStablePtrWrapperFunction, rtsMkBoolFunction, rtsMkDoubleFunction, rtsMkCharFunction, rtsMkIntFunction, rtsMkWordFunction, rtsMkPtrFunction, rtsMkStablePtrFunction, rtsGetBoolFunction, rtsGetDoubleFunction, loadI64Function, printI64Function, assertEqI64Function, printF32Function, printF64Function, strlenFunction, memchrFunction, memcpyFunction, memsetFunction, memcmpFunction, fromJSArrayBufferFunction, toJSArrayBufferFunction, fromJSStringFunction, fromJSArrayFunction, threadPausedFunction, dirtyMutVarFunction, raiseExceptionHelperFunction, barfFunction, getProgArgvFunction, suspendThreadFunction, resumeThreadFunction, performMajorGCFunction, performGCFunction, localeEncodingFunction ::
hsInitFunction, rtsApplyFunction, rtsGetSchedStatusFunction, rtsCheckSchedStatusFunction, scheduleWaitThreadFunction, createThreadFunction, createGenThreadFunction, createIOThreadFunction, createStrictIOThreadFunction, allocatePinnedFunction, newCAFFunction, stgReturnFunction, getStablePtrWrapperFunction, deRefStablePtrWrapperFunction, freeStablePtrWrapperFunction, rtsMkBoolFunction, rtsMkDoubleFunction, rtsMkCharFunction, rtsMkIntFunction, rtsMkWordFunction, rtsMkPtrFunction, rtsMkStablePtrFunction, rtsGetBoolFunction, rtsGetDoubleFunction, loadI64Function, printI64Function, assertEqI64Function, printF32Function, printF64Function, strlenFunction, memchrFunction, memcpyFunction, memsetFunction, memcmpFunction, fromJSArrayBufferFunction, toJSArrayBufferFunction, fromJSStringFunction, fromJSArrayFunction, threadPausedFunction, dirtyMutVarFunction, raiseExceptionHelperFunction, barfFunction, getProgArgvFunction, suspendThreadFunction, resumeThreadFunction, performMajorGCFunction, performGCFunction, localeEncodingFunction ::
BuiltinsOptions -> AsteriusModule
mainFunction BuiltinsOptions {} =
runEDSL "main" $ do
tid <- call' "rts_evalLazyIO" [symbol "Main_main_closure"] I32
call "rts_checkSchedStatus" [tid]
initCapability :: EDSL ()
initCapability = do
@ -739,16 +731,6 @@ enter i = callImport "__asterius_enter" [constI32 i]
exit i = callImport "__asterius_exit" [constI32 i]
rtsEvalHelper :: BuiltinsOptions -> AsteriusEntitySymbol -> EDSL ()
rtsEvalHelper BuiltinsOptions {..} create_thread_func_sym = do
setReturnTypes [I32]
p <- param I64
enter 0
tso <- call' create_thread_func_sym [p] I64
call "scheduleWaitThread" [tso]
exit 0
emit $ loadI32 tso offset_StgTSO_id
rtsApplyFunction _ =
runEDSL "rts_apply" $ do
setReturnTypes [I64]
@ -763,13 +745,6 @@ rtsApplyFunction _ =
storeI64 ap (offset_StgThunk_payload + 8) arg
emit ap
rtsEvalFunction opts = runEDSL "rts_eval" $ rtsEvalHelper opts "createGenThread"
rtsEvalIOFunction opts =
runEDSL "rts_evalIO" $ rtsEvalHelper opts "createStrictIOThread"
rtsEvalLazyIOFunction opts = runEDSL "rts_evalLazyIO" $ rtsEvalHelper opts "createIOThread"
rtsGetSchedStatusFunction _ =
runEDSL "rts_getSchedStatus" $ do
setReturnTypes [I32]
@ -801,7 +776,8 @@ dirtySTACK _ stack =
scheduleWaitThreadFunction BuiltinsOptions {} =
runEDSL "scheduleWaitThread" $ do
t <- param I64
[t, load_regs] <- params [I64, I32]
tid <- i32Local $ loadI32 t offset_StgTSO_id
block' [] $ \sched_block_lbl ->
loop' [] $ \sched_loop_lbl -> do
storeI64
@ -844,7 +820,7 @@ scheduleWaitThreadFunction BuiltinsOptions {} =
constI32 next_ThreadComplete)
(do callImport
"__asterius_setTSOret"
[ loadI32 t offset_StgTSO_id
[ tid
, convertUInt64ToFloat64 $
loadI64
(loadI64
@ -854,22 +830,15 @@ scheduleWaitThreadFunction BuiltinsOptions {} =
]
callImport
"__asterius_setTSOrstat"
[ loadI32 t offset_StgTSO_id
, constI32 scheduler_Success
]
[tid, constI32 scheduler_Success]
break' sched_block_lbl Nothing)
(do callImport
"__asterius_setTSOret"
[loadI32 t offset_StgTSO_id, ConstF64 0]
(do callImport "__asterius_setTSOret" [tid, ConstF64 0]
callImport
"__asterius_setTSOrstat"
[ loadI32 t offset_StgTSO_id
, constI32 scheduler_Killed
]
[tid, constI32 scheduler_Killed]
break' sched_block_lbl Nothing))
]
, emit $ emitErrorMessage [] "IllegalThreadReturnCode")
callImport "__asterius_gcRootTSO" [convertUInt64ToFloat64 t]
createThreadFunction BuiltinsOptions {..} =
runEDSL "createThread" $ do

View File

@ -11,6 +11,7 @@ module Asterius.JSFFI
( addFFIProcessor
, generateFFIFunctionImports
, generateFFIImportObjectFactory
, generateFFIExportObject
) where
import Asterius.Builtins
@ -467,106 +468,14 @@ generateFFIImportWrapperFunction k FFIImportDecl {..} =
import_func_type = recoverWasmImportFunctionType ffiFunctionType
wrapper_func_type = recoverWasmWrapperFunctionType ffiFunctionType
generateFFIExportFunction :: FFIExportDecl -> Function
generateFFIExportFunction FFIExportDecl {..} =
adjustLocalRegs
Function
{ functionType = recoverWasmWrapperFunctionType ffiFunctionType
, varTypes = []
, body =
Block
{ name = ""
, bodys =
[ UnresolvedSetLocal
{ unresolvedLocalReg = tid
, value =
Call
{ target =
if ffiInIO ffiFunctionType
then "rts_evalIO"
else "rts_eval"
, operands =
[ foldl'
(\tot_expr (ffi_param_i, ffi_param_t) ->
Call
{ target = "rts_apply"
, operands =
[ tot_expr
, Call
{ target =
AsteriusEntitySymbol
{ entityName =
"rts_mk" <> getHsTyCon ffi_param_t
}
, operands =
[ GetLocal
{ index = ffi_param_i
, valueType =
recoverWasmWrapperValueType
ffi_param_t
}
]
, callReturnTypes = [I64]
}
]
, callReturnTypes = [I64]
})
Symbol
{ unresolvedSymbol = ffiExportClosure
, symbolOffset = 0
}
(zip [0 ..] $ ffiParamTypes ffiFunctionType)
]
, callReturnTypes = [I32]
}
}
, Call
{ target = "rts_checkSchedStatus"
, operands = [UnresolvedGetLocal {unresolvedLocalReg = tid}]
, callReturnTypes = []
}
] <>
case ffiResultTypes ffiFunctionType of
[ffi_result_t] ->
[ Call
{ target =
AsteriusEntitySymbol
{entityName = "rts_get" <> getHsTyCon ffi_result_t}
, operands =
[ Unary TruncUFloat64ToInt64 $
CallImport
{ target' = "__asterius_getTSOret"
, operands =
[ UnresolvedGetLocal
{unresolvedLocalReg = tid}
]
, callImportReturnTypes = [F64]
}
]
, callReturnTypes =
[recoverWasmWrapperValueType ffi_result_t]
}
]
_ -> []
, blockReturnTypes =
map recoverWasmWrapperValueType $ ffiResultTypes ffiFunctionType
}
}
where
tid = UniqueLocalReg 0 I32
getHsTyCon FFI_VAL {..} = hsTyCon
getHsTyCon FFI_JSVAL = "StablePtr"
generateFFIWrapperModule :: FFIMarshalState -> AsteriusModule
generateFFIWrapperModule mod_ffi_state@FFIMarshalState {..} =
mempty
{ functionMap =
M.fromList $
[ (k <> "_wrapper", wrapper_func)
| (k, wrapper_func) <- import_wrapper_funcs
] <>
export_funcs <>
export_wrapper_funcs
M.fromList
[ (k <> "_wrapper", wrapper_func)
| (k, wrapper_func) <- import_wrapper_funcs
]
, ffiMarshalState = mod_ffi_state
}
where
@ -574,16 +483,6 @@ generateFFIWrapperModule mod_ffi_state@FFIMarshalState {..} =
[ (k, generateFFIImportWrapperFunction k ffi_decl)
| (k, ffi_decl) <- M.toList ffiImportDecls
]
export_funcs =
[ (k, generateFFIExportFunction ffi_decl)
| (k, ffi_decl) <- M.toList ffiExportDecls
]
export_wrapper_funcs =
[ ( AsteriusEntitySymbol
{entityName = "__asterius_jsffi_export_" <> entityName k}
, generateWrapperFunction k f)
| (k, f) <- export_funcs
]
generateFFIFunctionImports :: FFIMarshalState -> [FunctionImport]
generateFFIFunctionImports FFIMarshalState {..} =
@ -625,3 +524,48 @@ generateFFIImportObjectFactory FFIMarshalState {..} =
| (k, ffi_decl) <- M.toList ffiImportDecls
]) <>
"}})"
generateFFIExportObject :: FFIMarshalState -> Builder
generateFFIExportObject FFIMarshalState {..} =
"Object.freeze({" <>
mconcat
(intersperse
","
[ shortByteString (coerce k) <> ":" <>
generateFFIExportLambda export_decl
| (k, export_decl) <- M.toList ffiExportDecls
]) <>
"})"
generateFFIExportLambda :: FFIExportDecl -> Builder
generateFFIExportLambda FFIExportDecl { ffiFunctionType = FFIFunctionType {..}
, ..
} =
"function(" <>
mconcat (intersperse "," ["_" <> intDec i | i <- [1 .. length ffiParamTypes]]) <>
"){" <>
(if null ffiResultTypes
then tid
else "return " <> ret) <>
"}"
where
ret =
case ffiResultTypes of
[t] -> "this.rts_get" <> getHsTyCon t <> "(" <> ret_closure <> ")"
_ -> error "Asterius.JSFFI.generateFFIExportLambda"
ret_closure = "this.context.tsoManager.getTSOret(" <> tid <> ")"
tid = "this." <> eval_func <> "(" <> eval_closure <> ")"
eval_func
| ffiInIO = "rts_evalIO"
| otherwise = "rts_eval"
eval_closure =
foldl'
(\acc (i, t) ->
"this.rts_apply(" <> acc <> ",this.rts_mk" <> getHsTyCon t <> "(_" <>
intDec i <>
"))")
("this.context.symbolTable." <>
shortByteString (coerce ffiExportClosure))
(zip [1 ..] ffiParamTypes)
getHsTyCon FFI_VAL {..} = shortByteString hsTyCon
getHsTyCon FFI_JSVAL = "StablePtr"

View File

@ -20,10 +20,10 @@ newAsteriusInstance s lib_path mod_buf = do
eval s $ takeJSVal f_val <> "(" <> takeJSVal mod_val <> ")"
hsInit :: JSSession -> JSVal -> IO ()
hsInit s i = eval s $ deRefJSVal i <> ".wasmInstance.exports.hs_init()"
hsInit s i = eval s $ deRefJSVal i <> ".exports.hs_init()"
hsMain :: JSSession -> JSVal -> IO ()
hsMain s i = eval s $ deRefJSVal i <> ".wasmInstance.exports.main()"
hsMain s i = eval s $ deRefJSVal i <> ".exports.main()"
hsStdOut :: JSSession -> JSVal -> IO LBS.ByteString
hsStdOut s i = eval s $ deRefJSVal i <> ".stdio.stdout()"

View File

@ -52,6 +52,7 @@ rtsUsedSymbols =
, "ghczmprim_GHCziTypes_ZC_con_info"
, "ghczmprim_GHCziTypes_ZMZN_closure"
, "integerzmwiredzmin_GHCziIntegerziType_Integer_con_info"
, "Main_main_closure"
, "stg_ARR_WORDS_info"
, "stg_BLACKHOLE_info"
, "stg_DEAD_WEAK_info"
@ -66,7 +67,6 @@ linkModules ::
linkModules LinkTask {..} m =
linkStart
debug
True
gcSections
binaryen
verboseErr
@ -79,7 +79,7 @@ linkModules LinkTask {..} m =
, rtsUsedSymbols
, Set.fromList
[ AsteriusEntitySymbol {entityName = internalName}
| FunctionExport {..} <- rtsFunctionExports debug True
| FunctionExport {..} <- rtsFunctionExports debug
]
])
exportFunctions

View File

@ -201,6 +201,8 @@ genLib Task {..} LinkReport {..} =
, "export default module => \n"
, "rts.newAsteriusInstance({module: module, jsffiFactory: "
, generateFFIImportObjectFactory bundledFFIMarshalState
, ", exports: "
, generateFFIExportObject bundledFFIMarshalState
, ", symbolTable: "
, genSymbolDict symbol_table
, ", infoTables: "
@ -223,7 +225,13 @@ genLib Task {..} LinkReport {..} =
| fullSymTable = raw_symbol_table
| otherwise =
M.restrictKeys raw_symbol_table $
S.fromList extraRootSymbols <> rtsUsedSymbols
S.fromList
[ ffiExportClosure
| FFIExportDecl {..} <-
M.elems $ ffiExportDecls bundledFFIMarshalState
] <>
S.fromList extraRootSymbols <>
rtsUsedSymbols
genDefEntry :: Task -> Builder
genDefEntry Task {..} =
@ -242,13 +250,13 @@ genDefEntry Task {..} =
, mconcat
[ "module.then(m => "
, out_base
, "(m)).then(i => {\n"
, "(m)).then(async i => {\n"
, if debug
then "i.logger.onEvent = ev => console.log(`[${ev.level}] ${ev.event}`);\n"
else mempty
, "try {\n"
, "i.wasmInstance.exports.hs_init();\n"
, "i.wasmInstance.exports.main();\n"
, "i.exports.hs_init();\n"
, "await i.exports.main();\n"
, "} catch (err) {\n"
, "console.log(i.stdio.stdout());\n"
, "throw err;\n"

View File

@ -22,7 +22,6 @@ import Data.Binary
import qualified Data.ByteString as BS
import qualified Data.ByteString.Short as SBS
import Data.Data (Data, gmapQl)
import Data.List
import qualified Data.Map.Lazy as LM
import qualified Data.Set as S
import Data.String
@ -85,8 +84,9 @@ mergeSymbols ::
-> Bool
-> AsteriusModule
-> S.Set AsteriusEntitySymbol
-> [AsteriusEntitySymbol]
-> (AsteriusModule, LinkReport)
mergeSymbols _ gc_sections verbose_err store_mod root_syms
mergeSymbols _ gc_sections verbose_err store_mod root_syms export_funcs
| not gc_sections = (store_mod, mempty {bundledFFIMarshalState = ffi_all})
| otherwise = (final_m, mempty {bundledFFIMarshalState = ffi_this})
where
@ -96,8 +96,17 @@ mergeSymbols _ gc_sections verbose_err store_mod root_syms
{ ffiImportDecls =
flip LM.filterWithKey (ffiImportDecls ffi_all) $ \k _ ->
(k <> "_wrapper") `LM.member` functionMap final_m
, ffiExportDecls = ffi_exports
}
(_, _, final_m) = go (root_syms, S.empty, mempty)
ffi_exports
| not gc_sections = ffiExportDecls (ffiMarshalState store_mod)
| otherwise =
ffiExportDecls (ffiMarshalState store_mod) `LM.restrictKeys`
S.fromList export_funcs
root_syms' =
S.fromList [ffiExportClosure | FFIExportDecl {..} <- LM.elems ffi_exports] <>
root_syms
(_, _, final_m) = go (root_syms', S.empty, mempty)
go i@(i_staging_syms, _, _)
| S.null i_staging_syms = i
| otherwise = go $ iter i
@ -163,9 +172,7 @@ makeInfoTableSet AsteriusModule {..} sym_map =
resolveAsteriusModule ::
Bool
-> Bool
-> Bool
-> FFIMarshalState
-> [AsteriusEntitySymbol]
-> AsteriusModule
-> Int64
-> Int64
@ -174,7 +181,7 @@ resolveAsteriusModule ::
, LM.Map AsteriusEntitySymbol Int64
, Int
, Int)
resolveAsteriusModule debug has_main _ bundled_ffi_state export_funcs m_globals_resolved func_start_addr data_start_addr =
resolveAsteriusModule debug _ bundled_ffi_state m_globals_resolved func_start_addr data_start_addr =
(new_mod, ss_sym_map, func_sym_map, table_slots, initial_mblocks)
where
(func_sym_map, last_func_addr) =
@ -195,12 +202,7 @@ resolveAsteriusModule debug has_main _ bundled_ffi_state export_funcs m_globals_
Module
{ functionMap' = new_function_map
, functionImports = func_imports
, functionExports =
rtsFunctionExports debug has_main <>
[ FunctionExport
{internalName = "__asterius_jsffi_export_" <> k, externalName = k}
| k <- map entityName export_funcs
]
, functionExports = rtsFunctionExports debug
, functionTable = func_table
, tableImport =
TableImport
@ -220,12 +222,11 @@ linkStart ::
-> Bool
-> Bool
-> Bool
-> Bool
-> AsteriusModule
-> S.Set AsteriusEntitySymbol
-> [AsteriusEntitySymbol]
-> (AsteriusModule, Module, LinkReport)
linkStart debug has_main gc_sections binaryen verbose_err store root_syms export_funcs =
linkStart debug gc_sections binaryen verbose_err store root_syms export_funcs =
( merged_m
, result_m
, report
@ -242,12 +243,7 @@ linkStart debug has_main gc_sections binaryen verbose_err store root_syms export
gc_sections
verbose_err
store
(root_syms <>
S.fromList
[ AsteriusEntitySymbol
{entityName = "__asterius_jsffi_export_" <> entityName k}
| k <- export_funcs
])
root_syms export_funcs
merged_m1
| debug = addMemoryTrap merged_m0
| otherwise = merged_m0
@ -266,10 +262,8 @@ linkStart debug has_main gc_sections binaryen verbose_err store root_syms export
(result_m, ss_sym_map, func_sym_map, tbl_slots, static_mbs) =
resolveAsteriusModule
debug
has_main
binaryen
(bundledFFIMarshalState report)
export_funcs
merged_m
(1 .|. functionTag `shiftL` 32)
(dataTag `shiftL` 32)

View File

@ -1,5 +1,5 @@
import cloudflare from "./cloudflare.lib.mjs";
let i = cloudflare(m);
i.wasmInstance.exports.hs_init();
i.wasmInstance.exports.main();
i.exports.hs_init();
i.exports.main();

View File

@ -3,10 +3,10 @@ import jsffi from "./jsffi.lib.mjs";
process.on("unhandledRejection", err => { throw err; });
module.then(m => jsffi(m)).then(i => {
i.wasmInstance.exports.hs_init();
i.wasmInstance.exports.main();
console.log(i.wasmInstance.exports.mult_hs_int(9, 9));
console.log(i.wasmInstance.exports.mult_hs_double(9, 9));
i.wasmInstance.exports.putchar("H".codePointAt(0));
module.then(m => jsffi(m)).then(async i => {
i.exports.hs_init();
await i.exports.main();
console.log(i.exports.mult_hs_int(9, 9));
console.log(i.exports.mult_hs_double(9, 9));
i.exports.putchar("H".codePointAt(0));
});

View File

@ -27,12 +27,10 @@ main = do
hsInit s i
let x_closure = deRefJSVal i <> ".symbolTable.NoMain_x_closure"
x_tid =
deRefJSVal i <> ".wasmInstance.exports.rts_eval(" <> x_closure <> ")"
x_ret =
deRefJSVal i <> ".wasmInstance.exports.getTSOret(" <> x_tid <> ")"
x_sp =
deRefJSVal i <> ".wasmInstance.exports.rts_getStablePtr(" <> x_ret <>
")"
x_val = deRefJSVal i <> ".getJSVal(" <> x_sp <> ")"
"await " <> deRefJSVal i <> ".exports.rts_eval(" <> x_closure <> ")"
x_ret = deRefJSVal i <> ".exports.getTSOret(" <> x_tid <> ")"
x_sp = deRefJSVal i <> ".exports.rts_getStablePtr(" <> x_ret <> ")"
x_val' = deRefJSVal i <> ".getJSVal(" <> x_sp <> ")"
x_val = "(async () => " <> x_val' <> ")()"
x <- eval s x_val
LBS.putStr x

View File

@ -3,18 +3,18 @@ import rtsapi from "./rtsapi.lib.mjs";
process.on("unhandledRejection", err => { throw err; });
module.then(m => rtsapi(m)).then(i => {
i.wasmInstance.exports.hs_init();
i.wasmInstance.exports.main();
i.wasmInstance.exports.rts_evalLazyIO(i.wasmInstance.exports.rts_apply(i.symbolTable.Main_printInt_closure, i.wasmInstance.exports.rts_apply(i.symbolTable.Main_fact_closure, i.wasmInstance.exports.rts_mkInt(5))));
const tid_p1 = i.wasmInstance.exports.rts_eval(i.wasmInstance.exports.rts_apply(i.symbolTable.Main_fact_closure, i.wasmInstance.exports.rts_mkInt(5)));
console.log(i.wasmInstance.exports.rts_getInt(i.wasmInstance.exports.getTSOret(tid_p1)));
console.log(i.wasmInstance.exports.rts_getBool(i.symbolTable.ghczmprim_GHCziTypes_False_closure));
console.log(i.wasmInstance.exports.rts_getBool(i.symbolTable.ghczmprim_GHCziTypes_True_closure));
console.log(i.wasmInstance.exports.rts_getBool(i.wasmInstance.exports.rts_mkBool(0)));
console.log(i.wasmInstance.exports.rts_getBool(i.wasmInstance.exports.rts_mkBool(42)));
module.then(m => rtsapi(m)).then(async i => {
i.exports.hs_init();
await i.exports.main();
await i.exports.rts_evalLazyIO(i.exports.rts_apply(i.symbolTable.Main_printInt_closure, i.exports.rts_apply(i.symbolTable.Main_fact_closure, i.exports.rts_mkInt(5))));
const tid_p1 = await i.exports.rts_eval(i.exports.rts_apply(i.symbolTable.Main_fact_closure, i.exports.rts_mkInt(5)));
console.log(i.exports.rts_getInt(i.exports.getTSOret(tid_p1)));
console.log(i.exports.rts_getBool(i.symbolTable.ghczmprim_GHCziTypes_False_closure));
console.log(i.exports.rts_getBool(i.symbolTable.ghczmprim_GHCziTypes_True_closure));
console.log(i.exports.rts_getBool(i.exports.rts_mkBool(0)));
console.log(i.exports.rts_getBool(i.exports.rts_mkBool(42)));
const x0 = Math.random();
const tid_p3 = i.wasmInstance.exports.rts_eval(i.wasmInstance.exports.rts_apply(i.symbolTable.base_GHCziBase_id_closure, i.wasmInstance.exports.rts_mkDouble(x0)));
const x1 = i.wasmInstance.exports.rts_getDouble(i.wasmInstance.exports.getTSOret(tid_p3));
const tid_p3 = await i.exports.rts_eval(i.exports.rts_apply(i.symbolTable.base_GHCziBase_id_closure, i.exports.rts_mkDouble(x0)));
const x1 = i.exports.rts_getDouble(i.exports.getTSOret(tid_p3));
console.log([x0, x1, x0 === x1]);
});

View File

@ -21,11 +21,11 @@ The next step is locating the pointer of `fact`. The "asterius instance" type we
Since we'd like to call `fact`, we need to apply it to an argument, build a thunk representing the result, then evaluate the thunk to WHNF and retrieve the result. Assuming we're passing `--asterius-instance-callback=i=>{ ... }` to `ahc-link`, in the callback body, we can use RTS API like this:
```JavaScript
i.wasmInstance.exports.hs_init();
const argument = i.wasmInstance.exports.rts_mkInt(5);
const thunk = i.wasmInstance.exports.rts_apply(i.staticsSymbolMap.Main_fact_closure, argument);
const tid = i.wasmInstance.exports.rts_eval(thunk);
console.log(i.wasmInstance.exports.rts_getInt(i.wasmInstance.exports.getTSOret(tid)));
i.exports.hs_init();
const argument = i.exports.rts_mkInt(5);
const thunk = i.exports.rts_apply(i.staticsSymbolMap.Main_fact_closure, argument);
const tid = i.exports.rts_eval(thunk);
console.log(i.exports.rts_getInt(i.exports.getTSOret(tid)));
```
A line-by-line explanation follows: