public
Rubygem
Description: Johnson wraps JavaScript in a loving Ruby embrace.
Homepage: http://github.com/jbarnette/johnson/wikis
Clone URL: git://github.com/jbarnette/johnson.git
johnson / ext / spidermonkey / context.c
100644 122 lines (100 sloc) 3.645 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#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");
}