JSBool js_cocos2dx_CCBAnimationManager_animationCompleteCallback(JSContext *cx, uint32_t argc, jsval *vp) { if (argc >= 1) { jsval *argv = JS_ARGV(cx, vp); JSObject *obj = JS_THIS_OBJECT(cx, vp); js_proxy_t *proxy; JS_GET_NATIVE_PROXY(proxy, obj); cocos2d::extension::CCBAnimationManager *node = (cocos2d::extension::CCBAnimationManager *)(proxy ? proxy->ptr : NULL); JSCCBAnimationWrapper *tmpCobj = new JSCCBAnimationWrapper(); tmpCobj->autorelease(); tmpCobj->setJSCallbackThis(argv[0]); if(argc >= 2) { tmpCobj->setJSCallbackFunc(argv[1]); } node->setAnimationCompletedCallback(tmpCobj, callfunc_selector(JSCCBAnimationWrapper::animationCompleteCallback)); JS_SetReservedSlot(proxy->obj, 0, argv[0]); JS_SetReservedSlot(proxy->obj, 1, argv[1]); return JS_TRUE; } return JS_FALSE; }
JSBool WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) { // Slim wrappers don't expect to be wrapped, so morph them to fat wrappers // if we're about to wrap one. JSObject *innerObj = JSVAL_TO_OBJECT(v); if (IS_SLIM_WRAPPER(innerObj) && !MorphSlimWrapper(cx, innerObj)) { return ThrowException(NS_ERROR_FAILURE, cx); } JSObject *wrapperObj = JS_NewObjectWithGivenProto(cx, js::Jsvalify(&SOWClass), NULL, parent); if (!wrapperObj) { return JS_FALSE; } *vp = OBJECT_TO_JSVAL(wrapperObj); js::AutoObjectRooter tvr(cx, wrapperObj); if (!JS_SetReservedSlot(cx, wrapperObj, sWrappedObjSlot, v) || !JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, JSVAL_ZERO)) { return JS_FALSE; } return JS_TRUE; }
JSObject * xpc_CloneJSFunction(XPCCallContext &ccx, JSObject *funobj, JSObject *parent) { JSObject *clone = JS_CloneFunctionObject(ccx, funobj, parent); if(!clone) return nsnull; AUTO_MARK_JSVAL(ccx, OBJECT_TO_JSVAL(clone)); XPCWrappedNativeScope *scope = XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent); if (!scope) { return nsnull; } // Make sure to break the prototype chain to the function object // we cloned to prevent its scope from leaking into the clones // scope. JS_SetPrototype(ccx, clone, scope->GetPrototypeJSFunction()); // Copy the reserved slots to the clone. jsval ifaceVal, memberVal; if(!JS_GetReservedSlot(ccx, funobj, 0, &ifaceVal) || !JS_GetReservedSlot(ccx, funobj, 1, &memberVal)) return nsnull; if(!JS_SetReservedSlot(ccx, clone, 0, ifaceVal) || !JS_SetReservedSlot(ccx, clone, 1, memberVal)) return nsnull; return clone; }
JSBool XPCDispInterface::Member::GetValue(XPCCallContext& ccx, XPCNativeInterface * iface, jsval * retval) const { // This is a method or attribute - we'll be needing a function object // We need to use the safe context for this thread because we don't want // to parent the new (and cached forever!) function object to the current // JSContext's global object. That would be bad! if((mType & RESOLVED) == 0) { JSContext* cx = ccx.GetSafeJSContext(); if(!cx) return JS_FALSE; intN argc; JSNative callback; // Is this a function or a parameterized getter/setter if(IsFunction() || IsParameterizedProperty()) { argc = GetParamCount(); callback = XPC_IDispatch_CallMethod; } else { argc = 0; callback = XPC_IDispatch_GetterSetter; } JSFunction *fun = JS_NewFunctionById(cx, callback, argc, 0, nsnull, mName); if(!fun) return JS_FALSE; JSObject* funobj = JS_GetFunctionObject(fun); if(!funobj) return JS_FALSE; // Store ourselves and our native interface within the JSObject if(!JS_SetReservedSlot(ccx, funobj, 0, PRIVATE_TO_JSVAL((void *) this))) return JS_FALSE; if(!JS_SetReservedSlot(ccx, funobj, 1, PRIVATE_TO_JSVAL(iface))) return JS_FALSE; { // scoped lock XPCAutoLock lock(ccx.GetRuntime()->GetMapLock()); const_cast<Member*>(this)->mVal = OBJECT_TO_JSVAL(funobj); const_cast<Member*>(this)->mType |= RESOLVED; } } *retval = mVal; return JS_TRUE; }
// Because of the drastically different ways that same- and cross-origin XOWs // work, we have to call JS_ClearScope when a XOW changes from being same- // origin to cross-origin. Normally, there are defined places in Gecko where // this happens and they notify us. However, UniversalXPConnect causes the // same transition without any notifications. We could try to detect when this // happens, but doing so would require calling JS_ClearScope from random // hooks, which is bad. // // The compromise is the UXPCObject. When resolving a property on a XOW as // same-origin because of UniversalXPConnect, we actually resolve it on the // UXPCObject (which is just a XOW for the same object). This causes the JS // engine to do all of its work on another object, not polluting the main // object. However, if the get results in calling a setter, the engine still // uses the regular object as 'this', ensuring that the UXPCObject doesn't // leak to script. static JSObject * GetUXPCObject(JSContext *cx, JSObject *obj) { NS_ASSERTION(STOBJ_GET_CLASS(obj) == &sXPC_XOW_JSClass.base, "wrong object"); jsval v; if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sFlagsSlot, &v)) { return nsnull; } if (HAS_FLAGS(v, FLAG_IS_UXPC_OBJECT)) { return obj; } if (!JS_GetReservedSlot(cx, obj, sUXPCObjectSlot, &v)) { return nsnull; } if (JSVAL_IS_OBJECT(v)) { return JSVAL_TO_OBJECT(v); } JSObject *uxpco = JS_NewObjectWithGivenProto(cx, &sXPC_XOW_JSClass.base, nsnull, STOBJ_GET_PARENT(obj)); if (!uxpco) { return nsnull; } JSAutoTempValueRooter tvr(cx, uxpco); jsval wrappedObj, parentScope; if (!JS_GetReservedSlot(cx, obj, XPCWrapper::sWrappedObjSlot, &wrappedObj) || !JS_GetReservedSlot(cx, obj, XPC_XOW_ScopeSlot, &parentScope)) { return nsnull; } if (!JS_SetReservedSlot(cx, uxpco, XPCWrapper::sWrappedObjSlot, wrappedObj) || !JS_SetReservedSlot(cx, uxpco, XPCWrapper::sFlagsSlot, INT_TO_JSVAL(FLAG_IS_UXPC_OBJECT)) || !JS_SetReservedSlot(cx, uxpco, XPC_XOW_ScopeSlot, parentScope)) { return nsnull; } if (!JS_SetReservedSlot(cx, obj, sUXPCObjectSlot, OBJECT_TO_JSVAL(uxpco))) { return nsnull; } return uxpco; }
static JSObject * XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) { JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { ThrowException(NS_ERROR_INVALID_ARG, cx); return nsnull; } XPCCallContext ccx(JS_CALLER, cx); if (!ccx.IsValid()) { ThrowException(NS_ERROR_FAILURE, cx); return nsnull; } nsresult rv = CanAccessWrapper(cx, wrappedObj, nsnull); if (NS_FAILED(rv)) { if (rv == NS_ERROR_DOM_PROP_ACCESS_DENIED) { // Can't create iterators for foreign objects. ThrowException(rv, cx); return nsnull; } ThrowException(NS_ERROR_FAILURE, cx); return nsnull; } JSObject *wrapperIter = JS_NewObject(cx, &sXPC_XOW_JSClass.base, nsnull, JS_GetGlobalForObject(cx, obj)); if (!wrapperIter) { return nsnull; } JSAutoTempValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); // Initialize our XOW. jsval v = OBJECT_TO_JSVAL(wrappedObj); if (!JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sWrappedObjSlot, v) || !JS_SetReservedSlot(cx, wrapperIter, XPCWrapper::sFlagsSlot, JSVAL_ZERO) || !JS_SetReservedSlot(cx, wrapperIter, XPC_XOW_ScopeSlot, PRIVATE_TO_JSVAL(nsnull))) { return nsnull; } return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, wrappedObj, keysonly); }
static JSObject * GetScopeFunction(JSContext *cx, JSObject *outerObj) { jsval v; if (!JS_GetReservedSlot(cx, outerObj, sScopeFunSlot, &v)) { return nsnull; } JSObject *unsafeObj = GetUnsafeObject(outerObj); JSObject *scopeobj = JS_GetGlobalForObject(cx, unsafeObj); OBJ_TO_INNER_OBJECT(cx, scopeobj); if (!scopeobj) { return nsnull; } if (JSVAL_IS_OBJECT(v)) { JSObject *funobj = JSVAL_TO_OBJECT(v); if (JS_GetGlobalForObject(cx, funobj) == scopeobj) { return funobj; } } JSFunction *fun = JS_NewFunction(cx, DummyNative, 0, 0, scopeobj, "SJOWContentBoundary"); if (!fun) { return nsnull; } JSObject *funobj = JS_GetFunctionObject(fun); if (!JS_SetReservedSlot(cx, outerObj, sScopeFunSlot, OBJECT_TO_JSVAL(funobj))) { return nsnull; } return funobj; }
// Returns a weak reference. static nsIPrincipal * FindObjectPrincipals(JSContext *cx, JSObject *safeObj, JSObject *innerObj) { // Check if we have a cached principal first. jsval v; if (!JS_GetReservedSlot(cx, safeObj, XPC_SJOW_SLOT_PRINCIPAL, &v)) { return nsnull; } if (!JSVAL_IS_VOID(v)) { // Found one! No need to do any more refcounting. return static_cast<nsIPrincipal *>(JSVAL_TO_PRIVATE(v)); } nsCOMPtr<nsIPrincipal> objPrincipal; nsresult rv = FindPrincipals(cx, innerObj, getter_AddRefs(objPrincipal), nsnull, nsnull); if (NS_FAILED(rv)) { return nsnull; } if (!JS_SetReservedSlot(cx, safeObj, XPC_SJOW_SLOT_PRINCIPAL, PRIVATE_TO_JSVAL(objPrincipal.get()))) { return nsnull; } // The wrapper owns the principal now. return objPrincipal.forget().get(); }
// todo: similar code is also in ejsnet.cpp JSBool newStreamObject(JSContext* cx, JSObject* obj, std::streambuf* stream, jsval* rval) { // todo: this is quite ugly // create javascript Stream object and set stream pointer // the difficulty is that we do not have any native reference // => we must use the interpreter to indirectly create a native Stream // wrapper object and set the private data accordingly // this is only safe if we know that the created javascript object // is of the correct class (stream_class) otherwise this would be dangerous jsval streamval; if (!ejs_evalExpression(cx,obj,"new (ejs.ModuleLoader.get(\"Stream\").Stream)()",&streamval)) return JS_FALSE; // todo: is this enough to root this object? *rval=streamval; if (!JSVAL_IS_OBJECT(streamval)) EJS_THROW_ERROR(cx,obj,"failed to create Stream object"); JSObject* jsstream=JSVAL_TO_OBJECT(streamval); // make sure this object has a private slot and it is NULL JSClass* oclass; if ((!(oclass=JS_GET_CLASS(cx,jsstream))) || (!(oclass->flags & JSCLASS_HAS_PRIVATE)) || (JS_GetPrivate(cx,jsstream)) || (std::string("Stream")!=oclass->name)) EJS_THROW_ERROR(cx,obj,"you have messed with the Stream object"); if (!JS_SetPrivate(cx,jsstream,(void *)stream)) return JS_FALSE; // tell the stream object wether to delete this streambuf JS_SetReservedSlot(cx,jsstream,0,JSVAL_TRUE); return JS_TRUE; }
static JSBool vm_jschars(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSString *str = NULL; jschar *ptr; if (argc != 1) return gpsee_throw(cx, MODULE_ID ".jschars.arguments.count"); if (!JSVAL_IS_STRING(argv[0])) { str = JS_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; /* OOM */ argv[0] = STRING_TO_JSVAL(str); /* Provide a temporary GC root */ ptr = JS_GetStringChars(str); } else { ptr = JS_GetStringChars(JSVAL_TO_STRING(argv[0])); } obj = gpsee_newByteThing(cx, ptr, 0, JS_FALSE); if (!obj) return JS_FALSE; *rval = OBJECT_TO_JSVAL(obj); if (str) JS_SetReservedSlot(cx, obj, 0, STRING_TO_JSVAL(str)); /* Provide a proper lifetimed GC root */ return JS_TRUE; }
JSBool XPC_COW_WrapFunction(JSContext *cx, JSObject *outerObj, JSObject *funobj, jsval *rval) { jsval funobjVal = OBJECT_TO_JSVAL(funobj); JSFunction *wrappedFun = reinterpret_cast<JSFunction *>(xpc_GetJSPrivate(funobj)); JSNative native = JS_GetFunctionNative(cx, wrappedFun); if (!native || native == XPC_COW_FunctionWrapper) { *rval = funobjVal; return JS_TRUE; } JSFunction *funWrapper = JS_NewFunction(cx, XPC_COW_FunctionWrapper, JS_GetFunctionArity(wrappedFun), 0, JS_GetGlobalForObject(cx, outerObj), JS_GetFunctionName(wrappedFun)); if (!funWrapper) { return JS_FALSE; } JSObject *funWrapperObj = JS_GetFunctionObject(funWrapper); *rval = OBJECT_TO_JSVAL(funWrapperObj); return JS_SetReservedSlot(cx, funWrapperObj, XPCWrapper::eWrappedFunctionSlot, funobjVal); }
bool Library::Close(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject obj(cx); if (args.thisv().isObject()) obj = &args.thisv().toObject(); if (!obj || !IsLibrary(obj)) { JS_ReportErrorASCII(cx, "not a library"); return false; } if (args.length() != 0) { JS_ReportErrorASCII(cx, "close doesn't take any arguments"); return false; } // delete our internal objects UnloadLibrary(obj); JS_SetReservedSlot(obj, SLOT_LIBRARY, PrivateValue(nullptr)); args.rval().setUndefined(); return true; }
JSObject* JavaObject::construct(JSContext* ctx, SessionData* data, int objectRef) { // TODO: prototype? parent? Debug::log(Debug::Spam) << "JavaObject::construct objectId=" << objectRef << Debug::flush; JSObject* obj = JS_NewObject(ctx, &JavaObjectClass, NULL, NULL); Debug::log(Debug::Spam) << " obj=" << obj << Debug::flush; if (!obj) { return NULL; } // set the session data if (!JS_SetPrivate(ctx, obj, data)) { Debug::log(Debug::Error) << "Could not set private data" << Debug::flush; return NULL; } // set the objectId if (!JS_SetReservedSlot(ctx, obj, 0, INT_TO_JSVAL(objectRef))) { Debug::log(Debug::Error) << "Could not set reserved slot" << Debug::flush; return NULL; } // define toString (TODO: some way to avoid doing this each time) #if GECKO_VERSION < 2000 if (!JS_DefineFunction(ctx, obj, "toString", JavaObject::toString, 0, 0)) { Debug::log(Debug::Error) << "Could not define toString method on object" << Debug::flush; } #else if (!JS_DefineFunction(ctx, obj, "toString", JavaObject::toString20, 0, 0)) { Debug::log(Debug::Error) << "Could not define toString method on object" << Debug::flush; } #endif //GECKO_VERSION return obj; }
JSBool http_uri(JSContext* cx, JSObject* req, couch_args* args, jsval* uri_val) { FILE* uri_fp = NULL; JSString* uri_str; // Default is http://localhost:5984/ when no uri file is specified if (!args->uri_file) { uri_str = JS_InternString(cx, "http://localhost:5984/"); *uri_val = STRING_TO_JSVAL(uri_str); return JS_TRUE; } // Else check to see if the base url is cached in a reserved slot if (JS_GetReservedSlot(cx, req, 0, uri_val) && !JSVAL_IS_VOID(*uri_val)) { return JS_TRUE; } // Read the first line of the couch.uri file. if(!((uri_fp = fopen(args->uri_file, "r")) && (uri_str = couch_readline(cx, uri_fp)))) { JS_ReportError(cx, "Failed to read couch.uri file."); goto error; } fclose(uri_fp); *uri_val = STRING_TO_JSVAL(uri_str); JS_SetReservedSlot(cx, req, 0, *uri_val); return JS_TRUE; error: if(uri_fp) fclose(uri_fp); return JS_FALSE; }
JSObject *newDelegate() { static const JSClass delegateClass = { "delegate", JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_RESERVED_SLOTS(1), JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, nullptr, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; /* Create the global object. */ JS::CompartmentOptions options; options.setVersion(JSVERSION_LATEST); JS::RootedObject global(cx); global = JS_NewGlobalObject(cx, &delegateClass, nullptr, JS::FireOnNewGlobalHook, options); JS_SetReservedSlot(global, 0, JS::Int32Value(42)); /* * Ensure the delegate is not in the nursery because for the purpose of this * test we're going to put it in a private slot where it won't get updated. */ JS_GC(rt); return global; }
static JSBool get_nested_interface_object (JSContext *context, JSObject *parent_obj, Boxed *parent_priv, GIFieldInfo *field_info, GITypeInfo *type_info, GIBaseInfo *interface_info, jsval *value) { JSObject *obj; JSObject *proto; int offset; Boxed *priv; Boxed *proto_priv; if (!struct_is_simple ((GIStructInfo *)interface_info)) { gjs_throw(context, "Reading field %s.%s is not supported", g_base_info_get_name ((GIBaseInfo *)parent_priv->info), g_base_info_get_name ((GIBaseInfo *)field_info)); return JS_FALSE; } proto = gjs_lookup_boxed_prototype(context, (GIBoxedInfo*) interface_info); proto_priv = priv_from_js(context, proto); offset = g_field_info_get_offset (field_info); obj = JS_NewObjectWithGivenProto(context, JS_GET_CLASS(context, proto), proto, gjs_get_import_global (context)); if (obj == NULL) return JS_FALSE; GJS_INC_COUNTER(boxed); priv = g_slice_new0(Boxed); JS_SetPrivate(context, obj, priv); priv->info = (GIBoxedInfo*) interface_info; g_base_info_ref( (GIBaseInfo*) priv->info); priv->gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo*) interface_info); priv->can_allocate_directly = proto_priv->can_allocate_directly; /* A structure nested inside a parent object; doesn't have an independent allocation */ priv->gboxed = ((char *)parent_priv->gboxed) + offset; priv->not_owning_gboxed = TRUE; /* We never actually read the reserved slot, but we put the parent object * into it to hold onto the parent object. */ JS_SetReservedSlot(context, obj, 0, OBJECT_TO_JSVAL (parent_obj)); *value = OBJECT_TO_JSVAL(obj); return JS_TRUE; }
/** * Extract the FinalizationEvent from an instance of FinalizationWitness * and clear the slot containing the FinalizationEvent. */ already_AddRefed<FinalizationEvent> ExtractFinalizationEvent(JSObject *objSelf) { JS::Value slotEvent = JS_GetReservedSlot(objSelf, WITNESS_SLOT_EVENT); if (slotEvent.isUndefined()) { // Forget() has been called return nullptr; } JS_SetReservedSlot(objSelf, WITNESS_SLOT_EVENT, JS::UndefinedValue()); return dont_AddRef(static_cast<FinalizationEvent*>(slotEvent.toPrivate())); }
JSBool MakeSOW(JSContext *cx, JSObject *obj) { #ifdef DEBUG { js::Class *clasp = obj->getClass(); NS_ASSERTION(clasp != &SystemOnlyWrapper::SOWClass && clasp != &XPCCrossOriginWrapper::XOWClass, "bad call"); } #endif jsval flags; return JS_GetReservedSlot(cx, obj, sFlagsSlot, &flags) && JS_SetReservedSlot(cx, obj, sFlagsSlot, INT_TO_JSVAL(JSVAL_TO_INT(flags) | FLAG_SOW)); }
JSObject * ngx_http_js__nginx_chain__wrap(JSContext *cx, ngx_chain_t *ch, JSObject *request) { TRACE(); JSObject *chain; chain = JS_NewObject(cx, &ngx_http_js__nginx_chain__class, ngx_http_js__nginx_chain__prototype, NULL); if (!chain) { JS_ReportOutOfMemory(cx); return NULL; } JS_SetPrivate(cx, chain, ch); JS_SetReservedSlot(cx, chain, NGX_JS_CHAIN_SLOT__REQUEST, OBJECT_TO_JSVAL(request)); return chain; }
bool ScriptInterface::ReplaceNondeterministicRNG(boost::rand48& rng) { jsval math; if (JS_GetProperty(m->m_cx, m->m_glob, "Math", &math) && JSVAL_IS_OBJECT(math)) { JSFunction* random = JS_DefineFunction(m->m_cx, JSVAL_TO_OBJECT(math), "random", Math_random, 0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); if (random) { // Store the RNG in a slot which is sort-of-guaranteed to be unused by the JS engine if (JS_SetReservedSlot(m->m_cx, JS_GetFunctionObject(random), 0, PRIVATE_TO_JSVAL(&rng))) return true; } } LOGERROR(L"ReplaceNondeterministicRNG: failed to replace Math.random"); return false; }
// static XPCWrappedNativeScope* XPCWrappedNativeScope::GetNewOrUsed(XPCCallContext& ccx, JSObject* aGlobal) { XPCWrappedNativeScope* scope = FindInJSObjectScope(ccx, aGlobal, true); if (!scope) scope = new XPCWrappedNativeScope(ccx, aGlobal); else { // We need to call SetGlobal in order to refresh our cached // mPrototypeJSObject and to clear mPrototypeNoHelper (so we get a new // new one if requested in the new scope) in the case where the global // object is being reused (JS_ClearScope has been called). NOTE: We are // only called by nsXPConnect::InitClasses. scope->SetGlobal(ccx, aGlobal); } if (js::GetObjectClass(aGlobal)->flags & JSCLASS_XPCONNECT_GLOBAL) JS_SetReservedSlot(aGlobal, JSCLASS_GLOBAL_SLOT_COUNT, PRIVATE_TO_JSVAL(scope)); return scope; }
JSBool Library::Close(JSContext* cx, uintN argc, jsval* vp) { JSObject* obj = JS_THIS_OBJECT(cx, vp); if (!obj || !IsLibrary(cx, obj)) { JS_ReportError(cx, "not a library"); return JS_FALSE; } if (argc != 0) { JS_ReportError(cx, "close doesn't take any arguments"); return JS_FALSE; } // delete our internal objects Finalize(cx, obj); JS_SetReservedSlot(cx, obj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(NULL)); JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; }
JSObject* newDelegate() { static const js::Class delegateClass = { "delegate", JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_RESERVED_SLOTS(1), nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ nullptr, /* setProperty */ nullptr, /* enumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ nullptr, /* convert */ nullptr, /* finalize */ nullptr, /* call */ nullptr, /* hasInstance */ nullptr, /* construct */ JS_GlobalObjectTraceHook, JS_NULL_CLASS_SPEC, { nullptr, nullptr, false, nullptr, DelegateObjectMoved }, JS_NULL_OBJECT_OPS }; /* Create the global object. */ JS::CompartmentOptions options; options.setVersion(JSVERSION_LATEST); JS::RootedObject global(cx); global = JS_NewGlobalObject(cx, Jsvalify(&delegateClass), nullptr, JS::FireOnNewGlobalHook, options); JS_SetReservedSlot(global, 0, JS::Int32Value(42)); return global; }
void ScriptInterface_impl::Register(const char* name, JSNative fptr, uintN nargs) { JSFunction* func = JS_DefineFunction(m_cx, m_nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); if (!func) return; if (g_ScriptProfilingEnabled) { // Store the function name in a slot, so we can pass it to the profiler. // Use a flyweight std::string because we can't assume the caller has // a correctly-aligned string and that its lifetime is long enough typedef boost::flyweight< std::string, boost::flyweights::no_tracking // can't use no_locking; Register might be called in threads > LockedStringFlyweight; LockedStringFlyweight fw(name); JS_SetReservedSlot(m_cx, JS_GetFunctionObject(func), 0, PRIVATE_TO_JSVAL((void*)fw.get().c_str())); } }
JSBool WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj, XPCWrappedNativeScope *newScope) { typedef WrappedNative2WrapperMap::Link Link; XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance(); WrappedNative2WrapperMap *map = innerObj->GetScope()->GetWrapperMap(); Link *link; { // Scoped lock XPCAutoLock al(rt->GetMapLock()); link = map->FindLink(innerObj->GetFlatJSObject()); } if (!link) { // No link here means that there were no XOWs for this object. return JS_TRUE; } JSObject *xow = link->obj; { // Scoped lock. XPCAutoLock al(rt->GetMapLock()); if (!newScope->GetWrapperMap()->AddLink(innerObj->GetFlatJSObject(), link)) return JS_FALSE; map->Remove(innerObj->GetFlatJSObject()); } if (!xow) { // Nothing else to do. return JS_TRUE; } return JS_SetReservedSlot(cx, xow, XPC_XOW_ScopeSlot, PRIVATE_TO_JSVAL(newScope)) && JS_SetParent(cx, xow, newScope->GetGlobalJSObject()); }
bool Library::Close(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); JSObject* obj = JS_THIS_OBJECT(cx, vp); if (!obj) return false; if (!IsLibrary(obj)) { JS_ReportError(cx, "not a library"); return false; } if (args.length() != 0) { JS_ReportError(cx, "close doesn't take any arguments"); return false; } // delete our internal objects UnloadLibrary(obj); JS_SetReservedSlot(obj, SLOT_LIBRARY, PrivateValue(nullptr)); args.rval().setUndefined(); return true; }
JSObject* Library::Create(JSContext* cx, HandleValue path, const JSCTypesCallbacks* callbacks) { RootedObject libraryObj(cx, JS_NewObject(cx, &sLibraryClass)); if (!libraryObj) return nullptr; // initialize the library JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PrivateValue(nullptr)); // attach API functions if (!JS_DefineFunctions(cx, libraryObj, sLibraryFunctions)) return nullptr; if (!path.isString()) { JS_ReportErrorASCII(cx, "open takes a string argument"); return nullptr; } PRLibSpec libSpec; RootedFlatString pathStr(cx, JS_FlattenString(cx, path.toString())); if (!pathStr) return nullptr; AutoStableStringChars pathStrChars(cx); if (!pathStrChars.initTwoByte(cx, pathStr)) return nullptr; #ifdef XP_WIN // On Windows, converting to native charset may corrupt path string. // So, we have to use Unicode path directly. char16ptr_t pathChars = pathStrChars.twoByteChars(); libSpec.value.pathname_u = pathChars; libSpec.type = PR_LibSpec_PathnameU; #else // Convert to platform native charset if the appropriate callback has been // provided. char* pathBytes; if (callbacks && callbacks->unicodeToNative) { pathBytes = callbacks->unicodeToNative(cx, pathStrChars.twoByteChars(), pathStr->length()); if (!pathBytes) return nullptr; } else { // Fallback: assume the platform native charset is UTF-8. This is true // for Mac OS X, Android, and probably Linux. size_t nbytes = GetDeflatedUTF8StringLength(cx, pathStrChars.twoByteChars(), pathStr->length()); if (nbytes == (size_t) -1) return nullptr; pathBytes = static_cast<char*>(JS_malloc(cx, nbytes + 1)); if (!pathBytes) return nullptr; ASSERT_OK(DeflateStringToUTF8Buffer(cx, pathStrChars.twoByteChars(), pathStr->length(), pathBytes, &nbytes)); pathBytes[nbytes] = 0; } libSpec.value.pathname = pathBytes; libSpec.type = PR_LibSpec_Pathname; #endif PRLibrary* library = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW); #ifndef XP_WIN JS_free(cx, pathBytes); #endif if (!library) { #define MAX_ERROR_LEN 1024 char error[MAX_ERROR_LEN] = "Cannot get error from NSPR."; uint32_t errorLen = PR_GetErrorTextLength(); if (errorLen && errorLen < MAX_ERROR_LEN) PR_GetErrorText(error); #undef MAX_ERROR_LEN if (JS::StringIsASCII(error)) { JSAutoByteString pathCharsUTF8; if (pathCharsUTF8.encodeUtf8(cx, pathStr)) JS_ReportErrorUTF8(cx, "couldn't open library %s: %s", pathCharsUTF8.ptr(), error); } else { JSAutoByteString pathCharsLatin1; if (pathCharsLatin1.encodeLatin1(cx, pathStr)) JS_ReportErrorLatin1(cx, "couldn't open library %s: %s", pathCharsLatin1.ptr(), error); } return nullptr; } // stash the library JS_SetReservedSlot(libraryObj, SLOT_LIBRARY, PrivateValue(library)); return libraryObj; }
bool Library::Declare(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject obj(cx, JS_THIS_OBJECT(cx, vp)); if (!obj) return false; if (!IsLibrary(obj)) { JS_ReportErrorASCII(cx, "not a library"); return false; } PRLibrary* library = GetLibrary(obj); if (!library) { JS_ReportErrorASCII(cx, "library not open"); return false; } // We allow two API variants: // 1) library.declare(name, abi, returnType, argType1, ...) // declares a function with the given properties, and resolves the symbol // address in the library. // 2) library.declare(name, type) // declares a symbol of 'type', and resolves it. The object that comes // back will be of type 'type', and will point into the symbol data. // This data will be both readable and writable via the usual CData // accessors. If 'type' is a PointerType to a FunctionType, the result will // be a function pointer, as with 1). if (args.length() < 2) { JS_ReportErrorASCII(cx, "declare requires at least two arguments"); return false; } if (!args[0].isString()) { JS_ReportErrorASCII(cx, "first argument must be a string"); return false; } RootedObject fnObj(cx, nullptr); RootedObject typeObj(cx); bool isFunction = args.length() > 2; if (isFunction) { // Case 1). // Create a FunctionType representing the function. fnObj = FunctionType::CreateInternal(cx, args[1], args[2], HandleValueArray::subarray(args, 3, args.length() - 3)); if (!fnObj) return false; // Make a function pointer type. typeObj = PointerType::CreateInternal(cx, fnObj); if (!typeObj) return false; } else { // Case 2). if (args[1].isPrimitive() || !CType::IsCType(args[1].toObjectOrNull()) || !CType::IsSizeDefined(args[1].toObjectOrNull())) { JS_ReportErrorASCII(cx, "second argument must be a type of defined size"); return false; } typeObj = args[1].toObjectOrNull(); if (CType::GetTypeCode(typeObj) == TYPE_pointer) { fnObj = PointerType::GetBaseType(typeObj); isFunction = fnObj && CType::GetTypeCode(fnObj) == TYPE_function; } } void* data; PRFuncPtr fnptr; RootedString nameStr(cx, args[0].toString()); AutoCString symbol; if (isFunction) { // Build the symbol, with mangling if necessary. FunctionType::BuildSymbolName(nameStr, fnObj, symbol); AppendString(symbol, "\0"); // Look up the function symbol. fnptr = PR_FindFunctionSymbol(library, symbol.begin()); if (!fnptr) { JS_ReportErrorASCII(cx, "couldn't find function symbol in library"); return false; } data = &fnptr; } else { // 'typeObj' is another data type. Look up the data symbol. AppendString(symbol, nameStr); AppendString(symbol, "\0"); data = PR_FindSymbol(library, symbol.begin()); if (!data) { JS_ReportErrorASCII(cx, "couldn't find symbol in library"); return false; } } RootedObject result(cx, CData::Create(cx, typeObj, obj, data, isFunction)); if (!result) return false; if (isFunction) JS_SetReservedSlot(result, SLOT_FUNNAME, StringValue(nameStr)); args.rval().setObject(*result); // Seal the CData object, to prevent modification of the function pointer. // This permanently associates this object with the library, and avoids // having to do things like reset SLOT_REFERENT when someone tries to // change the pointer value. // XXX This will need to change when bug 541212 is fixed -- CData::ValueSetter // could be called on a sealed object. if (isFunction && !JS_FreezeObject(cx, result)) return false; return true; }
JSObject* Library::Create(JSContext* cx, jsval path, JSCTypesCallbacks* callbacks) { JSObject* libraryObj = JS_NewObject(cx, &sLibraryClass, NULL, NULL); if (!libraryObj) return NULL; js::AutoObjectRooter root(cx, libraryObj); // initialize the library if (!JS_SetReservedSlot(cx, libraryObj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(NULL))) return NULL; // attach API functions if (!JS_DefineFunctions(cx, libraryObj, sLibraryFunctions)) return NULL; if (!JSVAL_IS_STRING(path)) { JS_ReportError(cx, "open takes a string argument"); return NULL; } PRLibSpec libSpec; JSFlatString* pathStr = JS_FlattenString(cx, JSVAL_TO_STRING(path)); if (!pathStr) return NULL; #ifdef XP_WIN // On Windows, converting to native charset may corrupt path string. // So, we have to use Unicode path directly. const PRUnichar* pathChars = JS_GetFlatStringChars(pathStr); if (!pathChars) return NULL; libSpec.value.pathname_u = pathChars; libSpec.type = PR_LibSpec_PathnameU; #else // Convert to platform native charset if the appropriate callback has been // provided. char* pathBytes; if (callbacks && callbacks->unicodeToNative) { pathBytes = callbacks->unicodeToNative(cx, pathStr->chars(), pathStr->length()); if (!pathBytes) return NULL; } else { // Fallback: assume the platform native charset is UTF-8. This is true // for Mac OS X, Android, and probably Linux. size_t nbytes = js_GetDeflatedUTF8StringLength(cx, pathStr->chars(), pathStr->length()); if (nbytes == (size_t) -1) return NULL; pathBytes = static_cast<char*>(JS_malloc(cx, nbytes + 1)); if (!pathBytes) return NULL; ASSERT_OK(js_DeflateStringToUTF8Buffer(cx, pathStr->chars(), pathStr->length(), pathBytes, &nbytes)); pathBytes[nbytes] = 0; } libSpec.value.pathname = pathBytes; libSpec.type = PR_LibSpec_Pathname; #endif PRLibrary* library = PR_LoadLibraryWithFlags(libSpec, 0); #ifndef XP_WIN JS_free(cx, pathBytes); #endif if (!library) { JS_ReportError(cx, "couldn't open library"); return NULL; } // stash the library if (!JS_SetReservedSlot(cx, libraryObj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(library))) return NULL; return libraryObj; }
JSBool XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface) { if(IsConstant()) { const nsXPTConstant* constant; if(NS_FAILED(iface->GetInterfaceInfo()->GetConstant(mIndex, &constant))) return JS_FALSE; const nsXPTCMiniVariant& mv = *constant->GetValue(); // XXX Big Hack! nsXPTCVariant v; v.flags = 0; v.type = constant->GetType(); memcpy(&v.val, &mv.val, sizeof(mv.val)); jsval resultVal; if(!XPCConvert::NativeData2JS(ccx, &resultVal, &v.val, v.type, nsnull, nsnull, nsnull)) return JS_FALSE; { // scoped lock XPCAutoLock lock(ccx.GetRuntime()->GetMapLock()); mVal = resultVal; mFlags |= RESOLVED; } return JS_TRUE; } // else... // This is a method or attribute - we'll be needing a function object intN argc; intN flags; JSNative callback; if(IsMethod()) { const nsXPTMethodInfo* info; if(NS_FAILED(iface->GetInterfaceInfo()->GetMethodInfo(mIndex, &info))) return JS_FALSE; // Note: ASSUMES that retval is last arg. argc = (intN) info->GetParamCount(); if(argc && info->GetParam((uint8)(argc-1)).IsRetval()) argc-- ; flags = 0; callback = XPC_WN_CallMethod; } else { if(IsWritableAttribute()) flags = JSFUN_GETTER | JSFUN_SETTER; else flags = JSFUN_GETTER; argc = 0; callback = XPC_WN_GetterSetter; } // We need to use the safe context for this thread because we don't want // to parent the new (and cached forever!) function object to the current // JSContext's global object. That would be bad! JSContext* cx = ccx.GetSafeJSContext(); if(!cx) return JS_FALSE; const char *memberName = iface->GetMemberName(ccx, this); jsrefcount suspendDepth = 0; if(cx != ccx) { // Switching contexts, suspend the old and enter the new request. suspendDepth = JS_SuspendRequest(ccx); JS_BeginRequest(cx); } JSFunction *fun = JS_NewFunction(cx, callback, argc, flags, nsnull, memberName); if(suspendDepth) { JS_EndRequest(cx); JS_ResumeRequest(ccx, suspendDepth); } if(!fun) return JS_FALSE; JSObject* funobj = JS_GetFunctionObject(fun); if(!funobj) return JS_FALSE; AUTO_MARK_JSVAL(ccx, OBJECT_TO_JSVAL(funobj)); STOBJ_CLEAR_PARENT(funobj); STOBJ_CLEAR_PROTO(funobj); if(!JS_SetReservedSlot(ccx, funobj, 0, PRIVATE_TO_JSVAL(iface))|| !JS_SetReservedSlot(ccx, funobj, 1, PRIVATE_TO_JSVAL(this))) return JS_FALSE; { // scoped lock XPCAutoLock lock(ccx.GetRuntime()->GetMapLock()); mVal = OBJECT_TO_JSVAL(funobj); mFlags |= RESOLVED; } return JS_TRUE; }