#include "context.h"
#include "conversions.h"
#include "global.h"
#include "extensions.h"
#include "idhash.h"
#include "jsdbgapi.h"
// callback for JS_SetErrorReporter
static void report_js_error(JSContext* js, const char* message, JSErrorReport* UNUSED(report))
{
// first we find ourselves
VALUE self = (VALUE)JS_GetContextPrivate(js);
// then we find our bridge
JohnsonContext* context;
Data_Get_Struct(self, JohnsonContext, context);
// NOTE: SpiderMonkey REALLY doesn't like being interrupted. If we
// jump over to Ruby and raise here, segfaults and such ensue.
// Instead, we store the exception (if any) and the error message
// on the context. They're dealt with in the if (!ok) block of evaluate().
strncpy(context->msg, message, MAX_EXCEPTION_MESSAGE_SIZE);
JS_GetPendingException(context->js, &context->ex);
}
// callback for JS_SetBranchCallback
static JSBool branch_callback(JSContext* js, JSScript* UNUSED(script))
{
static unsigned long branch_counter = 0;
if( ++branch_counter % 0x1000 == 0 )
JS_MaybeGC( js );
return JS_TRUE;
}
/*
* call-seq:
* native_initialize(options={})
*
* Initializes the native spidermonkey values.
*/
static VALUE
initialize_native(VALUE self, VALUE rb_runtime, VALUE UNUSED(options))
{
JohnsonContext* context;
JohnsonRuntime* runtime;
Data_Get_Struct(self, JohnsonContext, context);
Data_Get_Struct(rb_runtime, JohnsonRuntime, runtime);
if ((context->js = JS_NewContext(runtime->js, 8192)))
{
// See if the runtime already has a shared global object.
JSObject* global = runtime->global;
// If it does, use it. If not,
if (!global)
// create one of our global objects.
global = johnson_create_global_object(context->js);
// Manually set the context's global object.
JS_SetGlobalObject(context->js, global);
JS_SetErrorReporter(context->js, report_js_error);
JS_SetBranchCallback(context->js, branch_callback);
JS_SetContextPrivate(context->js, (void *)self);
JS_SetOptions(context->js, JS_GetOptions(context->js)
#ifdef JSOPTION_DONT_REPORT_UNCAUGHT
| JSOPTION_DONT_REPORT_UNCAUGHT
#endif
#ifdef JSOPTION_VAROBJFIX
| JSOPTION_VAROBJFIX
#endif
// #ifdef JSOPTION_XML
// | JSOPTION_XML
// #endif
);
// Success.
return init_spidermonkey_extensions(context, self);
}
if (context->js) JS_DestroyContext(context->js);
rb_raise(rb_eRuntimeError, "Failed to initialize SpiderMonkey context");
}
///////////////////////////////////////////////////////////////////////////
//// INFRASTRUCTURE BELOW HERE ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
static void deallocate(JohnsonContext *context) {
JS_SetContextPrivate(context->js, 0);
JS_DestroyContext(context->js);
free(context);
}
static VALUE allocate(VALUE klass)
{
JohnsonContext* context = calloc(1, sizeof(JohnsonContext));
return Data_Wrap_Struct(klass, 0, deallocate, context);
}
void init_Johnson_SpiderMonkey_Context(VALUE spidermonkey)
{
/* HACK: These comments are *only* to make RDoc happy.
VALUE johnson = rb_define_module("Johnson");
VALUE spidermonkey = rb_define_module_under(johnson, "SpiderMonkey");
*/
/* This is the private context used for SpiderMonkey. */
VALUE context = rb_define_class_under(spidermonkey, "Context", rb_cObject);
rb_define_alloc_func(context, allocate);
rb_define_private_method(context, "initialize_native", initialize_native, 2);
}
VALUE Johnson_SpiderMonkey_JSLandProxy()
{
return rb_eval_string("Johnson::SpiderMonkey::JSLandProxy");
}