The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#include "JS.h"

/*!
    @struct PJS_TrapHandler
    @abstract A structure that encapsulates a closure.
    @field callback an SV reference to a CV
    @field data an SV, any
*/

typedef struct PJS_TrapHandler PJS_TrapHandler;

struct PJS_TrapHandler {
    SV	*callback;
    SV  *data;
};

PJS_TYPEDEF(TrapHandler);

static JSTrapStatus
PJS_trap_handler(
    JSContext *cx,
    JSScript *script,
    jsbytecode *pc,
    jsval *rval,
    void *closure 
) {
    dTHX;
    JSTrapStatus status = JSTRAP_CONTINUE;

    PJS_Runtime *runtime = (PJS_Runtime *)closure;
    IV tmp = SvIV( (SV*)SvRV( runtime->trap_handler) );
    PJS_TrapHandler *handler = INT2PTR(PJS_TrapHandler *, tmp);

    if(handler && handler->callback) {
	dSP;
	PJS_Context *pcx = PJS_GET_CONTEXT(cx);
	SV *scx, *rv;
	
	ENTER; SAVETMPS;
	PUSHMARK(SP) ;

	scx = sv_newmortal();
	sv_setref_pv(scx, Nullch, (void*) pcx);
	
	XPUSHs(scx);
	XPUSHs(sv_2mortal(newSViv(*pc)));
	XPUSHs(sv_mortalcopy(handler->data));
	
	PUTBACK;
	
	call_sv(handler->callback, G_SCALAR | G_EVAL);

	SPAGAIN;

	rv = POPs;

	if(!SvTRUE(rv)) status = JSTRAP_ERROR;

	if(SvTRUE(ERRSV)) {
	    sv_setsv(ERRSV, &PL_sv_undef);
	}
	
	PUTBACK;
	FREETMPS; LEAVE;
    }
    return status;
}

MODULE = JSPL::TrapHandler    PACKAGE = JSPL::TrapHandler
PROTOTYPES: DISABLE

JSPL::TrapHandler
new(self, cb, data = &PL_sv_undef)
    SV *self;
    CV *cb;
    SV *data;
    CODE:
	PERL_UNUSED_VAR(self); /* -W */
	Newxz(RETVAL, 1, PJS_TrapHandler);
	if(!RETVAL) XSRETURN_UNDEF;
	RETVAL->callback = newRV_inc((SV*)cb);
	RETVAL->data = SvREFCNT_inc_simple_NN(data);
    OUTPUT:
	RETVAL
        
void
DESTROY(handler)
    JSPL::TrapHandler handler;
    CODE:
	sv_free((SV *)handler->data);
	sv_free((SV *)handler->callback);
	Safefree(handler);


MODULE = JSPL::TrapHandler    PACKAGE = JSPL::RawRT	PREFIX = jsr_

void
jsr_add_interrupt_handler(runtime, handler)
    JSPL::RawRT runtime
    JSPL::TrapHandler handler
    CODE:
	PERL_UNUSED_VAR(handler); /* -W */
	if(runtime->trap_handler && SvOK(runtime->trap_handler))
	    sv_free(runtime->trap_handler);
	runtime->trap_handler = SvREFCNT_inc(ST(1));
	JS_SetInterrupt(runtime->rt, PJS_trap_handler, (void *)runtime);

void
jsr_remove_interrupt_handler(runtime)
    JSPL::RawRT runtime;
    CODE:
	if(runtime->trap_handler && SvOK(runtime->trap_handler))
	    SvREFCNT_dec(runtime->trap_handler);
	JS_SetInterrupt(runtime->rt, NULL, (void *)runtime);
	runtime->trap_handler = NULL;