JSContext* johnson_get_current_context(JohnsonRuntime * runtime) { JohnsonContext * context = NULL; VALUE self = (VALUE)JS_GetRuntimePrivate(runtime->js); Data_Get_Struct(rb_funcall(self, rb_intern("current_context"), 0), JohnsonContext, context); return context->js; }
static JSBool js_get_time_left(JSContext *cx, uintN argc, jsval *arglist) { JSObject *obj=JS_THIS_OBJECT(cx, arglist); jsval *argv=JS_ARGV(cx, arglist); private_t* p; int32 start_time=0; jsrefcount rc; scfg_t* scfg; scfg=JS_GetRuntimePrivate(JS_GetRuntime(cx)); JS_SET_RVAL(cx, arglist, JSVAL_VOID); if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) return JS_FALSE; if(argc) { if(!JS_ValueToInt32(cx, argv[0], &start_time)) return JS_FALSE; } rc=JS_SUSPENDREQUEST(cx); js_getuserdat(scfg,p); JS_SET_RVAL(cx, arglist, INT_TO_JSVAL((int32_t)gettimeleft(scfg, p->user, start_time))); JS_RESUMEREQUEST(cx, rc); return JS_TRUE; }
/* * call-seq: * runtime() * * Returns the Johnson::SpiderMonkey::Runtime against which this object * is registered. */ static VALUE runtime(VALUE self) { RubyLandProxy* proxy; Data_Get_Struct(self, RubyLandProxy, proxy); return (VALUE)JS_GetRuntimePrivate(proxy->runtime->js); }
/** * gjs_runtime_destroy: * @runtime: a #JSRuntime * * Calls JS_DestroyRuntime() on runtime and frees data allocated by * gjs_runtime_init(); these are unified into a single call because we * need to order things so that the allocated data is cleaned up * after JS_DestroyRuntime(). We might have finalizers run by * JS_DestroyRuntime() that rely on the information stored in the data, * such as the dynamic class structs. * * This should only be called by GJS, not by applications. */ void gjs_runtime_destroy(JSRuntime *runtime) { RuntimeData *rd; void *key; void *value; rd = JS_GetRuntimePrivate(runtime); if (rd->context_stack != NULL || rd->current_frame.depth != 0) gjs_fatal("gjs_runtime_destroy() called during gjs_push_context()"); gjs_debug(GJS_DEBUG_CONTEXT, "Destroying JS runtime"); JS_DestroyRuntime(runtime); gjs_debug(GJS_DEBUG_CONTEXT, "Destroying any remaining dataset items on runtime"); while (gjs_g_hash_table_remove_one(rd->dynamic_classes, &key, &value)) { JSClass *clasp = value; gjs_debug(GJS_DEBUG_GREPO, "Finalizing dynamic class '%s'", clasp->name); g_free( (char*) clasp->name); /* we know we malloc'd the char* even though it's const */ g_slice_free(DynamicJSClass, (DynamicJSClass*) clasp); } g_hash_table_destroy(rd->dynamic_classes); g_slice_free(RuntimeData, rd); }
static JSBool method_missing(JSContext* js_context, JSObject* obj, uintN argc, jsval* argv, jsval* retval) { VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context); JohnsonContext* context; JohnsonRuntime* runtime; Data_Get_Struct(ruby_context, JohnsonContext, context); VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context)); Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime); PREPARE_JROOTS(js_context, 0); VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL); assert(argc >= 2); char* key = JS_GetStringBytes(JSVAL_TO_STRING(argv[0])); VALUE ruby_id = rb_intern(key); // FIXME: this is horrible and lazy, to_a comes from enumerable on proxy (argv[1] is a JSArray) VALUE args; JCHECK(call_ruby_from_js2(runtime, &args, CONVERT_TO_RUBY(runtime, argv[1]), rb_intern("to_a"), 0)); JCHECK(call_ruby_from_js(runtime, retval, Johnson_SpiderMonkey_JSLandProxy(), rb_intern("send_with_possible_block"), 3, self, ID2SYM(ruby_id), args)); JRETURN; }
static JSBool js_posted_msg(JSContext *cx, uintN argc, jsval *arglist) { JSObject *obj=JS_THIS_OBJECT(cx, arglist); jsval *argv=JS_ARGV(cx, arglist); private_t* p; int32 count=1; jsrefcount rc; scfg_t* scfg; scfg=JS_GetRuntimePrivate(JS_GetRuntime(cx)); JS_SET_RVAL(cx, arglist, JSVAL_VOID); if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) return JS_FALSE; if(argc) { if(!JS_ValueToInt32(cx, argv[0], &count)) return JS_FALSE; } rc=JS_SUSPENDREQUEST(cx); js_getuserdat(scfg,p); JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(user_posted_msg(scfg, p->user, count))); JS_RESUMEREQUEST(cx, rc); return JS_TRUE; }
static JSBool call(JSContext* js_context, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* retval) { VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context); JohnsonContext* context; JohnsonRuntime* runtime; Data_Get_Struct(ruby_context, JohnsonContext, context); VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context)); Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime); PREPARE_JROOTS(js_context, 0); VALUE self = (VALUE)JS_GetInstancePrivate(context->js, JSVAL_TO_OBJECT(JS_ARGV_CALLEE(argv)), &JSLandCallableProxyClass, NULL); VALUE args = rb_ary_new(); uintN i; for (i = 0; i < argc; ++i) rb_ary_push(args, CONVERT_TO_RUBY(runtime, argv[i])); JCHECK(call_ruby_from_js(runtime, retval, Johnson_SpiderMonkey_JSLandProxy(), rb_intern("send_with_possible_block"), 3, self, ID2SYM(rb_intern("call")), args)); JRETURN; }
JSBool gc_callback(JSContext *context, JSGCStatus status) { if(status == JSGC_BEGIN) { VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(context)); if(rb_funcall(ruby_runtime, rb_intern("should_sm_gc?"), 0) == Qtrue) return JS_TRUE; } return JS_FALSE; }
static RuntimeData* get_data_from_runtime(JSRuntime *runtime) { RuntimeData *rd; rd = JS_GetRuntimePrivate(runtime); if (G_UNLIKELY(rd == NULL)) gjs_fatal("JSRuntime not initialized for use with GJS"); return rd; }
/* XXX FIXME: Iargv/Ienviron are now associated with running. */ rpmjs rpmjsNew(char ** av, uint32_t flags) { rpmjs js = #ifdef NOTYET (flags & 0x80000000) ? rpmjsI() : #endif rpmjsGetPool(_rpmjsPool); JSI_t I = NULL; #if defined(WITH_GPSEE) #if defined(XXX_GPSEE_DEBUGGER) /* XXX js->jsdc? */ JSDContext *jsdc; #endif if (flags == 0) flags = _rpmjs_options; if (F_ISSET(flags, NOUTF8) || getenv("GPSEE_NO_UTF8_C_STRINGS")) { JS_DestroyRuntime(JS_NewRuntime(1024)); putenv((char *) "GPSEE_NO_UTF8_C_STRINGS=1"); } /* XXX FIXME: js->Iargv/js->Ienviron for use by rpmjsRunFile() */ I = gpsee_createInterpreter(); #if defined(XXX_GPSEE_DEBUGGER) js->jsdc = gpsee_initDebugger(I->cx, I->realm, DEBUGGER_JS); #endif #ifdef NOTYET /* FIXME: dig out where NOCACHE has moved. */ if (F_ISSET(flags, NOCACHE)) I->useCompilerCache = 0; #endif if (F_ISSET(flags, NOWARN)) { gpsee_runtime_t * grt = JS_GetRuntimePrivate(JS_GetRuntime(I->cx)); grt->errorReport |= er_noWarnings; } JS_SetOptions(I->cx, (flags & 0xffff)); #if defined(JS_GC_ZEAL) JS_SetGCZeal(I->cx, _rpmjs_zeal); #endif #endif /* WITH_GPSEE */ js->flags = flags; js->I = I; return rpmjsLink(js); }
/** Deletes a single gpsee_addAsyncCallback() registration. You may call this function from within the callback closure * you are deleting, but not from within a different one. You must not call this function if you are not in the * JSContext associated with the callback you are removing. * * This call may traverse the entire linked list of registrations. Don't add and remove callbacks a lot. * * @param cx Current context; does not need to be a the context the callback was registered with. * @param cbHnd Handle for the callback we are deleting */ void gpsee_removeAsyncCallback(JSContext *cx, GPSEEAsyncCallback *cbHnd) { gpsee_runtime_t *grt = (gpsee_runtime_t *) JS_GetRuntimePrivate(JS_GetRuntime(cx)); GPSEEAsyncCallback *cb; /* Acquire mutex protecting grt->asyncCallbacks */ PR_Lock(grt->asyncCallbacks_lock); /* Locate the entry we want */ for (cb = grt->asyncCallbacks; cb && cb->next != cbHnd; cb = cb->next); /* Remove the entry from the linked list */ cb->next = cb->next->next; /* Relinquish mutex */ PR_Unlock(grt->asyncCallbacks_lock); /* Free the memory */ JS_free(cx, cbHnd); }
static JSBool to_array(JSContext* js_context, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* retval) { VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context); JohnsonContext* context; JohnsonRuntime* runtime; Data_Get_Struct(ruby_context, JohnsonContext, context); VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context)); Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime); PREPARE_JROOTS(js_context, 0); VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL); JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("to_a"), 0)); JRETURN; }
/** Deletes all async callbacks associated with the current context. Suitable for use as as JSContextCallback. * This is NOT SAFE to call from within an async callback. * You must not call this function if you are not in the JSContext associated with the * callback you are removing. This function is intended for being called during the finalization of a JSContext (ie. * during the context callback, gpsee_contextCallback().) * * @note This call may traverse the entire linked list of registrations. Don't add and remove callbacks a lot. * * @param cx The state of the JS context if used as a JSContextCallback. If calling directly, pass JSCONTEXT_DESTROY. * @param contextOp * @returns JS_TRUE * * @todo Investigate using gpsee_removeAsyncCallbackContext() to clean up async callbacks on context shutdown. */ JSBool gpsee_removeAsyncCallbackContext(JSContext *cx, uintN contextOp) { gpsee_runtime_t *grt = (gpsee_runtime_t *) JS_GetRuntimePrivate(JS_GetRuntime(cx)); GPSEEAsyncCallback **cb, **cc, *freeme = NULL; #ifdef GPSEE_DEBUG_BUILD /* Assert that cx is on current thread */ JS_BeginRequest(cx); JS_EndRequest(cx); #endif if (contextOp != JSCONTEXT_DESTROY) return JS_TRUE; if (!grt->asyncCallbacks) return JS_TRUE; /* Acquire mutex protecting grt->asyncCallbacks */ PR_Lock(grt->asyncCallbacks_lock); /* Locate the first entry we want to remove */ for (cb = &grt->asyncCallbacks; *cb && (*cb)->cx != cx; cb = &(*cb)->next); if (*cb) { freeme = *cb; /* Locate the final entry we want remove */ for (cc = cb; *cc && (*cc)->cx == cx; cc = &(*cc)->next); /* Remove all the entries we grabbed */ *cb = *cc; } /* Relinquish mutex */ PR_Unlock(grt->asyncCallbacks_lock); /* Free the memory */ while (freeme) { GPSEEAsyncCallback *next = freeme->next; JS_free(cx, freeme); /* Break at end of removed segment */ if (&freeme->next == cc) break; freeme = next; } return JS_TRUE; }
/** * gjs_runtime_init: * @runtime: a #JSRuntime * * Initializes a #JSRuntime for use with GJS * * This should only be called by GJS, not by applications. */ void gjs_runtime_init(JSRuntime *runtime) { RuntimeData *rd; /* If we went back to supporting foreign contexts, we couldn't use * JS_SetRuntimePrivate() because the runtime's owner might * already be using it. A simple solution would be to just store * the runtime data in a global variable - multiple copies of GJS * in the same process at the same time have issues anyways * because of limitations of GObject toggle references - if two * separate entities toggle reference an object it will leak. */ if (JS_GetRuntimePrivate(runtime) != NULL) gjs_fatal("JSRuntime already initialized or private data in use by someone else"); rd = g_slice_new0(RuntimeData); rd->dynamic_classes = g_hash_table_new(g_direct_hash, g_direct_equal); JS_SetRuntimePrivate(runtime, rd); }
static gpsee_realm_t *getRealm(JSContext *cx) { JSObject *global = JS_GetGlobalObject(cx); gpsee_runtime_t *grt; gpsee_realm_t *realm = NULL; if ((realm = gpsee_getModuleScopeRealm(cx, NULL))) return realm; grt = JS_GetRuntimePrivate(JS_GetRuntime(cx)); gpsee_enterAutoMonitor(cx, &grt->monitors.realms); if (grt && grt->realmsByContext) realm = gpsee_ds_get(grt->realmsByContext, cx); gpsee_leaveAutoMonitor(grt->monitors.realms); if (global && JS_GET_CLASS(cx, global) == gpsee_getGlobalClass()) GPSEE_ASSERT(realm); return realm; }
/** Our "Operation Callback" multiplexes this Spidermonkey facility. It is called automatically by Spidermonkey, and is * triggered on a regular interval by gpsee_asyncCallbackTriggerThreadFunc() */ JSBool gpsee_operationCallback(JSContext *cx) { gpsee_runtime_t *grt = (gpsee_runtime_t *) JS_GetRuntimePrivate(JS_GetRuntime(cx)); GPSEEAsyncCallback *cb; /* The callbacks registered with GPSEE may want to invoke JSAPI functionality, which might toss us back out * to another invocation of gpsee_operationCallback(). The JSAPI docs for "operation callbacks" [1] suggest * removing the operation callback before calling JSAPI functionality from within an operation callback, * then resetting it when we're done making JSAPI calls. Since it's rather inexpensive, we'll just do it here * and then consumers of gpsee_addAsyncCallback() needn't worry about it (we don't want them touching that * callback slot anyway! * * [1] https://developer.mozilla.org/en/JS_SetOperationCallback * * Another side note: we do it before if(cb) because if gpsee_asyncCallbacks is empty, we want to uninstall our * operation callback altogether. */ JS_SetOperationCallback(cx, NULL); cb = grt->asyncCallbacks; if (cb) { GPSEEAsyncCallback *next; do { /* Save the 'next' link in case the callback deletes itself */ next = cb->next; /* Invoke callback */ if (!((*(cb->callback))(cb->cx, cb->userdata, cb))) /* Propagate exceptions */ return JS_FALSE; } while ((cb = next)); /* Reinstall our operation callback */ JS_SetOperationCallback(cx, gpsee_operationCallback); return JS_TRUE; } return JS_TRUE; }
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)); } }
/** Registers a closure of the form callback(cx, userdata) to be called by Spidermonkey's Operation Callback API. * You must *NEVER* call this function from *within* a callback function which has been registered with this facility! * The punishment might just be deadlock! Don't call this function from a different thread/JSContext than the one that * that you're associating the callback with. * * This call may traverse the entire linked list of registrations. Don't add and remove callbacks a lot! * * @returns A pointer that can be used to delete the callback registration at a later time, or NULL on error. */ GPSEEAsyncCallback *gpsee_addAsyncCallback(JSContext *cx, GPSEEAsyncCallbackFunction callback, void *userdata) { gpsee_runtime_t *grt = (gpsee_runtime_t *) JS_GetRuntimePrivate(JS_GetRuntime(cx)); GPSEEAsyncCallback *newcb, **pp; /* Allocate the new callback entry struct */ newcb = JS_malloc(cx, sizeof(GPSEEAsyncCallback)); if (!newcb) { JS_ReportOutOfMemory(cx); return NULL; } /* Initialize the new callback entry struct (except 'next' member, which gets set while we have a lock on the list) */ newcb->callback = callback; newcb->userdata = userdata; newcb->cx = cx; /* Acquire mutex protecting grt->asyncCallbacks */ PR_Lock(grt->asyncCallbacks_lock); /* Insert the new callback into the list */ /* Locate a sorted insertion point into the linked list; sort by 'cx' member */ for (pp = &grt->asyncCallbacks; *pp && (*pp)->cx > cx; pp = &(*pp)->next); /* Insert! */ newcb->next = *pp; *pp = newcb; /* Relinquish mutex */ PR_Unlock(grt->asyncCallbacks_lock); /* If this is the first time this context has had a callback registered, we must register a context callback to clean * up all callbacks associated with this context. Note that we don't want to do this for the primordial context, but * it's a moot point because gpsee_maybeGC() is registered soon after context instantiation and should never be * removed until just before context finalization, anyway. */ if (!newcb->next || newcb->next->cx != cx) gpsee_getContextPrivate(cx, &grt->asyncCallbacks, 0, gpsee_removeAsyncCallbackContext); /* Return a pointer to the new callback entry struct */ return newcb; }
static void finalize(JSContext* js_context, JSObject* obj) { VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context); if (ruby_context) { JohnsonContext* context; JohnsonRuntime* runtime; Data_Get_Struct(ruby_context, JohnsonContext, context); VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context)); Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime); VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL); // remove the proxy OID from the id map JS_HashTableRemove(runtime->rbids, (void *)self); // free up the ruby value for GC rb_funcall(ruby_runtime, rb_intern("remove_gcthing"), 1, rb_obj_id(self)); } }
static JSBool js_user_constructor(JSContext *cx, uintN argc, jsval *arglist) { JSObject *obj; jsval *argv=JS_ARGV(cx, arglist); int i; int32 val=0; user_t user; private_t* p; scfg_t* scfg; scfg=JS_GetRuntimePrivate(JS_GetRuntime(cx)); obj=JS_NewObject(cx, &js_user_class, NULL, NULL); JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(obj)); if(argc && (!JS_ValueToInt32(cx,argv[0],&val))) return JS_FALSE; user.number=(ushort)val; if(user.number!=0 && (i=getuserdat(scfg,&user))!=0) { JS_ReportError(cx,"Error %d reading user number %d",i,val); return(JS_FALSE); } if((p=(private_t*)malloc(sizeof(private_t)))==NULL) return(JS_FALSE); memset(p,0,sizeof(private_t)); p->storage = user; p->user = &p->storage; p->cached = (user.number==0 ? FALSE : TRUE); JS_SetPrivate(cx, obj, p); return(JS_TRUE); }
static JSBool js_chk_ar(JSContext *cx, uintN argc, jsval *arglist) { JSObject *obj=JS_THIS_OBJECT(cx, arglist); jsval *argv=JS_ARGV(cx, arglist); uchar* ar; private_t* p; jsrefcount rc; char *ars; scfg_t* scfg; scfg=JS_GetRuntimePrivate(JS_GetRuntime(cx)); JS_SET_RVAL(cx, arglist, JSVAL_VOID); if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) return JS_FALSE; JSVALUE_TO_MSTRING(cx,argv[0], ars, NULL); HANDLE_PENDING(cx); if(ars==NULL) return JS_FALSE; rc=JS_SUSPENDREQUEST(cx); ar = arstr(NULL,ars,scfg); free(ars); js_getuserdat(scfg,p); JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(chk_ar(scfg,ar,p->user,p->client))); if(ar!=NULL && ar!=nular) free(ar); JS_RESUMEREQUEST(cx, rc); return JS_TRUE; }
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 JSBool set(JSContext* js_context, JSObject* obj, jsval id, jsval* value) { VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context); JohnsonContext* context; JohnsonRuntime* runtime; Data_Get_Struct(ruby_context, JohnsonContext, context); VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context)); Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime); PREPARE_JROOTS(js_context, 2); JROOT(id); JROOT_PTR(value); VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL); // Short-circuit for numeric indexes if (JSVAL_IS_INT(id)) { if (indexable_p(self)) { VALUE idx = INT2FIX(JSVAL_TO_INT(id)); VALUE val = CONVERT_TO_RUBY(runtime, *value); JCHECK(call_ruby_from_js(runtime, NULL, self, rb_intern("[]="), 2, idx, val)); } JRETURN; } VALUE ruby_key = CONVERT_TO_RUBY(runtime, id); VALUE ruby_value = CONVERT_TO_RUBY(runtime, *value); VALUE setter = rb_str_append(rb_str_new3(ruby_key), rb_str_new2("=")); VALUE setter_id = rb_intern(StringValueCStr(setter)); VALUE settable_p, indexable_p; JCHECK(call_ruby_from_js2(runtime, &settable_p, self, rb_intern("respond_to?"), 1, ID2SYM(setter_id))); JCHECK(call_ruby_from_js2(runtime, &indexable_p, self, rb_intern("respond_to?"), 1, ID2SYM(rb_intern("[]=")))); if (settable_p) { VALUE method, arity; JCHECK(call_ruby_from_js2(runtime, &method, self, rb_intern("method"), 1, ID2SYM(setter_id))); JCHECK(call_ruby_from_js2(runtime, &arity, method, rb_intern("arity"), 0)); // if the Ruby object has a 1-arity method named "property=", // call it with the converted value if (NUM2INT(arity) == 1) JCHECK(call_ruby_from_js(runtime, NULL, self, setter_id, 1, ruby_value)); } else if(indexable_p) { // otherwise, if the Ruby object quacks sorta like a hash for assignment // (it responds to "[]="), assign it by key JCHECK(call_ruby_from_js(runtime, NULL, self, rb_intern("[]="), 2, ruby_key, ruby_value)); } else { JCHECK(call_ruby_from_js(runtime, NULL, Johnson_SpiderMonkey_JSLandProxy(), rb_intern("autovivify"), 3, self, ruby_key, ruby_value)); } JRETURN; }
/** Process the script interpreter flags. * * @param flags An array of flags, in no particular order. */ static void processFlags(JSContext *cx, const char *flags, signed int *verbosity_p) { int gcZeal = 0; int jsOptions; const char *f; gpsee_runtime_t *grt = JS_GetRuntimePrivate(JS_GetRuntime(cx)); jsOptions = JS_GetOptions(cx) | JSOPTION_ANONFUNFIX | JSOPTION_STRICT | JSOPTION_RELIMIT | JSOPTION_JIT; *verbosity_p = 0; /* Iterate over each flag */ for (f=flags; *f; f++) { switch(*f) { /* 'C' flag disables compiler cache */ case 'C': grt->useCompilerCache = 0; break; case 'a': /* Handled in prmain() */ case 'R': /* Handled in loadRuntimeConfig() */ case 'U': /* Must be handled before 1st JS runtime */ break; case 'x': /* Parse <!-- comments --> as E4X tokens */ jsOptions |= JSOPTION_XML; break; case 'S': /* Disable Strict JS */ jsOptions &= ~JSOPTION_STRICT; break; case 'W': /* Suppress JS Warnings */ grt->errorReport |= er_noWarnings; break; case 'e': /* Allow regexps that are more than O(n^3) */ jsOptions &= ~JSOPTION_RELIMIT; break; case 'J': /* Disable Nanojit */ jsOptions &= ~JSOPTION_JIT; break; case 'z': /* GC Zeal */ gcZeal++; break; case 'd': /* increase debug level */ (*verbosity_p)++;; break; default: gpsee_log(cx, GLOG_WARNING, "Error: Unrecognized option flag %c!", *f); break; } } #ifdef JSFEATURE_GC_ZEAL if (JS_HasFeature(JSFEATURE_GC_ZEAL) == JS_TRUE) JS_SetGCZeal(cx, gcZeal); #else # ifdef JS_GC_ZEAL JS_SetGCZeal(cx, gcZeal); # else # warning JS_SetGCZeal not available when building with this version of SpiderMonkey (try a debug build?) # endif #endif JS_SetOptions(cx, jsOptions); }
static JSBool js_user_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) { jsval idval; char* str; char tmp[64]; jsint val; ulong usermisc; jsint tiny; private_t* p; int32 usernumber; jsrefcount rc; scfg_t* scfg; scfg=JS_GetRuntimePrivate(JS_GetRuntime(cx)); if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) return(JS_TRUE); JSVALUE_TO_MSTRING(cx, *vp, str, NULL); HANDLE_PENDING(cx); if(str==NULL) return(JS_FALSE); JS_IdToValue(cx, id, &idval); tiny = JSVAL_TO_INT(idval); rc=JS_SUSPENDREQUEST(cx); switch(tiny) { case USER_PROP_NUMBER: JS_RESUMEREQUEST(cx, rc); if(!JS_ValueToInt32(cx, *vp, &usernumber)) { free(str); return JS_FALSE; } rc=JS_SUSPENDREQUEST(cx); if(usernumber!=p->user->number) { p->user->number=(ushort)usernumber; p->cached=FALSE; } break; case USER_PROP_ALIAS: SAFECOPY(p->user->alias,str); /* update USER.DAT */ putuserrec(scfg,p->user->number,U_ALIAS,LEN_ALIAS,str); /* update NAME.DAT */ getuserrec(scfg,p->user->number,U_MISC,8,tmp); usermisc=ahtoul(tmp); if(!(usermisc&DELETED)) putusername(scfg,p->user->number,str); break; case USER_PROP_NAME: SAFECOPY(p->user->name,str); putuserrec(scfg,p->user->number,U_NAME,LEN_NAME,str); break; case USER_PROP_HANDLE: SAFECOPY(p->user->handle,str); putuserrec(scfg,p->user->number,U_HANDLE,LEN_HANDLE,str); break; case USER_PROP_NOTE: SAFECOPY(p->user->note,str); putuserrec(scfg,p->user->number,U_NOTE,LEN_NOTE,str); break; case USER_PROP_COMP: SAFECOPY(p->user->comp,str); putuserrec(scfg,p->user->number,U_COMP,LEN_COMP,str); break; case USER_PROP_COMMENT: SAFECOPY(p->user->comment,str); putuserrec(scfg,p->user->number,U_COMMENT,LEN_COMMENT,str); break; case USER_PROP_NETMAIL: SAFECOPY(p->user->netmail,str); putuserrec(scfg,p->user->number,U_NETMAIL,LEN_NETMAIL,str); break; case USER_PROP_ADDRESS: SAFECOPY(p->user->address,str); putuserrec(scfg,p->user->number,U_ADDRESS,LEN_ADDRESS,str); break; case USER_PROP_LOCATION: SAFECOPY(p->user->location,str); putuserrec(scfg,p->user->number,U_LOCATION,LEN_LOCATION,str); break; case USER_PROP_ZIPCODE: SAFECOPY(p->user->zipcode,str); putuserrec(scfg,p->user->number,U_ZIPCODE,LEN_ZIPCODE,str); break; case USER_PROP_PHONE: SAFECOPY(p->user->phone,str); putuserrec(scfg,p->user->number,U_PHONE,LEN_PHONE,str); break; case USER_PROP_BIRTH: SAFECOPY(p->user->birth,str); putuserrec(scfg,p->user->number,U_BIRTH,LEN_BIRTH,str); break; case USER_PROP_MODEM: SAFECOPY(p->user->modem,str); putuserrec(scfg,p->user->number,U_MODEM,LEN_MODEM,str); break; case USER_PROP_ROWS: p->user->rows=atoi(str); putuserrec(scfg,p->user->number,U_ROWS,0,str); /* base 10 */ break; case USER_PROP_SEX: p->user->sex=toupper(str[0]); putuserrec(scfg,p->user->number,U_SEX,0,strupr(str)); /* single char */ break; case USER_PROP_CURSUB: SAFECOPY(p->user->cursub,str); putuserrec(scfg,p->user->number,U_CURSUB,0,str); break; case USER_PROP_CURDIR: SAFECOPY(p->user->curdir,str); putuserrec(scfg,p->user->number,U_CURDIR,0,str); break; case USER_PROP_CURXTRN: SAFECOPY(p->user->curxtrn,str); putuserrec(scfg,p->user->number,U_CURXTRN,0,str); break; case USER_PROP_XEDIT: putuserrec(scfg,p->user->number,U_XEDIT,0,str); break; case USER_PROP_SHELL: putuserrec(scfg,p->user->number,U_SHELL,0,str); break; case USER_PROP_MISC: JS_RESUMEREQUEST(cx, rc); if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } putuserrec(scfg,p->user->number,U_MISC,0,ultoa(p->user->misc=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_QWK: JS_RESUMEREQUEST(cx, rc); if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } putuserrec(scfg,p->user->number,U_QWK,0,ultoa(p->user->qwk=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_CHAT: JS_RESUMEREQUEST(cx, rc); if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } putuserrec(scfg,p->user->number,U_CHAT,0,ultoa(p->user->chat=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_TMPEXT: SAFECOPY(p->user->tmpext,str); putuserrec(scfg,p->user->number,U_TMPEXT,0,str); break; case USER_PROP_NS_TIME: JS_RESUMEREQUEST(cx, rc); if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } putuserrec(scfg,p->user->number,U_NS_TIME,0,ultoa((ulong)(p->user->ns_time=val),tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_PROT: p->user->prot=toupper(str[0]); putuserrec(scfg,p->user->number,U_PROT,0,strupr(str)); /* single char */ break; case USER_PROP_LOGONTIME: JS_RESUMEREQUEST(cx, rc); if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } putuserrec(scfg,p->user->number,U_LOGONTIME,0,ultoa(p->user->logontime=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; /* security properties*/ case USER_PROP_PASS: SAFECOPY(p->user->pass,str); putuserrec(scfg,p->user->number,U_PASS,LEN_PASS,strupr(str)); break; case USER_PROP_PWMOD: JS_RESUMEREQUEST(cx, rc); if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } putuserrec(scfg,p->user->number,U_PWMOD,0,ultoa(p->user->pwmod=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_LEVEL: p->user->level=atoi(str); putuserrec(scfg,p->user->number,U_LEVEL,0,str); break; case USER_PROP_FLAGS1: JS_RESUMEREQUEST(cx, rc); if(JSVAL_IS_STRING(*vp)) { val=str_to_bits(p->user->flags1, str); } else { if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } } putuserrec(scfg,p->user->number,U_FLAGS1,0,ultoa(p->user->flags1=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_FLAGS2: JS_RESUMEREQUEST(cx, rc); if(JSVAL_IS_STRING(*vp)) { val=str_to_bits(p->user->flags1, str); } else { if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } } putuserrec(scfg,p->user->number,U_FLAGS2,0,ultoa(p->user->flags2=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_FLAGS3: JS_RESUMEREQUEST(cx, rc); if(JSVAL_IS_STRING(*vp)) { val=str_to_bits(p->user->flags1, str); } else { if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } } putuserrec(scfg,p->user->number,U_FLAGS3,0,ultoa(p->user->flags3=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_FLAGS4: JS_RESUMEREQUEST(cx, rc); if(JSVAL_IS_STRING(*vp)) { val=str_to_bits(p->user->flags1, str); } else { if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } } putuserrec(scfg,p->user->number,U_FLAGS4,0,ultoa(p->user->flags4=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_EXEMPT: JS_RESUMEREQUEST(cx, rc); if(JSVAL_IS_STRING(*vp)) { val=str_to_bits(p->user->flags1, str); } else { if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } } putuserrec(scfg,p->user->number,U_EXEMPT,0,ultoa(p->user->exempt=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_REST: JS_RESUMEREQUEST(cx, rc); if(JSVAL_IS_STRING(*vp)) { val=str_to_bits(p->user->flags1, str); } else { if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } } putuserrec(scfg,p->user->number,U_REST,0,ultoa(p->user->rest=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_CDT: p->user->cdt=strtoul(str,NULL,0); putuserrec(scfg,p->user->number,U_CDT,0,str); break; case USER_PROP_FREECDT: p->user->freecdt=strtoul(str,NULL,0); putuserrec(scfg,p->user->number,U_FREECDT,0,str); break; case USER_PROP_MIN: p->user->min=strtoul(str,NULL,0); putuserrec(scfg,p->user->number,U_MIN,0,str); break; case USER_PROP_TEXTRA: p->user->textra=(ushort)strtoul(str,NULL,0); putuserrec(scfg,p->user->number,U_TEXTRA,0,str); break; case USER_PROP_EXPIRE: JS_RESUMEREQUEST(cx, rc); if(!JS_ValueToInt32(cx,*vp,&val)) { free(str); return JS_FALSE; } putuserrec(scfg,p->user->number,U_EXPIRE,0,ultoa(p->user->expire=val,tmp,16)); rc=JS_SUSPENDREQUEST(cx); break; case USER_PROP_CACHED: JS_ValueToBoolean(cx, *vp, &p->cached); JS_RESUMEREQUEST(cx, rc); free(str); return(JS_TRUE); /* intentional early return */ } free(str); if(!(p->user->rest&FLAG('G'))) p->cached=FALSE; JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); }
static JSBool get(JSContext* js_context, JSObject* obj, jsval id, jsval* retval) { // pull out our Ruby context, which is embedded in js_context VALUE ruby_context = (VALUE)JS_GetContextPrivate(js_context); // get our struct, which is embedded in ruby_context JohnsonContext* context; JohnsonRuntime* runtime; Data_Get_Struct(ruby_context, JohnsonContext, context); VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(JS_GetRuntime(js_context)); Data_Get_Struct(ruby_runtime, JohnsonRuntime, runtime); PREPARE_JROOTS(js_context, 1); JROOT(id); // get the Ruby object that backs this proxy VALUE self = (VALUE)JS_GetInstancePrivate(context->js, obj, JS_GET_CLASS(context->js, obj), NULL); // Short-circuit for numeric indexes if (JSVAL_IS_INT(id)) { if (indexable_p(self)) { VALUE idx = INT2FIX(JSVAL_TO_INT(id)); JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("[]"), 1, idx)); } JRETURN; } char* name = JS_GetStringBytes(JSVAL_TO_STRING(id)); VALUE ruby_id = rb_intern(name); // FIXME: we should probably just JS_DefineProperty this, and it shouldn't be enumerable if (!strcasecmp("__iterator__", name)) { JCHECK(evaluate_js_property_expression(runtime, "Johnson.Generator.create", retval)); } // if the Ruby object has a dynamic js property with a key // matching the property we're looking for, pull the value out of // that map. else if (autovivified_p(ruby_context, self, name)) { JCHECK(call_ruby_from_js(runtime, retval, Johnson_SpiderMonkey_JSLandProxy(), rb_intern("autovivified"), 2, self, rb_str_new2(name))); } // if the Ruby object is a Module or Class and has a matching // const defined, return the converted result of const_get else if (const_p(self, name)) { JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("const_get"), 1, ID2SYM(ruby_id))); } // otherwise, if it's a global, return the global else if (global_p(name)) { JCHECK(convert_to_js(runtime, rb_gv_get(name), retval)); } // otherwise, if the Ruby object has a an attribute method matching // the property we're trying to get, call it and return the converted result else if (attribute_p(self, name)) { JCHECK(call_ruby_from_js(runtime, retval, self, ruby_id, 0)); } // otherwise, if the Ruby object quacks sorta like a hash (it responds to // "[]" and "key?"), index it by key and return the converted result else if (has_key_p(self, name)) { JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("[]"), 1, rb_str_new2(name))); } // otherwise, it's a method being accessed as a property, which means // we need to return a lambda // FIXME: this should really wrap the Method for 'name' in a JS class // rather than generating a wrapper Proc else if (method_p(self, name)) { JCHECK(call_ruby_from_js(runtime, retval, self, rb_intern("method"), 1, rb_str_new2(name))); } // else it's undefined (JS_VOID) by default JRETURN; }
static JSBool js_user_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { jsval idval; char* s=NULL; char tmp[128]; uint64_t val=0; jsint tiny; JSString* js_str; private_t* p; jsrefcount rc; scfg_t* scfg; scfg=JS_GetRuntimePrivate(JS_GetRuntime(cx)); if((p=(private_t*)JS_GetPrivate(cx,obj))==NULL) return(JS_TRUE); rc=JS_SUSPENDREQUEST(cx); js_getuserdat(scfg,p); JS_IdToValue(cx, id, &idval); tiny = JSVAL_TO_INT(idval); switch(tiny) { case USER_PROP_NUMBER: val=p->user->number; break; case USER_PROP_ALIAS: s=p->user->alias; break; case USER_PROP_NAME: s=p->user->name; break; case USER_PROP_HANDLE: s=p->user->handle; break; case USER_PROP_NOTE: s=p->user->note; break; case USER_PROP_COMP: s=p->user->comp; break; case USER_PROP_COMMENT: s=p->user->comment; break; case USER_PROP_NETMAIL: s=p->user->netmail; break; case USER_PROP_EMAIL: s=usermailaddr(scfg, tmp ,scfg->inetmail_misc&NMAIL_ALIAS ? p->user->alias : p->user->name); break; case USER_PROP_ADDRESS: s=p->user->address; break; case USER_PROP_LOCATION: s=p->user->location; break; case USER_PROP_ZIPCODE: s=p->user->zipcode; break; case USER_PROP_PASS: s=p->user->pass; break; case USER_PROP_PHONE: s=p->user->phone; break; case USER_PROP_BIRTH: s=p->user->birth; break; case USER_PROP_AGE: val=getage(scfg,p->user->birth); break; case USER_PROP_MODEM: s=p->user->modem; break; case USER_PROP_LASTON: val=p->user->laston; break; case USER_PROP_FIRSTON: val=p->user->firston; break; case USER_PROP_EXPIRE: val=p->user->expire; break; case USER_PROP_PWMOD: val=p->user->pwmod; break; case USER_PROP_LOGONS: val=p->user->logons; break; case USER_PROP_LTODAY: val=p->user->ltoday; break; case USER_PROP_TIMEON: val=p->user->timeon; break; case USER_PROP_TEXTRA: val=p->user->textra; break; case USER_PROP_TTODAY: val=p->user->ttoday; break; case USER_PROP_TLAST: val=p->user->tlast; break; case USER_PROP_POSTS: val=p->user->posts; break; case USER_PROP_EMAILS: val=p->user->emails; break; case USER_PROP_FBACKS: val=p->user->fbacks; break; case USER_PROP_ETODAY: val=p->user->etoday; break; case USER_PROP_PTODAY: val=p->user->ptoday; break; case USER_PROP_ULB: val=p->user->ulb; break; case USER_PROP_ULS: val=p->user->uls; break; case USER_PROP_DLB: val=p->user->dlb; break; case USER_PROP_DLS: val=p->user->dls; break; case USER_PROP_CDT: val=p->user->cdt; break; case USER_PROP_MIN: val=p->user->min; break; case USER_PROP_LEVEL: val=p->user->level; break; case USER_PROP_FLAGS1: val=p->user->flags1; break; case USER_PROP_FLAGS2: val=p->user->flags2; break; case USER_PROP_FLAGS3: val=p->user->flags3; break; case USER_PROP_FLAGS4: val=p->user->flags4; break; case USER_PROP_EXEMPT: val=p->user->exempt; break; case USER_PROP_REST: val=p->user->rest; break; case USER_PROP_ROWS: val=p->user->rows; break; case USER_PROP_SEX: sprintf(tmp,"%c",p->user->sex); s=tmp; break; case USER_PROP_MISC: val=p->user->misc; break; case USER_PROP_LEECH: val=p->user->leech; break; case USER_PROP_CURSUB: s=p->user->cursub; break; case USER_PROP_CURDIR: s=p->user->curdir; break; case USER_PROP_CURXTRN: s=p->user->curxtrn; break; case USER_PROP_FREECDT: val=p->user->freecdt; break; case USER_PROP_XEDIT: if(p->user->xedit>0 && p->user->xedit<=scfg->total_xedits) s=scfg->xedit[p->user->xedit-1]->code; else s=""; /* internal editor */ break; case USER_PROP_SHELL: s=scfg->shell[p->user->shell]->code; break; case USER_PROP_QWK: val=p->user->qwk; break; case USER_PROP_TMPEXT: s=p->user->tmpext; break; case USER_PROP_CHAT: val=p->user->chat; break; case USER_PROP_NS_TIME: val=p->user->ns_time; break; case USER_PROP_PROT: sprintf(tmp,"%c",p->user->prot); s=tmp; break; case USER_PROP_LOGONTIME: val=p->user->logontime; break; case USER_PROP_TIMEPERCALL: val=scfg->level_timepercall[p->user->level]; break; case USER_PROP_TIMEPERDAY: val=scfg->level_timeperday[p->user->level]; break; case USER_PROP_CALLSPERDAY: val=scfg->level_callsperday[p->user->level]; break; case USER_PROP_LINESPERMSG: val=scfg->level_linespermsg[p->user->level]; break; case USER_PROP_POSTSPERDAY: val=scfg->level_postsperday[p->user->level]; break; case USER_PROP_EMAILPERDAY: val=scfg->level_emailperday[p->user->level]; break; case USER_PROP_FREECDTPERDAY: val=scfg->level_freecdtperday[p->user->level]; break; case USER_PROP_MAIL_WAITING: val=getmail(scfg,p->user->number,/* sent? */FALSE); break; case USER_PROP_MAIL_PENDING: val=getmail(scfg,p->user->number,/* sent? */TRUE); break; case USER_PROP_CACHED: *vp = BOOLEAN_TO_JSVAL(p->cached); JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); /* intentional early return */ case USER_PROP_IS_SYSOP: *vp = BOOLEAN_TO_JSVAL(p->user->level >= SYSOP_LEVEL); JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); /* intentional early return */ default: /* This must not set vp in order for child objects to work (stats and security) */ JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } JS_RESUMEREQUEST(cx, rc); if(s!=NULL) { if((js_str=JS_NewStringCopyZ(cx, s))==NULL) return(JS_FALSE); *vp = STRING_TO_JSVAL(js_str); } else *vp=DOUBLE_TO_JSVAL((double)val); return(JS_TRUE); }
/** Error Reporter for Spidermonkey. Used to report warnings and * uncaught exceptions. */ void gpsee_errorReporter(JSContext *cx, const char *message, JSErrorReport *report) { const char *ctmp; char er_filename[64]; char er_exception[16]; char er_warning[16]; char er_number[16]; char er_lineno[16]; char er_charno[16]; char er_pfx[64]; gpsee_runtime_t *grt = JS_GetRuntimePrivate(JS_GetRuntime(cx)); int printOnTTY = 0; if (grt->errorReport == er_none) return; if (!report) { gpsee_log(cx, GLOG_NOTICE, "JS error from unknown source: %s\n", message); return; } /* Conditionally ignore reported warnings. */ if (JSREPORT_IS_WARNING(report->flags)) { if (grt->errorReport & er_noWarnings) return; if (cfg_bool_value(cfg, "gpsee_report_warnings") == cfg_false) return; if (gpsee_verbosity(0) >= GPSEE_WARNING_OUTPUT_VERBOSITY) printOnTTY = 1 && gpsee_isatty(STDERR_FILENO); } else if (gpsee_verbosity(0) >= GPSEE_ERROR_OUTPUT_VERBOSITY) printOnTTY = 1 && gpsee_isatty(STDERR_FILENO); if (report->filename) { const char *bn = strrchr(report->filename, '/'); if (bn) bn += 1; else bn = report->filename; snprintf(er_filename, sizeof(er_filename), "in %s ", bn); } else er_filename[0] = (char)0; if (report->lineno) snprintf(er_lineno, sizeof(er_lineno), "line %u ", report->lineno); else er_lineno[0] = (char)0; if (report->tokenptr && report->linebuf) snprintf(er_charno, sizeof(er_charno), "ch %ld ", (long int)(report->tokenptr - report->linebuf)); else er_charno[0] = (char)0; er_warning[0] = (char)0; if (JSREPORT_IS_EXCEPTION(report->flags)) { snprintf(er_exception, sizeof(er_exception), "exception "); if (!grt->exitType) grt->exitType = et_exception; } else { er_exception[0] = (char)0; if (JSREPORT_IS_WARNING(report->flags)) snprintf(er_warning, sizeof(er_warning), "%swarning ", (JSREPORT_IS_STRICT(report->flags) ? "strict " : "")); } if (report->errorNumber) snprintf(er_number, sizeof(er_number), "#%i ", report->errorNumber); else er_number[0] = (char)0; snprintf(er_pfx, sizeof(er_pfx), "JS %s%s%s%s" "%s" "%s%s%s" "-", er_warning, er_exception, ((er_exception[0] || er_warning[0]) ? "" : "error "), er_number, /* error 69 */ er_filename, /* in myprog.js */ ((er_lineno[0] || er_charno[0]) ? "at " :""), er_lineno, er_charno /* at line 12, ch 34 */ ); /* embedded newlines -- log each separately */ while ((ctmp = strchr(message, '\n')) != 0) { char log_message[strlen(message)]; ctmp++; strncpy(log_message, message, ctmp-message); log_message[ctmp - message] = (char)0; output_message(cx, grt, er_pfx, log_message, report, printOnTTY); message = ctmp; memset(er_pfx, ' ', strlen(er_pfx)); er_pfx[0] = '|'; } output_message(cx, grt, er_pfx, message, report, printOnTTY); }
JSBool make_js_land_proxy(JohnsonRuntime* runtime, VALUE value, jsval* retval) { jsval base_value = (jsval)JS_HashTableLookup(runtime->rbids, (void *)value); JSContext * context = johnson_get_current_context(runtime); PREPARE_JROOTS(context, 2); jsval johnson = JSVAL_NULL; JCHECK(evaluate_js_property_expression(runtime, "Johnson", &johnson)); JROOT(johnson); if (base_value) { JCHECK(JS_CallFunctionName(context, johnson, "applyConversions", 1, &base_value, retval)); JRETURN; } else { JSObject *jsobj; JSClass *klass = &JSLandProxyClass; if (T_CLASS == TYPE(value)) klass = &JSLandClassProxyClass; // FIXME: hack; should happen in Rubyland if (T_STRUCT == TYPE(value)) rb_funcall(Johnson_SpiderMonkey_JSLandProxy(), rb_intern("treat_all_properties_as_methods"), 1, value); bool callable_p = Qtrue == rb_funcall(value, rb_intern("respond_to?"), 1, rb_str_new2("call")); if (callable_p) klass = &JSLandCallableProxyClass; JCHECK((jsobj = JS_NewObject(context, klass, NULL, NULL))); JROOT(jsobj); JCHECK(JS_SetPrivate(context, jsobj, (void*)value)); JCHECK(JS_DefineFunction(context, jsobj, "__noSuchMethod__", method_missing, 2, 0)); JCHECK(JS_DefineFunction(context, jsobj, "toArray", to_array, 0, 0)); JCHECK(JS_DefineFunction(context, jsobj, "toString", to_string, 0, 0)); base_value = OBJECT_TO_JSVAL(jsobj); // root the ruby value for GC VALUE ruby_runtime = (VALUE)JS_GetRuntimePrivate(runtime->js); rb_funcall(ruby_runtime, rb_intern("add_gcthing"), 1, value); jsval wrapped_value = JSVAL_NULL; JCHECK(JS_CallFunctionName(context, johnson, "applyWrappers", 1, &base_value, &wrapped_value)); // put the proxy OID in the id map JCHECK(JS_HashTableAdd(runtime->rbids, (void *)value, (void *)(wrapped_value))); JCHECK(JS_CallFunctionName(context, johnson, "applyConversions", 1, &wrapped_value, retval)); JRETURN; } }
/** * Enter an auto-monitor (RAII). Infallible. Creates the monitor as-needed. * * @param cx A context belonging to the current runtime. Only used if we need to create * the monitor, to find the GPSEE runtime pointer. * @param monitor_p A pointer to the monitor. This address must stay valid for the lifetime of the runtime. * * @see gpsee_createMonitor(), gpsee_enterAutoMonitorRT(); */ void gpsee_enterAutoMonitor(JSContext *cx, gpsee_autoMonitor_t *monitor_p) { gpsee_runtime_t *grt = JS_GetRuntimePrivate(JS_GetRuntime(cx)); gpsee_enterAutoMonitorRT(grt, monitor_p); }