123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
- #ifndef mozilla_dom_BindingUtils_h__
- #define mozilla_dom_BindingUtils_h__
- #include "jsfriendapi.h"
- #include "jswrapper.h"
- #include "js/Conversions.h"
- #include "mozilla/ArrayUtils.h"
- #include "mozilla/Alignment.h"
- #include "mozilla/Array.h"
- #include "mozilla/Assertions.h"
- #include "mozilla/CycleCollectedJSContext.h"
- #include "mozilla/DeferredFinalize.h"
- #include "mozilla/dom/BindingDeclarations.h"
- #include "mozilla/dom/CallbackObject.h"
- #include "mozilla/dom/DOMJSClass.h"
- #include "mozilla/dom/DOMJSProxyHandler.h"
- #include "mozilla/dom/Exceptions.h"
- #include "mozilla/dom/NonRefcountedDOMObject.h"
- #include "mozilla/dom/Nullable.h"
- #include "mozilla/dom/RootedDictionary.h"
- #include "mozilla/SegmentedVector.h"
- #include "mozilla/dom/workers/Workers.h"
- #include "mozilla/ErrorResult.h"
- #include "mozilla/Likely.h"
- #include "mozilla/MemoryReporting.h"
- #include "nsAutoPtr.h"
- #include "nsIDocument.h"
- #include "nsIGlobalObject.h"
- #include "nsIXPConnect.h"
- #include "nsJSUtils.h"
- #include "nsISupportsImpl.h"
- #include "qsObjectHelper.h"
- #include "xpcpublic.h"
- #include "nsIVariant.h"
- #include "mozilla/dom/FakeString.h"
- #include "nsWrapperCacheInlines.h"
- class nsGenericHTMLElement;
- class nsIJSID;
- namespace mozilla {
- enum UseCounter : int16_t;
- namespace dom {
- class CustomElementReactionsStack;
- template<typename KeyType, typename ValueType> class Record;
- nsresult
- UnwrapArgImpl(JS::Handle<JSObject*> src, const nsIID& iid, void** ppArg);
- nsresult
- UnwrapWindowProxyImpl(JS::Handle<JSObject*> src, nsPIDOMWindowOuter** ppArg);
- /** Convert a jsval to an XPCOM pointer. Caller must not assume that src will
- keep the XPCOM pointer rooted. */
- template <class Interface>
- inline nsresult
- UnwrapArg(JS::Handle<JSObject*> src, Interface** ppArg)
- {
- return UnwrapArgImpl(src, NS_GET_TEMPLATE_IID(Interface),
- reinterpret_cast<void**>(ppArg));
- }
- template <>
- inline nsresult
- UnwrapArg<nsPIDOMWindowOuter>(JS::Handle<JSObject*> src, nsPIDOMWindowOuter** ppArg)
- {
- return UnwrapWindowProxyImpl(src, ppArg);
- }
- nsresult
- UnwrapXPConnectImpl(JSContext* cx, JS::MutableHandle<JS::Value> src,
- const nsIID& iid, void** ppArg);
- /*
- * Convert a jsval being used as a Web IDL interface implementation to an XPCOM
- * pointer; this is only used for Web IDL interfaces that specify
- * hasXPConnectImpls. This is not the same as UnwrapArg because caller _can_
- * assume that if unwrapping succeeds "val" will be updated so it's rooting the
- * XPCOM pointer. Also, UnwrapXPConnect doesn't need to worry about doing
- * XPCWrappedJS things.
- *
- * val must be an ObjectValue.
- */
- template<class Interface>
- inline nsresult
- UnwrapXPConnect(JSContext* cx, JS::MutableHandle<JS::Value> val,
- Interface** ppThis)
- {
- return UnwrapXPConnectImpl(cx, val, NS_GET_TEMPLATE_IID(Interface),
- reinterpret_cast<void**>(ppThis));
- }
- bool
- ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
- bool aSecurityError, const char* aInterfaceName);
- bool
- ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
- bool aSecurityError, prototypes::ID aProtoId);
- // Returns true if the JSClass is used for DOM objects.
- inline bool
- IsDOMClass(const JSClass* clasp)
- {
- return clasp->flags & JSCLASS_IS_DOMJSCLASS;
- }
- inline bool
- IsDOMClass(const js::Class* clasp)
- {
- return IsDOMClass(Jsvalify(clasp));
- }
- // Return true if the JSClass is used for non-proxy DOM objects.
- inline bool
- IsNonProxyDOMClass(const js::Class* clasp)
- {
- return IsDOMClass(clasp) && !clasp->isProxy();
- }
- inline bool
- IsNonProxyDOMClass(const JSClass* clasp)
- {
- return IsNonProxyDOMClass(js::Valueify(clasp));
- }
- // Returns true if the JSClass is used for DOM interface and interface
- // prototype objects.
- inline bool
- IsDOMIfaceAndProtoClass(const JSClass* clasp)
- {
- return clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS;
- }
- inline bool
- IsDOMIfaceAndProtoClass(const js::Class* clasp)
- {
- return IsDOMIfaceAndProtoClass(Jsvalify(clasp));
- }
- static_assert(DOM_OBJECT_SLOT == 0,
- "DOM_OBJECT_SLOT doesn't match the proxy private slot. "
- "Expect bad things");
- template <class T>
- inline T*
- UnwrapDOMObject(JSObject* obj)
- {
- MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
- "Don't pass non-DOM objects to this function");
- JS::Value val = js::GetReservedOrProxyPrivateSlot(obj, DOM_OBJECT_SLOT);
- return static_cast<T*>(val.toPrivate());
- }
- template <class T>
- inline T*
- UnwrapPossiblyNotInitializedDOMObject(JSObject* obj)
- {
- // This is used by the OjectMoved JSClass hook which can be called before
- // JS_NewObject has returned and so before we have a chance to set
- // DOM_OBJECT_SLOT to anything useful.
- MOZ_ASSERT(IsDOMClass(js::GetObjectClass(obj)),
- "Don't pass non-DOM objects to this function");
- JS::Value val = js::GetReservedOrProxyPrivateSlot(obj, DOM_OBJECT_SLOT);
- if (val.isUndefined()) {
- return nullptr;
- }
- return static_cast<T*>(val.toPrivate());
- }
- inline const DOMJSClass*
- GetDOMClass(const js::Class* clasp)
- {
- return IsDOMClass(clasp) ? DOMJSClass::FromJSClass(clasp) : nullptr;
- }
- inline const DOMJSClass*
- GetDOMClass(JSObject* obj)
- {
- return GetDOMClass(js::GetObjectClass(obj));
- }
- inline nsISupports*
- UnwrapDOMObjectToISupports(JSObject* aObject)
- {
- const DOMJSClass* clasp = GetDOMClass(aObject);
- if (!clasp || !clasp->mDOMObjectIsISupports) {
- return nullptr;
- }
- return UnwrapPossiblyNotInitializedDOMObject<nsISupports>(aObject);
- }
- inline bool
- IsDOMObject(JSObject* obj)
- {
- return IsDOMClass(js::GetObjectClass(obj));
- }
- // There are two valid ways to use UNWRAP_OBJECT: Either obj needs to
- // be a MutableHandle<JSObject*>, or value needs to be a strong-reference
- // smart pointer type (OwningNonNull or RefPtr or nsCOMPtr), in which case obj
- // can be anything that converts to JSObject*.
- #define UNWRAP_OBJECT(Interface, obj, value) \
- mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface, \
- mozilla::dom::Interface##Binding::NativeType>(obj, value)
- // Test whether the given object is an instance of the given interface.
- #define IS_INSTANCE_OF(Interface, obj) \
- mozilla::dom::IsInstanceOf<mozilla::dom::prototypes::id::Interface, \
- mozilla::dom::Interface##Binding::NativeType>(obj)
- // Unwrap the given non-wrapper object. This can be used with any obj that
- // converts to JSObject*; as long as that JSObject* is live the return value
- // will be valid.
- #define UNWRAP_NON_WRAPPER_OBJECT(Interface, obj, value) \
- mozilla::dom::UnwrapNonWrapperObject<mozilla::dom::prototypes::id::Interface, \
- mozilla::dom::Interface##Binding::NativeType>(obj, value)
- // Some callers don't want to set an exception when unwrapping fails
- // (for example, overload resolution uses unwrapping to tell what sort
- // of thing it's looking at).
- // U must be something that a T* can be assigned to (e.g. T* or an RefPtr<T>).
- //
- // The obj argument will be mutated to point to CheckedUnwrap of itself if the
- // passed-in value is not a DOM object and CheckedUnwrap succeeds.
- //
- // If mayBeWrapper is true, there are three valid ways to invoke
- // UnwrapObjectInternal: Either obj needs to be a class wrapping a
- // MutableHandle<JSObject*>, with an assignment operator that sets the handle to
- // the given object, or U needs to be a strong-reference smart pointer type
- // (OwningNonNull or RefPtr or nsCOMPtr), or the value being stored in "value"
- // must not escape past being tested for falsiness immediately after the
- // UnwrapObjectInternal call.
- //
- // If mayBeWrapper is false, obj can just be a JSObject*, and U anything that a
- // T* can be assigned to.
- namespace binding_detail {
- template <class T, bool mayBeWrapper, typename U, typename V>
- MOZ_ALWAYS_INLINE nsresult
- UnwrapObjectInternal(V& obj, U& value, prototypes::ID protoID,
- uint32_t protoDepth)
- {
- /* First check to see whether we have a DOM object */
- const DOMJSClass* domClass = GetDOMClass(obj);
- if (domClass) {
- /* This object is a DOM object. Double-check that it is safely
- castable to T by checking whether it claims to inherit from the
- class identified by protoID. */
- if (domClass->mInterfaceChain[protoDepth] == protoID) {
- value = UnwrapDOMObject<T>(obj);
- return NS_OK;
- }
- }
- /* Maybe we have a security wrapper or outer window? */
- if (!mayBeWrapper || !js::IsWrapper(obj)) {
- /* Not a DOM object, not a wrapper, just bail */
- return NS_ERROR_XPC_BAD_CONVERT_JS;
- }
- JSObject* unwrappedObj =
- js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
- if (!unwrappedObj) {
- return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
- }
- MOZ_ASSERT(!js::IsWrapper(unwrappedObj));
- // Recursive call is OK, because now we're using false for mayBeWrapper and
- // we never reach this code if that boolean is false, so can't keep calling
- // ourselves.
- //
- // Unwrap into a temporary pointer, because in general unwrapping into
- // something of type U might trigger GC (e.g. release the value currently
- // stored in there, with arbitrary consequences) and invalidate the
- // "unwrappedObj" pointer.
- T* tempValue;
- nsresult rv = UnwrapObjectInternal<T, false>(unwrappedObj, tempValue,
- protoID, protoDepth);
- if (NS_SUCCEEDED(rv)) {
- // It's very important to not update "obj" with the "unwrappedObj" value
- // until we know the unwrap has succeeded. Otherwise, in a situation in
- // which we have an overload of object and primitive we could end up
- // converting to the primitive from the unwrappedObj, whereas we want to do
- // it from the original object.
- obj = unwrappedObj;
- // And now assign to "value"; at this point we don't care if a GC happens
- // and invalidates unwrappedObj.
- value = tempValue;
- return NS_OK;
- }
- /* It's the wrong sort of DOM object */
- return NS_ERROR_XPC_BAD_CONVERT_JS;
- }
- struct MutableObjectHandleWrapper {
- explicit MutableObjectHandleWrapper(JS::MutableHandle<JSObject*> aHandle)
- : mHandle(aHandle)
- {
- }
- void operator=(JSObject* aObject)
- {
- MOZ_ASSERT(aObject);
- mHandle.set(aObject);
- }
- operator JSObject*() const
- {
- return mHandle;
- }
- private:
- JS::MutableHandle<JSObject*> mHandle;
- };
- struct MutableValueHandleWrapper {
- explicit MutableValueHandleWrapper(JS::MutableHandle<JS::Value> aHandle)
- : mHandle(aHandle)
- {
- }
- void operator=(JSObject* aObject)
- {
- MOZ_ASSERT(aObject);
- mHandle.setObject(*aObject);
- }
- operator JSObject*() const
- {
- return &mHandle.toObject();
- }
- private:
- JS::MutableHandle<JS::Value> mHandle;
- };
- } // namespace binding_detail
- // UnwrapObject overloads that ensure we have a MutableHandle to keep it alive.
- template<prototypes::ID PrototypeID, class T, typename U>
- MOZ_ALWAYS_INLINE nsresult
- UnwrapObject(JS::MutableHandle<JSObject*> obj, U& value)
- {
- binding_detail::MutableObjectHandleWrapper wrapper(obj);
- return binding_detail::UnwrapObjectInternal<T, true>(
- wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
- }
- template<prototypes::ID PrototypeID, class T, typename U>
- MOZ_ALWAYS_INLINE nsresult
- UnwrapObject(JS::MutableHandle<JS::Value> obj, U& value)
- {
- MOZ_ASSERT(obj.isObject());
- binding_detail::MutableValueHandleWrapper wrapper(obj);
- return binding_detail::UnwrapObjectInternal<T, true>(
- wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
- }
- // UnwrapObject overloads that ensure we have a strong ref to keep it alive.
- template<prototypes::ID PrototypeID, class T, typename U>
- MOZ_ALWAYS_INLINE nsresult
- UnwrapObject(JSObject* obj, RefPtr<U>& value)
- {
- return binding_detail::UnwrapObjectInternal<T, true>(
- obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
- }
- template<prototypes::ID PrototypeID, class T, typename U>
- MOZ_ALWAYS_INLINE nsresult
- UnwrapObject(JSObject* obj, nsCOMPtr<U>& value)
- {
- return binding_detail::UnwrapObjectInternal<T, true>(
- obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
- }
- template<prototypes::ID PrototypeID, class T, typename U>
- MOZ_ALWAYS_INLINE nsresult
- UnwrapObject(JSObject* obj, OwningNonNull<U>& value)
- {
- return binding_detail::UnwrapObjectInternal<T, true>(
- obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
- }
- // An UnwrapObject overload that just calls one of the JSObject* ones.
- template<prototypes::ID PrototypeID, class T, typename U>
- MOZ_ALWAYS_INLINE nsresult
- UnwrapObject(JS::Handle<JS::Value> obj, U& value)
- {
- MOZ_ASSERT(obj.isObject());
- return UnwrapObject<PrototypeID, T>(&obj.toObject(), value);
- }
- template<prototypes::ID PrototypeID, class T>
- MOZ_ALWAYS_INLINE bool
- IsInstanceOf(JSObject* obj)
- {
- void* ignored;
- nsresult unwrapped = binding_detail::UnwrapObjectInternal<T, true>(
- obj, ignored, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
- return NS_SUCCEEDED(unwrapped);
- }
- template<prototypes::ID PrototypeID, class T, typename U>
- MOZ_ALWAYS_INLINE nsresult
- UnwrapNonWrapperObject(JSObject* obj, U& value)
- {
- MOZ_ASSERT(!js::IsWrapper(obj));
- return binding_detail::UnwrapObjectInternal<T, false>(
- obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
- }
- inline bool
- IsNotDateOrRegExp(JSContext* cx, JS::Handle<JSObject*> obj,
- bool* notDateOrRegExp)
- {
- MOZ_ASSERT(obj);
- js::ESClass cls;
- if (!js::GetBuiltinClass(cx, obj, &cls)) {
- return false;
- }
- *notDateOrRegExp = cls != js::ESClass::Date && cls != js::ESClass::RegExp;
- return true;
- }
- MOZ_ALWAYS_INLINE bool
- IsObjectValueConvertibleToDictionary(JSContext* cx,
- JS::Handle<JS::Value> objVal,
- bool* convertible)
- {
- JS::Rooted<JSObject*> obj(cx, &objVal.toObject());
- return IsNotDateOrRegExp(cx, obj, convertible);
- }
- MOZ_ALWAYS_INLINE bool
- IsConvertibleToDictionary(JSContext* cx, JS::Handle<JS::Value> val,
- bool* convertible)
- {
- if (val.isNullOrUndefined()) {
- *convertible = true;
- return true;
- }
- if (!val.isObject()) {
- *convertible = false;
- return true;
- }
- return IsObjectValueConvertibleToDictionary(cx, val, convertible);
- }
- MOZ_ALWAYS_INLINE bool
- IsConvertibleToCallbackInterface(JSContext* cx, JS::Handle<JSObject*> obj,
- bool* convertible)
- {
- return IsNotDateOrRegExp(cx, obj, convertible);
- }
- // The items in the protoAndIfaceCache are indexed by the prototypes::id::ID,
- // constructors::id::ID and namedpropertiesobjects::id::ID enums, in that order.
- // The end of the prototype objects should be the start of the interface
- // objects, and the end of the interface objects should be the start of the
- // named properties objects.
- static_assert((size_t)constructors::id::_ID_Start ==
- (size_t)prototypes::id::_ID_Count &&
- (size_t)namedpropertiesobjects::id::_ID_Start ==
- (size_t)constructors::id::_ID_Count,
- "Overlapping or discontiguous indexes.");
- const size_t kProtoAndIfaceCacheCount = namedpropertiesobjects::id::_ID_Count;
- class ProtoAndIfaceCache
- {
- // The caching strategy we use depends on what sort of global we're dealing
- // with. For a window-like global, we want everything to be as fast as
- // possible, so we use a flat array, indexed by prototype/constructor ID.
- // For everything else (e.g. globals for JSMs), space is more important than
- // speed, so we use a two-level lookup table.
- class ArrayCache : public Array<JS::Heap<JSObject*>, kProtoAndIfaceCacheCount>
- {
- public:
- JSObject* EntrySlotIfExists(size_t i) {
- return (*this)[i];
- }
- JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
- return (*this)[i];
- }
- JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
- return (*this)[i];
- }
- void Trace(JSTracer* aTracer) {
- for (size_t i = 0; i < ArrayLength(*this); ++i) {
- JS::TraceEdge(aTracer, &(*this)[i], "protoAndIfaceCache[i]");
- }
- }
- size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
- return aMallocSizeOf(this);
- }
- };
- class PageTableCache
- {
- public:
- PageTableCache() {
- memset(mPages.begin(), 0, sizeof(mPages));
- }
- ~PageTableCache() {
- for (size_t i = 0; i < ArrayLength(mPages); ++i) {
- delete mPages[i];
- }
- }
- JSObject* EntrySlotIfExists(size_t i) {
- MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
- size_t pageIndex = i / kPageSize;
- size_t leafIndex = i % kPageSize;
- Page* p = mPages[pageIndex];
- if (!p) {
- return nullptr;
- }
- return (*p)[leafIndex];
- }
- JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
- MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
- size_t pageIndex = i / kPageSize;
- size_t leafIndex = i % kPageSize;
- Page* p = mPages[pageIndex];
- if (!p) {
- p = new Page;
- mPages[pageIndex] = p;
- }
- return (*p)[leafIndex];
- }
- JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
- MOZ_ASSERT(i < kProtoAndIfaceCacheCount);
- size_t pageIndex = i / kPageSize;
- size_t leafIndex = i % kPageSize;
- Page* p = mPages[pageIndex];
- MOZ_ASSERT(p);
- return (*p)[leafIndex];
- }
- void Trace(JSTracer* trc) {
- for (size_t i = 0; i < ArrayLength(mPages); ++i) {
- Page* p = mPages[i];
- if (p) {
- for (size_t j = 0; j < ArrayLength(*p); ++j) {
- JS::TraceEdge(trc, &(*p)[j], "protoAndIfaceCache[i]");
- }
- }
- }
- }
- size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
- size_t n = aMallocSizeOf(this);
- for (size_t i = 0; i < ArrayLength(mPages); ++i) {
- n += aMallocSizeOf(mPages[i]);
- }
- return n;
- }
- private:
- static const size_t kPageSize = 16;
- typedef Array<JS::Heap<JSObject*>, kPageSize> Page;
- static const size_t kNPages = kProtoAndIfaceCacheCount / kPageSize +
- size_t(bool(kProtoAndIfaceCacheCount % kPageSize));
- Array<Page*, kNPages> mPages;
- };
- public:
- enum Kind {
- WindowLike,
- NonWindowLike
- };
- explicit ProtoAndIfaceCache(Kind aKind) : mKind(aKind) {
- MOZ_COUNT_CTOR(ProtoAndIfaceCache);
- if (aKind == WindowLike) {
- mArrayCache = new ArrayCache();
- } else {
- mPageTableCache = new PageTableCache();
- }
- }
- ~ProtoAndIfaceCache() {
- if (mKind == WindowLike) {
- delete mArrayCache;
- } else {
- delete mPageTableCache;
- }
- MOZ_COUNT_DTOR(ProtoAndIfaceCache);
- }
- #define FORWARD_OPERATION(opName, args) \
- do { \
- if (mKind == WindowLike) { \
- return mArrayCache->opName args; \
- } else { \
- return mPageTableCache->opName args; \
- } \
- } while(0)
- // Return the JSObject stored in slot i, if that slot exists. If
- // the slot does not exist, return null.
- JSObject* EntrySlotIfExists(size_t i) {
- FORWARD_OPERATION(EntrySlotIfExists, (i));
- }
- // Return a reference to slot i, creating it if necessary. There
- // may not be an object in the returned slot.
- JS::Heap<JSObject*>& EntrySlotOrCreate(size_t i) {
- FORWARD_OPERATION(EntrySlotOrCreate, (i));
- }
- // Return a reference to slot i, which is guaranteed to already
- // exist. There may not be an object in the slot, if prototype and
- // constructor initialization for one of our bindings failed.
- JS::Heap<JSObject*>& EntrySlotMustExist(size_t i) {
- FORWARD_OPERATION(EntrySlotMustExist, (i));
- }
- void Trace(JSTracer *aTracer) {
- FORWARD_OPERATION(Trace, (aTracer));
- }
- size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
- size_t n = aMallocSizeOf(this);
- n += (mKind == WindowLike
- ? mArrayCache->SizeOfIncludingThis(aMallocSizeOf)
- : mPageTableCache->SizeOfIncludingThis(aMallocSizeOf));
- return n;
- }
- #undef FORWARD_OPERATION
- private:
- union {
- ArrayCache *mArrayCache;
- PageTableCache *mPageTableCache;
- };
- Kind mKind;
- };
- inline void
- AllocateProtoAndIfaceCache(JSObject* obj, ProtoAndIfaceCache::Kind aKind)
- {
- MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
- MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined());
- ProtoAndIfaceCache* protoAndIfaceCache = new ProtoAndIfaceCache(aKind);
- js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT,
- JS::PrivateValue(protoAndIfaceCache));
- }
- #ifdef DEBUG
- struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JS::CallbackTracer
- {
- bool ok;
- explicit VerifyTraceProtoAndIfaceCacheCalledTracer(JSContext* cx)
- : JS::CallbackTracer(cx), ok(false)
- {}
- void onChild(const JS::GCCellPtr&) override {
- // We don't do anything here, we only want to verify that
- // TraceProtoAndIfaceCache was called.
- }
- TracerKind getTracerKind() const override { return TracerKind::VerifyTraceProtoAndIface; }
- };
- #endif
- inline void
- TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj)
- {
- MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
- #ifdef DEBUG
- if (trc->isCallbackTracer() &&
- (trc->asCallbackTracer()->getTracerKind() ==
- JS::CallbackTracer::TracerKind::VerifyTraceProtoAndIface)) {
- // We don't do anything here, we only want to verify that
- // TraceProtoAndIfaceCache was called.
- static_cast<VerifyTraceProtoAndIfaceCacheCalledTracer*>(trc)->ok = true;
- return;
- }
- #endif
- if (!DOMGlobalHasProtoAndIFaceCache(obj))
- return;
- ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
- protoAndIfaceCache->Trace(trc);
- }
- inline void
- DestroyProtoAndIfaceCache(JSObject* obj)
- {
- MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL);
- if (!DOMGlobalHasProtoAndIFaceCache(obj)) {
- return;
- }
- ProtoAndIfaceCache* protoAndIfaceCache = GetProtoAndIfaceCache(obj);
- delete protoAndIfaceCache;
- }
- /**
- * Add constants to an object.
- */
- bool
- DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj,
- const ConstantSpec* cs);
- struct JSNativeHolder
- {
- JSNative mNative;
- const NativePropertyHooks* mPropertyHooks;
- };
- struct NamedConstructor
- {
- const char* mName;
- const JSNativeHolder mHolder;
- unsigned mNargs;
- };
- /*
- * Create a DOM interface object (if constructorClass is non-null) and/or a
- * DOM interface prototype object (if protoClass is non-null).
- *
- * global is used as the parent of the interface object and the interface
- * prototype object
- * protoProto is the prototype to use for the interface prototype object.
- * interfaceProto is the prototype to use for the interface object. This can be
- * null if both constructorClass and constructor are null (as in,
- * if we're not creating an interface object at all).
- * protoClass is the JSClass to use for the interface prototype object.
- * This is null if we should not create an interface prototype
- * object.
- * protoCache a pointer to a JSObject pointer where we should cache the
- * interface prototype object. This must be null if protoClass is and
- * vice versa.
- * constructorClass is the JSClass to use for the interface object.
- * This is null if we should not create an interface object or
- * if it should be a function object.
- * constructor holds the JSNative to back the interface object which should be a
- * Function, unless constructorClass is non-null in which case it is
- * ignored. If this is null and constructorClass is also null then
- * we should not create an interface object at all.
- * ctorNargs is the length of the constructor function; 0 if no constructor
- * constructorCache a pointer to a JSObject pointer where we should cache the
- * interface object. This must be null if both constructorClass
- * and constructor are null, and non-null otherwise.
- * properties contains the methods, attributes and constants to be defined on
- * objects in any compartment.
- * chromeProperties contains the methods, attributes and constants to be defined
- * on objects in chrome compartments. This must be null if the
- * interface doesn't have any ChromeOnly properties or if the
- * object is being created in non-chrome compartment.
- * defineOnGlobal controls whether properties should be defined on the given
- * global for the interface object (if any) and named
- * constructors (if any) for this interface. This can be
- * false in situations where we want the properties to only
- * appear on privileged Xrays but not on the unprivileged
- * underlying global.
- * unscopableNames if not null it points to a null-terminated list of const
- * char* names of the unscopable properties for this interface.
- * isGlobal if true, we're creating interface objects for a [Global] or
- * [PrimaryGlobal] interface, and hence shouldn't define properties on
- * the prototype object.
- *
- * At least one of protoClass, constructorClass or constructor should be
- * non-null. If constructorClass or constructor are non-null, the resulting
- * interface object will be defined on the given global with property name
- * |name|, which must also be non-null.
- */
- void
- CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global,
- JS::Handle<JSObject*> protoProto,
- const js::Class* protoClass, JS::Heap<JSObject*>* protoCache,
- JS::Handle<JSObject*> interfaceProto,
- const js::Class* constructorClass,
- unsigned ctorNargs, const NamedConstructor* namedConstructors,
- JS::Heap<JSObject*>* constructorCache,
- const NativeProperties* regularProperties,
- const NativeProperties* chromeOnlyProperties,
- const char* name, bool defineOnGlobal,
- const char* const* unscopableNames,
- bool isGlobal);
- /**
- * Define the properties (regular and chrome-only) on obj.
- *
- * obj the object to instal the properties on. This should be the interface
- * prototype object for regular interfaces and the instance object for
- * interfaces marked with Global.
- * properties contains the methods, attributes and constants to be defined on
- * objects in any compartment.
- * chromeProperties contains the methods, attributes and constants to be defined
- * on objects in chrome compartments. This must be null if the
- * interface doesn't have any ChromeOnly properties or if the
- * object is being created in non-chrome compartment.
- */
- bool
- DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
- const NativeProperties* properties,
- const NativeProperties* chromeOnlyProperties);
- /*
- * Define the unforgeable methods on an object.
- */
- bool
- DefineUnforgeableMethods(JSContext* cx, JS::Handle<JSObject*> obj,
- const Prefable<const JSFunctionSpec>* props);
- /*
- * Define the unforgeable attributes on an object.
- */
- bool
- DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj,
- const Prefable<const JSPropertySpec>* props);
- #define HAS_MEMBER_TYPEDEFS \
- private: \
- typedef char yes[1]; \
- typedef char no[2]
- #ifdef _MSC_VER
- #define HAS_MEMBER_CHECK(_name) \
- template<typename V> static yes& Check##_name(char (*)[(&V::_name == 0) + 1])
- #else
- #define HAS_MEMBER_CHECK(_name) \
- template<typename V> static yes& Check##_name(char (*)[sizeof(&V::_name) + 1])
- #endif
- #define HAS_MEMBER(_memberName, _valueName) \
- private: \
- HAS_MEMBER_CHECK(_memberName); \
- template<typename V> static no& Check##_memberName(...); \
- \
- public: \
- static bool const _valueName = \
- sizeof(Check##_memberName<T>(nullptr)) == sizeof(yes)
- template<class T>
- struct NativeHasMember
- {
- HAS_MEMBER_TYPEDEFS;
- HAS_MEMBER(GetParentObject, GetParentObject);
- HAS_MEMBER(WrapObject, WrapObject);
- };
- template<class T>
- struct IsSmartPtr
- {
- HAS_MEMBER_TYPEDEFS;
- HAS_MEMBER(get, value);
- };
- template<class T>
- struct IsRefcounted
- {
- HAS_MEMBER_TYPEDEFS;
- HAS_MEMBER(AddRef, HasAddref);
- HAS_MEMBER(Release, HasRelease);
- public:
- static bool const value = HasAddref && HasRelease;
- private:
- // This struct only works if T is fully declared (not just forward declared).
- // The IsBaseOf check will ensure that, we don't really need it for any other
- // reason (the static assert will of course always be true).
- static_assert(!IsBaseOf<nsISupports, T>::value || IsRefcounted::value,
- "Classes derived from nsISupports are refcounted!");
- };
- #undef HAS_MEMBER
- #undef HAS_MEMBER_CHECK
- #undef HAS_MEMBER_TYPEDEFS
- #ifdef DEBUG
- template <class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
- struct
- CheckWrapperCacheCast
- {
- static bool Check()
- {
- return reinterpret_cast<uintptr_t>(
- static_cast<nsWrapperCache*>(
- reinterpret_cast<T*>(1))) == 1;
- }
- };
- template <class T>
- struct
- CheckWrapperCacheCast<T, true>
- {
- static bool Check()
- {
- return true;
- }
- };
- #endif
- MOZ_ALWAYS_INLINE bool
- CouldBeDOMBinding(void*)
- {
- return true;
- }
- MOZ_ALWAYS_INLINE bool
- CouldBeDOMBinding(nsWrapperCache* aCache)
- {
- return aCache->IsDOMBinding();
- }
- inline bool
- TryToOuterize(JS::MutableHandle<JS::Value> rval)
- {
- if (js::IsWindow(&rval.toObject())) {
- JSObject* obj = js::ToWindowProxyIfWindow(&rval.toObject());
- MOZ_ASSERT(obj);
- rval.set(JS::ObjectValue(*obj));
- }
- return true;
- }
- // Make sure to wrap the given string value into the right compartment, as
- // needed.
- MOZ_ALWAYS_INLINE
- bool
- MaybeWrapStringValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
- {
- MOZ_ASSERT(rval.isString());
- JSString* str = rval.toString();
- if (JS::GetStringZone(str) != js::GetContextZone(cx)) {
- return JS_WrapValue(cx, rval);
- }
- return true;
- }
- // Make sure to wrap the given object value into the right compartment as
- // needed. This will work correctly, but possibly slowly, on all objects.
- MOZ_ALWAYS_INLINE
- bool
- MaybeWrapObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
- {
- MOZ_ASSERT(rval.isObject());
- // Cross-compartment always requires wrapping.
- JSObject* obj = &rval.toObject();
- if (js::GetObjectCompartment(obj) != js::GetContextCompartment(cx)) {
- return JS_WrapValue(cx, rval);
- }
- // We're same-compartment, but even then we might need to wrap
- // objects specially. Check for that.
- if (IsDOMObject(obj)) {
- return TryToOuterize(rval);
- }
- // It's not a WebIDL object, so it's OK to just leave it as-is: only WebIDL
- // objects (specifically only windows) require outerization.
- return true;
- }
- // Like MaybeWrapObjectValue, but also allows null
- MOZ_ALWAYS_INLINE
- bool
- MaybeWrapObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
- {
- MOZ_ASSERT(rval.isObjectOrNull());
- if (rval.isNull()) {
- return true;
- }
- return MaybeWrapObjectValue(cx, rval);
- }
- // Wrapping for objects that are known to not be DOM or XPConnect objects
- MOZ_ALWAYS_INLINE
- bool
- MaybeWrapNonDOMObjectValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
- {
- MOZ_ASSERT(rval.isObject());
- MOZ_ASSERT(!GetDOMClass(&rval.toObject()));
- MOZ_ASSERT(!(js::GetObjectClass(&rval.toObject())->flags &
- JSCLASS_PRIVATE_IS_NSISUPPORTS));
- JSObject* obj = &rval.toObject();
- if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
- return true;
- }
- return JS_WrapValue(cx, rval);
- }
- // Like MaybeWrapNonDOMObjectValue but allows null
- MOZ_ALWAYS_INLINE
- bool
- MaybeWrapNonDOMObjectOrNullValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
- {
- MOZ_ASSERT(rval.isObjectOrNull());
- if (rval.isNull()) {
- return true;
- }
- return MaybeWrapNonDOMObjectValue(cx, rval);
- }
- // If rval is a gcthing and is not in the compartment of cx, wrap rval
- // into the compartment of cx (typically by replacing it with an Xray or
- // cross-compartment wrapper around the original object).
- MOZ_ALWAYS_INLINE bool
- MaybeWrapValue(JSContext* cx, JS::MutableHandle<JS::Value> rval)
- {
- if (rval.isString()) {
- return MaybeWrapStringValue(cx, rval);
- }
- if (!rval.isObject()) {
- return true;
- }
- return MaybeWrapObjectValue(cx, rval);
- }
- namespace binding_detail {
- enum GetOrCreateReflectorWrapBehavior {
- eWrapIntoContextCompartment,
- eDontWrapIntoContextCompartment
- };
- template <class T>
- struct TypeNeedsOuterization
- {
- // We only need to outerize Window objects, so anything inheriting from
- // nsGlobalWindow (which inherits from EventTarget itself).
- static const bool value =
- IsBaseOf<nsGlobalWindow, T>::value || IsSame<EventTarget, T>::value;
- };
- #ifdef DEBUG
- template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
- struct CheckWrapperCacheTracing
- {
- static inline void Check(T* aObject)
- {
- }
- };
- template<typename T>
- struct CheckWrapperCacheTracing<T, true>
- {
- static void Check(T* aObject)
- {
- // Rooting analysis thinks QueryInterface may GC, but we're dealing with
- // a subset of QueryInterface, C++ only types here.
- JS::AutoSuppressGCAnalysis nogc;
- nsWrapperCache* wrapperCacheFromQI = nullptr;
- aObject->QueryInterface(NS_GET_IID(nsWrapperCache),
- reinterpret_cast<void**>(&wrapperCacheFromQI));
- MOZ_ASSERT(wrapperCacheFromQI,
- "Missing nsWrapperCache from QueryInterface implementation?");
- if (!wrapperCacheFromQI->GetWrapperPreserveColor()) {
- // Can't assert that we trace the wrapper, since we don't have any
- // wrapper to trace.
- return;
- }
- nsISupports* ccISupports = nullptr;
- aObject->QueryInterface(NS_GET_IID(nsCycleCollectionISupports),
- reinterpret_cast<void**>(&ccISupports));
- MOZ_ASSERT(ccISupports,
- "nsWrapperCache object which isn't cycle collectable?");
- nsXPCOMCycleCollectionParticipant* participant = nullptr;
- CallQueryInterface(ccISupports, &participant);
- MOZ_ASSERT(participant, "Can't QI to CycleCollectionParticipant?");
- bool wasPreservingWrapper = wrapperCacheFromQI->PreservingWrapper();
- wrapperCacheFromQI->SetPreservingWrapper(true);
- wrapperCacheFromQI->CheckCCWrapperTraversal(ccISupports, participant);
- wrapperCacheFromQI->SetPreservingWrapper(wasPreservingWrapper);
- }
- };
- void
- AssertReflectorHasGivenProto(JSContext* aCx, JSObject* aReflector,
- JS::Handle<JSObject*> aGivenProto);
- #endif // DEBUG
- template <class T, GetOrCreateReflectorWrapBehavior wrapBehavior>
- MOZ_ALWAYS_INLINE bool
- DoGetOrCreateDOMReflector(JSContext* cx, T* value,
- JS::Handle<JSObject*> givenProto,
- JS::MutableHandle<JS::Value> rval)
- {
- MOZ_ASSERT(value);
- // We can get rid of this when we remove support for hasXPConnectImpls.
- bool couldBeDOMBinding = CouldBeDOMBinding(value);
- JSObject* obj = value->GetWrapper();
- if (obj) {
- #ifdef DEBUG
- AssertReflectorHasGivenProto(cx, obj, givenProto);
- // Have to reget obj because AssertReflectorHasGivenProto can
- // trigger gc so the pointer may now be invalid.
- obj = value->GetWrapper();
- #endif
- } else {
- // Inline this here while we have non-dom objects in wrapper caches.
- if (!couldBeDOMBinding) {
- return false;
- }
- obj = value->WrapObject(cx, givenProto);
- if (!obj) {
- // At this point, obj is null, so just return false.
- // Callers seem to be testing JS_IsExceptionPending(cx) to
- // figure out whether WrapObject() threw.
- return false;
- }
- #ifdef DEBUG
- if (IsBaseOf<nsWrapperCache, T>::value) {
- CheckWrapperCacheTracing<T>::Check(value);
- }
- #endif
- }
- #ifdef DEBUG
- const DOMJSClass* clasp = GetDOMClass(obj);
- // clasp can be null if the cache contained a non-DOM object.
- if (clasp) {
- // Some sanity asserts about our object. Specifically:
- // 1) If our class claims we're nsISupports, we better be nsISupports
- // XXXbz ideally, we could assert that reinterpret_cast to nsISupports
- // does the right thing, but I don't see a way to do it. :(
- // 2) If our class doesn't claim we're nsISupports we better be
- // reinterpret_castable to nsWrapperCache.
- MOZ_ASSERT(clasp, "What happened here?");
- MOZ_ASSERT_IF(clasp->mDOMObjectIsISupports, (IsBaseOf<nsISupports, T>::value));
- MOZ_ASSERT(CheckWrapperCacheCast<T>::Check());
- }
- #endif
- rval.set(JS::ObjectValue(*obj));
- bool sameCompartment =
- js::GetObjectCompartment(obj) == js::GetContextCompartment(cx);
- if (sameCompartment && couldBeDOMBinding) {
- return TypeNeedsOuterization<T>::value ? TryToOuterize(rval) : true;
- }
- if (wrapBehavior == eDontWrapIntoContextCompartment) {
- if (TypeNeedsOuterization<T>::value) {
- JSAutoCompartment ac(cx, obj);
- return TryToOuterize(rval);
- }
- return true;
- }
- return JS_WrapValue(cx, rval);
- }
- } // namespace binding_detail
- // Create a JSObject wrapping "value", if there isn't one already, and store it
- // in rval. "value" must be a concrete class that implements a
- // GetWrapperPreserveColor() which can return its existing wrapper, if any, and
- // a WrapObject() which will try to create a wrapper. Typically, this is done by
- // having "value" inherit from nsWrapperCache.
- //
- // The value stored in rval will be ready to be exposed to whatever JS
- // is running on cx right now. In particular, it will be in the
- // compartment of cx, and outerized as needed.
- template <class T>
- MOZ_ALWAYS_INLINE bool
- GetOrCreateDOMReflector(JSContext* cx, T* value,
- JS::MutableHandle<JS::Value> rval,
- JS::Handle<JSObject*> givenProto = nullptr)
- {
- using namespace binding_detail;
- return DoGetOrCreateDOMReflector<T, eWrapIntoContextCompartment>(cx, value,
- givenProto,
- rval);
- }
- // Like GetOrCreateDOMReflector but doesn't wrap into the context compartment,
- // and hence does not actually require cx to be in a compartment.
- template <class T>
- MOZ_ALWAYS_INLINE bool
- GetOrCreateDOMReflectorNoWrap(JSContext* cx, T* value,
- JS::MutableHandle<JS::Value> rval)
- {
- using namespace binding_detail;
- return DoGetOrCreateDOMReflector<T, eDontWrapIntoContextCompartment>(cx,
- value,
- nullptr,
- rval);
- }
- // Create a JSObject wrapping "value", for cases when "value" is a
- // non-wrapper-cached object using WebIDL bindings. "value" must implement a
- // WrapObject() method taking a JSContext and a scope.
- template <class T>
- inline bool
- WrapNewBindingNonWrapperCachedObject(JSContext* cx,
- JS::Handle<JSObject*> scopeArg,
- T* value,
- JS::MutableHandle<JS::Value> rval,
- JS::Handle<JSObject*> givenProto = nullptr)
- {
- static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
- MOZ_ASSERT(value);
- // We try to wrap in the compartment of the underlying object of "scope"
- JS::Rooted<JSObject*> obj(cx);
- {
- // scope for the JSAutoCompartment so that we restore the compartment
- // before we call JS_WrapValue.
- Maybe<JSAutoCompartment> ac;
- // Maybe<Handle> doesn't so much work, and in any case, adding
- // more Maybe (one for a Rooted and one for a Handle) adds more
- // code (and branches!) than just adding a single rooted.
- JS::Rooted<JSObject*> scope(cx, scopeArg);
- JS::Rooted<JSObject*> proto(cx, givenProto);
- if (js::IsWrapper(scope)) {
- scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
- if (!scope)
- return false;
- ac.emplace(cx, scope);
- if (!JS_WrapObject(cx, &proto)) {
- return false;
- }
- }
- MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
- if (!value->WrapObject(cx, proto, &obj)) {
- return false;
- }
- }
- // We can end up here in all sorts of compartments, per above. Make
- // sure to JS_WrapValue!
- rval.set(JS::ObjectValue(*obj));
- return MaybeWrapObjectValue(cx, rval);
- }
- // Create a JSObject wrapping "value", for cases when "value" is a
- // non-wrapper-cached owned object using WebIDL bindings. "value" must implement a
- // WrapObject() method taking a JSContext, a scope, and a boolean outparam that
- // is true if the JSObject took ownership
- template <class T>
- inline bool
- WrapNewBindingNonWrapperCachedObject(JSContext* cx,
- JS::Handle<JSObject*> scopeArg,
- nsAutoPtr<T>& value,
- JS::MutableHandle<JS::Value> rval,
- JS::Handle<JSObject*> givenProto = nullptr)
- {
- static_assert(!IsRefcounted<T>::value, "Only pass owned classes in here.");
- // We do a runtime check on value, because otherwise we might in
- // fact end up wrapping a null and invoking methods on it later.
- if (!value) {
- NS_RUNTIMEABORT("Don't try to wrap null objects");
- }
- // We try to wrap in the compartment of the underlying object of "scope"
- JS::Rooted<JSObject*> obj(cx);
- {
- // scope for the JSAutoCompartment so that we restore the compartment
- // before we call JS_WrapValue.
- Maybe<JSAutoCompartment> ac;
- // Maybe<Handle> doesn't so much work, and in any case, adding
- // more Maybe (one for a Rooted and one for a Handle) adds more
- // code (and branches!) than just adding a single rooted.
- JS::Rooted<JSObject*> scope(cx, scopeArg);
- JS::Rooted<JSObject*> proto(cx, givenProto);
- if (js::IsWrapper(scope)) {
- scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
- if (!scope)
- return false;
- ac.emplace(cx, scope);
- if (!JS_WrapObject(cx, &proto)) {
- return false;
- }
- }
- MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
- if (!value->WrapObject(cx, proto, &obj)) {
- return false;
- }
- value.forget();
- }
- // We can end up here in all sorts of compartments, per above. Make
- // sure to JS_WrapValue!
- rval.set(JS::ObjectValue(*obj));
- return MaybeWrapObjectValue(cx, rval);
- }
- // Helper for smart pointers (nsRefPtr/nsCOMPtr).
- template <template <typename> class SmartPtr, typename T,
- typename U=typename EnableIf<IsRefcounted<T>::value, T>::Type,
- typename V=typename EnableIf<IsSmartPtr<SmartPtr<T>>::value, T>::Type>
- inline bool
- WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
- const SmartPtr<T>& value,
- JS::MutableHandle<JS::Value> rval,
- JS::Handle<JSObject*> givenProto = nullptr)
- {
- return WrapNewBindingNonWrapperCachedObject(cx, scope, value.get(), rval,
- givenProto);
- }
- // Helper for object references (as opposed to pointers).
- template <typename T,
- typename U=typename EnableIf<!IsSmartPtr<T>::value, T>::Type>
- inline bool
- WrapNewBindingNonWrapperCachedObject(JSContext* cx, JS::Handle<JSObject*> scope,
- T& value,
- JS::MutableHandle<JS::Value> rval,
- JS::Handle<JSObject*> givenProto = nullptr)
- {
- return WrapNewBindingNonWrapperCachedObject(cx, scope, &value, rval,
- givenProto);
- }
- // Only set allowNativeWrapper to false if you really know you need it, if in
- // doubt use true. Setting it to false disables security wrappers.
- bool
- NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx,
- JS::Handle<JSObject*> aScope,
- JS::MutableHandle<JS::Value> aRetval,
- xpcObjectHelper& aHelper,
- const nsIID* aIID,
- bool aAllowNativeWrapper);
- /**
- * A method to handle new-binding wrap failure, by possibly falling back to
- * wrapping as a non-new-binding object.
- */
- template <class T>
- MOZ_ALWAYS_INLINE bool
- HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
- T* value, JS::MutableHandle<JS::Value> rval)
- {
- if (JS_IsExceptionPending(cx)) {
- return false;
- }
- qsObjectHelper helper(value, GetWrapperCache(value));
- return NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval,
- helper, nullptr, true);
- }
- // Helper for calling HandleNewBindingWrappingFailure with smart pointers
- // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
- template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
- struct HandleNewBindingWrappingFailureHelper
- {
- static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope,
- const T& value, JS::MutableHandle<JS::Value> rval)
- {
- return HandleNewBindingWrappingFailure(cx, scope, value.get(), rval);
- }
- };
- template <class T>
- struct HandleNewBindingWrappingFailureHelper<T, false>
- {
- static inline bool Wrap(JSContext* cx, JS::Handle<JSObject*> scope, T& value,
- JS::MutableHandle<JS::Value> rval)
- {
- return HandleNewBindingWrappingFailure(cx, scope, &value, rval);
- }
- };
- template<class T>
- inline bool
- HandleNewBindingWrappingFailure(JSContext* cx, JS::Handle<JSObject*> scope,
- T& value, JS::MutableHandle<JS::Value> rval)
- {
- return HandleNewBindingWrappingFailureHelper<T>::Wrap(cx, scope, value, rval);
- }
- template<bool Fatal>
- inline bool
- EnumValueNotFound(JSContext* cx, JS::HandleString str, const char* type,
- const char* sourceDescription);
- template<>
- inline bool
- EnumValueNotFound<false>(JSContext* cx, JS::HandleString str, const char* type,
- const char* sourceDescription)
- {
- // TODO: Log a warning to the console.
- return true;
- }
- template<>
- inline bool
- EnumValueNotFound<true>(JSContext* cx, JS::HandleString str, const char* type,
- const char* sourceDescription)
- {
- JSAutoByteString deflated;
- if (!deflated.encodeUtf8(cx, str)) {
- return false;
- }
- return ThrowErrorMessage(cx, MSG_INVALID_ENUM_VALUE, sourceDescription,
- deflated.ptr(), type);
- }
- template<typename CharT>
- inline int
- FindEnumStringIndexImpl(const CharT* chars, size_t length, const EnumEntry* values)
- {
- int i = 0;
- for (const EnumEntry* value = values; value->value; ++value, ++i) {
- if (length != value->length) {
- continue;
- }
- bool equal = true;
- const char* val = value->value;
- for (size_t j = 0; j != length; ++j) {
- if (unsigned(val[j]) != unsigned(chars[j])) {
- equal = false;
- break;
- }
- }
- if (equal) {
- return i;
- }
- }
- return -1;
- }
- template<bool InvalidValueFatal>
- inline bool
- FindEnumStringIndex(JSContext* cx, JS::Handle<JS::Value> v, const EnumEntry* values,
- const char* type, const char* sourceDescription, int* index)
- {
- // JS_StringEqualsAscii is slow as molasses, so don't use it here.
- JS::RootedString str(cx, JS::ToString(cx, v));
- if (!str) {
- return false;
- }
- {
- size_t length;
- JS::AutoCheckCannotGC nogc;
- if (js::StringHasLatin1Chars(str)) {
- const JS::Latin1Char* chars = JS_GetLatin1StringCharsAndLength(cx, nogc, str,
- &length);
- if (!chars) {
- return false;
- }
- *index = FindEnumStringIndexImpl(chars, length, values);
- } else {
- const char16_t* chars = JS_GetTwoByteStringCharsAndLength(cx, nogc, str,
- &length);
- if (!chars) {
- return false;
- }
- *index = FindEnumStringIndexImpl(chars, length, values);
- }
- if (*index >= 0) {
- return true;
- }
- }
- return EnumValueNotFound<InvalidValueFatal>(cx, str, type, sourceDescription);
- }
- inline nsWrapperCache*
- GetWrapperCache(const ParentObject& aParentObject)
- {
- return aParentObject.mWrapperCache;
- }
- template<class T>
- inline T*
- GetParentPointer(T* aObject)
- {
- return aObject;
- }
- inline nsISupports*
- GetParentPointer(const ParentObject& aObject)
- {
- return aObject.mObject;
- }
- template <typename T>
- inline bool
- GetUseXBLScope(T* aParentObject)
- {
- return false;
- }
- inline bool
- GetUseXBLScope(const ParentObject& aParentObject)
- {
- return aParentObject.mUseXBLScope;
- }
- template<class T>
- inline void
- ClearWrapper(T* p, nsWrapperCache* cache)
- {
- cache->ClearWrapper();
- }
- template<class T>
- inline void
- ClearWrapper(T* p, void*)
- {
- nsWrapperCache* cache;
- CallQueryInterface(p, &cache);
- ClearWrapper(p, cache);
- }
- template<class T>
- inline void
- UpdateWrapper(T* p, nsWrapperCache* cache, JSObject* obj, const JSObject* old)
- {
- JS::AutoAssertGCCallback inCallback(obj);
- cache->UpdateWrapper(obj, old);
- }
- template<class T>
- inline void
- UpdateWrapper(T* p, void*, JSObject* obj, const JSObject* old)
- {
- JS::AutoAssertGCCallback inCallback(obj);
- nsWrapperCache* cache;
- CallQueryInterface(p, &cache);
- UpdateWrapper(p, cache, obj, old);
- }
- // Attempt to preserve the wrapper, if any, for a Paris DOM bindings object.
- // Return true if we successfully preserved the wrapper, or there is no wrapper
- // to preserve. In the latter case we don't need to preserve the wrapper, because
- // the object can only be obtained by JS once, or they cannot be meaningfully
- // owned from the native side.
- //
- // This operation will return false only for non-nsISupports cycle-collected
- // objects, because we cannot determine if they are wrappercached or not.
- bool
- TryPreserveWrapper(JSObject* obj);
- // Can only be called with a DOM JSClass.
- bool
- InstanceClassHasProtoAtDepth(const js::Class* clasp,
- uint32_t protoID, uint32_t depth);
- // Only set allowNativeWrapper to false if you really know you need it, if in
- // doubt use true. Setting it to false disables security wrappers.
- bool
- XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope,
- xpcObjectHelper& helper, const nsIID* iid,
- bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval);
- // Special-cased wrapping for variants
- bool
- VariantToJsval(JSContext* aCx, nsIVariant* aVariant,
- JS::MutableHandle<JS::Value> aRetval);
- // Wrap an object "p" which is not using WebIDL bindings yet. This _will_
- // actually work on WebIDL binding objects that are wrappercached, but will be
- // much slower than GetOrCreateDOMReflector. "cache" must either be null or be
- // the nsWrapperCache for "p".
- template<class T>
- inline bool
- WrapObject(JSContext* cx, T* p, nsWrapperCache* cache, const nsIID* iid,
- JS::MutableHandle<JS::Value> rval)
- {
- if (xpc_FastGetCachedWrapper(cx, cache, rval))
- return true;
- qsObjectHelper helper(p, cache);
- JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
- return XPCOMObjectToJsval(cx, scope, helper, iid, true, rval);
- }
- // A specialization of the above for nsIVariant, because that needs to
- // do something different.
- template<>
- inline bool
- WrapObject<nsIVariant>(JSContext* cx, nsIVariant* p,
- nsWrapperCache* cache, const nsIID* iid,
- JS::MutableHandle<JS::Value> rval)
- {
- MOZ_ASSERT(iid);
- MOZ_ASSERT(iid->Equals(NS_GET_IID(nsIVariant)));
- return VariantToJsval(cx, p, rval);
- }
- // Wrap an object "p" which is not using WebIDL bindings yet. Just like the
- // variant that takes an nsWrapperCache above, but will try to auto-derive the
- // nsWrapperCache* from "p".
- template<class T>
- inline bool
- WrapObject(JSContext* cx, T* p, const nsIID* iid,
- JS::MutableHandle<JS::Value> rval)
- {
- return WrapObject(cx, p, GetWrapperCache(p), iid, rval);
- }
- // Just like the WrapObject above, but without requiring you to pick which
- // interface you're wrapping as. This should only be used for objects that have
- // classinfo, for which it doesn't matter what IID is used to wrap.
- template<class T>
- inline bool
- WrapObject(JSContext* cx, T* p, JS::MutableHandle<JS::Value> rval)
- {
- return WrapObject(cx, p, nullptr, rval);
- }
- // Helper to make it possible to wrap directly out of an nsCOMPtr
- template<class T>
- inline bool
- WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
- const nsIID* iid, JS::MutableHandle<JS::Value> rval)
- {
- return WrapObject(cx, p.get(), iid, rval);
- }
- // Helper to make it possible to wrap directly out of an nsCOMPtr
- template<class T>
- inline bool
- WrapObject(JSContext* cx, const nsCOMPtr<T>& p,
- JS::MutableHandle<JS::Value> rval)
- {
- return WrapObject(cx, p, nullptr, rval);
- }
- // Helper to make it possible to wrap directly out of an nsRefPtr
- template<class T>
- inline bool
- WrapObject(JSContext* cx, const RefPtr<T>& p,
- const nsIID* iid, JS::MutableHandle<JS::Value> rval)
- {
- return WrapObject(cx, p.get(), iid, rval);
- }
- // Helper to make it possible to wrap directly out of an nsRefPtr
- template<class T>
- inline bool
- WrapObject(JSContext* cx, const RefPtr<T>& p,
- JS::MutableHandle<JS::Value> rval)
- {
- return WrapObject(cx, p, nullptr, rval);
- }
- // Specialization to make it easy to use WrapObject in codegen.
- template<>
- inline bool
- WrapObject<JSObject>(JSContext* cx, JSObject* p,
- JS::MutableHandle<JS::Value> rval)
- {
- rval.set(JS::ObjectOrNullValue(p));
- return true;
- }
- inline bool
- WrapObject(JSContext* cx, JSObject& p, JS::MutableHandle<JS::Value> rval)
- {
- rval.set(JS::ObjectValue(p));
- return true;
- }
- // Given an object "p" that inherits from nsISupports, wrap it and return the
- // result. Null is returned on wrapping failure. This is somewhat similar to
- // WrapObject() above, but does NOT allow Xrays around the result, since we
- // don't want those for our parent object.
- template<typename T>
- static inline JSObject*
- WrapNativeISupports(JSContext* cx, T* p, nsWrapperCache* cache)
- {
- qsObjectHelper helper(ToSupports(p), cache);
- JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
- JS::Rooted<JS::Value> v(cx);
- return XPCOMObjectToJsval(cx, scope, helper, nullptr, false, &v) ?
- v.toObjectOrNull() :
- nullptr;
- }
- // Fallback for when our parent is not a WebIDL binding object.
- template<typename T, bool isISupports=IsBaseOf<nsISupports, T>::value>
- struct WrapNativeFallback
- {
- static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
- {
- return nullptr;
- }
- };
- // Fallback for when our parent is not a WebIDL binding object but _is_ an
- // nsISupports object.
- template<typename T >
- struct WrapNativeFallback<T, true >
- {
- static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
- {
- return WrapNativeISupports(cx, parent, cache);
- }
- };
- // Wrapping of our native parent, for cases when it's a WebIDL object (though
- // possibly preffed off).
- template<typename T, bool hasWrapObject=NativeHasMember<T>::WrapObject>
- struct WrapNativeHelper
- {
- static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
- {
- MOZ_ASSERT(cache);
- JSObject* obj;
- if ((obj = cache->GetWrapper())) {
- // GetWrapper always unmarks gray.
- MOZ_ASSERT(!JS::ObjectIsMarkedGray(obj));
- return obj;
- }
- // Inline this here while we have non-dom objects in wrapper caches.
- if (!CouldBeDOMBinding(parent)) {
- // WrapNativeFallback never returns a gray thing.
- obj = WrapNativeFallback<T>::Wrap(cx, parent, cache);
- MOZ_ASSERT_IF(obj, !JS::ObjectIsMarkedGray(obj));
- } else {
- // WrapObject never returns a gray thing.
- obj = parent->WrapObject(cx, nullptr);
- MOZ_ASSERT_IF(obj, !JS::ObjectIsMarkedGray(obj));
- }
- return obj;
- }
- };
- // Wrapping of our native parent, for cases when it's not a WebIDL object. In
- // this case it must be nsISupports.
- template<typename T>
- struct WrapNativeHelper<T, false>
- {
- static inline JSObject* Wrap(JSContext* cx, T* parent, nsWrapperCache* cache)
- {
- JSObject* obj;
- if (cache && (obj = cache->GetWrapper())) {
- #ifdef DEBUG
- JS::Rooted<JSObject*> rootedObj(cx, obj);
- NS_ASSERTION(WrapNativeISupports(cx, parent, cache) == rootedObj,
- "Unexpected object in nsWrapperCache");
- obj = rootedObj;
- #endif
- MOZ_ASSERT(!JS::ObjectIsMarkedGray(obj));
- return obj;
- }
- obj = WrapNativeISupports(cx, parent, cache);
- MOZ_ASSERT_IF(obj, !JS::ObjectIsMarkedGray(obj));
- return obj;
- }
- };
- // Finding the associated global for an object.
- template<typename T>
- static inline JSObject*
- FindAssociatedGlobal(JSContext* cx, T* p, nsWrapperCache* cache,
- bool useXBLScope = false)
- {
- if (!p) {
- return JS::CurrentGlobalOrNull(cx);
- }
- JSObject* obj = WrapNativeHelper<T>::Wrap(cx, p, cache);
- if (!obj) {
- return nullptr;
- }
- MOZ_ASSERT(!JS::ObjectIsMarkedGray(obj));
- obj = js::GetGlobalForObjectCrossCompartment(obj);
- if (!useXBLScope) {
- return obj;
- }
- // If useXBLScope is true, it means that the canonical reflector for this
- // native object should live in the content XBL scope. Note that we never put
- // anonymous content inside an add-on scope.
- if (xpc::IsInContentXBLScope(obj)) {
- return obj;
- }
- JS::Rooted<JSObject*> rootedObj(cx, obj);
- JSObject* xblScope = xpc::GetXBLScope(cx, rootedObj);
- MOZ_ASSERT_IF(xblScope, JS_IsGlobalObject(xblScope));
- MOZ_ASSERT_IF(xblScope, !JS::ObjectIsMarkedGray(xblScope));
- return xblScope;
- }
- // Finding of the associated global for an object, when we don't want to
- // explicitly pass in things like the nsWrapperCache for it.
- template<typename T>
- static inline JSObject*
- FindAssociatedGlobal(JSContext* cx, const T& p)
- {
- return FindAssociatedGlobal(cx, GetParentPointer(p), GetWrapperCache(p), GetUseXBLScope(p));
- }
- // Specialization for the case of nsIGlobalObject, since in that case
- // we can just get the JSObject* directly.
- template<>
- inline JSObject*
- FindAssociatedGlobal(JSContext* cx, nsIGlobalObject* const& p)
- {
- if (!p) {
- return JS::CurrentGlobalOrNull(cx);
- }
- JSObject* global = p->GetGlobalJSObject();
- if (!global) {
- return nullptr;
- }
- MOZ_ASSERT(JS_IsGlobalObject(global));
- // This object could be gray if the nsIGlobalObject is the only thing keeping
- // it alive.
- JS::ExposeObjectToActiveJS(global);
- return global;
- }
- template<typename T,
- bool hasAssociatedGlobal=NativeHasMember<T>::GetParentObject>
- struct FindAssociatedGlobalForNative
- {
- static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
- {
- MOZ_ASSERT(js::IsObjectInContextCompartment(obj, cx));
- T* native = UnwrapDOMObject<T>(obj);
- return FindAssociatedGlobal(cx, native->GetParentObject());
- }
- };
- template<typename T>
- struct FindAssociatedGlobalForNative<T, false>
- {
- static JSObject* Get(JSContext* cx, JS::Handle<JSObject*> obj)
- {
- MOZ_CRASH();
- return nullptr;
- }
- };
- // Helper for calling GetOrCreateDOMReflector with smart pointers
- // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
- template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
- struct GetOrCreateDOMReflectorHelper
- {
- static inline bool GetOrCreate(JSContext* cx, const T& value,
- JS::Handle<JSObject*> givenProto,
- JS::MutableHandle<JS::Value> rval)
- {
- return GetOrCreateDOMReflector(cx, value.get(), rval, givenProto);
- }
- };
- template <class T>
- struct GetOrCreateDOMReflectorHelper<T, false>
- {
- static inline bool GetOrCreate(JSContext* cx, T& value,
- JS::Handle<JSObject*> givenProto,
- JS::MutableHandle<JS::Value> rval)
- {
- static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
- return GetOrCreateDOMReflector(cx, &value, rval, givenProto);
- }
- };
- template<class T>
- inline bool
- GetOrCreateDOMReflector(JSContext* cx, T& value,
- JS::MutableHandle<JS::Value> rval,
- JS::Handle<JSObject*> givenProto = nullptr)
- {
- return GetOrCreateDOMReflectorHelper<T>::GetOrCreate(cx, value, givenProto,
- rval);
- }
- // Helper for calling GetOrCreateDOMReflectorNoWrap with smart pointers
- // (nsAutoPtr/nsRefPtr/nsCOMPtr) or references.
- template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
- struct GetOrCreateDOMReflectorNoWrapHelper
- {
- static inline bool GetOrCreate(JSContext* cx, const T& value,
- JS::MutableHandle<JS::Value> rval)
- {
- return GetOrCreateDOMReflectorNoWrap(cx, value.get(), rval);
- }
- };
- template <class T>
- struct GetOrCreateDOMReflectorNoWrapHelper<T, false>
- {
- static inline bool GetOrCreate(JSContext* cx, T& value,
- JS::MutableHandle<JS::Value> rval)
- {
- return GetOrCreateDOMReflectorNoWrap(cx, &value, rval);
- }
- };
- template<class T>
- inline bool
- GetOrCreateDOMReflectorNoWrap(JSContext* cx, T& value,
- JS::MutableHandle<JS::Value> rval)
- {
- return
- GetOrCreateDOMReflectorNoWrapHelper<T>::GetOrCreate(cx, value, rval);
- }
- template <class T>
- inline JSObject*
- GetCallbackFromCallbackObject(T* aObj)
- {
- return aObj->Callback();
- }
- // Helper for getting the callback JSObject* of a smart ptr around a
- // CallbackObject or a reference to a CallbackObject or something like
- // that.
- template <class T, bool isSmartPtr=IsSmartPtr<T>::value>
- struct GetCallbackFromCallbackObjectHelper
- {
- static inline JSObject* Get(const T& aObj)
- {
- return GetCallbackFromCallbackObject(aObj.get());
- }
- };
- template <class T>
- struct GetCallbackFromCallbackObjectHelper<T, false>
- {
- static inline JSObject* Get(T& aObj)
- {
- return GetCallbackFromCallbackObject(&aObj);
- }
- };
- template<class T>
- inline JSObject*
- GetCallbackFromCallbackObject(T& aObj)
- {
- return GetCallbackFromCallbackObjectHelper<T>::Get(aObj);
- }
- static inline bool
- AtomizeAndPinJSString(JSContext* cx, jsid& id, const char* chars)
- {
- if (JSString *str = ::JS_AtomizeAndPinString(cx, chars)) {
- id = INTERNED_STRING_TO_JSID(cx, str);
- return true;
- }
- return false;
- }
- // Spec needs a name property
- template <typename Spec>
- static bool
- InitIds(JSContext* cx, const Prefable<Spec>* prefableSpecs, jsid* ids)
- {
- MOZ_ASSERT(prefableSpecs);
- MOZ_ASSERT(prefableSpecs->specs);
- do {
- // We ignore whether the set of ids is enabled and just intern all the IDs,
- // because this is only done once per application runtime.
- Spec* spec = prefableSpecs->specs;
- do {
- if (!JS::PropertySpecNameToPermanentId(cx, spec->name, ids)) {
- return false;
- }
- } while (++ids, (++spec)->name);
- // We ran out of ids for that pref. Put a JSID_VOID in on the id
- // corresponding to the list terminator for the pref.
- *ids = JSID_VOID;
- ++ids;
- } while ((++prefableSpecs)->specs);
- return true;
- }
- bool
- QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
- template <class T>
- struct
- WantsQueryInterface
- {
- static_assert(IsBaseOf<nsISupports, T>::value,
- "QueryInterface can't work without an nsISupports.");
- static bool Enabled(JSContext* aCx, JSObject* aGlobal)
- {
- return NS_IsMainThread() && IsChromeOrXBL(aCx, aGlobal);
- }
- };
- void
- GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor,
- nsWrapperCache* aCache, nsIJSID* aIID,
- JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError);
- template<class T>
- void
- GetInterface(JSContext* aCx, T* aThis, nsIJSID* aIID,
- JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError)
- {
- GetInterfaceImpl(aCx, aThis, aThis, aIID, aRetval, aError);
- }
- bool
- ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
- bool
- ThrowConstructorWithoutNew(JSContext* cx, const char* name);
- bool
- GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
- JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
- bool* found, JS::MutableHandle<JS::Value> vp);
- //
- bool
- HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
- JS::Handle<jsid> id, bool* has);
- // Append the property names in "names" to "props". If
- // shadowPrototypeProperties is false then skip properties that are also
- // present on the proto chain of proxy. If shadowPrototypeProperties is true,
- // then the "proxy" argument is ignored.
- bool
- AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy,
- nsTArray<nsString>& names,
- bool shadowPrototypeProperties, JS::AutoIdVector& props);
- namespace binding_detail {
- class FastErrorResult :
- public mozilla::binding_danger::TErrorResult<
- mozilla::binding_danger::JustAssertCleanupPolicy>
- {
- };
- } // namespace binding_detail
- enum StringificationBehavior {
- eStringify,
- eEmpty,
- eNull
- };
- template<typename T>
- static inline bool
- ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v,
- StringificationBehavior nullBehavior,
- StringificationBehavior undefinedBehavior,
- T& result)
- {
- JSString *s;
- if (v.isString()) {
- s = v.toString();
- } else {
- StringificationBehavior behavior;
- if (v.isNull()) {
- behavior = nullBehavior;
- } else if (v.isUndefined()) {
- behavior = undefinedBehavior;
- } else {
- behavior = eStringify;
- }
- if (behavior != eStringify) {
- if (behavior == eEmpty) {
- result.Truncate();
- } else {
- result.SetIsVoid(true);
- }
- return true;
- }
- s = JS::ToString(cx, v);
- if (!s) {
- return false;
- }
- }
- return AssignJSString(cx, result, s);
- }
- template<typename T>
- static inline bool
- ConvertJSValueToString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
- {
- return ConvertJSValueToString(cx, v, eStringify, eStringify, result);
- }
- void
- NormalizeUSVString(nsAString& aString);
- void
- NormalizeUSVString(binding_detail::FakeString& aString);
- template<typename T>
- static inline bool
- ConvertJSValueToUSVString(JSContext* cx, JS::Handle<JS::Value> v, T& result)
- {
- if (!ConvertJSValueToString(cx, v, eStringify, eStringify, result)) {
- return false;
- }
- NormalizeUSVString(result);
- return true;
- }
- template<typename T>
- inline bool
- ConvertIdToString(JSContext* cx, JS::HandleId id, T& result, bool& isSymbol)
- {
- if (MOZ_LIKELY(JSID_IS_STRING(id))) {
- if (!AssignJSString(cx, result, JSID_TO_STRING(id))) {
- return false;
- }
- } else if (JSID_IS_SYMBOL(id)) {
- isSymbol = true;
- return true;
- } else {
- JS::RootedValue nameVal(cx, js::IdToValue(id));
- if (!ConvertJSValueToString(cx, nameVal, eStringify, eStringify, result)) {
- return false;
- }
- }
- isSymbol = false;
- return true;
- }
- bool
- ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
- bool nullable, nsACString& result);
- inline bool
- ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v,
- nsACString& result)
- {
- return ConvertJSValueToByteString(cx, v, false, result);
- }
- template<typename T>
- void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq);
- template<typename T>
- void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq);
- // Class used to trace sequences, with specializations for various
- // sequence types.
- template<typename T,
- bool isDictionary=IsBaseOf<DictionaryBase, T>::value,
- bool isTypedArray=IsBaseOf<AllTypedArraysBase, T>::value,
- bool isOwningUnion=IsBaseOf<AllOwningUnionBase, T>::value>
- class SequenceTracer
- {
- explicit SequenceTracer() = delete; // Should never be instantiated
- };
- // sequence<object> or sequence<object?>
- template<>
- class SequenceTracer<JSObject*, false, false, false>
- {
- explicit SequenceTracer() = delete; // Should never be instantiated
- public:
- static void TraceSequence(JSTracer* trc, JSObject** objp, JSObject** end) {
- for (; objp != end; ++objp) {
- JS::UnsafeTraceRoot(trc, objp, "sequence<object>");
- }
- }
- };
- // sequence<any>
- template<>
- class SequenceTracer<JS::Value, false, false, false>
- {
- explicit SequenceTracer() = delete; // Should never be instantiated
- public:
- static void TraceSequence(JSTracer* trc, JS::Value* valp, JS::Value* end) {
- for (; valp != end; ++valp) {
- JS::UnsafeTraceRoot(trc, valp, "sequence<any>");
- }
- }
- };
- // sequence<sequence<T>>
- template<typename T>
- class SequenceTracer<Sequence<T>, false, false, false>
- {
- explicit SequenceTracer() = delete; // Should never be instantiated
- public:
- static void TraceSequence(JSTracer* trc, Sequence<T>* seqp, Sequence<T>* end) {
- for (; seqp != end; ++seqp) {
- DoTraceSequence(trc, *seqp);
- }
- }
- };
- // sequence<sequence<T>> as return value
- template<typename T>
- class SequenceTracer<nsTArray<T>, false, false, false>
- {
- explicit SequenceTracer() = delete; // Should never be instantiated
- public:
- static void TraceSequence(JSTracer* trc, nsTArray<T>* seqp, nsTArray<T>* end) {
- for (; seqp != end; ++seqp) {
- DoTraceSequence(trc, *seqp);
- }
- }
- };
- // sequence<someDictionary>
- template<typename T>
- class SequenceTracer<T, true, false, false>
- {
- explicit SequenceTracer() = delete; // Should never be instantiated
- public:
- static void TraceSequence(JSTracer* trc, T* dictp, T* end) {
- for (; dictp != end; ++dictp) {
- dictp->TraceDictionary(trc);
- }
- }
- };
- // sequence<SomeTypedArray>
- template<typename T>
- class SequenceTracer<T, false, true, false>
- {
- explicit SequenceTracer() = delete; // Should never be instantiated
- public:
- static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
- for (; arrayp != end; ++arrayp) {
- arrayp->TraceSelf(trc);
- }
- }
- };
- // sequence<SomeOwningUnion>
- template<typename T>
- class SequenceTracer<T, false, false, true>
- {
- explicit SequenceTracer() = delete; // Should never be instantiated
- public:
- static void TraceSequence(JSTracer* trc, T* arrayp, T* end) {
- for (; arrayp != end; ++arrayp) {
- arrayp->TraceUnion(trc);
- }
- }
- };
- // sequence<T?> with T? being a Nullable<T>
- template<typename T>
- class SequenceTracer<Nullable<T>, false, false, false>
- {
- explicit SequenceTracer() = delete; // Should never be instantiated
- public:
- static void TraceSequence(JSTracer* trc, Nullable<T>* seqp,
- Nullable<T>* end) {
- for (; seqp != end; ++seqp) {
- if (!seqp->IsNull()) {
- // Pretend like we actually have a length-one sequence here so
- // we can do template instantiation correctly for T.
- T& val = seqp->Value();
- T* ptr = &val;
- SequenceTracer<T>::TraceSequence(trc, ptr, ptr+1);
- }
- }
- }
- };
- template<typename K, typename V>
- void TraceRecord(JSTracer* trc, Record<K, V>& record)
- {
- for (auto& entry : record.Entries()) {
- // Act like it's a one-element sequence to leverage all that infrastructure.
- SequenceTracer<V>::TraceSequence(trc, &entry.mValue, &entry.mValue + 1);
- }
- }
- // sequence<record>
- template<typename K, typename V>
- class SequenceTracer<Record<K, V>, false, false, false>
- {
- explicit SequenceTracer() = delete; // Should never be instantiated
- public:
- static void TraceSequence(JSTracer* trc, Record<K, V>* seqp,
- Record<K, V>* end) {
- for (; seqp != end; ++seqp) {
- TraceRecord(trc, *seqp);
- }
- }
- };
- template<typename T>
- void DoTraceSequence(JSTracer* trc, FallibleTArray<T>& seq)
- {
- SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
- seq.Elements() + seq.Length());
- }
- template<typename T>
- void DoTraceSequence(JSTracer* trc, InfallibleTArray<T>& seq)
- {
- SequenceTracer<T>::TraceSequence(trc, seq.Elements(),
- seq.Elements() + seq.Length());
- }
- // Rooter class for sequences; this is what we mostly use in the codegen
- template<typename T>
- class MOZ_RAII SequenceRooter final : private JS::CustomAutoRooter
- {
- public:
- SequenceRooter(JSContext *aCx, FallibleTArray<T>* aSequence
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
- mFallibleArray(aSequence),
- mSequenceType(eFallibleArray)
- {
- }
- SequenceRooter(JSContext *aCx, InfallibleTArray<T>* aSequence
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
- mInfallibleArray(aSequence),
- mSequenceType(eInfallibleArray)
- {
- }
- SequenceRooter(JSContext *aCx, Nullable<nsTArray<T> >* aSequence
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
- mNullableArray(aSequence),
- mSequenceType(eNullableArray)
- {
- }
- private:
- enum SequenceType {
- eInfallibleArray,
- eFallibleArray,
- eNullableArray
- };
- virtual void trace(JSTracer *trc) override
- {
- if (mSequenceType == eFallibleArray) {
- DoTraceSequence(trc, *mFallibleArray);
- } else if (mSequenceType == eInfallibleArray) {
- DoTraceSequence(trc, *mInfallibleArray);
- } else {
- MOZ_ASSERT(mSequenceType == eNullableArray);
- if (!mNullableArray->IsNull()) {
- DoTraceSequence(trc, mNullableArray->Value());
- }
- }
- }
- union {
- InfallibleTArray<T>* mInfallibleArray;
- FallibleTArray<T>* mFallibleArray;
- Nullable<nsTArray<T> >* mNullableArray;
- };
- SequenceType mSequenceType;
- };
- // Rooter class for Record; this is what we mostly use in the codegen.
- template<typename K, typename V>
- class MOZ_RAII RecordRooter final : private JS::CustomAutoRooter
- {
- public:
- RecordRooter(JSContext *aCx, Record<K, V>* aRecord
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
- mRecord(aRecord),
- mRecordType(eRecord)
- {
- }
- RecordRooter(JSContext *aCx, Nullable<Record<K, V>>* aRecord
- MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
- : JS::CustomAutoRooter(aCx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT),
- mNullableRecord(aRecord),
- mRecordType(eNullableRecord)
- {
- }
- private:
- enum RecordType {
- eRecord,
- eNullableRecord
- };
- virtual void trace(JSTracer *trc) override
- {
- if (mRecordType == eRecord) {
- TraceRecord(trc, *mRecord);
- } else {
- MOZ_ASSERT(mRecordType == eNullableRecord);
- if (!mNullableRecord->IsNull()) {
- TraceRecord(trc, mNullableRecord->Value());
- }
- }
- }
- union {
- Record<K, V>* mRecord;
- Nullable<Record<K, V>>* mNullableRecord;
- };
- RecordType mRecordType;
- };
- template<typename T>
- class MOZ_RAII RootedUnion : public T,
- private JS::CustomAutoRooter
- {
- public:
- explicit RootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
- T(),
- JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
- {
- }
- virtual void trace(JSTracer *trc) override
- {
- this->TraceUnion(trc);
- }
- };
- template<typename T>
- class MOZ_STACK_CLASS NullableRootedUnion : public Nullable<T>,
- private JS::CustomAutoRooter
- {
- public:
- explicit NullableRootedUnion(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) :
- Nullable<T>(),
- JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT)
- {
- }
- virtual void trace(JSTracer *trc) override
- {
- if (!this->IsNull()) {
- this->Value().TraceUnion(trc);
- }
- }
- };
- inline bool
- IdEquals(jsid id, const char* string)
- {
- return JSID_IS_STRING(id) &&
- JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), string);
- }
- inline bool
- AddStringToIDVector(JSContext* cx, JS::AutoIdVector& vector, const char* name)
- {
- return vector.growBy(1) &&
- AtomizeAndPinJSString(cx, *(vector[vector.length() - 1]).address(), name);
- }
- // We use one constructor JSNative to represent all DOM interface objects (so
- // we can easily detect when we need to wrap them in an Xray wrapper). We store
- // the real JSNative in the mNative member of a JSNativeHolder in the
- // CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
- // specific interface object. We also store the NativeProperties in the
- // JSNativeHolder.
- // Note that some interface objects are not yet a JSFunction but a normal
- // JSObject with a DOMJSClass, those do not use these slots.
- enum {
- CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0
- };
- bool
- Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
- // Implementation of the bits that XrayWrapper needs
- /**
- * This resolves operations, attributes and constants of the interfaces for obj.
- *
- * wrapper is the Xray JS object.
- * obj is the target object of the Xray, a binding's instance object or a
- * interface or interface prototype object.
- */
- bool
- XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
- JS::Handle<JSObject*> obj,
- JS::Handle<jsid> id,
- JS::MutableHandle<JS::PropertyDescriptor> desc,
- bool& cacheOnHolder);
- /**
- * Define a property on obj through an Xray wrapper.
- *
- * wrapper is the Xray JS object.
- * obj is the target object of the Xray, a binding's instance object or a
- * interface or interface prototype object.
- * id and desc are the parameters for the property to be defined.
- * result is the out-parameter indicating success (read it only if
- * this returns true and also sets *defined to true).
- * defined will be set to true if a property was set as a result of this call.
- */
- bool
- XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
- JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
- JS::Handle<JS::PropertyDescriptor> desc,
- JS::ObjectOpResult &result,
- bool *defined);
- /**
- * Add to props the property keys of all indexed or named properties of obj and
- * operations, attributes and constants of the interfaces for obj.
- *
- * wrapper is the Xray JS object.
- * obj is the target object of the Xray, a binding's instance object or a
- * interface or interface prototype object.
- * flags are JSITER_* flags.
- */
- bool
- XrayOwnPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
- JS::Handle<JSObject*> obj,
- unsigned flags, JS::AutoIdVector& props);
- /**
- * Returns the prototype to use for an Xray for a DOM object, wrapped in cx's
- * compartment. This always returns the prototype that would be used for a DOM
- * object if we ignore any changes that might have been done to the prototype
- * chain by JS, the XBL code or plugins.
- *
- * cx should be in the Xray's compartment.
- * obj is the target object of the Xray, a binding's instance object or an
- * interface or interface prototype object.
- */
- inline bool
- XrayGetNativeProto(JSContext* cx, JS::Handle<JSObject*> obj,
- JS::MutableHandle<JSObject*> protop)
- {
- JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj));
- {
- JSAutoCompartment ac(cx, global);
- const DOMJSClass* domClass = GetDOMClass(obj);
- if (domClass) {
- ProtoHandleGetter protoGetter = domClass->mGetProto;
- if (protoGetter) {
- protop.set(protoGetter(cx));
- } else {
- protop.set(JS::GetRealmObjectPrototype(cx));
- }
- } else if (JS_ObjectIsFunction(cx, obj)) {
- MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
- protop.set(JS::GetRealmFunctionPrototype(cx));
- } else {
- const js::Class* clasp = js::GetObjectClass(obj);
- MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
- ProtoGetter protoGetter =
- DOMIfaceAndProtoJSClass::FromJSClass(clasp)->mGetParentProto;
- protop.set(protoGetter(cx));
- }
- }
- return JS_WrapObject(cx, protop);
- }
- /**
- * Get the Xray expando class to use for the given DOM object.
- */
- const JSClass*
- XrayGetExpandoClass(JSContext* cx, JS::Handle<JSObject*> obj);
- /**
- * Delete a named property, if any. Return value is false if exception thrown,
- * true otherwise. The caller should not do any more work after calling this
- * function, because it has no way whether a deletion was performed and hence
- * opresult already has state set on it. If callers ever need to change that,
- * add a "bool* found" argument and change the generated DeleteNamedProperty to
- * use it instead of a local variable.
- */
- bool
- XrayDeleteNamedProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
- JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
- JS::ObjectOpResult& opresult);
- /**
- * Get the object which should be used to cache the return value of a property
- * getter in the case of a [Cached] or [StoreInSlot] property. `obj` is the
- * `this` value for our property getter that we're working with.
- *
- * This function can return null on failure to allocate the object, throwing on
- * the JSContext in the process.
- *
- * The isXray outparam will be set to true if obj is an Xray and false
- * otherwise.
- *
- * Note that the Slow version should only be called from
- * GetCachedSlotStorageObject.
- */
- JSObject*
- GetCachedSlotStorageObjectSlow(JSContext* cx, JS::Handle<JSObject*> obj,
- bool* isXray);
- inline JSObject*
- GetCachedSlotStorageObject(JSContext* cx, JS::Handle<JSObject*> obj,
- bool* isXray) {
- if (IsDOMObject(obj)) {
- *isXray = false;
- return obj;
- }
- return GetCachedSlotStorageObjectSlow(cx, obj, isXray);
- }
- extern NativePropertyHooks sEmptyNativePropertyHooks;
- extern const js::ClassOps sBoringInterfaceObjectClassClassOps;
- extern const js::ObjectOps sInterfaceObjectClassObjectOps;
- inline bool
- UseDOMXray(JSObject* obj)
- {
- const js::Class* clasp = js::GetObjectClass(obj);
- return IsDOMClass(clasp) ||
- JS_IsNativeFunction(obj, Constructor) ||
- IsDOMIfaceAndProtoClass(clasp);
- }
- #ifdef DEBUG
- inline bool
- HasConstructor(JSObject* obj)
- {
- return JS_IsNativeFunction(obj, Constructor) ||
- js::GetObjectClass(obj)->getConstruct();
- }
- #endif
- // Helpers for creating a const version of a type.
- template<typename T>
- const T& Constify(T& arg)
- {
- return arg;
- }
- // Helper for turning (Owning)NonNull<T> into T&
- template<typename T>
- T& NonNullHelper(T& aArg)
- {
- return aArg;
- }
- template<typename T>
- T& NonNullHelper(NonNull<T>& aArg)
- {
- return aArg;
- }
- template<typename T>
- const T& NonNullHelper(const NonNull<T>& aArg)
- {
- return aArg;
- }
- template<typename T>
- T& NonNullHelper(OwningNonNull<T>& aArg)
- {
- return aArg;
- }
- template<typename T>
- const T& NonNullHelper(const OwningNonNull<T>& aArg)
- {
- return aArg;
- }
- inline
- void NonNullHelper(NonNull<binding_detail::FakeString>& aArg)
- {
- // This overload is here to make sure that we never end up applying
- // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
- // try to, it should fail to compile, since presumably the caller will try to
- // use our nonexistent return value.
- }
- inline
- void NonNullHelper(const NonNull<binding_detail::FakeString>& aArg)
- {
- // This overload is here to make sure that we never end up applying
- // NonNullHelper to a NonNull<binding_detail::FakeString>. If we
- // try to, it should fail to compile, since presumably the caller will try to
- // use our nonexistent return value.
- }
- inline
- void NonNullHelper(binding_detail::FakeString& aArg)
- {
- // This overload is here to make sure that we never end up applying
- // NonNullHelper to a FakeString before we've constified it. If we
- // try to, it should fail to compile, since presumably the caller will try to
- // use our nonexistent return value.
- }
- MOZ_ALWAYS_INLINE
- const nsAString& NonNullHelper(const binding_detail::FakeString& aArg)
- {
- return aArg;
- }
- // Reparent the wrapper of aObj to whatever its native now thinks its
- // parent should be.
- nsresult
- ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObj);
- /**
- * Used to implement the Symbol.hasInstance property of an interface object.
- */
- bool
- InterfaceHasInstance(JSContext* cx, unsigned argc, JS::Value* vp);
- bool
- InterfaceHasInstance(JSContext* cx, int prototypeID, int depth,
- JS::Handle<JSObject*> instance,
- bool* bp);
- // Helper for lenient getters/setters to report to console. If this
- // returns false, we couldn't even get a global.
- bool
- ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj);
- // Given a JSObject* that represents the chrome side of a JS-implemented WebIDL
- // interface, get the nsIGlobalObject corresponding to the content side, if any.
- // A false return means an exception was thrown.
- bool
- GetContentGlobalForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj,
- nsIGlobalObject** global);
- void
- ConstructJSImplementation(const char* aContractId,
- nsIGlobalObject* aGlobal,
- JS::MutableHandle<JSObject*> aObject,
- ErrorResult& aRv);
- already_AddRefed<nsIGlobalObject>
- ConstructJSImplementation(const char* aContractId,
- const GlobalObject& aGlobal,
- JS::MutableHandle<JSObject*> aObject,
- ErrorResult& aRv);
- /**
- * Convert an nsCString to jsval, returning true on success.
- * These functions are intended for ByteString implementations.
- * As such, the string is not UTF-8 encoded. Any UTF8 strings passed to these
- * methods will be mangled.
- */
- bool NonVoidByteStringToJsval(JSContext *cx, const nsACString &str,
- JS::MutableHandle<JS::Value> rval);
- inline bool ByteStringToJsval(JSContext *cx, const nsACString &str,
- JS::MutableHandle<JS::Value> rval)
- {
- if (str.IsVoid()) {
- rval.setNull();
- return true;
- }
- return NonVoidByteStringToJsval(cx, str, rval);
- }
- template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
- struct PreserveWrapperHelper
- {
- static void PreserveWrapper(T* aObject)
- {
- aObject->PreserveWrapper(aObject, NS_CYCLE_COLLECTION_PARTICIPANT(T));
- }
- };
- template<class T>
- struct PreserveWrapperHelper<T, true>
- {
- static void PreserveWrapper(T* aObject)
- {
- aObject->PreserveWrapper(reinterpret_cast<nsISupports*>(aObject));
- }
- };
- template<class T>
- void PreserveWrapper(T* aObject)
- {
- PreserveWrapperHelper<T>::PreserveWrapper(aObject);
- }
- template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
- struct CastingAssertions
- {
- static bool ToSupportsIsCorrect(T*)
- {
- return true;
- }
- static bool ToSupportsIsOnPrimaryInheritanceChain(T*, nsWrapperCache*)
- {
- return true;
- }
- };
- template<class T>
- struct CastingAssertions<T, true>
- {
- static bool ToSupportsIsCorrect(T* aObject)
- {
- return ToSupports(aObject) == reinterpret_cast<nsISupports*>(aObject);
- }
- static bool ToSupportsIsOnPrimaryInheritanceChain(T* aObject,
- nsWrapperCache* aCache)
- {
- return reinterpret_cast<void*>(aObject) != aCache;
- }
- };
- template<class T>
- bool
- ToSupportsIsCorrect(T* aObject)
- {
- return CastingAssertions<T>::ToSupportsIsCorrect(aObject);
- }
- template<class T>
- bool
- ToSupportsIsOnPrimaryInheritanceChain(T* aObject, nsWrapperCache* aCache)
- {
- return CastingAssertions<T>::ToSupportsIsOnPrimaryInheritanceChain(aObject,
- aCache);
- }
- // The BindingJSObjectCreator class is supposed to be used by a caller that
- // wants to create and initialise a binding JSObject. After initialisation has
- // been successfully completed it should call ForgetObject().
- // The BindingJSObjectCreator object will root the JSObject until ForgetObject()
- // is called on it. If the native object for the binding is refcounted it will
- // also hold a strong reference to it, that reference is transferred to the
- // JSObject (which holds the native in a slot) when ForgetObject() is called. If
- // the BindingJSObjectCreator object is destroyed and ForgetObject() was never
- // called on it then the JSObject's slot holding the native will be set to
- // undefined, and for a refcounted native the strong reference will be released.
- template<class T>
- class MOZ_STACK_CLASS BindingJSObjectCreator
- {
- public:
- explicit BindingJSObjectCreator(JSContext* aCx)
- : mReflector(aCx)
- {
- }
- ~BindingJSObjectCreator()
- {
- if (mReflector) {
- js::SetReservedOrProxyPrivateSlot(mReflector, DOM_OBJECT_SLOT,
- JS::UndefinedValue());
- }
- }
- void
- CreateProxyObject(JSContext* aCx, const js::Class* aClass,
- const DOMProxyHandler* aHandler,
- JS::Handle<JSObject*> aProto, T* aNative,
- JS::MutableHandle<JSObject*> aReflector)
- {
- js::ProxyOptions options;
- options.setClass(aClass);
- JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aNative));
- aReflector.set(js::NewProxyObject(aCx, aHandler, proxyPrivateVal, aProto,
- options));
- if (aReflector) {
- mNative = aNative;
- mReflector = aReflector;
- }
- }
- void
- CreateObject(JSContext* aCx, const JSClass* aClass,
- JS::Handle<JSObject*> aProto,
- T* aNative, JS::MutableHandle<JSObject*> aReflector)
- {
- aReflector.set(JS_NewObjectWithGivenProto(aCx, aClass, aProto));
- if (aReflector) {
- js::SetReservedSlot(aReflector, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
- mNative = aNative;
- mReflector = aReflector;
- }
- }
- void
- InitializationSucceeded()
- {
- void* dummy;
- mNative.forget(&dummy);
- mReflector = nullptr;
- }
- private:
- struct OwnedNative
- {
- // Make sure the native objects inherit from NonRefcountedDOMObject so
- // that we log their ctor and dtor.
- static_assert(IsBaseOf<NonRefcountedDOMObject, T>::value,
- "Non-refcounted objects with DOM bindings should inherit "
- "from NonRefcountedDOMObject.");
- OwnedNative&
- operator=(T* aNative)
- {
- return *this;
- }
- // This signature sucks, but it's the only one that will make a nsRefPtr
- // just forget about its pointer without warning.
- void
- forget(void**)
- {
- }
- };
- JS::Rooted<JSObject*> mReflector;
- typename Conditional<IsRefcounted<T>::value, RefPtr<T>, OwnedNative>::Type mNative;
- };
- template<class T>
- struct DeferredFinalizerImpl
- {
- typedef typename Conditional<IsSame<T, nsISupports>::value,
- nsCOMPtr<T>,
- typename Conditional<IsRefcounted<T>::value,
- RefPtr<T>,
- nsAutoPtr<T>>::Type>::Type SmartPtr;
- typedef SegmentedVector<SmartPtr> SmartPtrArray;
- static_assert(IsSame<T, nsISupports>::value || !IsBaseOf<nsISupports, T>::value,
- "nsISupports classes should all use the nsISupports instantiation");
- static inline void
- AppendAndTake(SegmentedVector<nsCOMPtr<nsISupports>>& smartPtrArray, nsISupports* ptr)
- {
- smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
- }
- template<class U>
- static inline void
- AppendAndTake(SegmentedVector<RefPtr<U>>& smartPtrArray, U* ptr)
- {
- smartPtrArray.InfallibleAppend(dont_AddRef(ptr));
- }
- template<class U>
- static inline void
- AppendAndTake(SegmentedVector<nsAutoPtr<U>>& smartPtrArray, U* ptr)
- {
- smartPtrArray.InfallibleAppend(ptr);
- }
- static void*
- AppendDeferredFinalizePointer(void* aData, void* aObject)
- {
- SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
- if (!pointers) {
- pointers = new SmartPtrArray();
- }
- AppendAndTake(*pointers, static_cast<T*>(aObject));
- return pointers;
- }
- static bool
- DeferredFinalize(uint32_t aSlice, void* aData)
- {
- MOZ_ASSERT(aSlice > 0, "nonsensical/useless call with aSlice == 0");
- SmartPtrArray* pointers = static_cast<SmartPtrArray*>(aData);
- uint32_t oldLen = pointers->Length();
- if (oldLen < aSlice) {
- aSlice = oldLen;
- }
- uint32_t newLen = oldLen - aSlice;
- pointers->PopLastN(aSlice);
- if (newLen == 0) {
- delete pointers;
- return true;
- }
- return false;
- }
- };
- template<class T,
- bool isISupports=IsBaseOf<nsISupports, T>::value>
- struct DeferredFinalizer
- {
- static void
- AddForDeferredFinalization(T* aObject)
- {
- typedef DeferredFinalizerImpl<T> Impl;
- DeferredFinalize(Impl::AppendDeferredFinalizePointer,
- Impl::DeferredFinalize, aObject);
- }
- };
- template<class T>
- struct DeferredFinalizer<T, true>
- {
- static void
- AddForDeferredFinalization(T* aObject)
- {
- DeferredFinalize(reinterpret_cast<nsISupports*>(aObject));
- }
- };
- template<class T>
- static void
- AddForDeferredFinalization(T* aObject)
- {
- DeferredFinalizer<T>::AddForDeferredFinalization(aObject);
- }
- // This returns T's CC participant if it participates in CC or null if it
- // doesn't. This also returns null for classes that don't inherit from
- // nsISupports (QI should be used to get the participant for those).
- template<class T, bool isISupports=IsBaseOf<nsISupports, T>::value>
- class GetCCParticipant
- {
- // Helper for GetCCParticipant for classes that participate in CC.
- template<class U>
- static nsCycleCollectionParticipant*
- GetHelper(int, typename U::NS_CYCLE_COLLECTION_INNERCLASS* dummy=nullptr)
- {
- return T::NS_CYCLE_COLLECTION_INNERCLASS::GetParticipant();
- }
- // Helper for GetCCParticipant for classes that don't participate in CC.
- template<class U>
- static nsCycleCollectionParticipant*
- GetHelper(double)
- {
- return nullptr;
- }
- public:
- static nsCycleCollectionParticipant*
- Get()
- {
- // Passing int() here will try to call the GetHelper that takes an int as
- // its firt argument. If T doesn't participate in CC then substitution for
- // the second argument (with a default value) will fail and because of
- // SFINAE the next best match (the variant taking a double) will be called.
- return GetHelper<T>(int());
- }
- };
- template<class T>
- class GetCCParticipant<T, true>
- {
- public:
- static nsCycleCollectionParticipant*
- Get()
- {
- return nullptr;
- }
- };
- void
- FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
- bool
- ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
- JS::Handle<jsid> aId, bool* aResolvedp);
- bool
- MayResolveGlobal(const JSAtomState& aNames, jsid aId, JSObject* aMaybeObj);
- bool
- EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj);
- template <class T>
- struct CreateGlobalOptions
- {
- static const ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
- ProtoAndIfaceCache::NonWindowLike;
- static void TraceGlobal(JSTracer* aTrc, JSObject* aObj)
- {
- mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj);
- }
- static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
- {
- MOZ_ALWAYS_TRUE(TryPreserveWrapper(aGlobal));
- return true;
- }
- };
- template <>
- struct CreateGlobalOptions<nsGlobalWindow>
- {
- static const ProtoAndIfaceCache::Kind ProtoAndIfaceCacheKind =
- ProtoAndIfaceCache::WindowLike;
- static void TraceGlobal(JSTracer* aTrc, JSObject* aObj);
- static bool PostCreateGlobal(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
- };
- nsresult
- RegisterDOMNames();
- // The return value is true if we created and successfully performed our part of
- // the setup for the global, false otherwise.
- //
- // Typically this method's caller will want to ensure that
- // xpc::InitGlobalObjectOptions is called before, and xpc::InitGlobalObject is
- // called after, this method, to ensure that this global object and its
- // compartment are consistent with other global objects.
- template <class T, ProtoHandleGetter GetProto>
- bool
- CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache,
- const JSClass* aClass, JS::CompartmentOptions& aOptions,
- JSPrincipals* aPrincipal, bool aInitStandardClasses,
- JS::MutableHandle<JSObject*> aGlobal)
- {
- aOptions.creationOptions().setTrace(CreateGlobalOptions<T>::TraceGlobal);
- if (xpc::SharedMemoryEnabled()) {
- aOptions.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
- }
- aGlobal.set(JS_NewGlobalObject(aCx, aClass, aPrincipal,
- JS::DontFireOnNewGlobalHook, aOptions));
- if (!aGlobal) {
- NS_WARNING("Failed to create global");
- return false;
- }
- JSAutoCompartment ac(aCx, aGlobal);
- {
- js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
- NS_ADDREF(aNative);
- aCache->SetWrapper(aGlobal);
- dom::AllocateProtoAndIfaceCache(aGlobal,
- CreateGlobalOptions<T>::ProtoAndIfaceCacheKind);
- if (!CreateGlobalOptions<T>::PostCreateGlobal(aCx, aGlobal)) {
- return false;
- }
- }
- if (aInitStandardClasses &&
- !JS_InitStandardClasses(aCx, aGlobal)) {
- NS_WARNING("Failed to init standard classes");
- return false;
- }
- JS::Handle<JSObject*> proto = GetProto(aCx);
- if (!proto || !JS_SplicePrototype(aCx, aGlobal, proto)) {
- NS_WARNING("Failed to set proto");
- return false;
- }
- bool succeeded;
- if (!JS_SetImmutablePrototype(aCx, aGlobal, &succeeded)) {
- return false;
- }
- MOZ_ASSERT(succeeded,
- "making a fresh global object's [[Prototype]] immutable can "
- "internally fail, but it should never be unsuccessful");
- return true;
- }
- /*
- * Holds a jsid that is initialized to a pinned string, with automatic
- * conversion to Handle<jsid>, as it is held live forever by pinning.
- */
- class PinnedStringId
- {
- jsid id;
- public:
- PinnedStringId() : id(JSID_VOID) {}
- bool init(JSContext *cx, const char *string) {
- JSString* str = JS_AtomizeAndPinString(cx, string);
- if (!str)
- return false;
- id = INTERNED_STRING_TO_JSID(cx, str);
- return true;
- }
- operator const jsid& () {
- return id;
- }
- operator JS::Handle<jsid> () {
- /* This is safe because we have pinned the string. */
- return JS::Handle<jsid>::fromMarkedLocation(&id);
- }
- };
- bool
- GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp);
- bool
- GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp);
- bool
- GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
- bool
- GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
- bool
- StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp);
- // ConvertExceptionToPromise should only be called when we have an error
- // condition (e.g. returned false from a JSAPI method). Note that there may be
- // no exception on cx, in which case this is an uncatchable failure that will
- // simply be propagated. Otherwise this method will attempt to convert the
- // exception to a Promise rejected with the exception that it will store in
- // rval.
- //
- // promiseScope should be the scope in which the Promise should be created.
- bool
- ConvertExceptionToPromise(JSContext* cx,
- JSObject* promiseScope,
- JS::MutableHandle<JS::Value> rval);
- #ifdef DEBUG
- void
- AssertReturnTypeMatchesJitinfo(const JSJitInfo* aJitinfo,
- JS::Handle<JS::Value> aValue);
- #endif
- // This function is called by the bindings layer for methods/getters/setters
- // that are not safe to be called in prerendering mode. It checks to make sure
- // that the |this| object is not running in a global that is in prerendering
- // mode. Otherwise, it aborts execution of timers and event handlers, and
- // returns false which gets converted to an uncatchable exception by the
- // bindings layer.
- bool
- EnforceNotInPrerendering(JSContext* aCx, JSObject* aObj);
- // Handles the violation of a blacklisted action in prerendering mode by
- // aborting the scripts, and preventing timers and event handlers from running
- // in the window in the future.
- void
- HandlePrerenderingViolation(nsPIDOMWindowInner* aWindow);
- bool
- CallerSubsumes(JSObject* aObject);
- MOZ_ALWAYS_INLINE bool
- CallerSubsumes(JS::Handle<JS::Value> aValue)
- {
- if (!aValue.isObject()) {
- return true;
- }
- return CallerSubsumes(&aValue.toObject());
- }
- template<class T>
- inline bool
- WrappedJSToDictionary(JSContext* aCx, nsISupports* aObject, T& aDictionary)
- {
- nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
- if (!wrappedObj) {
- return false;
- }
- JS::Rooted<JSObject*> obj(aCx, wrappedObj->GetJSObject());
- if (!obj) {
- return false;
- }
- JSAutoCompartment ac(aCx, obj);
- JS::Rooted<JS::Value> v(aCx, JS::ObjectValue(*obj));
- return aDictionary.Init(aCx, v);
- }
- template<class T>
- inline bool
- WrappedJSToDictionary(nsISupports* aObject, T& aDictionary)
- {
- nsCOMPtr<nsIXPConnectWrappedJS> wrappedObj = do_QueryInterface(aObject);
- NS_ENSURE_TRUE(wrappedObj, false);
- JS::Rooted<JSObject*> obj(RootingCx(), wrappedObj->GetJSObject());
- NS_ENSURE_TRUE(obj, false);
- nsIGlobalObject* global = xpc::NativeGlobal(obj);
- NS_ENSURE_TRUE(global, false);
- // we need this AutoEntryScript here because the spec requires us to execute
- // getters when parsing a dictionary
- AutoEntryScript aes(global, "WebIDL dictionary creation");
- JS::Rooted<JS::Value> v(aes.cx(), JS::ObjectValue(*obj));
- return aDictionary.Init(aes.cx(), v);
- }
- template<class T, class S>
- inline RefPtr<T>
- StrongOrRawPtr(already_AddRefed<S>&& aPtr)
- {
- return aPtr.template downcast<T>();
- }
- template<class T,
- class ReturnType=typename Conditional<IsRefcounted<T>::value, T*,
- nsAutoPtr<T>>::Type>
- inline ReturnType
- StrongOrRawPtr(T* aPtr)
- {
- return ReturnType(aPtr);
- }
- template<class T, template<typename> class SmartPtr, class S>
- inline void
- StrongOrRawPtr(SmartPtr<S>&& aPtr) = delete;
- template<class T>
- struct StrongPtrForMember
- {
- typedef typename Conditional<IsRefcounted<T>::value,
- RefPtr<T>, nsAutoPtr<T>>::Type Type;
- };
- namespace binding_detail {
- inline
- JSObject*
- GetHackedNamespaceProtoObject(JSContext* aCx)
- {
- return JS_NewPlainObject(aCx);
- }
- } // namespace binding_detail
- // Resolve an id on the given global object that wants to be included in
- // Exposed=System webidl annotations. False return value means exception
- // thrown.
- bool SystemGlobalResolve(JSContext* cx, JS::Handle<JSObject*> obj,
- JS::Handle<jsid> id, bool* resolvedp);
- // Enumerate all ids on the given global object that wants to be included in
- // Exposed=System webidl annotations. False return value means exception
- // thrown.
- bool SystemGlobalEnumerate(JSContext* cx, JS::Handle<JSObject*> obj);
- // Slot indexes for maplike/setlike forEach functions
- #define FOREACH_CALLBACK_SLOT 0
- #define FOREACH_MAPLIKEORSETLIKEOBJ_SLOT 1
- // Backing function for running .forEach() on maplike/setlike interfaces.
- // Unpacks callback and maplike/setlike object from reserved slots, then runs
- // callback for each key (and value, for maplikes)
- bool ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp);
- // Unpacks backing object (ES6 map/set) from the reserved slot of a reflector
- // for a maplike/setlike interface. If backing object does not exist, creates
- // backing object in the compartment of the reflector involved, making this safe
- // to use across compartments/via xrays. Return values of these methods will
- // always be in the context compartment.
- bool GetMaplikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
- size_t aSlotIndex,
- JS::MutableHandle<JSObject*> aBackingObj,
- bool* aBackingObjCreated);
- bool GetSetlikeBackingObject(JSContext* aCx, JS::Handle<JSObject*> aObj,
- size_t aSlotIndex,
- JS::MutableHandle<JSObject*> aBackingObj,
- bool* aBackingObjCreated);
- // Get the desired prototype object for an object construction from the given
- // CallArgs. Null is returned if the default prototype should be used.
- bool
- GetDesiredProto(JSContext* aCx, const JS::CallArgs& aCallArgs,
- JS::MutableHandle<JSObject*> aDesiredProto);
- // This function is expected to be called from the constructor function for an
- // HTML element interface; the global/callargs need to be whatever was passed to
- // that constructor function.
- already_AddRefed<nsGenericHTMLElement>
- CreateHTMLElement(const GlobalObject& aGlobal, const JS::CallArgs& aCallArgs,
- JS::Handle<JSObject*> aGivenProto, ErrorResult& aRv);
- void
- SetDocumentAndPageUseCounter(JSContext* aCx, JSObject* aObject,
- UseCounter aUseCounter);
- // Warnings
- void
- DeprecationWarning(JSContext* aCx, JSObject* aObject,
- nsIDocument::DeprecatedOperations aOperation);
- // A callback to perform funToString on an interface object
- JSString*
- InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
- unsigned /* indent */);
- namespace binding_detail {
- // Get a JS global object that can be used for some temporary allocations. The
- // idea is that this should be used for situations when you need to operate in
- // _some_ compartment but don't care which one. A typical example is when you
- // have non-JS input, non-JS output, but have to go through some sort of JS
- // representation in the middle, so need a compartment to allocate things in.
- //
- // It's VERY important that any consumers of this function only do things that
- // are guaranteed to be side-effect-free, even in the face of a script
- // environment controlled by a hostile adversary. This is because in the worker
- // case the global is in fact the worker global, so it and its standard objects
- // are controlled by the worker script. This is why this function is in the
- // binding_detail namespace. Any use of this function MUST be very carefully
- // reviewed by someone who is sufficiently devious and has a very good
- // understanding of all the code that will run while we're using the return
- // value, including the SpiderMonkey parts.
- JSObject* UnprivilegedJunkScopeOrWorkerGlobal();
- } // namespace binding_detail
- } // namespace dom
- } // namespace mozilla
- #endif /* mozilla_dom_BindingUtils_h__ */
|