/* * call-seq: * call_function_property(name, arguments) * * Calls this JavaScript object's +name+ method, passing the given * arguments. * * Equivalent to: * proxy[name].native_call(proxy, *arguments) */ static VALUE call_function_property(int argc, VALUE* argv, VALUE self) { RubyLandProxy* proxy; Data_Get_Struct(self, RubyLandProxy, proxy); JSContext * context = johnson_get_current_context(proxy->runtime); if (argc < 1) rb_raise(rb_eArgError, "Function name required"); PREPARE_RUBY_JROOTS(context, 2); jsval proxy_value; JCHECK(get_jsval_for_proxy(proxy, &proxy_value)); JROOT(proxy_value); jsval function; VALUE name = argv[0]; CALL_RUBY_WRAPPER(rb_string_value_cstr, &name); JCHECK(JS_GetProperty(context, JSVAL_TO_OBJECT(proxy_value), StringValueCStr(name), &function)); JROOT(function); // should never be anything but a function if (!JS_ObjectIsFunction(context, function)) JERROR("Specified property \"%s\" isn't a function.", StringValueCStr(name)); REMOVE_JROOTS; return call_js_function_value(proxy->runtime, proxy_value, function, argc - 1, &(argv[1])); }
/* * call-seq: * function_property?(name) * * Returns <code>true</code> if this JavaScript object's +name+ property * is a function. */ static VALUE function_property_p(VALUE self, VALUE name) { if (TYPE(name) == T_SYMBOL) name = rb_funcall(name, rb_intern("to_s"), 0); rb_string_value_cstr(&name); RubyLandProxy* proxy; Data_Get_Struct(self, RubyLandProxy, proxy); JSContext * context = johnson_get_current_context(proxy->runtime); PREPARE_RUBY_JROOTS(context, 2); jsval proxy_value; JCHECK(get_jsval_for_proxy(proxy, &proxy_value)); JROOT(proxy_value); jsval js_value; JCHECK(JS_GetProperty(context, JSVAL_TO_OBJECT(proxy_value), StringValueCStr(name), &js_value)); JROOT(js_value); JSType type = JS_TypeOfValue(context, js_value); JRETURN_RUBY(type == JSTYPE_FUNCTION ? Qtrue : Qfalse); }
/* * call-seq: * length() * * Returns the number of entries in the JavaScript array, or the number * of properties on the JavaScript object. */ static VALUE length(VALUE self) { RubyLandProxy* proxy; Data_Get_Struct(self, RubyLandProxy, proxy); JSContext * context = johnson_get_current_context(proxy->runtime); PREPARE_RUBY_JROOTS(context, 2); jsval proxy_value; JCHECK(get_jsval_for_proxy(proxy, &proxy_value)); JROOT(proxy_value); JSObject* value = JSVAL_TO_OBJECT(proxy_value); JROOT(value); if (JS_IsArrayObject(context, value)) { jsuint length; JCHECK(JS_GetArrayLength(context, value, &length)); JRETURN_RUBY(INT2FIX(length)); } else { JSIdArray* ids = JS_Enumerate(context, value); JCHECK(ids); VALUE length = INT2FIX(ids->length); JS_DestroyIdArray(context, ids); JRETURN_RUBY(length); } }
static VALUE call_js_function_value(JohnsonRuntime* runtime, jsval target, jsval function, int argc, VALUE* argv) { JSContext * context = johnson_get_current_context(runtime); PREPARE_RUBY_JROOTS(context, argc + 2); JROOT(target); JROOT(function); assert(JSVAL_IS_OBJECT(target)); jsval args[argc]; jsval result; int i; for(i = 0; i < argc; ++i) { JCHECK(convert_to_js(runtime, argv[i], &(args[i]))); JROOT(args[i]); } JCHECK(JS_CallFunctionValue(context, JSVAL_TO_OBJECT(target), function, (unsigned) argc, args, &result)); JRETURN_RUBY(CONVERT_TO_RUBY(runtime, result)); }
JSBool report_ruby_error_in_js(JohnsonRuntime* runtime, int state, VALUE old_errinfo) { JSContext * context = johnson_get_current_context(runtime); assert(state); switch (state) { case TAG_RAISE: { VALUE local_error = ruby_errinfo; jsval js_err; ruby_errinfo = old_errinfo; if (!convert_to_js(runtime, local_error, &js_err)) return JS_FALSE; JS_SetPendingException(context, js_err); return JS_FALSE; } case TAG_THROW: // FIXME: This should be propagated to JS... as an exception? default: { JSString* str = JS_NewStringCopyZ(context, "Unexpected longjmp from ruby!"); if (str) JS_SetPendingException(context, STRING_TO_JSVAL(str)); return JS_FALSE; } } }
/* * call-seq: * []=(name, value) * * Sets this JavaScript object's +name+ property to +value+. */ static VALUE set(VALUE self, VALUE name, VALUE value) { RubyLandProxy* proxy; Data_Get_Struct(self, RubyLandProxy, proxy); JSContext * context = johnson_get_current_context(proxy->runtime); PREPARE_RUBY_JROOTS(context, 2); jsval proxy_value; JCHECK(get_jsval_for_proxy(proxy, &proxy_value)); JROOT(proxy_value); jsval js_value; JCHECK(convert_to_js(proxy->runtime, value, &js_value)); JROOT(js_value); switch(TYPE(name)) { case T_FIXNUM: JCHECK(JS_SetElement(context, JSVAL_TO_OBJECT(proxy_value), (jsint)(NUM2INT(name)), &js_value)); break; case T_SYMBOL: name = RB_FUNCALL_0(name, RB_INTERN("to_s")); default: CALL_RUBY_WRAPPER(rb_string_value_cstr, &name); JCHECK(JS_SetProperty(context, JSVAL_TO_OBJECT(proxy_value), StringValueCStr(name), &js_value)); break; } JRETURN_RUBY(value); }
JSBool report_ruby_error_in_js(JohnsonRuntime* runtime, int state, VALUE old_errinfo) { JSContext * context = johnson_get_current_context(runtime); assert(state); switch (state) { case TAG_RAISE: { VALUE local_error = ruby_errinfo; ruby_errinfo = old_errinfo; local_error = rb_funcall(local_error, rb_intern("inspect"), 0); JS_ReportError(context, StringValuePtr(local_error)); return JS_FALSE ; } case TAG_THROW: // FIXME: This should be propagated to JS... as an exception? default: { JSString* str = JS_NewStringCopyZ(context, "Unexpected longjmp from ruby!"); if (str) JS_SetPendingException(context, STRING_TO_JSVAL(str)); return JS_FALSE; } } }
static jsval evaluate_js_property_expression(JohnsonRuntime * runtime, const char * property, jsval* retval) { JSContext * context = johnson_get_current_context(runtime); assert(strlen(property) < INT_MAX); return JS_EvaluateScript(context, runtime->global, property, (unsigned int)strlen(property), "johnson:evaluate_js_property_expression", 1, retval); }
/* * call-seq: * respond_to?(symbol) * * Returns <code>true</code> if this JavaScript object responds to the * named method. */ static VALUE respond_to_p(int argc, const VALUE* argv, VALUE self) { VALUE sym, priv; rb_scan_args(argc, argv, "11", &sym, &priv); RubyLandProxy* proxy; Data_Get_Struct(self, RubyLandProxy, proxy); JSContext * context = johnson_get_current_context(proxy->runtime); PREPARE_RUBY_JROOTS(context, 2); VALUE stringval = rb_funcall(sym, rb_intern("to_s"), 0); char* name = StringValuePtr(stringval); // assignment is always okay if (name[strlen(name) - 1] == '=') JRETURN_RUBY(Qtrue); jsval proxy_value; JCHECK(get_jsval_for_proxy(proxy, &proxy_value)); JROOT(proxy_value); JSObject *obj; JSBool found; JCHECK(JS_ValueToObject(context, proxy_value, &obj)); JROOT(obj); JCHECK(JS_HasProperty(context, obj, name, &found)); JRETURN_RUBY(found ? Qtrue : CALL_RUBY_WRAPPER(rb_call_super, argc, argv)); }
static bool js_value_is_regexp(JohnsonRuntime* runtime, jsval maybe_regexp) { JSContext * context = johnson_get_current_context(runtime); PREPARE_RUBY_JROOTS(context, 1); JROOT(maybe_regexp); JSBool result = JS_InstanceOf(context, JSVAL_TO_OBJECT(maybe_regexp), &js_RegExpClass, NULL); JRETURN_RUBY(result ? true : false); }
VALUE convert_js_string_to_ruby(JohnsonRuntime* runtime, JSString* str) { JSContext * context = johnson_get_current_context(runtime); PREPARE_RUBY_JROOTS(context, 1); JROOT(str); char* bytes = JS_GetStringBytes(str); JCHECK(bytes); JRETURN_RUBY(rb_str_new(bytes, (signed long)JS_GetStringLength(str))); }
bool js_value_is_proxy(JohnsonRuntime* MAYBE_UNUSED(runtime), jsval maybe_proxy) { JSClass* klass = JS_GET_CLASS( johnson_get_current_context(runtime), JSVAL_TO_OBJECT(maybe_proxy)); return &JSLandProxyClass == klass || &JSLandClassProxyClass == klass || &JSLandCallableProxyClass == klass; }
VALUE unwrap_js_land_proxy(JohnsonRuntime* runtime, jsval proxy) { VALUE value; JSObject *proxy_object = JSVAL_TO_OBJECT(proxy); JSContext * context = johnson_get_current_context(runtime); value = (VALUE)JS_GetInstancePrivate(context, proxy_object, JS_GET_CLASS(context, proxy_object), NULL); return value; }
static VALUE convert_regexp_to_ruby(JohnsonRuntime* runtime, jsval regexp) { JSContext * context = johnson_get_current_context(runtime); PREPARE_RUBY_JROOTS(context, 1); JROOT(regexp); JSRegExp* re = (JSRegExp*)JS_GetPrivate(context, JSVAL_TO_OBJECT(regexp)); JRETURN_RUBY(CALL_RUBY_WRAPPER(rb_funcall_2, rb_cRegexp, rb_intern("new"), 2, convert_js_string_to_ruby(runtime, re->source), INT2NUM((long)re->flags))); }
/* * call-seq: * function?() * * Returns <code>true</code> if this JavaScript object is a function. */ static VALUE function_p(VALUE self) { RubyLandProxy* proxy; Data_Get_Struct(self, RubyLandProxy, proxy); JSContext * context = johnson_get_current_context(proxy->runtime); PREPARE_RUBY_JROOTS(context, 1); jsval proxy_value; JCHECK(get_jsval_for_proxy(proxy, &proxy_value)); JROOT(proxy_value); JRETURN_RUBY(JS_TypeOfValue(context, proxy_value) == JSTYPE_FUNCTION ? Qtrue : Qfalse); }
/* * call-seq: * gc_zeal=(level) * * Sets the GC zeal. * 0 = normal, 1 = Very Frequent, 2 = Extremely Frequent */ static VALUE set_gc_zeal(VALUE self, VALUE zeal) { JohnsonRuntime* runtime; Data_Get_Struct(self, JohnsonRuntime, runtime); JSContext* context = johnson_get_current_context(runtime); JS_SetGCZeal(context, NUM2INT(zeal)); return zeal; }
static void deallocate(JohnsonRuntime* runtime) { JS_RemoveRoot(johnson_get_current_context(runtime), &(runtime->global)); JSContext *context; JSContext *iterator = NULL; while ((context = JS_ContextIterator(runtime->js, &iterator)) != NULL) JS_DestroyContext(context); JS_DestroyRuntime(runtime->js); free(runtime); }
JSBool unwrap_ruby_land_proxy(JohnsonRuntime* runtime, VALUE wrapped, jsval* retval) { JSContext * context = johnson_get_current_context(runtime); assert(ruby_value_is_proxy(wrapped)); PREPARE_JROOTS(context, 0); RubyLandProxy* proxy; Data_Get_Struct(wrapped, RubyLandProxy, proxy); JCHECK(get_jsval_for_proxy(proxy, retval)); JRETURN; }
/* * call-seq: * set_trap(script, parsecode, block) * * Set the trap at +script+ and +parsecode+ to +block+ */ static VALUE set_trap(VALUE self, VALUE script, VALUE linenum, VALUE block) { JohnsonRuntime* runtime; Data_Get_Struct(self, JohnsonRuntime, runtime); JSContext * context = johnson_get_current_context(runtime); jsval compiled_js; if(!convert_to_js(runtime, script, &compiled_js)) rb_raise(rb_eRuntimeError, "Couldn't get compiled script."); JSScript * js_script = (JSScript *)JS_GetPrivate(context, JSVAL_TO_OBJECT(compiled_js)); jsbytecode * pc = JS_LineNumberToPC(context, js_script, (uintN)NUM2INT(linenum)); return JS_SetTrap(context, js_script, pc, trap_handler, (void*)block) ? Qtrue : Qfalse; }
/* * call-seq: * to_s() * * Converts the JavaScript object to a string, using its toString method * if available. */ static VALUE to_s(VALUE self) { RubyLandProxy* proxy; Data_Get_Struct(self, RubyLandProxy, proxy); JSContext * context = johnson_get_current_context(proxy->runtime); PREPARE_RUBY_JROOTS(context, 1); jsval proxy_value; JCHECK(get_jsval_for_proxy(proxy, &proxy_value)); JROOT(proxy_value); JSString* str = JS_ValueToString(context, proxy_value); JRETURN_RUBY(CONVERT_JS_STRING_TO_RUBY(proxy->runtime, str)); }
VALUE convert_to_ruby(JohnsonRuntime* runtime, jsval js) { if (JSVAL_NULL == js) return Qnil; JSContext * context = johnson_get_current_context(runtime); PREPARE_RUBY_JROOTS(context, 1); JROOT(js); switch (JS_TypeOfValue(context, js)) { case JSTYPE_VOID: JRETURN_RUBY(Qnil); case JSTYPE_FUNCTION: case JSTYPE_OBJECT: if (OBJECT_TO_JSVAL(runtime->global) == js) // global gets special treatment, since the Prelude might not be loaded JRETURN_RUBY(make_ruby_land_proxy(runtime, js, "GlobalProxy")); // this conditional requires the Prelude if (js_value_is_symbol(runtime, js)) JRETURN_RUBY(ID2SYM(rb_intern(JS_GetStringBytes(JS_ValueToString(context, js))))); if (js_value_is_proxy(runtime, js)) JRETURN_RUBY(unwrap_js_land_proxy(runtime, js)); if (js_value_is_regexp(runtime, js)) JRETURN_RUBY(convert_regexp_to_ruby(runtime, js)); JRETURN_RUBY(make_ruby_land_proxy(runtime, js, "RubyLandProxy")); case JSTYPE_BOOLEAN: JRETURN_RUBY(JSVAL_TRUE == js ? Qtrue : Qfalse); case JSTYPE_STRING: JRETURN_RUBY(convert_js_string_to_ruby(runtime, JSVAL_TO_STRING(js))); case JSTYPE_NUMBER: if (JSVAL_IS_INT(js)) JRETURN_RUBY(INT2FIX(JSVAL_TO_INT(js))); else JRETURN_RUBY(rb_float_new(*JSVAL_TO_DOUBLE(js))); default: JERROR("unknown js type in switch"); } JRETURN_RUBY(Qnil); }
static JSBool convert_regexp_to_js(JohnsonRuntime* runtime, VALUE regexp, jsval* retval) { JSContext * context = johnson_get_current_context(runtime); PREPARE_JROOTS(context, 0); VALUE source = rb_funcall(regexp, rb_intern("source"), 0); jsint options = (jsint)(NUM2INT(rb_funcall(regexp, rb_intern("options"), 0))); JSObject* obj = JS_NewRegExpObject(context, StringValuePtr(source), (size_t) StringValueLen(source), (unsigned) options); JCHECK(obj); *retval = OBJECT_TO_JSVAL(obj); JRETURN; }
/* * call-seq: * debugger=(debugger) * * Sets a debugger object */ static VALUE set_debugger(VALUE self, VALUE debugger) { JohnsonRuntime* runtime; JSDebugHooks* debug_hooks; rb_iv_set(self, "@debugger", debugger); Data_Get_Struct(self, JohnsonRuntime, runtime); Data_Get_Struct(debugger, JSDebugHooks, debug_hooks); JSContext * context = johnson_get_current_context(runtime); JS_SetInterrupt( runtime->js, debug_hooks->interruptHandler, debug_hooks->interruptHandlerData); JS_SetNewScriptHook( runtime->js, debug_hooks->newScriptHook, debug_hooks->newScriptHookData); JS_SetDestroyScriptHook( runtime->js, debug_hooks->destroyScriptHook, debug_hooks->destroyScriptHookData); JS_SetDebuggerHandler( runtime->js, debug_hooks->debuggerHandler, debug_hooks->debuggerHandlerData); JS_SetSourceHandler( runtime->js, debug_hooks->sourceHandler, debug_hooks->sourceHandlerData); JS_SetExecuteHook( runtime->js, debug_hooks->executeHook, debug_hooks->executeHookData); JS_SetCallHook( runtime->js, debug_hooks->callHook, debug_hooks->callHookData); JS_SetObjectHook( runtime->js, debug_hooks->objectHook, debug_hooks->objectHookData); JS_SetThrowHook( runtime->js, debug_hooks->throwHook, debug_hooks->throwHookData); JS_SetDebugErrorHook( runtime->js, debug_hooks->debugErrorHook, debug_hooks->debugErrorHookData); JS_SetContextDebugHooks(context, debug_hooks); return debugger; }
static JSBool convert_symbol_to_js(JohnsonRuntime* runtime, VALUE symbol, jsval* retval) { JSContext * context = johnson_get_current_context(runtime); PREPARE_JROOTS(context, 2); VALUE to_s = CALL_RUBY_WRAPPER(rb_funcall_0, symbol, rb_intern("to_s"), 0); jsval name = STRING_TO_JSVAL(JS_NewStringCopyN(context, StringValuePtr(to_s), (size_t) StringValueLen(to_s))); JROOT(name); // calls Johnson.symbolize(name) in JS-land. See lib/prelude.js jsval nsJohnson; JCHECK(JS_GetProperty(context, runtime->global, "Johnson", &nsJohnson)); JROOT(nsJohnson); JCHECK(JS_CallFunctionName(context, JSVAL_TO_OBJECT(nsJohnson), "symbolize", 1, &name, retval)); JRETURN; }
VALUE make_ruby_land_proxy(JohnsonRuntime* runtime, jsval value, const char const* root_name) { RubyLandProxy * our_proxy = (RubyLandProxy *)JS_HashTableLookup(runtime->jsids, (void *)value); if (our_proxy) { // if we already have a proxy, return it return apply_conversions(our_proxy->self); } else { // otherwise make one and cache it VALUE proxy = Data_Make_Struct((strncmp(root_name, "JSScriptProxy", strlen("JSScriptProxy")) ? proxy_class : script_class), RubyLandProxy, 0, finalize, our_proxy); JSContext * context = johnson_get_current_context(runtime); PREPARE_RUBY_JROOTS(context, 1); JROOT(value); VALUE rb_runtime = (VALUE)JS_GetRuntimePrivate(runtime->js); rb_iv_set(proxy, "@runtime", rb_runtime); our_proxy->runtime = runtime; our_proxy->key = (void *)value; our_proxy->self = proxy; // root the value for JS GC and lookups JCHECK(JS_AddNamedRootRT(runtime->js, &(our_proxy->key), root_name)); // put the proxy OID in the id map JCHECK(JS_HashTableAdd(runtime->jsids, (void *)value, (void *)our_proxy)); VALUE final_proxy = JPROTECT(apply_wrappers, proxy); our_proxy->self = final_proxy; JRETURN_RUBY(JPROTECT(apply_conversions, final_proxy)); } }
/* * call-seq: * evaluate_compiled_script(script) * * Evaluate +script+ */ static VALUE evaluate_compiled_script(VALUE self, VALUE compiled_script) { JohnsonRuntime* runtime; Data_Get_Struct(self, JohnsonRuntime, runtime); JSContext * context = johnson_get_current_context(runtime); JohnsonContext * johnson_context = OUR_CONTEXT(context); // clean things up first johnson_context->ex = 0; memset(johnson_context->msg, 0, MAX_EXCEPTION_MESSAGE_SIZE); jsval compiled_js; if(!convert_to_js(runtime, compiled_script, &compiled_js)) rb_raise(rb_eRuntimeError, "Script compilation failed"); JSScript * js_script = (JSScript *)JS_GetPrivate(context, JSVAL_TO_OBJECT(compiled_js)); jsval js; JSBool ok = JS_ExecuteScript(context, runtime->global, js_script, &js); if (!ok) { if (JS_IsExceptionPending(context)) { // If there's an exception pending here, it's a syntax error. JS_GetPendingException(context, &johnson_context->ex); JS_ClearPendingException(context); } if (johnson_context->ex) { RAISE_JS_ERROR(self, johnson_context->ex); return Qnil; } } return convert_to_ruby(runtime, js); }
static bool js_value_is_symbol(JohnsonRuntime* runtime, jsval maybe_symbol) { jsval nsJohnson, cSymbol; JSContext * context = johnson_get_current_context(runtime); PREPARE_RUBY_JROOTS(context, 3); JROOT(maybe_symbol); JCHECK(JS_GetProperty(context, runtime->global, "Johnson", &nsJohnson)); if (!JSVAL_IS_OBJECT(nsJohnson)) JERROR("Unable to retrieve Johnson from JSLand"); JROOT(nsJohnson); JCHECK(JS_GetProperty(context, JSVAL_TO_OBJECT(nsJohnson), "Symbol", &cSymbol)); if (!JSVAL_IS_OBJECT(cSymbol)) JERROR("Unable to retrieve Johnson.Symbol from JSLand"); JROOT(cSymbol); JSBool is_a_symbol; JCHECK(JS_HasInstance(context, JSVAL_TO_OBJECT(cSymbol), maybe_symbol, &is_a_symbol)); JRETURN_RUBY(is_a_symbol != JS_FALSE); }
NORETURN(void) raise_js_error_in_ruby(JohnsonRuntime* runtime) { JSContext * context = johnson_get_current_context(runtime); JohnsonContext * johnson_context = OUR_CONTEXT(context); if (JS_IsExceptionPending(context)) { assert(JS_GetPendingException(context, &(johnson_context->ex))); JS_AddNamedRoot(context, &(johnson_context->ex), "raise_js_error_in_ruby"); JS_ClearPendingException(context); JS_RemoveRoot(context, &(johnson_context->ex)); } VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(runtime->js); if (johnson_context->ex) RAISE_JS_ERROR(ruby_runtime, johnson_context->ex); // FIXME: I don't think this is needed, it should // be done on the Ruby side. if (!johnson_context->msg) rb_raise(rb_eRuntimeError, "Unknown JavaScriptError"); // FIXME: I don't think this can ever happen.... rb_raise(rb_eRuntimeError, johnson_context->msg); }
static VALUE initialize_native(VALUE self, VALUE UNUSED(options)) { JohnsonRuntime* runtime; Data_Get_Struct(self, JohnsonRuntime, runtime); if ((runtime->js = JS_NewRuntime(0x100000)) && (runtime->jsids = create_id_hash()) && (runtime->rbids = create_id_hash()) ) { JS_SetRuntimePrivate(runtime->js, (void *)self); JS_SetGCCallbackRT(runtime->js, gc_callback); JSContext* context = johnson_get_current_context(runtime); if( (runtime->global = JS_GetGlobalObject(context)) && (JS_AddNamedRoot(context, &(runtime->global), "runtime->global")) ) { return self; } } if (runtime->rbids) JS_HashTableDestroy(runtime->rbids); if (runtime->jsids) JS_HashTableDestroy(runtime->jsids); if (runtime->js) JS_DestroyRuntime(runtime->js); rb_raise(rb_eRuntimeError, "Couldn't initialize the runtime!"); return Qnil; }
/* * call-seq: * native_compile(script, filename, linenum) * * Compile +script+ with +filename+ using +linenum+ */ static VALUE native_compile(VALUE self, VALUE script, VALUE filename, VALUE linenum) { JohnsonRuntime* runtime; Data_Get_Struct(self, JohnsonRuntime, runtime); JSContext * context = johnson_get_current_context(runtime); JohnsonContext * johnson_context = OUR_CONTEXT(context); JSScript * compiled_js = JS_CompileScript( context, runtime->global, StringValuePtr(script), (size_t)StringValueLen(script), StringValueCStr(filename), (unsigned)NUM2INT(linenum) ); if(compiled_js == NULL) { if (JS_IsExceptionPending(context)) { // If there's an exception pending here, it's a syntax error. JS_GetPendingException(context, &johnson_context->ex); JS_ClearPendingException(context); } if (johnson_context->ex) { RAISE_JS_ERROR(self, johnson_context->ex); return Qnil; } } JSObject * script_object = JS_NewScriptObject(context, compiled_js); PREPARE_RUBY_JROOTS(context, 1); JROOT(script_object); JRETURN_RUBY(make_ruby_land_proxy(runtime, OBJECT_TO_JSVAL(script_object), "JSScriptProxy")); }