/* * 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])); }
JSBool WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) { if (JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(v))) { return WrapFunction(cx, parent, JSVAL_TO_OBJECT(v), vp); } JSObject *wrapperObj = JS_NewObjectWithGivenProto(cx, &COWClass.base, NULL, parent); if (!wrapperObj) { return JS_FALSE; } *vp = OBJECT_TO_JSVAL(wrapperObj); jsval exposedProps = JSVAL_VOID; JSAutoTempValueRooter tvr(cx, 1, &exposedProps); if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), &exposedProps)) { return JS_FALSE; } if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, v) || !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO) || !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, exposedProps)) { return JS_FALSE; } return JS_TRUE; }
std::string ValueWriter::typeAsString() { if (_value.isNull()) return "null"; if (_value.isUndefined()) return "undefined"; if (_value.isString()) return "string"; if (JS_IsArrayObject(_context, _value)) return "array"; if (_value.isBoolean()) return "boolean"; if (_value.isNumber()) return "number"; if (_value.isObject()) { JS::RootedObject obj(_context, _value.toObjectOrNull()); if (JS_IsArrayObject(_context, obj)) return "array"; if (JS_ObjectIsDate(_context, obj)) return "date"; if (JS_ObjectIsFunction(_context, obj)) return "function"; return ObjectWrapper(_context, _value).getClassName(); } uasserted(ErrorCodes::BadValue, "unable to get type"); }
int ValueWriter::type() { if (_value.isNull()) return jstNULL; if (_value.isUndefined()) return Undefined; if (_value.isString()) return String; if (JS_IsArrayObject(_context, _value)) return Array; if (_value.isBoolean()) return Bool; // We could do something more sophisticated here by checking to see if we // round trip through int32_t, int64_t and double and picking a type that // way, for now just always come back as double for numbers though (it's // what we did for v8) if (_value.isNumber()) return NumberDouble; if (_value.isObject()) { JS::RootedObject obj(_context, _value.toObjectOrNull()); if (JS_ObjectIsDate(_context, obj)) return Date; if (JS_ObjectIsFunction(_context, obj)) return Code; return Object; } uasserted(ErrorCodes::BadValue, "unable to get type"); }
JSBool js_addsubprovider(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { js_subprovider_t *sp; js_plugin_t *jsp = JS_GetPrivate(cx, obj); if(!JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(argv[0]))) { JS_ReportError(cx, "Argument is not a function"); return JS_FALSE; } sp = calloc(1, sizeof(js_subprovider_t)); sp->super.sp_query = js_sub_query; sp->super.sp_retain = js_sub_retain; sp->sp_title = prop_create_root(NULL); prop_set_string(sp->sp_title, jsp->jsp_id); subtitle_provider_register(&sp->super, jsp->jsp_id, sp->sp_title, 0, "plugin", 1, 1); sp->sp_jsp = jsp; LIST_INSERT_HEAD(&jsp->jsp_subproviders, sp, sp_plugin_link); sp->sp_func = argv[0]; atomic_set(&sp->sp_refcnt, 1); JS_AddNamedRoot(cx, &sp->sp_func, "subprovider"); *rval = JSVAL_VOID; return JS_TRUE; }
static JSBool js_item_onEvent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { js_item_t *ji = JS_GetPrivate(cx, obj); if(!JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(argv[1]))) { JS_ReportError(cx, "Argument is not a function"); return JS_FALSE; } if(ji->ji_eventsub == NULL) { ji->ji_eventsub = prop_subscribe(PROP_SUB_TRACK_DESTROY, PROP_TAG_CALLBACK, js_item_eventsub, ji, PROP_TAG_ROOT, ji->ji_root, PROP_TAG_COURIER, ji->ji_model->jm_pc, NULL); ji->ji_model->jm_subs++; ji->ji_this = OBJECT_TO_JSVAL(obj); JS_AddNamedRoot(cx, &ji->ji_this, "item_this"); } js_event_handler_create(cx, &ji->ji_event_handlers, JSVAL_IS_STRING(argv[0]) ? JS_GetStringBytes(JS_ValueToString(cx, argv[0])) : NULL, argv[1]); *rval = JSVAL_VOID; return JS_TRUE; }
/* Mimick the behaviour exposed by standard Error objects (http://mxr.mozilla.org/mozilla-central/source/js/src/jsexn.cpp#554) */ static char* jsvalue_to_string(JSContext* cx, jsval val, gboolean* is_string) { char* value = NULL; JSString* value_str = NULL; if (JSVAL_IS_PRIMITIVE(val)) { value_str = JS_ValueToSource(cx, val); } else { JSObject *obj = JSVAL_TO_OBJECT(val); if (JS_ObjectIsFunction(cx, obj)) { JSFunction *fn = JS_ValueToFunction(cx, val); value_str = JS_GetFunctionId(fn); if (!value_str) value = g_strdup("[unknown function]"); } else { value = g_strdup_printf("[object %s]", JS_GetClass(cx, obj)->name); } } if (!value && value_str) value = gjs_value_debug_string(cx, val); if (is_string) *is_string = JSVAL_IS_STRING(val); return value; }
JSThreadConfig(JSContext* cx, JS::CallArgs args) : _started(false), _done(false), _sharedData(new SharedData()) { auto scope = getScope(cx); uassert(ErrorCodes::JSInterpreterFailure, "need at least one argument", args.length() > 0); uassert(ErrorCodes::JSInterpreterFailure, "first argument must be a function", args.get(0).isObject() && JS_ObjectIsFunction(cx, args.get(0).toObjectOrNull())); BSONObjBuilder b; for (unsigned i = 0; i < args.length(); ++i) { // 10 decimal digits for a 32 bit unsigned, then 1 for the null char buf[11]; std::sprintf(buf, "%i", i); ValueWriter(cx, args.get(i)).writeThis(&b, buf); } _sharedData->_args = b.obj(); _sharedData->_stack = currentJSStackToString(cx); if (!scope->getParentStack().empty()) { _sharedData->_stack = _sharedData->_stack + scope->getParentStack(); } }
static inline void build_frame(JSContext *cx, JSObject *target, unsigned argc, jsval *vp, void (*next)(view_animation *, anim_frame *, unsigned int, unsigned int)) { LOGFN("build_frame"); JSObject *thiz = JSVAL_TO_OBJECT(JS_THIS(cx, vp)); view_animation *anim = (view_animation*)JS_GetPrivate(thiz); anim_frame *frame = anim_frame_get(); // TODO: what if these defaults change? it probably won't... int32_t duration = 500; int32_t transition = 0; if (JS_ObjectIsFunction(cx, target)) { duration = 0; build_func_frame(frame, target); } else { build_style_frame(frame, target); } jsval *vals = JS_ARGV(cx, vp); if (argc > 1) { duration = JSValToInt32(cx, vals[1], duration); if (argc > 2) { transition = JSValToInt32(cx, vals[2], transition); } } next(anim, frame, duration, transition); LOGFN("end build_frame"); }
static js_setting_t * jss_create(JSContext *cx, JSObject *obj, const char *id, jsval *rval, JSObject *func, js_setting_group_t *jsg, int persistent) { if(jsg->jsg_root == NULL) { JS_ReportError(cx, "Settings group has been destroyed"); return NULL; } if(!JS_ObjectIsFunction(cx, func)) { JS_ReportError(cx, "Callback is not a function"); return NULL; } js_setting_t *jss = calloc(1, sizeof(js_setting_t)); jss->jss_cx = cx; jss->jss_refcount = 1; jss->jss_jsg = jsg; jss->jss_key = persistent && jsg->jsg_kv_url ? strdup(id) : NULL; LIST_INSERT_HEAD(&jsg->jsg_settings, jss, jss_link); atomic_add(&jsg->jsg_refcount, 1); JS_AddNamedRoot(cx, &jss->jss_obj, "jss"); jss->jss_obj = OBJECT_TO_JSVAL(JS_DefineObject(cx, obj, id, &setting_class, NULL, 0)); *rval = jss->jss_obj; JS_SetPrivate(cx, JSVAL_TO_OBJECT(jss->jss_obj), jss); jsval v = OBJECT_TO_JSVAL(func); JS_SetProperty(cx, JSVAL_TO_OBJECT(jss->jss_obj), "callback", &v); return jss; }
static void _gjs_builder_connect_func (GtkBuilder *builder, GObject *object, const gchar *signal_name, const gchar *handler_name, GObject *connect_object, GConnectFlags flags, gpointer user_data) { builder_ud *priv = (builder_ud *)user_data; JSContext *ctx = priv->ctx; JSObject *obj = priv->obj; GClosure *closure; JSObject *callable; builder_cd *cd; closure_data *c; jsval func; if (!gjs_object_get_property (ctx, obj, handler_name, &func)) return; if (!JSVAL_IS_OBJECT(func)) return; callable = JSVAL_TO_OBJECT (func); if (!JS_ObjectIsFunction(ctx, callable)) return; /* Protect from garbage collection. */ cd = g_object_get_data (G_OBJECT (builder), GJS_BUILDER_CLOSURE_KEY); if (!cd) { cd = g_new0 (builder_cd, 1); cd->context = ctx; cd->closures = NULL; g_object_set_data_full (G_OBJECT (builder), GJS_BUILDER_CLOSURE_KEY, cd, (GDestroyNotify) _builder_cd_free); } g_assert (cd->context == ctx); c = g_new0 (closure_data, 1); c->jsobj = callable; cd->closures = g_slist_prepend (cd->closures, c); JS_AddObjectRoot (ctx, &c->jsobj); closure = gjs_closure_new_for_signal (ctx, callable, "signal handler (GtkBuilder)", 0); if (connect_object != NULL) g_object_watch_closure (connect_object, closure); c->object = g_object_ref (object); c->handler_id = g_signal_connect_closure (object, signal_name, closure, FALSE); }
JSBool add_prop(JSContext* jscx, JSObject* jsobj, jsval key, jsval* rval) { JSObject* obj = NULL; if(JSVAL_IS_NULL(*rval) || !JSVAL_IS_OBJECT(*rval)) return JS_TRUE; obj = JSVAL_TO_OBJECT(*rval); if(JS_ObjectIsFunction(jscx, obj)) return set_prop(jscx, jsobj, key, rval); return JS_TRUE; }
void MozJSImplScope::_MozJSCreateFunction(const char* raw, ScriptingFunction functionNumber, JS::MutableHandleValue fun) { std::string code = str::stream() << "_funcs" << functionNumber << " = " << parseJSFunctionOrExpression(_context, StringData(raw)); JS::CompileOptions co(_context); setCompileOptions(&co); _checkErrorState(JS::Evaluate(_context, _global, co, code.c_str(), code.length(), fun)); uassert(10232, "not a function", fun.isObject() && JS_ObjectIsFunction(_context, fun.toObjectOrNull())); }
static void GetMethodInfo(JSContext *cx, jsval *vp, const char **ifaceName, const char **memberName) { JSObject *funobj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); NS_ASSERTION(JS_ObjectIsFunction(cx, funobj), "JSFastNative callee should be Function object"); JSString *str = JS_GetFunctionId((JSFunction *) JS_GetPrivate(cx, funobj)); jsval methodId = str ? STRING_TO_JSVAL(str) : JSVAL_NULL; GetMemberInfo(JSVAL_TO_OBJECT(vp[1]), methodId, ifaceName, memberName); }
XPCDispJSPropertyInfo::XPCDispJSPropertyInfo(JSContext* cx, PRUint32 memid, JSObject* obj, jsval val) : mPropertyType(INVALID), mMemID(memid) { PRUint32 len; jschar * chars = xpc_JSString2String(cx, val, &len); if(!chars) return; mName = nsString(reinterpret_cast<const PRUnichar *>(chars), len); JSBool found; uintN attr; // Get the property's attributes, and make sure it's found and enumerable if(!JS_GetUCPropertyAttributes(cx, obj, chars, len, &attr, &found) || !found || (attr & JSPROP_ENUMERATE) == 0) return; // Retrieve the property if(!chars || !JS_GetUCProperty(cx, obj, chars, len, &mProperty) || JSVAL_IS_NULL(mProperty)) return; // If this is a function if(JSVAL_IS_OBJECT(mProperty) && JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(mProperty))) { mPropertyType = FUNCTION; JSObject * funcObj = JSVAL_TO_OBJECT(mProperty); JSIdArray * funcObjArray = JS_Enumerate(cx, funcObj); if(funcObjArray) { mParamCount = funcObjArray->length; } } else // It's a property { mParamCount = 0; if((attr & JSPROP_READONLY) != 0) { mPropertyType = READONLY_PROPERTY; } else { mPropertyType = PROPERTY; } } }
js::Function JSInterpreter::evaluateScript(std::string script){ jsval rval; JSBool ok; const char *filename = "noname"; uintN lineno = 0; ok = JS_EvaluateScript(cx, global, script.c_str(), script.length(), filename, lineno, &rval); if (rval == JSVAL_NULL || rval == JS_FALSE || ok == JS_FALSE){ throw * new std::runtime_error("Could not evaluate script"); } JSObject *obj; JS_ValueToObject(cx, rval, &obj); JSBool func = JS_ObjectIsFunction(cx, obj); //todo guard! return js::Function(obj); }
static JSBool js_item_onEvent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { js_item_t *ji = JS_GetPrivate(cx, obj); if(!JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(argv[1]))) { JS_ReportError(cx, "Argument is not a function"); return JS_FALSE; } js_event_handler_create(cx, &ji->ji_event_handlers, JSVAL_IS_STRING(argv[0]) ? JS_GetStringBytes(JS_ValueToString(cx, argv[0])) : NULL, argv[1]); *rval = JSVAL_VOID; return JS_TRUE; }
JSBool XPC_COW_RewrapForContent(JSContext *cx, JSObject *wrapperObj, jsval *vp) { jsval v = *vp; if (JSVAL_IS_PRIMITIVE(v)) { return JS_TRUE; } JSObject *obj = GetWrappedJSObject(cx, JSVAL_TO_OBJECT(v)); if (!obj) { *vp = JSVAL_NULL; return JS_TRUE; } if (JS_ObjectIsFunction(cx, obj)) { return XPC_COW_WrapFunction(cx, wrapperObj, obj, vp); } return XPC_COW_WrapObject(cx, JS_GetScopeChain(cx), OBJECT_TO_JSVAL(obj), vp); }
void DBQueryInfo::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolvedp) { *resolvedp = false; IdWrapper wid(cx, id); // We only use this for index access if (!wid.isInt()) { return; } JS::RootedObject parent(cx); if (!JS_GetPrototype(cx, obj, &parent)) uasserted(ErrorCodes::InternalError, "Couldn't get prototype"); ObjectWrapper parentWrapper(cx, parent); JS::RootedValue arrayAccess(cx); parentWrapper.getValue(InternedString::arrayAccess, &arrayAccess); if (arrayAccess.isObject() && JS_ObjectIsFunction(cx, arrayAccess.toObjectOrNull())) { JS::AutoValueArray<1> args(cx); args[0].setInt32(wid.toInt32()); JS::RootedValue vp(cx); ObjectWrapper(cx, obj).callMethod(arrayAccess, args, &vp); if (!vp.isNullOrUndefined()) { ObjectWrapper o(cx, obj); // Assumes the user won't modify the contents of what DBQuery::arrayAccess returns // otherwise we need to install a getter. o.defineProperty(id, vp, 0); } *resolvedp = true; } }
// TODO: This function identification code is broken. Fix it up to be more robust // // See: SERVER-16703 for more info void MozJSImplScope::_MozJSCreateFunction(const char* raw, ScriptingFunction functionNumber, JS::MutableHandleValue fun) { std::string code = jsSkipWhiteSpace(raw); if (!hasFunctionIdentifier(code)) { if (code.find('\n') == std::string::npos && !hasJSReturn(code) && (code.find(';') == std::string::npos || code.find(';') == code.size() - 1)) { code = "return " + code; } code = "function(){ " + code + "}"; } code = str::stream() << "_funcs" << functionNumber << " = " << code; JS::CompileOptions co(_context); setCompileOptions(&co); _checkErrorState(JS::Evaluate(_context, _global, co, code.c_str(), code.length(), fun)); uassert(10232, "not a function", fun.isObject() && JS_ObjectIsFunction(_context, fun.toObjectOrNull())); }
JSBool XPC_XOW_RewrapIfNeeded(JSContext *cx, JSObject *outerObj, jsval *vp) { // Don't need to wrap primitive values. if (JSVAL_IS_PRIMITIVE(*vp)) { return JS_TRUE; } JSObject *obj = JSVAL_TO_OBJECT(*vp); if (JS_ObjectIsFunction(cx, obj)) { return XPC_XOW_WrapFunction(cx, outerObj, obj, vp); } XPCWrappedNative *wn = nsnull; if (STOBJ_GET_CLASS(obj) == &sXPC_XOW_JSClass.base && STOBJ_GET_PARENT(outerObj) != STOBJ_GET_PARENT(obj)) { *vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, obj)); } else if (!(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, obj))) { return JS_TRUE; } return XPC_XOW_WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp, wn); }
int to_erl_from_handler(emonk_buf_t* buf, JSContext* cx, JSObject* obj) { JSObject* func; jsval tojson; jsval rval; if(!JS_GetProperty(cx, obj, "toJSON", &tojson)) { return ERROR; } if(!JSVAL_IS_OBJECT(tojson)) return IGNORE; func = JSVAL_TO_OBJECT(tojson); if(func == NULL) return ERROR; if(!JS_ObjectIsFunction(cx, func)) return IGNORE; if(!JS_CallFunctionValue(cx, obj, tojson, 0, NULL, &rval)) { return ERROR; } return to_erl_intern(buf, cx, rval); }
void def_animate_finish(void *a) { JSObject *js_anim = (JSObject*)a; LOGFN("js_animate_finish"); JSContext *cx = get_js_context(); JS_BeginRequest(cx); view_animation *anim = (view_animation *)JS_GetPrivate(js_anim); JSObject *js_group = (JSObject*)anim->js_group; jsval finish_val; JS_GetProperty(cx, js_group, "onAnimationFinish", &finish_val); if (JSVAL_IS_OBJECT(finish_val)) { JSObject *finish = JSVAL_TO_OBJECT(finish_val); jsval args[] = {OBJECT_TO_JSVAL(js_anim)}; if (JS_ObjectIsFunction(cx, finish)) { jsval ret; JS_CallFunctionValue(cx, js_group, finish_val, 1, args, &ret); } } JS_EndRequest(cx); LOGFN("end def_animate_finish"); }
JSBool RewrapIfNeeded(JSContext *cx, JSObject *outerObj, jsval *vp) { // Don't need to wrap primitive values. if (JSVAL_IS_PRIMITIVE(*vp)) { return JS_TRUE; } JSObject *obj = JSVAL_TO_OBJECT(*vp); if (JS_ObjectIsFunction(cx, obj)) { return WrapFunction(cx, outerObj, obj, vp); } XPCWrappedNative *wn = nsnull; if (obj->getClass() == &XOWClass && outerObj->getParent() != obj->getParent()) { *vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, obj)); } else if (!(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, obj))) { return JS_TRUE; } return WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp, wn); }
int to_erl_convert(ErlNifEnv* env, JSContext* cx, JSObject* obj, ERL_NIF_TERM* term) { JSObject* func; jsval tojson; jsval rval; if(!JS_GetProperty(cx, obj, "toJSON", &tojson)) { return ERROR; } if(!JSVAL_IS_OBJECT(tojson)) return ERROR; func = JSVAL_TO_OBJECT(tojson); if(func == NULL) return ERROR; if(!JS_ObjectIsFunction(cx, func)) return ERROR; if(!JS_CallFunctionValue(cx, obj, tojson, 0, NULL, &rval)) { return ERROR; } return to_erl_intern(env, cx, rval, term); }
static gboolean peas_extension_gjs_call (PeasExtensionWrapper *exten, GType exten_type, GICallableInfo *func_info, const gchar *method_name, GIArgument *args, GIArgument *retval) { PeasExtensionGjs *gexten = PEAS_EXTENSION_GJS (exten); gboolean success = FALSE; jsval js_method, js_retval; jsval *js_args; CachedArg *arg_cache; gint i, n_args, nth_out_arg; gint n_in_args = 0; gint n_out_args = 0; gint cached_args = 0; /* Fetch the JS method we want to call */ if (!JS_GetProperty (gexten->js_context, gexten->js_object, method_name, &js_method) || JSVAL_IS_VOID (js_method)) { g_warning ("Method '%s.%s' was not found", g_type_name (exten_type), method_name); return FALSE; } if (JSVAL_IS_NULL (js_method) || !JSVAL_IS_OBJECT (js_method) || !JS_ObjectIsFunction (gexten->js_context, JSVAL_TO_OBJECT (js_method))) { g_warning ("Method '%s.%s' in not a function", g_type_name (exten_type), method_name); return FALSE; } n_args = g_callable_info_get_n_args (func_info); if (n_args < 0) { g_warn_if_fail (n_args >= 0); return FALSE; } js_args = g_newa (jsval, n_args); arg_cache = g_newa (CachedArg, n_args + 1); /* Return value is an out arg */ g_callable_info_load_return_type (func_info, &arg_cache[0].type_info); if (g_type_info_get_tag (&arg_cache[0].type_info) != GI_TYPE_TAG_VOID) { ++n_out_args; arg_cache[cached_args++].ptr = &retval->v_pointer; } /* Handle the arguments */ for (i = 0; i < n_args; ++i, ++cached_args) { GIDirection direction; g_callable_info_load_arg (func_info, i, &arg_cache[cached_args].arg_info); direction = g_arg_info_get_direction (&arg_cache[cached_args].arg_info); g_arg_info_load_type (&arg_cache[cached_args].arg_info, &arg_cache[cached_args].type_info); if (direction == GI_DIRECTION_IN && !gjs_value_from_g_argument (gexten->js_context, &js_args[n_in_args++], &arg_cache[cached_args].type_info, &args[i], TRUE)) { g_warning ("Error failed to convert argument '%s'", g_base_info_get_name (&arg_cache[cached_args].arg_info)); return FALSE; } if (direction == GI_DIRECTION_INOUT) { GIArgument arg; peas_gi_pointer_to_argument (&arg_cache[cached_args].type_info, args[i].v_pointer, &arg); if (!gjs_value_from_g_argument (gexten->js_context, &js_args[n_in_args++], &arg_cache[cached_args].type_info, &arg, TRUE)) { g_warning ("Error failed to convert argument '%s'", g_base_info_get_name (&arg_cache[cached_args].arg_info)); return FALSE; } } if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) { ++n_out_args; arg_cache[cached_args].ptr = args[i].v_pointer; } } success = JS_CallFunctionValue (gexten->js_context, gexten->js_object, js_method, n_in_args, js_args, &js_retval); if (!success) { if (!gjs_log_exception (gexten->js_context, NULL)) { g_warning ("Error while calling '%s.%s'", g_type_name (exten_type), method_name); } return FALSE; } /* First we need to release in argument */ for (i = 0; i < cached_args; ++i) { GIDirection direction; /* First cached argument may be the return value */ if (i == 0 && cached_args > n_args) continue; direction = g_arg_info_get_direction (&arg_cache[i].arg_info); if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) { GITransfer transfer; transfer = g_arg_info_get_ownership_transfer (&arg_cache[i].arg_info); if (!gjs_g_argument_release_in_arg (gexten->js_context, transfer, &arg_cache[i].type_info, &args[i])) { g_warning ("Error failed to release IN argument '%s'", g_base_info_get_name (&arg_cache[i].arg_info)); } } } /* Check that we have a valid return value */ if (n_out_args > 1) { if (!JSVAL_IS_OBJECT (js_retval) || !JS_IsArrayObject (gexten->js_context, JSVAL_TO_OBJECT (js_retval))) { g_warning ("Error return value is not an array"); return FALSE; } } /* Set out arguments */ for (i = 0, nth_out_arg = 0; i < cached_args && success; ++i) { gboolean is_return_value; is_return_value = i == 0 && cached_args > n_args; /* Return value does not have a GIArgInfo and is always out */ if (!is_return_value) { GIDirection direction; direction = g_arg_info_get_direction (&arg_cache[i].arg_info); if (direction == GI_DIRECTION_IN) continue; } if (n_out_args == 1) { success = set_out_arg (gexten->js_context, func_info, is_return_value, &arg_cache[i].arg_info, &arg_cache[i].type_info, arg_cache[i].ptr, js_retval); break; } else if (n_out_args > 1) { jsval js_value; if (!JS_GetElement (gexten->js_context, JSVAL_TO_OBJECT (js_retval), nth_out_arg++, &js_value) || js_value == JSVAL_VOID) { g_warning ("Error failed to get out argument %i", nth_out_arg); return FALSE; } else { success = set_out_arg (gexten->js_context, func_info, is_return_value, &arg_cache[i].arg_info, &arg_cache[i].type_info, arg_cache[i].ptr, js_value); } } } return success; }
JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsid id, JSBool UNUSED(strict), jsval* vp) { IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL); if (!e) return JS_FALSE; jsval idval; if (!JS_IdToValue(cx, id, &idval)) return JS_FALSE; std::string propName; if (!ScriptInterface::FromJSVal(cx, idval, propName)) return JS_FALSE; if (propName == "name") { std::string value; if (!ScriptInterface::FromJSVal(cx, *vp, value)) return JS_FALSE; e->SetName(value); return JS_TRUE; } // Use onWhatever to set event handlers if (propName.substr(0, 2) == "on") { if (!JSVAL_IS_OBJECT(*vp) || !JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(*vp))) { JS_ReportError(cx, "on- event-handlers must be functions"); return JS_FALSE; } CStr eventName (CStr(propName.substr(2)).LowerCase()); e->SetScriptHandler(eventName, JSVAL_TO_OBJECT(*vp)); return JS_TRUE; } // Retrieve the setting's type (and make sure it actually exists) EGUISettingType Type; if (e->GetSettingType(propName, Type) != PSRETURN_OK) { JS_ReportError(cx, "Invalid setting '%s'", propName.c_str()); return JS_TRUE; } switch (Type) { case GUIST_CStr: { std::string value; if (!ScriptInterface::FromJSVal(cx, *vp, value)) return JS_FALSE; GUI<CStr>::SetSetting(e, propName, value); break; } case GUIST_CStrW: { std::wstring value; if (!ScriptInterface::FromJSVal(cx, *vp, value)) return JS_FALSE; GUI<CStrW>::SetSetting(e, propName, value); break; } case GUIST_CGUISpriteInstance: { std::string value; if (!ScriptInterface::FromJSVal(cx, *vp, value)) return JS_FALSE; GUI<CGUISpriteInstance>::SetSetting(e, propName, CGUISpriteInstance(value)); break; } case GUIST_CGUIString: { std::wstring value; if (!ScriptInterface::FromJSVal(cx, *vp, value)) return JS_FALSE; CGUIString str; str.SetValue(value); GUI<CGUIString>::SetSetting(e, propName, str); break; } case GUIST_EAlign: { std::string value; if (!ScriptInterface::FromJSVal(cx, *vp, value)) return JS_FALSE; EAlign a; if (value == "left") a = EAlign_Left; else if (value == "right") a = EAlign_Right; else if (value == "center" || value == "centre") a = EAlign_Center; else { JS_ReportError(cx, "Invalid alignment (should be 'left', 'right' or 'center')"); return JS_FALSE; } GUI<EAlign>::SetSetting(e, propName, a); break; } case GUIST_EVAlign: { std::string value; if (!ScriptInterface::FromJSVal(cx, *vp, value)) return JS_FALSE; EVAlign a; if (value == "top") a = EVAlign_Top; else if (value == "bottom") a = EVAlign_Bottom; else if (value == "center" || value == "centre") a = EVAlign_Center; else { JS_ReportError(cx, "Invalid alignment (should be 'top', 'bottom' or 'center')"); return JS_FALSE; } GUI<EVAlign>::SetSetting(e, propName, a); break; } case GUIST_int: { int32 value; if (JS_ValueToInt32(cx, *vp, &value) == JS_TRUE) GUI<int>::SetSetting(e, propName, value); else { JS_ReportError(cx, "Cannot convert value to int"); return JS_FALSE; } break; } case GUIST_float: { jsdouble value; if (JS_ValueToNumber(cx, *vp, &value) == JS_TRUE) GUI<float>::SetSetting(e, propName, (float)value); else { JS_ReportError(cx, "Cannot convert value to float"); return JS_FALSE; } break; } case GUIST_bool: { JSBool value; if (JS_ValueToBoolean(cx, *vp, &value) == JS_TRUE) GUI<bool>::SetSetting(e, propName, value||0); // ||0 to avoid int-to-bool compiler warnings else { JS_ReportError(cx, "Cannot convert value to bool"); return JS_FALSE; } break; } case GUIST_CClientArea: { if (JSVAL_IS_STRING(*vp)) { std::wstring value; if (!ScriptInterface::FromJSVal(cx, *vp, value)) return JS_FALSE; if (e->SetSetting(propName, value) != PSRETURN_OK) { JS_ReportError(cx, "Invalid value for setting '%s'", propName.c_str()); return JS_FALSE; } } else if (JSVAL_IS_OBJECT(*vp) && JS_InstanceOf(cx, JSVAL_TO_OBJECT(*vp), &JSI_GUISize::JSI_class, NULL)) { CClientArea area; GUI<CClientArea>::GetSetting(e, propName, area); JSObject* obj = JSVAL_TO_OBJECT(*vp); #define P(x, y, z) area.x.y = (float)g_ScriptingHost.GetObjectProperty_Double(obj, #z) P(pixel, left, left); P(pixel, top, top); P(pixel, right, right); P(pixel, bottom, bottom); P(percent, left, rleft); P(percent, top, rtop); P(percent, right, rright); P(percent, bottom, rbottom); #undef P GUI<CClientArea>::SetSetting(e, propName, area); } else { JS_ReportError(cx, "Size only accepts strings or GUISize objects"); return JS_FALSE; } break; } case GUIST_CColor: { if (JSVAL_IS_STRING(*vp)) { std::wstring value; if (!ScriptInterface::FromJSVal(cx, *vp, value)) return JS_FALSE; if (e->SetSetting(propName, value) != PSRETURN_OK) { JS_ReportError(cx, "Invalid value for setting '%s'", propName.c_str()); return JS_FALSE; } } else if (JSVAL_IS_OBJECT(*vp) && JS_InstanceOf(cx, JSVAL_TO_OBJECT(*vp), &JSI_GUIColor::JSI_class, NULL)) { CColor colour; JSObject* obj = JSVAL_TO_OBJECT(*vp); jsval t; double s; #define PROP(x) JS_GetProperty(cx, obj, #x, &t); \ JS_ValueToNumber(cx, t, &s); \ colour.x = (float)s PROP(r); PROP(g); PROP(b); PROP(a); #undef PROP GUI<CColor>::SetSetting(e, propName, colour); } else { JS_ReportError(cx, "Color only accepts strings or GUIColor objects"); return JS_FALSE; } break; } case GUIST_CGUIList: { JSObject* obj = JSVAL_TO_OBJECT(*vp); jsuint length; if (JSVAL_IS_OBJECT(*vp) && JS_GetArrayLength(cx, obj, &length) == JS_TRUE) { CGUIList list; for (int i=0; i<(int)length; ++i) { jsval element; if (! JS_GetElement(cx, obj, i, &element)) { JS_ReportError(cx, "Failed to get list element"); return JS_FALSE; } std::wstring value; if (!ScriptInterface::FromJSVal(cx, element, value)) return JS_FALSE; CGUIString str; str.SetValue(value); list.m_Items.push_back(str); } GUI<CGUIList>::SetSetting(e, propName, list); } else { JS_ReportError(cx, "List only accepts a GUIList object"); return JS_FALSE; } break; } // TODO Gee: (2004-09-01) EAlign and EVAlign too. default: JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str()); break; } return !JS_IsExceptionPending(cx); }
JSBool jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval) { return !JSVAL_IS_PRIMITIVE(jsdval->val) && JS_ObjectIsFunction(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val)); }
void DBInfo::getProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) { // 2nd look into real values, may be cached collection object if (!vp.isUndefined()) { auto scope = getScope(cx); auto opContext = scope->getOpContext(); if (opContext && vp.isObject()) { ObjectWrapper o(cx, vp); if (o.hasOwnField(InternedString::_fullName)) { // need to check every time that the collection did not get sharded if (haveLocalShardingInfo(opContext, o.getString(InternedString::_fullName))) uasserted(ErrorCodes::BadValue, "can't use sharded collection from db.eval"); } } return; } JS::RootedObject parent(cx); if (!JS_GetPrototype(cx, obj, &parent)) uasserted(ErrorCodes::JSInterpreterFailure, "Couldn't get prototype"); ObjectWrapper parentWrapper(cx, parent); if (parentWrapper.hasOwnField(id)) { parentWrapper.getValue(id, vp); return; } IdWrapper idw(cx, id); // if starts with '_' we dont return collection, one must use getCollection() if (idw.isString()) { JSStringWrapper jsstr; auto sname = idw.toStringData(&jsstr); if (sname.size() == 0 || sname[0] == '_') { return; } } // no hit, create new collection JS::RootedValue getCollection(cx); parentWrapper.getValue(InternedString::getCollection, &getCollection); if (!(getCollection.isObject() && JS_ObjectIsFunction(cx, getCollection.toObjectOrNull()))) { uasserted(ErrorCodes::BadValue, "getCollection is not a function"); } JS::AutoValueArray<1> args(cx); idw.toValue(args[0]); JS::RootedValue coll(cx); ObjectWrapper(cx, obj).callMethod(getCollection, args, &coll); uassert(16861, "getCollection returned something other than a collection", getScope(cx)->getProto<DBCollectionInfo>().instanceOf(coll)); // cache collection for reuse, don't enumerate ObjectWrapper(cx, obj).defineProperty(id, coll, 0); vp.set(coll); }
void WrapperPromiseCallback::Call(JSContext* aCx, JS::Handle<JS::Value> aValue) { JSAutoCompartment ac(aCx, mGlobal); JS::Rooted<JS::Value> value(aCx, aValue); if (!JS_WrapValue(aCx, &value)) { NS_WARNING("Failed to wrap value into the right compartment."); return; } ErrorResult rv; // If invoking callback threw an exception, run resolver's reject with the // thrown exception as argument and the synchronous flag set. JS::Rooted<JS::Value> retValue(aCx); mCallback->Call(value, &retValue, rv, CallbackObject::eRethrowExceptions); rv.WouldReportJSException(); if (rv.Failed() && rv.IsJSException()) { JS::Rooted<JS::Value> value(aCx); rv.StealJSException(aCx, &value); if (!JS_WrapValue(aCx, &value)) { NS_WARNING("Failed to wrap value into the right compartment."); return; } mNextPromise->RejectInternal(aCx, value, Promise::SyncTask); return; } // If the return value is the same as the promise itself, throw TypeError. if (retValue.isObject()) { JS::Rooted<JSObject*> valueObj(aCx, &retValue.toObject()); Promise* returnedPromise; nsresult r = UNWRAP_OBJECT(Promise, valueObj, returnedPromise); if (NS_SUCCEEDED(r) && returnedPromise == mNextPromise) { const char* fileName = nullptr; uint32_t lineNumber = 0; // Try to get some information about the callback to report a sane error, // but don't try too hard (only deals with scripted functions). JS::Rooted<JSObject*> unwrapped(aCx, js::CheckedUnwrap(mCallback->Callback())); if (unwrapped) { JSAutoCompartment ac(aCx, unwrapped); if (JS_ObjectIsFunction(aCx, unwrapped)) { JS::Rooted<JS::Value> asValue(aCx, JS::ObjectValue(*unwrapped)); JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, asValue)); MOZ_ASSERT(func); JSScript* script = JS_GetFunctionScript(aCx, func); if (script) { fileName = JS_GetScriptFilename(script); lineNumber = JS_GetScriptBaseLineNumber(aCx, script); } } } // We're back in aValue's compartment here. JS::Rooted<JSString*> stack(aCx, JS_GetEmptyString(JS_GetRuntime(aCx))); JS::Rooted<JSString*> fn(aCx, JS_NewStringCopyZ(aCx, fileName)); if (!fn) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(aCx); return; } JS::Rooted<JSString*> message(aCx, JS_NewStringCopyZ(aCx, "then() cannot return same Promise that it resolves.")); if (!message) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(aCx); return; } JS::Rooted<JS::Value> typeError(aCx); if (!JS::CreateTypeError(aCx, stack, fn, lineNumber, 0, nullptr, message, &typeError)) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(aCx); return; } mNextPromise->RejectInternal(aCx, typeError, Promise::SyncTask); return; } } // Otherwise, run resolver's resolve with value and the synchronous flag // set. if (!JS_WrapValue(aCx, &retValue)) { NS_WARNING("Failed to wrap value into the right compartment."); return; } mNextPromise->ResolveInternal(aCx, retValue, Promise::SyncTask); }