summaryrefslogtreecommitdiff
path: root/rts/js/rts.js
diff options
context:
space:
mode:
Diffstat (limited to 'rts/js/rts.js')
-rw-r--r--rts/js/rts.js715
1 files changed, 715 insertions, 0 deletions
diff --git a/rts/js/rts.js b/rts/js/rts.js
new file mode 100644
index 0000000000..e3dcf07137
--- /dev/null
+++ b/rts/js/rts.js
@@ -0,0 +1,715 @@
+//#OPTIONS: CPP
+
+var h$start = new Date();
+
+function h$rts_eval(action, unbox) {
+ return new Promise((accept, reject) =>
+ h$run(MK_AP3( h$baseZCGHCziJSziPrimziresolveIO
+ , x => { accept(unbox(x))}
+ , e => { reject(new h$HaskellException(e))}
+ , action
+ ))
+ );
+}
+
+function h$rts_eval_sync(closure, unbox) {
+ var res, status = 0;
+ try {
+ h$runSync(MK_AP3( h$baseZCGHCziJSziPrimziresolveIO
+ , MK_JSVAL(x => { status = 1; res = unbox(x); })
+ , MK_JSVAL(e => { status = 2; res = new h$HaskellException(e); })
+ , closure), false);
+ } catch(e) { status = 2; res = e; }
+ switch(status) {
+ case 0: throw new h$HaskellException("internal error"); // thread didn't reach update frame
+ case 1: return res;
+ default: throw res;
+ }
+}
+
+
+function h$rts_apply(f, x) {
+ return MK_AP1(f, x);
+}
+
+/*
+ marshalling for "foreign export"
+ */
+/*
+ | getUnique tc `elem` [ intTyConKey, int8TyConKey, int16TyConKey
+ , int32TyConKey, int64TyConKey
+ , wordTyConKey, word8TyConKey, word16TyConKey
+ , word32TyConKey, word64TyConKey
+ , floatTyConKey, doubleTyConKey
+ , ptrTyConKey, funPtrTyConKey
+ , charTyConKey
+ , stablePtrTyConKey
+ , boolTyConKey
+ ]
+ */
+
+function h$rts_mkChar(x) { return x|0; }
+function h$rts_getChar(x) { return UNWRAP_NUMBER(x); }
+
+function h$rts_mkWord(x) { return x|0; }
+function h$rts_getWord(x) { return UNWRAP_NUMBER(x); }
+
+function h$rts_mkInt(x) { return x|0; }
+function h$rts_getInt(x) { return UNWRAP_NUMBER(x); }
+
+function h$rts_mkInt32(x) { return x|0; }
+function h$rts_getInt32(x) { return UNWRAP_NUMBER(x); }
+
+function h$rts_mkWord32(x) { return x|0; }
+function h$rts_getWord32(x) { return UNWRAP_NUMBER(x); }
+
+function h$rts_mkInt16(x) { return (x<<16)>>16; }
+function h$rts_getInt16(x) { return UNWRAP_NUMBER(x); }
+
+function h$rts_mkInt64(x) { throw new Error("rts_mkInt64"); /* return MK_INT64(); */ }
+function h$rts_getInt64(x) { throw new Error("rts_getInt64"); }
+
+function h$rts_mkWord64(x) { throw new Error("rts_mkWord64"); /* return MK_WORD64(); */ }
+function h$rts_getWord64(x) { throw new Error("rts_getWord64"); }
+
+function h$rts_mkWord16(x) { return x&0xffff; }
+function h$rts_getWord16(x) { return UNWRAP_NUMBER(x); }
+
+function h$rts_mkInt8(x) { return (x<<24)>>24; }
+function h$rts_getInt8(x) { return UNWRAP_NUMBER(x); }
+
+function h$rts_mkWord8(x) { return x&0xff; }
+function h$rts_getWord8(x) { return UNWRAP_NUMBER(x); }
+
+function h$rts_mkFloat(x) { return x; }
+function h$rts_getFloat(x) { return x; }
+
+function h$rts_mkDouble(x) { return x; }
+function h$rts_getDouble(x) { return x; }
+
+function h$rts_mkBool(x) { return x; }
+function h$rts_getBool(x) { return x; }
+
+function h$rts_getUnit(x) { return 0; }
+
+function h$rts_toString(x) {
+ var buf;
+ if(typeof x === 'object' &&
+ typeof x.len === 'number' &&
+ x.buf instanceof ArrayBuffer) {
+ buf = x;
+ } else if(typeof x === 'object' &&
+ x.buffer instanceof ArrayBuffer &&
+ typeof x.byteOffset === 'number') {
+ buf = h$wrapBuffer(x.buffer, true, x.byteOffset, x.byteLength);
+ } else if(x instanceof ArrayBuffer) {
+ buf = h$wrapBuffer(x, true, 0, x.byteLength);
+ } else {
+ throw new Error("rts_toString: unsupported value" + x);
+ }
+ return h$decodeUtf8z(buf);
+}
+
+function h$rts_mkPtr(x) {
+ var buf, off = 0;
+ if(typeof x == 'string') {
+ // string: UTF-8 encode
+ buf = h$encodeUtf8(x);
+ off = 0;
+ } else if(typeof x == 'object' &&
+ typeof x.len == 'number' &&
+ x.buf instanceof ArrayBuffer) {
+ // already a Haskell ByteArray
+ buf = x;
+ off = 0;
+ } else if(x.isView) {
+ // ArrayBufferView: make ByteArray with the same byteOffset
+ buf = h$wrapBuffer(x.buffer, true, 0, x.buffer.byteLength);
+ off = x.byteOffset;
+ } else {
+ // plain ArrayBuffer
+ buf = h$wrapBuffer(x, true, 0, x.byteLength);
+ off = 0;
+ }
+ return MK_PTR(buf, off);
+}
+
+function h$rts_getPtr(x) {
+ var arr = x.d1;
+ var offset = x.d2;
+ return new Uint8Array(arr.buf, offset);
+}
+
+function h$rts_mkFunPtr(x) {
+ // not yet implemented
+ throw new Error("rts_mkFunPtr");
+}
+
+function h$rts_getFunPtr(x) {
+ // not yet implemented
+ throw new Error("rts_getFunPtr");
+}
+
+function h$rts_toIO(x) {
+ return MK_AP1(h$baseZCGHCziJSziPrimzitoIO, x);
+}
+
+// running IO actions
+
+function h$rts_evalIO_sync(closure) {
+ // return h$runSyncReturn(closure, false);
+}
+
+async function h$rts_evalIO(closure) {
+
+}
+
+/*
+function h$handleCallback(f, result) {
+ try {
+ f(result);
+ } catch() {
+
+ }
+}
+*/
+
+/* end foreign export stuff */
+
+function h$runio(c) {
+ return h$c1(h$runio_e, c);
+}
+
+function h$runInitStatic() {
+ if(h$initStatic.length == 0) return;
+ for(var i=h$initStatic.length - 1;i>=0;i--) {
+ h$initStatic[i]();
+ }
+ h$initStatic = [];
+}
+
+function h$o(o, typ, a, size, regs, srefs) {
+ h$setObjInfo(o, typ, "", [], a, size, regs, srefs);
+}
+
+// set heap/stack object information
+function h$setObjInfo(o, typ, name, fields, a, size, regs, srefs) {
+ o.t = typ;
+ o.i = fields;
+ o.n = name;
+ o.a = a;
+ o.r = regs;
+ o.s = srefs;
+ o.m = 0
+ o.size = size;
+}
+
+var h$gccheckcnt = 0;
+
+function h$gc_check(next) {
+ // h$log("gc_check: todo");
+ if(++h$gccheckcnt > 1000) {
+ for(var i=h$sp+1;i<h$stack.length;i++) {
+ h$stack[i] = null;
+ }
+ h$gccheckcnt = 0;
+ }
+ return 0;
+}
+
+// print a closure
+// fixme, property access here might be closure compiler incompatible
+
+function h$printcl(i) {
+ var cl = i.f;
+ var d = i.d1;
+ var r = "";
+ switch(cl.t) {
+ case h$ct_thunk:
+ r += "thunk";
+ break;
+ case h$ct_con:
+ r += "con[" + cl.a + "]";
+ break;
+ case h$ct_fun:
+ r += "fun[" + cl.a + "]";
+ break;
+ default:
+ r += "unknown closure type";
+ break;
+ }
+ r += " :: " + cl.n + " ->";
+ var idx = 1;
+ // fixme update for single field data
+ for(var i=0;i<cl.i.length;i++) {
+ r += " ";
+ switch(cl.i[i]) {
+ case h$vt_ptr:
+ r += "[ Ptr :: " + d["d"+idx].f.n + "]";
+ idx++;
+ break;
+ case h$vt_void:
+ r += "void";
+ break;
+ case h$vt_double:
+ r += "(" + d["d"+idx] + " :: double)";
+ idx++;
+ break;
+ case h$vt_int:
+ r += "(" + d["d"+idx] + " :: int)";
+ idx++;
+ break;
+ case h$vt_long:
+ r += "(" + d["d"+idx] + "," + d["d"+(idx+1)] + " :: long)";
+ idx+=2;
+ break;
+ case h$vt_addr:
+ r += "(" + d["d"+idx].length + "," + d["d"+(idx+1)] + " :: ptr)";
+ idx+=2;
+ break;
+ case h$vt_rtsobj:
+ r += "(" + d["d"+idx].toString() + " :: RTS object)";
+ idx++;
+ break;
+ default:
+ r += "unknown field: " + cl.i[i];
+ }
+ }
+
+}
+
+function h$init_closure(c, xs) {
+ c.m = 0;
+ switch(xs.length) {
+ case 0:
+ c.d1 = null; c.d2 = null;
+ return c;
+ case 1:
+ c.d1 = xs[0]; c.d2 = null;
+ return c;
+ case 2:
+ c.d1 = xs[0]; c.d2 = xs[1];
+ return c;
+ case 3:
+ c.d1 = xs[0]; c.d2 = { d1: xs[1], d2: xs[2] };
+ return c;
+ case 4:
+ c.d1 = xs[0]; c.d2 = { d1: xs[1], d2: xs[2], d3: xs[3] };
+ return c;
+ case 5:
+ c.d1 = xs[0]; c.d2 = { d1: xs[1], d2: xs[2], d3: xs[3], d4: xs[4] };
+ return c;
+ case 6:
+ c.d1 = xs[0]; c.d2 = { d1: xs[1], d2: xs[2], d3: xs[3], d4: xs[4], d5: xs[5] };
+ return c;
+ case 7:
+ c.d1 = xs[0]; c.d2 = { d1: xs[1], d2: xs[2], d3: xs[3], d4: xs[4], d5: xs[5], d6: xs[6] };
+ return c;
+ default:
+ c.d1 = xs[0]; c.d2 = { d1: xs[1], d2: xs[2], d3: xs[3], d4: xs[4], d5: xs[5], d6: xs[6] };
+ // fixme does closure compiler bite us here?
+ for(var i=7;i<xs.length;i++) {
+ c.d2["d"+i] = xs[i];
+ }
+ return c;
+ }
+}
+
+
+
+function h$checkStack(f) {
+ // some code doesn't write a stack frame header when called immediately
+ if(f.t === h$ct_stackframe) h$stack[h$sp] = f;
+ var idx = h$sp;
+ while(idx >= 0) {
+ f = h$stack[idx];
+ var size, offset;
+ if(typeof(f) === 'function') {
+ if(f === h$ap_gen) {
+ size = (h$stack[idx - 1] >> 8) + 2;
+ offset = 2;
+ } else {
+ var tag = h$stack[idx].size;
+ if(tag <= 0) {
+ size = h$stack[idx-1];
+ offset = 2;
+ } else {
+ size = (tag & 0xff) + 1;
+ offset = 1;
+ }
+ }
+ // if(size < 1) throw("invalid stack frame size at: stack[" + idx + "], frame: " + h$stack[idx].n);
+ // h$log("checking frame: " + h$stack[idx].n + " size " + size);
+ // if(f !== h$returnf && f !== h$restoreThread) {
+ // for(var i=0;i<size-offset;i++) {
+ // if(typeof h$stack[idx-offset-i] === 'function') {
+ // h$dumpStackTop(h$stack, 0, h$sp);
+ // throw("unexpected function in frame at: " + idx + " " + h$stack[idx].n);
+ // }
+ // }
+ // }
+ idx = idx - size;
+ } else {
+ h$dumpStackTop(h$stack, 0, h$sp);
+ throw("invalid stack object at: " + idx);
+ }
+ }
+}
+
+function h$printReg(r) {
+ if(r === null) {
+ return "null";
+ } else if(typeof r === 'object' && r.hasOwnProperty('f') && r.hasOwnProperty('d1') && r.hasOwnProperty('d2')) {
+ if(typeof(r.f) !== 'function') {
+ return "dodgy object";
+ } else if(r.f.t === h$ct_blackhole && r.x) {
+ return ("blackhole: -> " + h$printReg({ f: r.x.x1, d: r.d1.x2 }) + ")");
+ } else {
+ var iv = "";
+ if(r.f.n === "integer-gmp:GHC.Integer.Type.Jp#" ||
+ r.f.n === "integer-gmp:GHC.Integer.Type.Jn#") {
+ iv = ' [' + r.d1.join(',') + '](' + h$ghcjsbn_showBase(r.d1, 10) + ')'
+ } else if(r.f.n === "integer-gmp:GHC.Integer.Type.S#") {
+ iv = ' (S: ' + r.d1 + ')';
+ }
+ return ((r.alloc ? r.alloc + ': ' : '') + r.f.n + " (" + h$closureTypeName(r.f.t) + ", " + r.f.a + ")" + iv);
+ }
+ } else if(typeof r === 'object') {
+ var res = h$collectProps(r);
+ if(res.length > 40) {
+ return (res.substr(0,40)+"...");
+ } else {
+ return res;
+ }
+ } else {
+ var xs = new String(r) + "";
+ if(xs.length > 40) {
+ return xs.substr(0,40)+"...";
+ } else {
+ return xs;
+ }
+ }
+}
+
+
+function h$stackFrameSize(f) {
+ if(f === h$ap_gen) { // h$ap_gen is special
+ return (h$stack[h$sp - 1] >> 8) + 2;
+ } else {
+ var tag = f.size;
+ if(tag < 0) {
+ return h$stack[h$sp-1];
+ } else {
+ return (tag & 0xff) + 1;
+ }
+ }
+}
+
+
+// throw an exception: unwind the thread's stack until you find a handler
+function h$throw(e, async) {
+ //h$log("throwing exception: " + async);
+ //h$dumpStackTop(h$stack, 0, h$sp);
+ var origSp = h$sp;
+ var lastBh = null; // position of last blackhole frame
+ var f;
+ while(h$sp > 0) {
+ //h$log("unwinding frame: " + h$sp);
+ f = h$stack[h$sp];
+ if(f === null || f === undefined) {
+ throw("h$throw: invalid object while unwinding stack");
+ }
+ if(f === h$catch_e) break;
+ if(f === h$atomically_e) {
+ if(async) { // async exceptions always propagate
+ h$currentThread.transaction = null;
+ } else if(!h$stmValidateTransaction()) { // restart transaction if invalid, don't propagate exception
+ h$sp++;
+ h$stack[h$sp] = h$checkInvariants_e;
+ return h$stmStartTransaction(h$stack[h$sp-1]);
+ }
+ }
+ if(f === h$catchStm_e && !async) break; // catchSTM only catches sync
+ if(f === h$upd_frame) {
+ var t = h$stack[h$sp-1];
+ // wake up threads blocked on blackhole
+ var waiters = t.d2;
+ if(waiters !== null) {
+ for(var i=0;i<waiters.length;i++) {
+ h$wakeupThread(waiters[i]);
+ }
+ }
+ if(async) {
+ // convert blackhole back to thunk
+ if(lastBh === null) {
+ h$makeResumable(t,h$sp+1,origSp,[]); // [`R1`,h$return]);
+ } else {
+ h$makeResumable(t,h$sp+1,lastBh-2,[h$ap_0_0,h$stack[lastBh-1],h$return]);
+ }
+ lastBh = h$sp;
+ } else {
+ // just raise the exception in the thunk
+ t.f = h$raise_e;
+ t.d1 = e;
+ t.d2 = null;
+ }
+ }
+ var size = h$stackFrameSize(f);
+ h$sp = h$sp - size;
+}
+//h$log("unwound stack to: " + `Sp`);
+//h$dumpStackTop(`Stack`,0,origSp);
+if(h$sp > 0) {
+ var maskStatus = h$stack[h$p - 2];
+ var handler = h$stack[h$sp - 1];
+ if(f === h$catchStm_e) {
+ h$currentThread.transaction = h$stack[h$sp-3];
+ h$sp -= 4;
+ } else if(h$sp > 3) { // don't pop the toplevel handler
+ h$sp -= 3;
+}
+h$r1 = handler;
+h$r2 = e;
+if(f !== h$catchStm_e) { // don't clobber mask in STM?
+if(maskStatus === 0 && h$stack[h$sp] !== h$maskFrame && h$stack[h$sp] !== h$maskUnintFrame) {
+ h$stack[h$sp+1] = h$unmaskFrame;
+ h$sp += 1;
+} else if(maskStatus === 1) {
+ h$stack[h$sp+1] = h$maskUnintFrame;
+ h$sp += 1;
+}
+h$currentThread.mask = 2;
+}
+return h$ap_2_1_fast();
+} else {
+ throw "unhandled exception in haskell thread";
+}
+}
+
+// print top stack frame
+function h$logStack() {
+ if(typeof h$stack[h$sp] === 'undefined') {
+ h$log("warning: invalid stack frame");
+ return;
+ }
+ var size = 0;
+ var gt = h$stack[h$sp].size;
+ if(gt === -1) {
+ size = h$stack[h$sp - 1] & 0xff;
+ } else {
+ size = gt & 0xff;
+ }
+ h$dumpStackTop(h$stack, h$sp-size-2, h$sp);
+ for(var i=Math.max(0,h$sp-size+1); i <= h$sp; i++) {
+ if(typeof h$stack[i] === 'undefined') {
+ throw "undefined on stack";
+ }
+ }
+}
+
+// fixme check if still used
+function h$ascii(s) {
+ var res = [];
+ for(var i=0;i<s.length;i++) {
+ res.push(s.charCodeAt(i));
+ }
+ res.push(0);
+ return res;
+}
+
+
+function h$dumpStackTop(stack, start, sp) {
+ start = Math.max(start,0);
+ for(var i=start;i<=sp;i++) {
+ var s = stack[i];
+ if(s && s.n) {
+ h$log("stack[" + i + "] = " + s.n);
+ } else {
+ if(s === null) {
+ h$log("stack[" + i + "] = null WARNING DANGER");
+ } else if(typeof s === 'object' && s !== null && s.hasOwnProperty("f") && s.hasOwnProperty("d1") && s.hasOwnProperty("d2")) {
+ if(typeof(s.f) !== 'function') {
+ h$log("stack[" + i + "] = WARNING: dodgy object");
+ } else {
+ if(s.d1 === undefined) { h$log("WARNING: stack[" + i + "] d1 undefined"); }
+ if(s.d2 === undefined) { h$log("WARNING: stack[" + i + "] d2 undefined"); }
+ if(s.f.t === h$ct_blackhole && s.d1 && s.d1.x1 && s.d1.x1.n) {
+ h$log("stack[" + i + "] = blackhole -> " + s.d1.x1.n);
+ } else {
+ var iv = "";
+ if(s.f.n === "integer-gmp:GHC.Integer.Type.Jp#" ||
+ s.f.n === "integer-gmp:GHC.Integer.Type.Jn#") {
+ iv = ' [' + s.d1.join(',') + '](' + h$ghcjsbn_showBase(s.d1, 10) + ')'
+ } else if(s.f.n === "integer-gmp:GHC.Integer.Type.S#") {
+ iv = ' (S: ' + s.d1 + ')';
+ }
+ h$log("stack[" + i + "] = -> " + (s.alloc ? s.alloc + ': ' : '') + s.f.n + " (" + h$closureTypeName(s.f.t) + ", a: " + s.f.a + ")" + iv);
+ }
+ }
+ } else if(h$isInstanceOf(s,h$MVar)) {
+ var val = s.val ===
+ null ? " empty"
+ : " value -> " + (typeof s.val === 'object' ? s.val.f.n + " (" + h$closureTypeName(s.val.f.t) + ", a: " + s.val.f.a + ")" : s.val);
+ h$log("stack[" + i + "] = MVar " + val);
+ } else if(h$isInstanceOf(s,h$MutVar)) {
+ h$log("stack[" + i + "] = IORef -> " + (typeof s.val === 'object' ? (s.val.f.n + " (" + h$closureTypeName(s.val.f.t) + ", a: " + s.val.f.a + ")") : s.val));
+ } else if(Array.isArray(s)) {
+ h$log("stack[" + i + "] = " + ("[" + s.join(",") + "]").substring(0,50));
+ } else if(typeof s === 'object') {
+ h$log("stack[" + i + "] = " + h$collectProps(s).substring(0,50));
+ } else if(typeof s === 'function') {
+ var re = new RegExp("([^\\n]+)\\n(.|\\n)*");
+ h$log("stack[" + i + "] = " + (""+s).substring(0,50).replace(re,"$1"));
+ } else {
+ h$log("stack[" + i + "] = " + (""+s).substring(0,50));
+ }
+ }
+ }
+}
+
+
+/* check that a haskell heap object is what we expect:
+f is a haskell entry function
+d exists, but might be null, if it isn't, warn for any undefined/null fields or fields with unfamiliar names
+*/
+function h$checkObj(obj) {
+ if(typeof obj === 'boolean' || typeof obj === 'number') { return; }
+ if(!obj.hasOwnProperty("f") ||
+ obj.f === null ||
+ obj.f === undefined ||
+ obj.f.a === undefined ||
+ typeof obj.f !== 'function') {
+ h$log("h$checkObj: WARNING, something wrong with f:");
+ h$log((""+obj).substring(0,200));
+ h$log(h$collectProps(obj));
+ h$log(typeof obj.f);
+ }
+ if(!obj.hasOwnProperty("d1") || obj.d1 === undefined) {
+ h$log("h$checkObj: WARNING, something wrong with d1:");
+ h$log((""+obj).substring(0,200));
+ } else if(!obj.hasOwnProperty("d2") || obj.d2 === undefined) {
+ h$log("h$checkObj: WARNING, something wrong with d2:");
+ h$log((""+obj).substring(0,200));
+ } else if(obj.d2 !== null && typeof obj.d2 === 'object' && obj.f.size !== 2) {
+ var d = obj.d2;
+ for(var p in d) {
+ if(d.hasOwnProperty(p)) {
+ if(p.substring(0,1) != "d") {
+ h$log("h$checkObj: WARNING, unexpected field name: " + p);
+ h$log((""+obj).substring(0,200));
+ }
+ if(d[p] === undefined) {
+ h$log("h$checkObj: WARNING, undefined field detected: " + p);
+ h$log((""+obj).substring(0,200));
+ }
+ // if(d[p] === null) {
+ // h$log("h$checkObj: WARNING, null field detected: " + p);
+ // h$log((""+obj).substring(0,200));
+ // }
+ }
+ }
+ switch(obj.f.size) {
+ case 6: if(d.d5 === undefined) { h$log("h$checkObj: WARNING, undefined field detected: d5"); }
+ case 5: if(d.d4 === undefined) { h$log("h$checkObj: WARNING, undefined field detected: d4"); }
+ case 4: if(d.d3 === undefined) { h$log("h$checkObj: WARNING, undefined field detected: d3"); }
+ case 3: if(d.d2 === undefined) { h$log("h$checkObj: WARNING, undefined field detected: d2"); }
+ if(d.d1 === undefined) { h$log("h$checkObj: WARNING, undefined field detected: d1"); }
+ default: d = obj.d2; // dummy
+ }
+ }
+}
+
+function h$traceForeign(f, as) {
+ if(!h$rts_traceForeign) { return; }
+ var bs = [];
+ for(var i=0;i<as.length;i++) {
+ var ai = as[i];
+ if(ai === null) {
+ bs.push("null");
+ } else if(typeof ai === 'object') {
+ var astr = ai.toString();
+ if(astr.length > 40) {
+ bs.push(astr.substring(0,40)+"...");
+ } else {
+ bs.push(astr);
+ }
+ } else {
+ bs.push(""+ai);
+ }
+ }
+ h$log("ffi: " + f + "(" + bs.join(",") + ")");
+}
+
+function h$papArity(cp) {
+ return cp.d2.d1;
+}
+
+// carefully suspend the current thread, looking at the
+// function that would be called next
+function h$suspendCurrentThread(next) {
+ // `assertRts s (next |!== (TxtI "h$reschedule")) ("suspend called with h$reschedule"::String)`;
+ if(next === h$reschedule) { throw "suspend called with h$reschedule"; }
+ // some stack calls do not write the function to the stack top as an optimization
+ // do it here
+ if(next.t === h$ct_stackframe) h$stack[h$sp] = next;
+ if(h$stack[h$sp] === h$restoreThread || next === h$return) {
+ h$currentThread.sp = h$sp;
+ return;
+ }
+ var nregs;
+ var skipregs = 0;
+ var t = next.t;
+ // pap arity
+ if(t === h$ct_pap) {
+ nregs = (h$papArity(h$r1) >> 8) + 1;
+ } else if(t === h$ct_fun || t === h$ct_stackframe) {
+ // for normal functions, the number active registers is in the .r proprty
+ nregs = next.r >> 8;
+ skipregs = next.r & 0xff;
+ } else {
+ nregs = 1; // Thunk, Con, Blackhole only have R1
+ }
+ // h$log("suspending: " + `Sp` + " nregs: " + nregs);
+ h$sp = h$sp+nregs+skipregs+3;
+ var i;
+ for(i=1;i<=skipregs;i++) {
+ h$stack[h$sp-2-i] = null;
+ }
+ for(i=skipregs+1;i<=nregs+skipregs;i++) {
+ h$stack[h$sp-2-i] = h$getReg(i);
+ }
+ h$stack[h$sp-2] = next;
+ h$stack[h$sp-1] = nregs+skipregs+3;
+ h$stack[h$sp] = h$restoreThread;
+ h$currentThread.sp = h$sp;
+}
+
+function h$static_thunk(f) {
+ // fixme push stuff to restore stuff here
+ var h;
+ if(!h$rts_profiling) {
+ h = { f: f, d1: null, d2: null, m: 0 };
+ } else {
+ h = { f: f, d1: null, d2: null, m: 0, cc: h$CCS_SYSTEM };
+ }
+ h$CAFs.push(h);
+ h$CAFsReset.push(f);
+ return h;
+}
+
+function h$catch(a, handler) {
+ h$sp += 3;
+ h$stack[h$sp-2] = h$currentThread.mask;
+ h$stack[h$sp-1] = handler;
+ h$stack[h$sp] = h$catch_e;
+ h$r1 = a;
+ return h$ap_1_0_fast();
+}
+
+function h$keepAlive(x, f) {
+ h$sp += 2;
+ h$stack[h$sp-1] = x;
+ h$stack[h$sp] = h$keepAlive_e;
+ h$r1 = f;
+ return h$ap_1_0_fast();
+}